diff options
402 files changed, 150297 insertions, 0 deletions
diff --git a/.distribution b/.distribution new file mode 100644 index 0000000..63738cc --- /dev/null +++ b/.distribution @@ -0,0 +1 @@ +1.14 diff --git a/.patchlevel b/.patchlevel new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/.patchlevel @@ -0,0 +1 @@ +7 @@ -0,0 +1,257 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 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 +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. + + 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. + + 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 +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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +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. + + 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. + + 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 + 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. + + 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. + + 7. 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 +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 +Foundation. + + 8. 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 +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 +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. 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 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +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 +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 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + 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. + + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + +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 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. + +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: + + 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. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/CWRU/PLATFORMS b/CWRU/PLATFORMS new file mode 100644 index 0000000..a792966 --- /dev/null +++ b/CWRU/PLATFORMS @@ -0,0 +1,18 @@ +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 diff --git a/CWRU/POSIX.NOTES b/CWRU/POSIX.NOTES new file mode 100644 index 0000000..bc9a969 --- /dev/null +++ b/CWRU/POSIX.NOTES @@ -0,0 +1,63 @@ +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. + +The following list is what's changed when `posixly_correct' is enabled: + +1. When a command in the hash table no longer exists, bash will re-search + $PATH to find the new location. + +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. The <> redirection does not open a file for both stdin and stdout, but + rather opens it for read-write on fd 0. + +5. Reserved words may not be aliased. + +6. The Posix.2 PS1 and PS2 expansions of `!' -> history number and `!!' -> `!' + are enabled. + +7. Interactive comments are enabled by default. (Note that this version has + them on by default anyway.) + +8. 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. + +10. The default history file is ~/.sh_history (default value of $HISTFILE). + +11. 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. + +13. Redirection operators do not perform pathname 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 + +There is other Posix.2 behavior that bash does not implement. Specifically: + +1. There are no `special builtins' and `regular builtins'. All builtins + are equivalent. This means that: + + 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 + +2. $LINENO does not represent the line number of a command within a function + +3. The arithmetic evaluator does not implement the `e ? e1 : e2' conditional + expression diff --git a/CWRU/README b/CWRU/README new file mode 100644 index 0000000..8e3398d --- /dev/null +++ b/CWRU/README @@ -0,0 +1,26 @@ +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 + +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 +OS-BUGS - directory with messages detailing some OS bugs and + the bash workarounds diff --git a/CWRU/changelog b/CWRU/changelog new file mode 100644 index 0000000..11d6775 --- /dev/null +++ b/CWRU/changelog @@ -0,0 +1,786 @@ + 6/2 + --- +lib/readline/readline.c + - fixed an off-by-one error in the kill ring reallocation code + in rl_kill_text + +Makefile + - replaced instances of /bin/sh with $(SHELL) + +Makefile, cpp-Makefile, documentation/Makefile + - added a working `uninstall' target + +[1.14.0 FCS release made available for FTP] + + 6/3 + --- +README + - added note about building with gcc, same as in Makefile + +documentation/Makefile + - some versions of make don't understand `$*' in a regular recipe; + replace with features.dvi in the recipe for features.ps + + 6/4 + --- +subst.c + - fix up the calls to string_extract_double_quoted and + string_extract_single_quoted in char_is_quoted so the initial + value of the index is *after* the opening quote character + - make sure we only return 1 from char_is_quoted if the index + into the string after a call to string_extract_double_quoted or + string_extract_single_quoted is *greater than* `eindex' + +lib/readline/complete.c + - change the order and sense of the quoting tests in + rl_complete_internal so that the expensive char_is_quoted + is only called if `scan' actually is a word break character + +shell.c + - fixed a typo in the test for a restricted shell + +builtins/exec.def + - need to include flags.h + + 6/6 + --- +make_cmd.c + - make sure that we don't try to walk down a null command tree + in connect_async_list (tickled by `(command &) &') + - if a command has the CMD_WANT_SUBSHELL bit set in its flags, + don't even try to walk the command tree and move the `&'; + just connect the command with a null command using `&' + +execute_cmd.c + - make sure we don't try to reference a command struct without + first checking it (case '&') + + 6/7 + --- +machines.h + - fix a typo in the NeXT/i386 description; change the NeXT description + to #define HAVE_RESOURCE if not already defined rather than putting + -DHAVE_RESOURCE into the SYSDEP_CFLAGS + + 6/9 + --- +Makefile + - make sure all of the rules that reinvoke `make' have the + `-f bash-Makefile' before the assignment statements; some + versions of make like it that way + +variables.c + - make sure that `interactive' is set to 0 before evaluating the + string containing an exported function obtained from the + environment, so that it does not try to execute PROMPT_COMMAND + (this may not be the best fix) + + 6/13 + ---- +documentation/Makefile + - make sure all of the directories exist before trying to install + doc files into them + +lib/readline/history.c + - add a missing O_TRUNC to the open call for writing in + history_truncate_file + +trap.c + - run_interrupt_trap should only try to run the trap command if + the value is not IMPOSSIBLE_TRAP_HANDLER + +Makefile + - add `realclean' + +lib/readline/complete.c + - do the same kind of double-quoting a replacement string if the + user supplies the opening double quote as we would if we were + adding both quotes ourselves + +variables.c + - fixed the variable initialization so that history_control/HISTCONTROL + can be inherited from a parent shell + +INSTALL, README, cpp-Makefile, documentation/bash.1, documentation/readline.3 + - ai.mit.edu -> prep.ai.mit.edu + +shell.c + - fixed a problem with setting no_line_editing to the result of the + check for running inside emacs, thereby losing any value + initialized by the `-nolineediting' flag + +cpp-Makefile + - `make distclean' will now remove the `installed-bash' link + +print_cmd.c + - fixed a problem with undefined variables when HAVE_VARARGS_H is + not defined + + 6/14 + ---- +lib/readline/history.c + - fixed an error in the csh history expansion code so that the + `-y' word designator now expands to `0-y' rather than `1-y' + +lib/readline/isearch.c + - changed an absolute check for a character falling within the + ASCII 32-126 range (printable chars) with checks for CTRL_P + and META_CHAR and a check against the value RUBOUT + - changed a `break' to a `continue' so that the first non-matching + character in the search string does not cause the search to + end abruptly + - initialize prev_line_found to 0 at the top of rl_search_history + to avoid duplicate history lines being saved across searches + +lib/readline/rltty.c + - consolidated repeated code for setting special characters into + `SET_SPECIAL' defines + +lib/readline/readline.c + - include <sys/ioctl.h> if VSTATUS is defined + - add bindable command rl_tty_status (unbound by default) + +lib/readline/funmap.c + - assign bindable command name `tty-status' to rl_tty_status + +INSTALL + - add note about compiling with gcc, same text as README + +lib/readline/display.c + - many changes and tweaks to make redisplay work better when the + prompt has invisible characters. These changes are non-optimal + in that the prompt is redrawn more than it needs to be, but + things are a hell of a lot better than they were + + 6/15 + ---- +documentation/Makefile + - make a variable NROFF that people can set to `groff -Tascii' if + they don't have real nroff + - changed the suffix rules to use $< + +support/bashbug.sh + - if rmail doesn't exist or fails, save the bug report in + ~/dead.bashbug + +execute_cmd.c + - in setup_async_signals, only ignore SIGINT and SIGQUIT if job + control is not active. If it is active and the job is restarted, + SIGINT remains ignored, and the now-foregrounded job is not + interruptible + +subst.c + - fixed up a problem with char_is_quoted that caused backslash- + escaped characters to cause incorrect results + +tests/run-dollars, tests/dollar-at.sh, tests/dollar-star.sh + - since the error messages produced by `cat' vary, changed `cat' + to `recho' and updated the correct answers file + +machines.h + - fixes to CRAY_STACKSEG_END definitions for different versions of + Unicos on the YMP (from Bill Jones) + - Motorola SVR4 machines have getcwd() and should not undef + HAVE_GETCWD + - on hpux 9.x, don't try to link with -lPW if compiling with gcc + (for alloca) + +parse.y + - an ugly fix for a compiler problem with structure assignment on + the cray + + 6/16 + ---- +builtins/wait.def + - replaced a call to sscanf with a validity check using all_digits() + and a call to atoi, since a pid_t is not necessarily an int, and + the sscanf clobbered the stack frame on systems where it is shorter + than an int (e.g., SCO) + +lib/readline/display.c + - since META_CHAR and the other macros only work with unsigned + chars, make rl_character_len convert its argument to an unsigned + char before testing it + +documentation/Makefile + - use $(INSTALL_DATA) instead of $(CP) to install the man pages and + info files + +cpp-Makefile + - use INSTALL_PROGRAM and INSTALL_DATA to install binaries and + documentation; pass both values to installs in subdirectories + + 6/18 + ---- +builtins/ulimit.def + - compensate for systems which define RLIMIT_OFILE instead of + RLIMIT_NOFILE, or don't provide such a compatibility define + themselves + +shell.c + - make maybe_execute_file check for directories and print an + appropriate error message, since it's doing an fstat anyway + +support/mksysdefs + - added support for a `-s srcdir' option so it can find + cpp-Makefile if ansi-Makefile is to be created + +Makefile + - call mksysdefs with -s $(srcdir) + +jobs.c + - add the magic #undef lines to avoid redefinition warnings on + SunOS 4 only + + 6/20 + ---- +cpp-Makefile + - install `bashbug' with `make install' + +trap.c + - make sure that `interactive' is set to 0 when running trap + commands + +builtins/umask.c + - fixed typo in usage error message + +subst.c + - fix process_substitute to set subshell_environment + +jobs.c, nojobs.c + - only mess with the terminal settings for an interactive shell + that is not in a subshell environment + + 6/21 + ---- +lib/readline/history.h + - add extern declaration of history_get + +builtins/fc.def + - make history replacement when using `r' or `fc -s' obey the + setting of HISTCONTROL + +general.c + - in canonicalize_pathname, preserve a double // at the start + of an absolute pathname, since that means something special + for the network directory system + +README, INSTALL + - updated information about submitting bug reports + +lib/readline/vi_mode.c, lib/readline/isearch.c + - make sure unistd.h is included before rldefs.h, if + HAVE_UNISTD_H is defined + + 6/24 + ---- +lib/readline/complete.c + - add `#' to the list of characters which cause a completed filename + to be quoted + +execute_cmd.c + - be more careful about closing pipe file descriptors in do_piping; + don't want to have `dup2(i, i); close(i);' problem + +lib/readline/{keymaps,readline}.h + - include local copies of include files if READLINE_LIBRARY is + defined, otherwise include the `official, installed' versions + using #include <readline/xxx.h> + +lib/readline/*.c + - define READLINE_LIBRARY before including any files + - include only `local' copies of include files using #include "xxx.h" + rather than #include <readline/xxx.h> + + 6/26 + ---- +execute_cmd.c + - check for clobbering the bash input stream before closing a file + descriptor due to an r_close_this redirection + +lib/readline/history.c + - made history_expand inhibit history expansion if the history + expansion char is set to 0 + +lib/readline/chardefs.h + - moved savestring() definition to rldefs.h + - changed lowercase_p, uppercase_p, to_lower, to_upper defines to + use <ctype.h> macros rather than assume ASCII + +lib/readline/bind.c, general.c, general.h + - use strcasecmp, strncasecmp instead of str[n]icmp if + HAVE_STRCASECMP is defined + +cpp-Makefile + - pass -DHAVE_STRCASECMP to builds in the libraries, primarily + readline + +machines.h + - add HAVE_STRCASECMP to the entries for BSD/386, NetBSD, FreeBSD, + and 4.4 BSD + +builtins/hash.def + - add a fourth parameter to remember_filename, the initial value + of times_found (0 if we're just looking it up for `hash', 1 + for the command execution code) + +execute_cmd.c + - call remember_filename with an initial value of 1 for times_found + +builtins/wait.def + - handle a null argument with an error message + +builtins/common.c + - parse_and_execute now takes a third parameter: the value for + `interactive' while it is executing commands + +bashline.c, jobs.c, parse.y, shell.c, subst.c, trap.c, variables.c + - set the new third argument to parse_and_execute appropriately + +builtins/eval.def, builtins/fc.def, builtins/source.def + - set the new third argument to parse_and_execute appropriately + +builtins/help.def + - changed a call to strnicmp to strncmp when trying to find what + to give help on; it seems more correct + + 6/27 + ---- +machines.h + - cleaned up the SunOS section so it no longer relies on + HAVE_SHARED_LIBS being defined; it uses SunOS4 and SunOS5 + instead + +support/mksysdefs + - define SYSDEF to be SunOS4 or SunOS5 depending on the output + of uname rather than looking for ld.so + + 6/29 + ---- +machines.h + - minor change to the ardent titan machine description + - move the ardent and stardent descriptions before the + mips riscos description + +print_cmd.c + - ardent machines also need the extern declaration for printf + +make_cmd.c + - connect_async_list should do its work only if the lists to be + backgrounded are connected with `;'. This makes `;' bind tighter + than `&', so only the last job in the list is backgrounded. All + other lists should have the entire thing put in the background + +parse.y + - added a function `print_prompt' to take care of displaying the + prompt string if readline is not being used. This fixes problems + with the prompt being displayed before the status of completed + jobs is printed + + 6/30 + ---- +builtins/fg_bg.def + - `fg' and `bg' now print error messages if invoked when job control + is disabled + +lib/readline/rltty.c + - if not compiled into the shell, make get_tty_settings get and set + the window size. This noop stops the process if it is started in + the background + +lib/readline/readline.c + - provide a function version of savestring, if not being compiled + into the shell, since the macro has been removed from the + `public' header files + +lib/readline/readline.h + - provide all extern function declarations without checking whether + VI_MODE or PAREN_MATCHING are defined. It does not hurt to define + them if they are not used and not in the library, and other + applications using readline can't tell whether or not VI_MODE was + defined when the library was compiled anyway + + 7/1 + --- +machines.h + - add #undef HAVE_DIRENT_H to the ardent titan description + + 7/2 + --- +lib/readline/chardefs.h + - removed META_P define, renamed CTRL_P to CTRL_CHAR + +lib/readline/bind.c, lib/readline/isearch.c + - changed instances of CTRL_P to CTRL_CHAR + +lib/readline/search.c + - include <unistd.h> before rldefs.h, if HAVE_UNISTD_H is defined + +lib/readline/readline.c + - declare PC, UP, and BC as extern rather than `local' to the + readline library + + 7/5 + --- +bashline.c + - implement command word completion inside of command substitution + with a new function: `command_subst_completion_function' + +subst.c + - new function to help with command subst completion: unclosed_pair + +lib/readline/complete.c + - new variable rl_filename_quoting_desired, which can be set to 0 + to inhibit the quoting of filenames after completion + +lib/readline/readline.h + - declare rl_filename_completion_desired and + rl_filename_quoting_desired + +builtins/bind.def + - don't save the old value of rl_outstream before initializing + readline -- it saves garbage values and screws up readline + +parse.y + - don't have private state telling whether or not readline has + been initialized -- use bash_readline_initialized like other + functions in bashline.c + +lib/readline/readline.c + - make the default 8-bit behavior be based on whether LC_CTYPE is + defined and its value (accept iso-8859-1 or iso_8859_1) + + 7/6 + --- +variables.c + - fix up the declaration of getenv() for convex machines + + 7/7 + --- +lib/readline/readline.c + - fixed up typos in the declaration of `savestring' + +lib/readline/history.c + - fixed an off-by-one error in the ADD_CHAR macro which caused one + extra character to be overwritten, causing the gnu malloc to abort + when that one character was at the end of an allocated block + - changed the ADD_STRING macro to avoid some unnecessary xreallocs + +lib/readline/display.c + - fixed a problem with move_cursor_relative -- function now returns + immediately if it has nothing to do + - fixed another problem with displaying prompts with invisible chars + +lib/readline/chardefs.h + - fixed the CTRL macro to be right (agree with the BSD kernel, for + example) + +cpp-Makefile + - fixed typo in the `install' recipe + + 7/8 + --- +support/srcdir + - fixed to handle srcdir when it begins with ./ or ../ to handle + $(srcdir) being a relative path better + +cpp-Makefile + - changed some include paths to $(BUILTIN_ABSSRC) when building in + `builtins' to handle $(srcdir) being a relative path + - change the `chmod' on bashbug to turn on read and execute for all + - added a couple of definitions to make it easier for a later + `configure' program + +support/mksysdefs + - added a -i option to specify an alternate set of directories to + search for include files + +lib/readline/bind.c + - in rl_read_init_file, when skipping whitespace at the start of + the line, decrement `i' so that we don't jump past the start + of the next line + +machines.h + - SCOv4 has a `robust' opendir that checks that you're actually + opening a directory + + 7/11 + ---- +lib/readline/complete.c + - make sure a word break character is unquoted before using it to + separate out the current word for completing + +machines.h + - new machine description: NetBSD on motorola m68k machines like + the hp300 + - undef HAVE_GETWD in the generic svr4 machine description, like + other svr4 descriptions + +lib/readline/rltty.c + - make sure to fflush (rl_outstream) after toggling the setting + of the keypad and meta key + +portbash/libc.sh + - add a test for OPENDIR_NOT_ROBUST + +support/getcppsyms.c + - output __svr4__ if we find __uxps__ (this makes the Fujitsu port of + SVR4 to the sparc build OK) + + 7/12 + ---- +lib/readline/display.c + - more display-related fixes when the prompt has invisible chars; + this time for screen updates when moving between screen lines + +lib/readline/readline.c, lib/readline/display.c + - changes to make readline work with terminals that have auto-wrap + from Per Bothner (new function _rl_update_final, term_xn changes, + some efficiency speedups, new function space_to_eol) + + 7/13 + ---- +lib/readline/display.c + - after moving up screen lines using term_up in _rl_move_vert, if + the new screen line is 0, _rl_last_c_pos needs to be adjusted + to take invisible characters into account. This was the source + of many bugs + + + 7/14 + ---- +documentation/Makefile + - change instances of `groff' to `${GROFF}', GROFF is set to + `groff' by default + +general.c, variables.c + - moved `qsort_string_compare' from variables.c to general.c + +general.h, variables.h + - moved declaration of `qsort_string_compare' from variables.h + to general.h + +alias.c, lib/readline/funmap.c + - moved qsort auxiliary functions after their use and added + forward declarations to avoid warnings from ANSI C compilers + +memalloc.h + - hpux_9 needs alloca declared as `extern void *' if __STDC__ + is defined + +support/mksysdefs + - removed HAVE_SHARED_LIBS entirely + - make a call to /bin/uname -X for SCO machines to avoid running + a different uname from the $PATH + +machines.h + - new descriptions: Intel i860 running SVR4, Tahoe running 4.3 BSD + - changed descriptions: Mips/RiscOS, DG AViiON, unknown machine + +jobs.c + - changes to how the shell handles foreground jobs dying of SIGINT: + an interactive shell using job control will no longer + act as if it received a SIGINT if the foreground job + dies from a SIGINT + + a non-interactive shell or shell without job control tries + to differentiate between SIGINTs it has seen (in + wait_sigint_handler) and a foreground job dying of a SIGINT + not sent from the keyboard, and runs the normal SIGINT code + only in the former case + + 7/15 + ---- +support/mksysdefs + - check for ${UNAME}${RELEASE} expanding to `SunOS4*' or `SunOS5*' + to set SYSDEF to SunOS4 or SunOS5, respectively. Apparently + this does not work for Solbourne + + 7/18 + ---- + +lib/readline/rltty.c + - if output is being flushed on termios systems, loop until the + FLUSHO bit is no longer set in the termios struct + +support/mksysdefs + - added a -A flag to force creation of ansi-Makefile + +machines.h + - new entry for Tandem machines running SVR3 + + 7/19 + ---- +lib/readline/rldefs.h + - include <termcap.h> if HAVE_TERMCAP_H is defined + - use <termio.h> stuff if HAVE_TERMIO_H is defined and _POSIX_VERSION + is not defined + +lib/readline/rldefs.h, lib/readline/history.c + - include "config.h" if HAVE_CONFIG_H is defined + +lib/readline/{rldefs.h,signals.c,readline.c} + - WINSIZE_IN_IOCTL_H -> GWINSZ_IN_SYS_IOCTL for compatibility with + other GNU programs + +lib/readline/doc/Makefile + - fixed up to create the readline and history manuals in dvi and + ps format + +lib/readline/Makefile + - changes inspired by the standalone readline-2.0 distribution + + 7/20 + ---- +lib/readline/history.c + - new function, history_is_stifled (), returns history_stifled + - set history_state flags member in the history state functions + +lib/readline/history.h + - reorganized the function declarations, added missing declarations + - history_stifled is no longer exported by the library + - added a `flags' member to the HISTORY_STATE structure + +bashline.c + - use history_is_stifled () instead of history_stifled + +lib/readline/readline.c, lib/readline/vi_mode.c + - filled in correct argument declarations for functions called via + keymaps (count, key) + +lib/readline/complete.c + - efficiency improvement for compare_strings + + 7/21 + ---- +examples/dirfuncs + - new directory functions from ksh book, contributed by + Ken Konecki (kenk@wfg.com) + +machines.h + - hpux_8 and hpux_9 should both #undef HAVE_ALLOCA unless gcc is + being used + + 7/22 + ---- +bashline.c + - fixed up command_word_completion_function so that filenames with + leading tildes are completed correctly + + 7/26 + ---- +builtins/read.def + - if -r not given, make sure CTLESC is removed from input string + when reading \<newline> + +lib/readline/readline.c + - new function bind_arrow_keys, which binds vt100/ansi arrow key + escape sequences after reading the termcap definition and the + inputrc file + - new function rl_yank_last_arg, which does what insert-last-arg + does in bash + +lib/readline/emacs_keymap.c + - remove default bindings to rl_arrow_keys for M-[ and M-O + - rl_yank_last_arg is now bound to `M-.' and `M-_' in + emacs_meta_keymap + +subst.c + - when performing process substitution on systems with /dev/fd, + make sure the child clears the slot in dev_fd_list it gets + from its parent so the file descriptor does not get closed + inappropriately if reallocated by, e.g., pipe(2) + +bashline.c + - removed insert_last_arg and the calls to bind in to `M-.' and `M-_'. + `insert-last-argument' is now bound to rl_yank_last_arg for + backwards compatibility + +lib/readline/funmap.c + - `yank-last-arg' is now a named command for rl_yank_last_arg + + +documentation/bash.1, documentation/readline.3 + - add description of yank-last-arg as one of the readline user + commands + +lib/readline/doc/rluser.texinfo + - added description of yank-last-arg + +builtins/getopts.def + - fixed a typo in the int-to-string code computing the value to set + OPTIND to: had '\0' instead of '0' + - made getopts handle the case where there are more than 9 dollar + variables (where rest_of_args is non-null) correctly + + 7/28 + ---- +lib/readline/display.c + - fixes to the display code for single-line-display in the presence + of prompts containing invisible characters + +lib/readline/readline.c + - if we are using horizontal scrolling and we have term_xn, decrement + the screenwidth by 1, since we won't be doing any line wrapping + + 7/31 + ---- +jobs.c + - new variable `freeze_jobs_list' to set when changes to the jobs + list or status of jobs in the list (other than calling something + like `jobs -n') are undesirable. This is set when execuing traps + on SIGCHLD + + 8/1 + --- +subst.c + - check that `~' is unquoted before performing tilde expansion in + an assignment statement + + 8/3 + --- +bracecomp.c + - keep brace completion from dumping core if there is only one + match + +lib/readline/chardefs.h + - add a define for digit_p, which returns the value of isdigit() + +lib/readline/readline.c + - added function equivalents for uppercase_p, lowercase_p, to_upper, + to_lower, pure_alphabetic, digit_p, and digit_value + - replaced calls to numeric () with calls to digit_p, removed + definition of numeric () + +lib/readline/history.c + - digit -> digit_p + +lib/readline/vi_mode.c + - replaced uses of the `isletter' define to use pure_alphabetic + from chartypes.h + - replaced uses of `numeric' with calls to digit_p + - added do...while(0) to `exchange' define + + + 8/4 + --- +execute_cmd.c + - make sure execute_function saves and restores the current loop + count with unwind_protect_int + +documentation/features.texi + - change the `Shell Command Line Options' section to `Invoking + Bash' to be closer to the GNU coding standards + + 8/5 + --- +builtins/read.def + - fixed up a memory leak and made behavior correct when no + variables given and backslash escaped at least one input char + - if we added CTLESC anywhere while reading the input string, + make sure we call dequote_string on each word of the input + before calling bind_variable with that string + +subst.c + - made an efficiency improvement to dequote_string -- don't + do anything when we see CTLESC, just `continue' the loop diff --git a/CWRU/misc/aux-mach-desc b/CWRU/misc/aux-mach-desc new file mode 100644 index 0000000..71a8dab --- /dev/null +++ b/CWRU/misc/aux-mach-desc @@ -0,0 +1,20 @@ +/* ************************ */ +/* */ +/* 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/CWRU/misc/bison b/CWRU/misc/bison new file mode 100755 index 0000000..b819c90 --- /dev/null +++ b/CWRU/misc/bison @@ -0,0 +1,7 @@ +#! /bin/sh + +if [ "$1" = '-y' ]; then + shift +fi + +exec /usr/bin/yacc ${1+"$@"} diff --git a/CWRU/misc/open-files.c b/CWRU/misc/open-files.c new file mode 100644 index 0000000..8f4d18e --- /dev/null +++ b/CWRU/misc/open-files.c @@ -0,0 +1,16 @@ +#include <sys/types.h> +#include <fcntl.h> +#include <sys/file.h> +#include <stdio.h> + +main() +{ + register int i; + + for (i = 0; i < getdtablesize(); i++) { + if (fcntl(i, F_GETFD, 0) != -1) + fprintf(stderr, "fd %d: open\n", i); + } + exit(0); +} + diff --git a/CWRU/misc/pid.c b/CWRU/misc/pid.c new file mode 100644 index 0000000..458fde4 --- /dev/null +++ b/CWRU/misc/pid.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +main() +{ + fprintf(stderr, "%d\n", getpid()); + exit(0); +} diff --git a/CWRU/misc/sigs.c b/CWRU/misc/sigs.c new file mode 100644 index 0000000..ea9f955 --- /dev/null +++ b/CWRU/misc/sigs.c @@ -0,0 +1,27 @@ +#include <signal.h> +#include <stdio.h> + +extern char *sys_siglist[]; + +typedef void sighandler(); + +main(argc, argv) +int argc; +char **argv; +{ + register int i; + sighandler *h; + + for (i = 1; i < NSIG; i++) { + h = signal(i, SIG_DFL); + if (h != SIG_DFL) { + if (h == SIG_IGN) + fprintf(stderr, "%d: ignored (%s)\n", i, sys_siglist[i]); + else + fprintf(stderr, "%d: caught (%s)\n", i, sys_siglist[i]); + } + } + exit(0); +} + + diff --git a/CWRU/misc/sigstat.c b/CWRU/misc/sigstat.c new file mode 100644 index 0000000..f1ac557 --- /dev/null +++ b/CWRU/misc/sigstat.c @@ -0,0 +1,206 @@ +/* + * sigstat - print out useful information about signal arguments + * + */ + +#include <sys/types.h> +#include <signal.h> +#include <stdio.h> + +extern char *strrchr(); +static char *signames[NSIG]; + +char *progname; + +void sigstat(); + +main(argc, argv) +int argc; +char **argv; +{ + register int i; + char *t; + + if (t = strrchr(argv[0], '/')) + progname = ++t; + else + progname = argv[0]; + init_signames(); + if (argc == 1) { + for (i = 1; i < NSIG; i++) + sigstat(i); + exit(0); + } + for (i = 1; i < argc; i++) + sigstat(atoi(argv[i])); + exit(0); +} + +void +sigstat(sig) +int sig; +{ + struct sigaction oact; + char *signame; + sigset_t set, oset; + int blocked; + + if (sig < 0 || sig >= NSIG) { + fprintf(stderr, "%s: %d: signal out of range\n", progname, sig); + return; + } + signame = signames[sig]; + sigemptyset(&oset); + sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset); + if (sigismember(&oset, sig)) + printf("%s: signal is blocked\n", signame); + sigaction(sig, (struct sigaction *)NULL, &oact); + if (oact.sa_handler == SIG_IGN) + printf("%s: signal is ignored\n", signame); + else if (oact.sa_handler == SIG_DFL) + printf("%s: signal is defaulted\n", signame); + else + printf("%s: signal is trapped (?)\n", signame); +} + +init_signames() +{ + register int i; + bzero(signames, sizeof(signames)); + +#if defined (SIGHUP) /* hangup */ + signames[SIGHUP] = "SIGHUP"; +#endif +#if defined (SIGINT) /* interrupt */ + signames[SIGINT] = "SIGINT"; +#endif +#if defined (SIGQUIT) /* quit */ + signames[SIGQUIT] = "SIGQUIT"; +#endif +#if defined (SIGILL) /* illegal instruction (not reset when caught) */ + signames[SIGILL] = "SIGILL"; +#endif +#if defined (SIGTRAP) /* trace trap (not reset when caught) */ + signames[SIGTRAP] = "SIGTRAP"; +#endif +#if defined (SIGABRT) /* */ + signames[SIGABRT] = "SIGABRT"; +#endif +#if defined (SIGIOT) /* IOT instruction */ + signames[SIGIOT] = "SIGIOT"; +#endif +#if defined (SIGEMT) /* EMT instruction */ + signames[SIGEMT] = "SIGEMT"; +#endif +#if defined (SIGFPE) /* floating point exception */ + signames[SIGFPE] = "SIGFPE"; +#endif +#if defined (SIGKILL) /* kill (cannot be caught or ignored) */ + signames[SIGKILL] = "SIGKILL"; +#endif +#if defined (SIGBUS) /* bus error */ + signames[SIGBUS] = "SIGBUS"; +#endif +#if defined (SIGSEGV) /* segmentation violation */ + signames[SIGSEGV] = "SIGSEGV"; +#endif +#if defined (SIGSYS) /* bad argument to system call */ + signames[SIGSYS] = "SIGSYS"; +#endif +#if defined (SIGPIPE) /* write on a pipe with no one to read it */ + signames[SIGPIPE] = "SIGPIPE"; +#endif +#if defined (SIGALRM) /* alarm clock */ + signames[SIGALRM] = "SIGALRM"; +#endif +#if defined (SIGTERM) /* software termination signal from kill */ + signames[SIGTERM] = "SIGTERM"; +#endif +#if defined (SIGCLD) /* Like SIGCHLD. */ + signames[SIGCLD] = "SIGCLD"; +#endif +#if defined (SIGPWR) /* Magic thing for some machines. */ + signames[SIGPWR] = "SIGPWR"; +#endif +#if defined (SIGPOLL) /* For keyboard input? */ + signames[SIGPOLL] = "SIGPOLL"; +#endif +#if defined (SIGURG) /* urgent condition on IO channel */ + signames[SIGURG] = "SIGURG"; +#endif +#if defined (SIGSTOP) /* sendable stop signal not from tty */ + signames[SIGSTOP] = "SIGSTOP"; +#endif +#if defined (SIGTSTP) /* stop signal from tty */ + signames[SIGTSTP] = "SIGTSTP"; +#endif +#if defined (SIGCONT) /* continue a stopped process */ + signames[SIGCONT] = "SIGCONT"; +#endif +#if defined (SIGCHLD) /* to parent on child stop or exit */ + signames[SIGCHLD] = "SIGCHLD"; +#endif +#if defined (SIGTTIN) /* to readers pgrp upon background tty read */ + signames[SIGTTIN] = "SIGTTIN"; +#endif +#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local<OSTOP) */ + signames[SIGTTOU] = "SIGTTOU"; +#endif +#if defined (SIGIO) /* input/output possible signal */ + signames[SIGIO] = "SIGIO"; +#endif +#if defined (SIGXCPU) /* exceeded CPU time limit */ + signames[SIGXCPU] = "SIGXCPU"; +#endif +#if defined (SIGXFSZ) /* exceeded file size limit */ + signames[SIGXFSZ] = "SIGXFSZ"; +#endif +#if defined (SIGVTALRM) /* virtual time alarm */ + signames[SIGVTALRM] = "SIGVTALRM"; +#endif +#if defined (SIGPROF) /* profiling time alarm */ + signames[SIGPROF] = "SIGPROF"; +#endif +#if defined (SIGWINCH) /* window changed */ + signames[SIGWINCH] = "SIGWINCH"; +#endif +#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */ + signames[SIGLOST] = "SIGLOST"; +#endif +#if defined (SIGUSR1) /* user defined signal 1 */ + signames[SIGUSR1] = "SIGUSR1"; +#endif +#if defined (SIGUSR2) /* user defined signal 2 */ + signames[SIGUSR2] = "SIGUSR2"; +#endif +#if defined (SIGMSG) /* HFT input data pending */ + signames[SIGMSG] = "SIGMSG"; +#endif +#if defined (SIGPWR) /* power failure imminent (save your data) */ + signames[SIGPWR] = "SIGPWR"; +#endif +#if defined (SIGDANGER) /* system crash imminent */ + signames[SIGDANGER] = "SIGDANGER"; +#endif +#if defined (SIGMIGRATE) /* migrate process to another CPU */ + signames[SIGMIGRATE] = "SIGMIGRATE"; +#endif +#if defined (SIGPRE) /* programming error */ + signames[SIGPRE] = "SIGPRE"; +#endif +#if defined (SIGGRANT) /* HFT monitor mode granted */ + signames[SIGGRANT] = "SIGGRANT"; +#endif +#if defined (SIGRETRACT) /* HFT monitor mode retracted */ + signames[SIGRETRACT] = "SIGRETRACT"; +#endif +#if defined (SIGSOUND) /* HFT sound sequence has completed */ + signames[SIGSOUND] = "SIGSOUND"; +#endif + + for (i = 0; i < NSIG; i++) + if (signames[i] == (char *)NULL) { + signames[i] = (char *)malloc (16);; + sprintf (signames[i], "signal %d", i); + } +} diff --git a/CWRU/sh-redir-hack b/CWRU/sh-redir-hack new file mode 100644 index 0000000..413b297 --- /dev/null +++ b/CWRU/sh-redir-hack @@ -0,0 +1,15 @@ +Add to `subshell' production in parse.y and recompile -DREDIRECTION_HACK to +get `< xx (command)' sh compatibility. + + | redirections '(' list ')' + { +#if defined (REDIRECTION_HACK) + /* XXX - C News sh compatibility hack - XXX */ + $3->redirects = $1; + $3->flags |= CMD_WANT_SUBSHELL; + $$ = $3; +#else + yyerror (); + YYABORT; +#endif + } @@ -0,0 +1,212 @@ +File: bash.info, Node: Install, Next: Invoke, Prev: Built-in, Up: Top + +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. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..4307b2f --- /dev/null +++ b/MANIFEST @@ -0,0 +1,421 @@ +# +# Master distribution manifest for bash +# +# +# Filename type +# +CWRU d +CWRU/misc d +builtins d +documentation d +examples d +examples/functions d +examples/scripts d +examples/startup-files 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 +lib/readline/examples d +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 +COPYING f +MANIFEST f +configure f +Makefile f +cpp-Makefile f +print_cmd.c f +general.c f +variables.c f +make_cmd.c f +copy_cmd.c f +unwind_prot.c f +dispose_cmd.c f +getcwd.c f +bashhist.c f +hash.c f +parse.y f +subst.c f +shell.c f +trap.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 +expr.c f +alias.c f +execute_cmd.c f +bashline.c f +braces.c f +bracecomp.c f +nojobs.c f +vprint.c f +error.c f +signames.c f +endian.c f +alias.h f +config.h f +config.h.mini f +builtins.h f +parser.h f +variables.h f +machines.h f +jobs.h f +maxpath.h f +filecntl.h f +hash.h f +quit.h f +flags.h f +shell.h f +trap.h f +general.h f +unwind_prot.h f +input.h f +error.h f +command.h f +externs.h f +siglist.h f +subst.h f +dispose_cmd.h f +bashansi.h f +make_cmd.h f +bashhist.h f +execute_cmd.h f +bashtypes.h f +y.tab.c f +y.tab.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/alias.def f +builtins/bind.def f +builtins/break.def f +builtins/builtin.def f +builtins/cd.def f +builtins/colon.def f +builtins/command.def f +builtins/common.c f +builtins/declare.def f +builtins/echo.def f +builtins/enable.def f +builtins/eval.def f +builtins/exec.def f +builtins/exit.def f +builtins/fc.def f +builtins/fg_bg.def f +builtins/getopt.c f +builtins/getopt.h f +builtins/getopts.def f +builtins/hash.def f +builtins/hashcom.h f +builtins/help.def f +builtins/let.def f +builtins/history.def f +builtins/jobs.def f +builtins/kill.def f +builtins/mkbuiltins.c 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/source.def f +builtins/suspend.def f +builtins/test.def f +builtins/times.def f +builtins/trap.def f +builtins/type.def f +builtins/ulimit.def f +builtins/umask.def f +builtins/wait.def f +builtins/psize.c f +builtins/psize.sh f +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/fnmatch.c f +lib/glob/fnmatch.h f +lib/glob/glob.c 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/getpagesize.h f +lib/malloc/i386-alloca.s f +lib/malloc/malloc.c f +lib/malloc/x386-alloca.s 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/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/ChangeLog 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/funmap.c f +lib/readline/keymaps.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/tilde.c f +lib/readline/tilde.h f +lib/readline/posixstat.h f +lib/readline/ansi_stdlib.h f +lib/readline/memalloc.h f +lib/termcap/Makefile f +lib/termcap/termcap.c f +lib/termcap/termcap.h f +lib/termcap/tparam.c f +lib/termcap/version.c f +lib/termcap/grot/termcap.info f +lib/termcap/grot/termcap.info-1 f +lib/termcap/grot/termcap.info-2 f +lib/termcap/grot/termcap.info-3 f +lib/termcap/grot/termcap.info-4 f +lib/termcap/grot/NEWS f +lib/termcap/grot/INSTALL f +lib/termcap/grot/ChangeLog f +lib/termcap/grot/texinfo.tex f +lib/termcap/grot/termcap.texi f +lib/termcap/grot/Makefile.in f +lib/termcap/grot/configure f +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/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 +support/bash.xbm f +support/FAQ f +support/PORTING f +support/mklinks f +support/mkdirs f +support/clone-bash f +support/bashbug.sh f +support/mkmachtype f +support/recho.c f +support/srcdir f +support/SYMLINKS f +support/fixlinks f +examples/functions/substr f +examples/functions/kshenv f +examples/functions/autoload f +examples/functions/csh-compat f +examples/functions/shcat f +examples/functions/substr2 f +examples/functions/term f +examples/functions/whatis f +examples/functions/whence f +examples/functions/func f +examples/functions/dirname f +examples/functions/dirfuncs f +examples/functions/basename f +examples/functions/exitstat f +examples/functions/external f +examples/functions/fact f +examples/functions/manpage f +examples/functions/fstty f +examples/functions/jj.bash f +examples/functions/notify.bash f +examples/scripts/shprompt f +examples/scripts/adventure.sh f +examples/scripts/precedence f +examples/scripts/bcsh.sh 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 +tests/README f +tests/dollar-at.sh f +tests/dollar-star.sh f +tests/dollar.right f +tests/exp-tests f +tests/exp.right f +tests/glob-test f +tests/glob.right f +tests/ifs-test-1.sh f +tests/ifs-test-2.sh f +tests/ifs-test-3.sh f +tests/ifs.1.right f +tests/ifs.2.right f +tests/ifs.3.right f +tests/input-line.sh f +tests/input-line.sub f +tests/input.right f +tests/minus-e f +tests/minus-e.right f +tests/new-exp.tests f +tests/new-exp.right f +tests/prec.right f +tests/precedence f +tests/run-all f +tests/run-dollars f +tests/run-exp-tests f +tests/run-glob-test f +tests/run-ifs-tests f +tests/run-input-test f +tests/run-minus-e f +tests/run-new-exp f +tests/run-precedence f +tests/run-set-e-test f +tests/run-strip f +tests/run-varenv f +tests/set-e-test f +tests/set-e.right f +tests/strip.tests f +tests/strip.right f +tests/tilde-tests f +tests/tilde.right f +tests/varenv.right f +tests/varenv.sh f +tests/misc/chld-trap.sh f +tests/misc/dot-test-1.sh f +tests/misc/dot-test-1.sub f +tests/misc/gotest f +tests/misc/perf-script f +tests/misc/redir.t1.sh f +tests/misc/redir.t2.sh f +tests/misc/redir.t3.sh f +tests/misc/redir.t3.sub f +tests/misc/redir.t4.sh f +tests/misc/run.r1.sh f +tests/misc/run.r2.sh f +tests/misc/run.r3.sh f +tests/misc/sigint.t1.sh f +tests/misc/sigint.t2.sh f +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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..da50f7a --- /dev/null +++ b/Makefile @@ -0,0 +1,115 @@ +# 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 @@ -0,0 +1,10 @@ +This file documents the bugs fixed between this release, bash-1.14.7, +and the last public bash release, 1.14.6. + +1. Bugs fixed in Bash + +a. A memory leak that caused long-running scripts to eventually consume + all available memory was fixed. + +b. A sign-extension bug that caused a security hole for non-interactive + shells was fixed. @@ -0,0 +1,52 @@ +This README file is in -*- text -*- mode, because Emacs likes it that way. + +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); +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. + +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''. + +You may want to read the file INSTALL in this directory for more +information if the make fails. + +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 +as a starting point. + +Bug reports for 1.14 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. + +When you send a bug report to bash-maintainers@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 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. + +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. + +Enjoy! + +Chet Ramey +chet@po.cwru.edu @@ -0,0 +1,269 @@ +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. @@ -0,0 +1,535 @@ +/* alias.c -- Not a full alias, but just the kind that we use in the + shell. Csh style alias is somewhere else (`over there, in a box'). */ + +/* 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. */ + +#include <stdio.h> +#include "bashansi.h" +#include "config.h" +#include "command.h" +#include "general.h" +#include "hash.h" +#include "alias.h" + +static int qsort_alias_compare (); + +/* Non-zero means expand all words on the line. Otherwise, expand + after first expansion if the expansion ends in a space. */ +int alias_expand_all = 0; + +/* The list of aliases that we have. */ +HASH_TABLE *aliases = (HASH_TABLE *)NULL; + +void +initialize_aliases () +{ + if (!aliases) + aliases = make_hash_table (0); +} + +/* 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 * +find_alias (name) + char *name; +{ + BUCKET_CONTENTS *al; + + if (!aliases) + return ((ASSOC *)NULL); + else + al = find_hash_item (name, aliases); + + if (al) + return ((ASSOC *)al->data); + else + return ((ASSOC *)NULL); +} + +/* Return the value of the alias for NAME, or NULL if there is none. */ +char * +get_alias_value (name) + char *name; +{ + ASSOC *alias = find_alias (name); + if (alias) + return (alias->value); + else + return ((char *)NULL); +} + +/* Make a new alias from NAME and VALUE. If NAME can be found, + then replace its value. */ +void +add_alias (name, value) + char *name, *value; +{ + ASSOC *temp = (ASSOC *)NULL; + + if (!aliases) + initialize_aliases (); + else + temp = find_alias (name); + + if (temp) + { + free (temp->value); + temp->value = savestring (value); + } + else + { + BUCKET_CONTENTS *elt; + + temp = (ASSOC *)xmalloc (sizeof (ASSOC)); + temp->name = savestring (name); + temp->value = savestring (value); + + elt = add_hash_item (savestring (name), aliases); + elt->data = (char *)temp; + } +} + +/* 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. */ +int +remove_alias (name) + char *name; +{ + BUCKET_CONTENTS *elt; + + if (!aliases) + return (-1); + + elt = remove_hash_item (name, aliases); + if (elt) + { + ASSOC *t; + + t = (ASSOC *)elt->data; + free (t->name); + free (t->value); + 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) + return; + + for (i = 0; i < aliases->nbuckets; i++) + { + register BUCKET_CONTENTS *bp; + + bp = get_hash_bucket (i, aliases); + delete_alias_list (bp); + } + 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 ** +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; + + for (i = 0; i < aliases->nbuckets; i++) + { + tlist = get_hash_bucket (i, aliases); + + while (tlist) + { + alias = (ASSOC *)tlist->data; + + if (!function || (*function) (alias)) + { + if (list_index + 1 >= list_size) + list = (ASSOC **) + xrealloc ((char *)list, (list_size += 20) * sizeof (ASSOC *)); + + list[list_index++] = alias; + list[list_index] = (ASSOC *)NULL; + } + tlist = tlist->next; + } + } + return (list); +} + +static void +sort_aliases (array) + ASSOC **array; +{ + qsort (array, array_len ((char **)array), sizeof (ASSOC *), qsort_alias_compare); +} + +static int +qsort_alias_compare (as1, as2) + ASSOC **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 ** +all_aliases () +{ + ASSOC **list; + + if (!aliases) + return ((ASSOC **)NULL); + + list = map_over_aliases ((Function *)NULL); + if (list) + sort_aliases (list); + return (list); +} + +char * +alias_expand_word (s) + char *s; +{ + ASSOC *r = find_alias (s); + + if (r) + return (savestring (r->value)); + else + return ((char *)NULL); +} + +/* Return non-zero if CHARACTER is a member of the class of characters + that are self-delimiting in the shell (this really means that these + characters delimit tokens). */ +#define self_delimiting(character) (member ((character), " \t\n\r;|&()")) + +/* Return non-zero if CHARACTER is a member of the class of characters + that delimit commands in the shell. */ +#define command_separator(character) (member ((character), "\r\n;|&(")) + +/* If this is 1, we are checking the next token read for alias expansion + because it is the first word in a command. */ +static int command_word; + +/* This is for skipping quoted strings in alias expansions. */ +#define quote_char(c) (((c) == '\'') || ((c) == '"')) + +/* Consume a quoted string from STRING, starting at string[START] (so + string[START] is the opening quote character), and return the index + of the closing quote character matching the opening quote character. + This handles single matching pairs of unquoted quotes; it could afford + to be a little smarter... This skips words between balanced pairs of + quotes, words where the first character is quoted with a `\', and other + backslash-escaped characters. */ + +static int +skipquotes (string, start) + char *string; + int start; +{ + register int i; + int delimiter = string[start]; + + /* i starts at START + 1 because string[START] is the opening quote + character. */ + for (i = start + 1 ; string[i] ; i++) + { + if (string[i] == '\\') + { + i++; /* skip backslash-quoted quote characters, too */ + continue; + } + + if (string[i] == delimiter) + return i; + } + return (i); +} + +/* Skip the white space and any quoted characters in STRING, starting at + START. Return the new index into STRING, after zero or more characters + have been skipped. */ +static int +skipws (string, start) + char *string; + int start; +{ + register int i = 0; + int pass_next, backslash_quoted_word, peekc; + + /* skip quoted strings, in ' or ", and words in which a character is quoted + with a `\'. */ + backslash_quoted_word = pass_next = 0; + + /* Skip leading whitespace (or separator characters), and quoted words. + But save it in the output. */ + + for (i = start; string[i]; i++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + + if (whitespace (string[i])) + { + backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */ + continue; + } + + if (string[i] == '\\') + { + peekc = string[i+1]; + if (isletter (peekc)) + backslash_quoted_word++; /* this is a backslash-quoted word */ + else + pass_next++; + continue; + } + + /* This only handles single pairs of non-escaped quotes. This + overloads backslash_quoted_word to also mean that a word like + ""f is being scanned, so that the quotes will inhibit any expansion + of the word. */ + if (quote_char(string[i])) + { + i = skipquotes (string, i); + /* This could be a line that contains a single quote character, + in which case skipquotes () terminates with string[i] == '\0' + (the end of the string). Check for that here. */ + if (string[i] == '\0') + break; + + peekc = string[i + 1]; + if (isletter (peekc)) + backslash_quoted_word++; + continue; + } + + /* If we're in the middle of some kind of quoted word, let it + pass through. */ + if (backslash_quoted_word) + continue; + + /* If this character is a shell command separator, then set a hint for + alias_expand that the next token is the first word in a command. */ + + if (command_separator (string[i])) + { + command_word++; + continue; + } + break; + } + return (i); +} + +/* Characters that may appear in a token. Basically, anything except white + space and a token separator. */ +#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i])))) + +/* Read from START in STRING until the next separator character, and return + the index of that separator. Skip backslash-quoted characters. Call + skipquotes () for quoted strings in the middle or at the end of tokens, + so all characters show up (e.g. foo'' and foo""bar) */ +static int +rd_token (string, start) + char *string; + int start; +{ + register int i; + + /* From here to next separator character is a token. */ + for (i = start; string[i] && token_char (string[i]); i++) + { + if (string[i] == '\\') + { + i++; /* skip backslash-escaped character */ + continue; + } + + /* 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 + inhibit expansion. */ + if (quote_char (string[i])) + { + i = skipquotes (string, i); + /* Now string[i] is the matching quote character, and the + quoted portion of the token has been scanned. */ + continue; + } + } + return (i); +} + +/* Return a new line, with any aliases substituted. */ +char * +alias_expand (string) + char *string; +{ + int line_len = 1 + strlen (string); + char *line = (char *)xmalloc (line_len); + register int i, j, start; + char *token = xmalloc (line_len); + int tl, real_start, expand_next, expand_this_token; + ASSOC *alias; + + line[0] = i = 0; + expand_next = 0; + command_word = 1; /* initialized to expand the first word on the line */ + + /* Each time through the loop we find the next word in line. If it + has an alias, substitute + the alias value. If the value ends in ` ', then try again + with the next word. Else, if there is no value, or if + the value does not end in space, we are done. */ + + for (;;) + { + + token[0] = 0; + start = i; + + /* Skip white space and quoted characters */ + i = skipws (string, start); + + if (start == i && string[i] == '\0') + { + free (token); + return (line); + } + + /* copy the just-skipped characters into the output 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)); + strncpy (line + j, string + start, tl); + line[j + tl] = '\0'; + + real_start = i; + + command_word = command_word || (command_separator (string[i])); + expand_this_token = (command_word || expand_next); + expand_next = 0; + + /* Read the next token, and copy it into TOKEN. */ + start = i; + i = rd_token (string, start); + + tl = i - start; /* token length */ + + /* If tl == 0, but we're not at the end of the string, then we have a + single-character token, probably a delimiter */ + if (tl == 0 && string[i] != '\0') + { + tl = 1; + i++; /* move past it */ + } + + strncpy (token, string + start, tl); + token [tl] = '\0'; + + /* If there is a backslash-escaped character quoted in TOKEN, + then we don't do alias expansion. This should check for all + other quoting characters, too. */ + if (strchr (token, '\\')) + expand_this_token = 0; + + /* If we should be expanding here, if we are expanding all words, or if + we are in a location in the string where an expansion is supposed to + take place, see if this word has a substitution. If it does, then do + the expansion. Note that we defer the alias value lookup until we + are sure we are expanding this token. */ + + if ((token[0]) && + (expand_this_token || alias_expand_all) && + (alias = find_alias (token))) + { + char *v = alias->value; + int l = strlen (v); + + /* +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)); + + strcat (line, v); + + if ((expand_this_token && l && whitespace (v[l - 1])) || + alias_expand_all) + expand_next = 1; + } + else + { + int ll = strlen (line); + int tlen = i - real_start; /* tlen == strlen(token) */ + + if (ll + tlen + 2 > line_len) + line = (char *)xrealloc (line, line_len += 50 + ll + tlen); + + strncpy (line + ll, string + real_start, tlen); + line[ll + tlen] = '\0'; + } + command_word = 0; + } +} @@ -0,0 +1,75 @@ +/* alias.h -- structure definitions. */ + +/* 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 (_ALIAS_) +#define _ALIAS_ + +#include "hash.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 { + char *name; + char *value; +} ASSOC; + +/* The list of known aliases. */ +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 (); + +/* Return the value of the alias for NAME, or NULL if there is none. */ +extern char *get_alias_value (); + +/* Make a new alias from NAME and VALUE. If NAME can be found, + then replace its value. */ +extern void add_alias (); + +/* Remove the alias with name NAME from the alias list. Returns + the index of the removed alias, or -1 if the alias didn't exist. */ +extern int remove_alias (); + +/* Return a new line, with any aliases expanded. */ +extern char *alias_expand (); + +/* Return an array of all defined aliases. */ +extern ASSOC **all_aliases (); + +#endif /* _ALIAS_ */ diff --git a/ansi_stdlib.h b/ansi_stdlib.h new file mode 100644 index 0000000..52339da --- /dev/null +++ b/ansi_stdlib.h @@ -0,0 +1,41 @@ +/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */ +/* A minimal stdlib.h containing extern declarations for those functions + that bash uses. */ + +/* 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 (_STDLIB_H_) +#define _STDLIB_H_ 1 + +/* String conversion functions. */ +extern int atoi (); +extern long int atol (); + +/* Memory allocation functions. */ +extern char *malloc (); +extern char *realloc (); +extern void free (); + +/* Other miscellaneous functions. */ +extern void abort (); +extern void exit (); +extern char *getenv (); +extern void qsort (); + +#endif /* _STDLIB_H */ diff --git a/bashansi.h b/bashansi.h new file mode 100644 index 0000000..4411970 --- /dev/null +++ b/bashansi.h @@ -0,0 +1,36 @@ +/* bashansi.h -- Typically included information required by picky compilers. */ + +/* 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 (_BASHANSI_H_) +#define _BASHANSI_H_ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* !HAVE_STDLIB_H */ + +#endif /* !_BASHANSI_H_ */ diff --git a/bashhist.c b/bashhist.c new file mode 100644 index 0000000..cd7134b --- /dev/null +++ b/bashhist.c @@ -0,0 +1,390 @@ +/* bashhist.c -- bash interface to the GNU history library. */ + +/* 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 <sys/types.h> +#include <stdio.h> +#include <errno.h> +#include "bashansi.h" +#include "posixstat.h" +#include "filecntl.h" +#include "shell.h" +#include "flags.h" +#include <readline/history.h> + +/* Declarations of bash history variables. */ +/* Non-zero means to remember lines typed to the shell on the history + list. This is different than the user-controlled behaviour; this + becomes zero when we read lines from a file, for example. */ +int remember_on_history = 1; + +/* The number of lines that Bash has added to this history session. */ +int history_lines_this_session = 0; + +/* The number of lines that Bash has read from the history file. */ +int history_lines_in_file = 0; + +/* Non-zero means do no history expansion on this line, regardless + of what history_expansion says. */ +int history_expansion_inhibited = 0; + +/* 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 + 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 + 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 + 10 for i in a b c + do + echo $i + done + 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; + +/* 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; + +/* Variables declared in other files used here. */ +extern int interactive; +extern int current_command_line_count; +extern int delimiter_depth; + +extern char *history_delimiting_chars (); +extern void maybe_add_history (); /* forward declaration */ + +static void bash_add_history (); + +/* Load the history list from the history file. */ +void +load_history () +{ + char *hf; + + /* 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"); + + /* Read the history in HISTFILE into the history list. */ + hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + struct stat buf; + + if (stat (hf, &buf) == 0) + { + read_history (hf); + using_history (); + history_lines_in_file = where_history (); + } + } +} + +/* Write the existing history out to the history file. */ +void +save_history () +{ + char *hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + struct stat buf; + + 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 ()) + append_history (history_lines_this_session, hf); + else + write_history (hf); + } + } +} + +/* If this is an interactive shell, then append the lines executed + this session to the history file. */ +int +maybe_save_shell_history () +{ + int result = 0; + + if (history_lines_this_session) + { + char *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); + if (file != -1) + close (file); + } + + /* Now actually append the lines if the history hasn't been + stifled. If the history has been stifled, rewrite the + history file. */ + using_history (); + if (history_lines_this_session <= where_history ()) + { + result = append_history (history_lines_this_session, hf); + history_lines_in_file += history_lines_this_session; + } + else + { + result = write_history (hf); + history_lines_in_file = history_lines_this_session; + } + history_lines_this_session = 0; + } + } + return (result); +} + +#if defined (HISTORY_REEDITING) +/* 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) + bash_re_edit (text); +#endif /* READLINE */ +} +#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. + If there is an error, return NULL, otherwise the expanded line is + returned. If ADDIT is non-zero the line is added to the history + list after history expansion. ADDIT is just a suggestion; + REMEMBER_ON_HISTORY can veto, and does. + Right now this does history expansion. */ +char * +pre_process_line (line, print_changes, addit) + char *line; + int print_changes, addit; +{ + char *history_value; + char *return_value; + int expanded = 0; + + return_value = line; + +# 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) + { + expanded = history_expand (line, &history_value); + + if (expanded) + { + if (print_changes) + { + if (expanded < 0) + internal_error (history_value); + else + fprintf (stderr, "%s\n", history_value); + } + + /* If there was an error, return NULL. */ + if (expanded < 0 || expanded == 2) /* 2 == print only */ + { + free (history_value); + +# if defined (HISTORY_REEDITING) + /* New hack. We can allow the user to edit the + failed history expansion. */ + re_edit (line); +# endif /* HISTORY_REEDITING */ + return ((char *)NULL); + } + } + + /* Let other expansions know that return_value can be free'ed, + and that a line has been added to the history list. Note + that we only add lines that have something in them. */ + expanded = 1; + return_value = history_value; + } +# endif /* BANG_HISTORY */ + + if (addit && remember_on_history && *return_value) + maybe_add_history (return_value); + + if (!expanded) + return_value = savestring (line); + + return (return_value); +} + +/* Add LINE to the history list depending on the value of HISTORY_CONTROL. */ +void +maybe_add_history (line) + char *line; +{ + int h; + + /* 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; + + switch (h) + { + case 0: + bash_add_history (line); + break; + case 1: + if (*line != ' ') + bash_add_history (line); + break; + case 3: + if (*line == ' ') + break; + /* FALLTHROUGH if case == 3 (`ignoreboth') */ + case 2: + { + HIST_ENTRY *temp; + + using_history (); + temp = previous_history (); + + if (!temp || (STREQ (temp->line, line) == 0)) + bash_add_history (line); + + using_history (); + } + break; + } +} + +/* Add a line to the history list. + The variable COMMAND_ORIENTED_HISTORY controls the style of history + remembering; when non-zero, and LINE is not the first line of a + complete parser construct, append LINE to the last history line instead + of adding it as a new line. */ +static void +bash_add_history (line) + char *line; +{ + int 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 (); + + using_history (); + + current = previous_history (); + + if (current) + { + /* 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] == '\\' && + current->line[curlen - 2] != '\\') + { + current->line[curlen - 1] = '\0'; + curlen--; + 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); + 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); + } + add_it = 0; + } + } + + if (add_it) + { + add_history (line); + history_lines_this_session++; + } + using_history (); +} + +int +history_number () +{ + using_history (); + if (get_string_value ("HISTSIZE")) + return (history_base + where_history ()); + else + return (1); /* default to command number 1 */ +} diff --git a/bashhist.h b/bashhist.h new file mode 100644 index 0000000..c1c24fc --- /dev/null +++ b/bashhist.h @@ -0,0 +1,42 @@ +/* bashhist.h -- interface to the bash history functions in bashhist.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 (__BASHHIST_H__) +#define __BASHHIST_H__ + +extern int remember_on_history; +extern int history_lines_this_session; +extern int history_lines_in_file; +extern int history_expansion; +extern int history_control; +extern int command_oriented_history; + +# if defined (BANG_HISTORY) +extern int history_expansion_inhibited; +# endif /* BANG_HISTORY */ + +extern void load_history (); +extern void save_history (); +extern int maybe_save_shell_history (); +extern char *pre_process_line (); +extern int history_number (); +extern void maybe_add_history (); + +#endif /* __BASHHIST_H__ */ diff --git a/bashline.c b/bashline.c new file mode 100644 index 0000000..a924b05 --- /dev/null +++ b/bashline.c @@ -0,0 +1,1797 @@ +/* bashline.c -- Bash's interface to the readline library. */ + +/* 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. */ + +#include "bashtypes.h" +#include "posixstat.h" + +#include <stdio.h> +#include "bashansi.h" +#include <readline/rlconf.h> +#include <readline/readline.h> +#include <readline/history.h> +#include "shell.h" +#include "builtins.h" +#include "builtins/common.h" +#include "bashhist.h" +#include "execute_cmd.h" + +#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 */ + +/* Functions bound to keys in Readline for Bash users. */ +static void shell_expand_line (); +static void display_shell_version (), operate_and_get_next (); +static void history_expand_line (), bash_ignore_filenames (); + +/* Helper functions for Readline. */ +static int bash_directory_completion_hook (); +static void filename_completion_ignore (); +static void bash_push_line (); + +static char **attempt_shell_completion (); +static char *variable_completion_function (); +static char *hostname_completion_function (); +static char *command_word_completion_function (); +static char *command_subst_completion_function (); + +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 */ + +/* Variables used here but defined in other files. */ +extern int posixly_correct, no_symbolic_links; +extern int rl_explicit_arg; +extern char *current_prompt_string, *ps1_prompt; +extern STRING_INT_ALIST word_token_alist[]; +extern Function *rl_last_func; +extern int rl_filename_completion_desired; + +/* 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 + the readline library. */ +#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 (); +#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 + +static Function *old_rl_startup_hook = (Function *) NULL; + +/* 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 defined (VI_MODE) + 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 ("#"); + } + else + rl_bind_key_in_map (CTRL('I'), rl_complete, vi_insertion_keymap); +#endif +} + +/* Called once from parse.y if we are going to use readline. */ +void +initialize_readline () +{ + if (bash_readline_initialized) + return; + + 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); + + /* Bind up our special shell functions. */ + rl_add_defun ("history-expand-line", (Function *)history_expand_line, -1); + rl_bind_key_in_map ('^', (Function *)history_expand_line, emacs_meta_keymap); + + /* Backwards compatibility. */ + rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); + + rl_add_defun + ("operate-and-get-next", (Function *)operate_and_get_next, CTRL('O')); + + 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); + + /* In Bash, the user can switch editing modes with "set -o [vi emacs]", + so it is not necessary to allow C-M-j for context switching. Turn + off this occasionally confusing behaviour. */ + rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); + rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); +#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); +#endif /* BRACE_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_add_defun ("complete-filename", bash_complete_filename, -1); + 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_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_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_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_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); + +#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; + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ + rl_directory_completion_hook = bash_directory_completion_hook; + + /* Tell the filename completer we want a chance to ignore some names. */ + rl_ignore_some_completions_function = (Function *)filename_completion_ignore; + +#if defined (VI_MODE) + rl_bind_key_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +#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\"'@><=;|&("; /**/ + + if (posixly_correct) + posix_readline_initialize (1); + + bash_readline_initialized = 1; +} + +/* On Sun systems at least, rl_attempted_completion_function can end up + getting set to NULL, and rl_completion_entry_function set to do command + word completion if Bash is interrupted while trying to complete a command + word. This just resets all the completion functions to the right thing. + It's called from throw_to_top_level(). */ +void +bashline_reinitialize () +{ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = (Function *)NULL; + rl_directory_completion_hook = bash_directory_completion_hook; + rl_ignore_some_completions_function = (Function *)filename_completion_ignore; +} + +/* Contains the line to push into readline. */ +static char *push_to_readline = (char *)NULL; + +/* Push the contents of push_to_readline into the + readline buffer. */ +static void +bash_push_line () +{ + if (push_to_readline) + { + rl_insert_text (push_to_readline); + free (push_to_readline); + push_to_readline = (char *)NULL; + rl_startup_hook = old_rl_startup_hook; + } +} + +/* Call this to set the initial text for the next line to read + from readline. */ +int +bash_re_edit (line) + char *line; +{ + if (push_to_readline) + free (push_to_readline); + + push_to_readline = savestring (line); + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = (Function *)bash_push_line; + + return (0); +} + +static void +display_shell_version (count, c) + int count, c; +{ + crlf (); + show_shell_version (); + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); +} + +/* **************************************************************** */ +/* */ +/* Readline Stuff */ +/* */ +/* **************************************************************** */ + +/* 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; + +/* The length of the above list. */ +static int hostname_list_length = 0; + +/* 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 () +{ + char *temp; + + temp = get_string_value ("HOSTFILE"); + if (!temp) + temp = get_string_value ("hostname_completion_file"); + if (!temp) + temp = ETCHOSTS; + + snarf_hosts_from_file (temp); + sort_hostname_list (); + + if (hostname_list) + hostname_list_initialized++; +} + +/* Add NAME to the list of hosts. */ +static void +add_host_name (name) + char *name; +{ + if (hostname_list_length + 2 > hostname_list_size) + { + hostname_list = (char **) + xrealloc (hostname_list, + (1 + (hostname_list_size += 100)) * sizeof (char *)); + } + + 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; +} + +#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) + +static void +snarf_hosts_from_file (filename) + char *filename; +{ + FILE *file = fopen (filename, "r"); + char *temp, buffer[256], name[256]; + register int i, start; + + if (!file) + return; + + while (temp = fgets (buffer, 255, file)) + { + /* Skip to first character. */ + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++); + + /* If comment, ignore. */ + if (buffer[i] == '#') + continue; + + /* If `preprocessor' directive, do the include. */ + if (strncmp (&buffer[i], "$include ", 9) == 0) + { + char *includefile = &buffer[i + 9]; + char *t; + + /* Find start of filename. */ + while (*includefile && whitespace (*includefile)) + includefile++; + + t = includefile; + + /* Find end of filename. */ + while (*t && !cr_whitespace (*t)) + t++; + + *t = '\0'; + + snarf_hosts_from_file (includefile); + continue; + } + + /* Skip internet address. */ + for (; buffer[i] && !cr_whitespace (buffer[i]); i++); + + /* Gobble up names. Each name is separated with whitespace. */ + while (buffer[i] && 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) + continue; + strncpy (name, buffer + start, i - start); + name[i - start] = '\0'; + add_host_name (name); + } + } + fclose (file); +} + +/* Return a NULL terminated list of hostnames which begin with TEXT. + Initialize the hostname list the first time if neccessary. + The array is malloc ()'ed, but not the individual strings. */ +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; + + if (!hostname_list_initialized) + { + 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; + + /* Special case. If TEXT consists of nothing, then the whole list is + what is desired. */ + if (!*text) + { + result = (char **)xmalloc ((1 + hostname_list_length) * sizeof (char *)); + for (i = 0; i < hostname_list_length; i++) + result[i] = hostname_list[i]; + result[i] = (char *)NULL; + return (result); + } + + /* Scan until found, or failure. */ + while (end != begin) + { + int r = 0; + + i = ((end - begin) / 2) + begin; + if (i == last_search) + break; + + if (hostname_list[i] && + (r = strncmp (hostname_list[i], text, len)) == 0) + { + 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); + } + + last_search = i; + + if (r < 0) + begin = i; + else + end = i; + } + return ((char **)NULL); +} + +/* The equivalent of the K*rn shell C-o operate-and-get-next-history-line + editing command. */ +static int saved_history_line_to_use = 0; + +static void +set_saved_history () +{ + if (saved_history_line_to_use) + rl_get_previous_history (history_length - saved_history_line_to_use); + saved_history_line_to_use = 0; + rl_startup_hook = old_rl_startup_hook; +} + +static void +operate_and_get_next (count, c) + int count, c; +{ + int where; + + /* Accept the current line. */ + rl_newline (); + + /* Find the current line, and find the next line to use. */ + where = where_history (); + + if ((history_is_stifled () && (history_length >= max_input_history)) || + (where >= history_length - 1)) + saved_history_line_to_use = where; + else + saved_history_line_to_use = where + 1; + + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = (Function *)set_saved_history; +} + +#if defined (VI_MODE) +/* This vi mode command causes VI_EDIT_COMMAND to be run on the current + command being entered (if no explicit argument is given), otherwise on + a command from the history file. */ + +#define VI_EDIT_COMMAND "fc -e ${VISUAL:-${EDITOR:-vi}}" + +static void +vi_edit_and_execute_command (count, c) +{ + char *command; + + /* Accept the current line. */ + rl_newline (); + + if (rl_explicit_arg) + { + command = xmalloc (strlen (VI_EDIT_COMMAND) + 8); + sprintf (command, "%s %d", VI_EDIT_COMMAND, count); + } + else + { + /* Take the command we were just editing, add it to the history file, + then call fc to operate on it. We have to add a dummy command to + the end of the history because fc ignores the last command (assumes + it's supposed to deal with the command before the `fc'). */ + using_history (); + add_history (rl_line_buffer); + add_history (""); + history_lines_this_session++; + using_history (); + command = savestring (VI_EDIT_COMMAND); + } + parse_and_execute (command, "v", -1); + rl_line_buffer[0] = '\0'; /* erase pre-edited command */ +} +#endif /* VI_MODE */ + +/* **************************************************************** */ +/* */ +/* How To Do Shell Completion */ +/* */ +/* **************************************************************** */ + +/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are + at START and END. Return an array of matches, or NULL if none. */ +static char ** +attempt_shell_completion (text, start, end) + char *text; + int start, end; +{ + int in_command_position, ti; + char **matches = (char **)NULL; + char *command_separator_chars = ";|&{(`"; + + 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 + appears after a character that separates commands. It cannot be a + command word if we aren't at the top-level prompt. */ + ti = start - 1; + + while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) + ti--; + + in_command_position = 0; + if (ti < 0) + { + /* Only do command completion at the start of a line when we + are prompting at the top level. */ + if (current_prompt_string == ps1_prompt) + in_command_position++; + } + else if (member (rl_line_buffer[ti], command_separator_chars)) + { + register int this_char, prev_char; + + in_command_position++; + + /* Handle the two character tokens `>&', `<&', and `>|'. + We are not in a command position after one of these. */ + this_char = rl_line_buffer[ti]; + prev_char = rl_line_buffer[ti - 1]; + + if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || + (this_char == '|' && prev_char == '>')) + in_command_position = 0; + else if (char_is_quoted (rl_line_buffer, ti)) + in_command_position = 0; + } + else + { + /* This still could be in command position. It is possible + that all of the previous words on the line are variable + assignments. */ + } + + /* Special handling for command substitution. XXX - this should handle + `$(' as well. */ + if (*text == '`' && unclosed_pair (rl_line_buffer, start, "`")) + matches = completion_matches (text, command_subst_completion_function); + + /* Variable name? */ + if (!matches && *text == '$') + matches = completion_matches (text, variable_completion_function); + + /* If the word starts in `~', and there is no slash in the word, then + try completing this word as a username. */ + if (!matches && *text == '~' && !strchr (text, '/')) + matches = completion_matches (text, username_completion_function); + + /* Another one. Why not? If the word starts in '@', then look through + the world of known hostnames for completion first. */ + if (!matches && *text == '@') + matches = completion_matches (text, hostname_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. */ + if (!matches && in_command_position) + { + matches = completion_matches (text, command_word_completion_function); + /* If we are attempting command completion and nothing matches, we + do not want readline to perform filename completion for us. We + still want to be able to complete partial pathnames, so set the + completion ignore function to something which will remove filenames + and leave directories in the match list. */ + if (!matches) + rl_ignore_some_completions_function = (Function *)bash_ignore_filenames; + } + + return (matches); +} + +/* This is the function to call when the word to complete is in a position + where a command word can be found. It grovels $PATH, looking for commands + that match. It also scans aliases, function names, and the shell_builtin + table. */ +static char * +command_word_completion_function (hint_text, state) + char *hint_text; + int state; +{ + static char *hint = (char *)NULL; + static char *path = (char *)NULL; + static char *val = (char *)NULL; + static char *filename_hint = (char *)NULL; + static int path_index, hint_len, istate; + static int mapping_over, local_index; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; +#if defined (ALIAS) + static ASSOC **alias_list = (ASSOC **)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) + free (hint); + + mapping_over = 0; + val = (char *)NULL; + + /* If this is an absolute program name, do not check it against + aliases, reserved words, functions or builtins. We must check + whether or not it is unique, and, if so, whether that filename + is executable. */ + if (absolute_program (hint_text)) + { + /* 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); + else + hint = savestring (hint_text); + hint_len = strlen (hint); + + if (filename_hint) + free (filename_hint); + filename_hint = savestring (hint); + + mapping_over = 4; + istate = 0; + goto inner; + } + + hint = savestring (hint_text); + hint_len = strlen (hint); + + path = get_string_value ("PATH"); + path_index = 0; + + /* Initialize the variables for each type of command word. */ + local_index = 0; + + if (varlist) + free (varlist); + + varlist = all_visible_functions (); + +#if defined (ALIAS) + if (alias_list) + free (alias_list); + + alias_list = all_aliases (); +#endif /* ALIAS */ + } + + /* mapping_over says what we are currently hacking. Note that every case + in this list must fall through when there are no more possibilities. */ + + switch (mapping_over) + { + case 0: /* Aliases come first. */ +#if defined (ALIAS) + while (alias_list && alias_list[local_index]) + { + register char *alias; + + alias = alias_list[local_index++]->name; + + if (STREQN (alias, hint, hint_len)) + return (savestring (alias)); + } +#endif /* ALIAS */ + local_index = 0; + mapping_over++; + + case 1: /* Then shell reserved words. */ + { + while (word_token_alist[local_index].word) + { + register char *reserved_word; + + reserved_word = word_token_alist[local_index++].word; + + if (STREQN (reserved_word, hint, hint_len)) + return (savestring (reserved_word)); + } + local_index = 0; + mapping_over++; + } + + case 2: /* Then function names. */ + while (varlist && varlist[local_index]) + { + register char *varname; + + varname = varlist[local_index++]->name; + + if (STREQN (varname, hint, hint_len)) + return (savestring (varname)); + } + local_index = 0; + mapping_over++; + + case 3: /* Then shell builtins. */ + for (; local_index < num_shell_builtins; local_index++) + { + /* Ignore it if it doesn't have a function pointer or if it + is not currently enabled. */ + if (!shell_builtins[local_index].function || + (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) + continue; + + if (STREQN (shell_builtins[local_index].name, hint, hint_len)) + { + int i = local_index++; + + return (savestring (shell_builtins[i].name)); + } + } + local_index = 0; + mapping_over++; + } + + /* Repeatedly call filename_completion_func<tion while we have + members of PATH left. Question: should we stat each file? + Answer: we call executable_file () on each file. */ + outer: + + istate = (val != (char *)NULL); + + if (!istate) + { + char *current_path; + + /* Get the next directory from the path. If there is none, then we + are all done. */ + if (!path || !path[path_index] || + (current_path = extract_colon_unit (path, &path_index)) == 0) + return ((char *)NULL); + + if (*current_path == 0) + { + free (current_path); + current_path = savestring ("."); + } + + if (*current_path == '~') + { + char *t; + + t = tilde_expand (current_path); + free (current_path); + current_path = t; + } + + if (filename_hint) + free (filename_hint); + + filename_hint = xmalloc (2 + strlen (current_path) + hint_len); + sprintf (filename_hint, "%s/%s", current_path, hint); + + free (current_path); + } + + inner: + val = filename_completion_function (filename_hint, istate); + istate = 1; + + if (!val) + { + /* If the hint text is an absolute program, then don't bother + searching through PATH. */ + if (absolute_program (hint)) + return ((char *)NULL); + + goto outer; + } + else + { + int match; + char *temp; + + if (absolute_program (hint)) + { + match = strncmp (val, hint, hint_len) == 0; + /* If we performed tilde expansion, restore the original + filename. */ + if (*hint_text == '~') + { + int l, tl, vl; + vl = strlen (val); + tl = strlen (hint_text); + l = vl - hint_len; /* # of chars added */ + temp = xmalloc (l + 2 + tl); + strcpy (temp, hint_text); + strcpy (temp + tl, val + vl - l); + } + else + temp = savestring (val); + } + else + { + temp = strrchr (val, '/'); + + if (temp) + { + temp++; + match = strncmp (temp, hint, hint_len) == 0; + if (match) + temp = savestring (temp); + } + else + match = 0; + } + + /* If we have found a match, and it is an executable file, return it. */ + if (match && executable_file (val)) + { + free (val); + val = ""; /* So it won't be NULL. */ + return (temp); + } + else + { + free (val); + goto inner; + } + } +} + +static char * +command_subst_completion_function (text, state) + int state; + char *text; +{ + static char **matches = (char **)NULL; + static char *orig_start, *filename_text = (char *)NULL; + static int cmd_index, start_len; + + if (state == 0) + { + if (filename_text) + free (filename_text); + orig_start = text; + if (*text == '`') + text++; + else if (*text == '$' && text[1] == '(') + text += 2; + start_len = text - orig_start; + filename_text = savestring (text); + if (matches) + free (matches); + matches = completion_matches (filename_text, command_word_completion_function); + cmd_index = 0; + } + + if (!matches || !matches[cmd_index]) + { + rl_filename_quoting_desired = 0; /* disable quoting */ + return ((char *)NULL); + } + else + { + char *value; + + value = xmalloc (1 + start_len + strlen (matches[cmd_index])); + + if (start_len == 1) + value[0] = *orig_start; + else + strncpy (value, orig_start, start_len); + + strcpy (value + start_len, matches[cmd_index]); + + cmd_index++; + return (value); + } +} + +/* Okay, now we write the entry_function for variable completion. */ +static char * +variable_completion_function (text, state) + int state; + char *text; +{ + register SHELL_VAR *var = (SHELL_VAR *)NULL; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; + static int varlist_index; + static char *varname = (char *)NULL; + static int namelen; + static int first_char, first_char_loc; + + if (!state) + { + if (varname) + free (varname); + + first_char_loc = 0; + first_char = text[0]; + + if (first_char == '$') + first_char_loc++; + + varname = savestring (text + first_char_loc); + + namelen = strlen (varname); + if (varlist) + free (varlist); + varlist = all_visible_variables (); + varlist_index = 0; + } + + while (varlist && varlist[varlist_index]) + { + var = varlist[varlist_index]; + + /* Compare. You can't do better than Zayre. No text is also + a match. */ + if (!*varname || (strncmp (varname, var->name, namelen) == 0)) + break; + varlist_index++; + } + + if (!varlist || !varlist[varlist_index]) + { + return ((char *)NULL); + } + else + { + char *value = xmalloc (2 + strlen (var->name)); + + if (first_char_loc) + *value = first_char; + + strcpy (&value[first_char_loc], var->name); + + varlist_index++; + return (value); + } +} + +/* How about a completion function for hostnames? */ +static char * +hostname_completion_function (text, state) + int state; + char *text; +{ + static char **list = (char **)NULL; + static int list_index = 0; + static int first_char, first_char_loc; + + /* If we don't have any state, make some. */ + if (!state) + { + if (list) + free (list); + + list = (char **)NULL; + + first_char_loc = 0; + first_char = *text; + + if (first_char == '@') + first_char_loc++; + + list = hostnames_matching (&text[first_char_loc]); + list_index = 0; + } + + if (list && list[list_index]) + { + char *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); +} + +/* History and alias expand the line. */ +static char * +history_expand_line_internal (line) + char *line; +{ + char *new_line; + + new_line = pre_process_line (line, 0, 0); + return new_line; +} + +#if defined (ALIAS) +/* Perform alias expansion on LINE and return the new line. */ +static char * +alias_expand_line_internal (line) + char *line; +{ + char *alias_line; + + alias_line = alias_expand (line); + return alias_line; +} +#endif + +/* There was an error in expansion. Let the preprocessor print + the error here. */ +static void +cleanup_expansion_error () +{ + char *to_free; + + fprintf (rl_outstream, "\r\n"); + to_free = pre_process_line (rl_line_buffer, 1, 0); + free (to_free); + putc ('\r', rl_outstream); + rl_forced_update_display (); +} + +/* If NEW_LINE differs from what is in the readline line buffer, add an + undo record to get from the readline line buffer contents to the new + line and make NEW_LINE the current readline line. */ +static void +maybe_make_readline_line (new_line) + char *new_line; +{ + if (strcmp (new_line, rl_line_buffer) != 0) + { + rl_point = rl_end; + + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + rl_delete_text (0, rl_point); + rl_point = rl_end = 0; + rl_insert_text (new_line); + rl_add_undo (UNDO_END, 0, 0, 0); + } +} + +/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ +static void +set_up_new_line (new_line) + char *new_line; +{ + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + 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); + } +} + +/* History expand the line. */ +static void +history_expand_line (ignore) + int ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + + if (new_line) + set_up_new_line (new_line); + else + cleanup_expansion_error (); +} + +/* History and alias expand the line. */ +static void +history_and_alias_expand_line (ignore) + int ignore; +{ + char *new_line; + + new_line = pre_process_line (rl_line_buffer, 0, 0); + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + set_up_new_line (new_line); + else + cleanup_expansion_error (); +} + +/* History and alias expand the line, then perform the shell word + expansions by calling expand_string. */ +static void +shell_expand_line (ignore) + int ignore; +{ + char *new_line; + + new_line = pre_process_line (rl_line_buffer, 0, 0); + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* 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); + } + + 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); + } + } + } + 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 + 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<TAB> produces names[0] = "und", names[1] = "under.c", names[2] = + "undun.c", name[3] = NULL). */ + +struct ign { + char *val; + int len; +}; + +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 () +{ + 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); +} + +/* 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) + char **names; + Function *name_func; +{ + char **newnames; + int idx, nidx; + + /* If there is only one completion, see if it is acceptable. If it is + not, free it up. In any case, short-circuit and return. This is a + special case because names[0] is not the prefix of the list of names + if there is only one completion; it is the completion itself. */ + if (names[1] == (char *)0) + { + if ((*name_func) (names[0]) == 0) + { + free (names[0]); + names[0] = (char *)NULL; + } + return; + } + + /* Allocate space for array to hold list of pointers to matching + filenames. The pointers are copied back to NAMES when done. */ + for (nidx = 1; names[nidx]; nidx++) + ; + newnames = (char **)xmalloc ((nidx + 1) * (sizeof (char *))); + + newnames[0] = names[0]; + for (idx = nidx = 1; names[idx]; idx++) + { + if ((*name_func) (names[idx])) + newnames[nidx++] = names[idx]; + else + free (names[idx]); + } + + newnames[nidx] = (char *)NULL; + + /* If none are acceptable then let the completer handle it. */ + if (nidx == 1) + { + free (names[0]); + names[0] = (char *)NULL; + free (newnames); + return; + } + + /* If only one is acceptable, copy it to names[0] and return. */ + if (nidx == 2) + { + free (names[0]); + names[0] = newnames[1]; + names[1] = (char *)NULL; + 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; +} + +static void +filename_completion_ignore (names) + char **names; +{ + setup_ignore_patterns (); + + if (num_ignores == 0) + return; + + _ignore_names (names, name_is_acceptable); +} + +/* Return 1 if NAME is a directory. */ +static int +test_for_directory (name) + char *name; +{ + struct stat finfo; + char *fn; + + fn = tilde_expand (name); + if (stat (fn, &finfo) != 0) + { + free (fn); + return 0; + } + free (fn); + return (S_ISDIR (finfo.st_mode)); +} + +/* Remove files from NAMES, leaving directories. */ +static void +bash_ignore_filenames (names) + char **names; +{ + _ignore_names (names, test_for_directory); +} + +/* Handle symbolic link references and other directory name + expansions while hacking completion. */ +static int +bash_directory_completion_hook (dirname) + char **dirname; +{ + char *local_dirname, *t; + int return_value = 0; + WORD_LIST *wl; + + local_dirname = *dirname; + if (strchr (local_dirname, '$') || strchr (local_dirname, '`')) + { + wl = expand_string (local_dirname, 0); + if (wl) + { + *dirname = string_list (wl); + /* Tell the completer to replace the directory name only if we + actually expanded something. */ + return_value = STREQ (local_dirname, *dirname) == 0; + free (local_dirname); + dispose_words (wl); + local_dirname = *dirname; + } + else + { + free (local_dirname); + *dirname = savestring (""); + return 1; + } + } + + if (!no_symbolic_links && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = canonicalize_pathname (temp1); + len1 = strlen (temp1); + if (temp1[len1 - 1] == '/') + { + len2 = strlen (temp2); + temp2 = xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } + free (local_dirname); + *dirname = temp2; + free (temp1); + } + 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 void +build_history_completion_array () +{ + register int i; + + /* First, clear out the current dynamic history completion list. */ + if (harry_size) + { + for (i = 0; history_completion_array[i]; i++) + free (history_completion_array[i]); + + free (history_completion_array); + + history_completion_array = (char **)NULL; + harry_size = 0; + harry_len = 0; + } + + /* 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; + + for (i = 0; hlist[i]; i++) + { + char **tokens; + + /* 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) + 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); + } + + /* Sort the complete list of tokens. */ + qsort (history_completion_array, harry_len, sizeof (char *), + (Function *)qsort_string_compare); + + /* Instead of removing the duplicate entries here, we let the + code in the completer handle it. */ + } + } +} + +static char * +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; + + /* If this is the first call to the generator, then initialize the + list of strings to complete over. */ + if (!state) + { + local_index = 0; + build_history_completion_array (); + text = hint_text; + len = strlen (text); + } + + while (history_completion_array && history_completion_array[local_index]) + { + if (strncmp (text, history_completion_array[local_index++], len) == 0) + return (savestring (history_completion_array[local_index - 1])); + } + return ((char *)NULL); +} + +static void +dynamic_complete_history (count, key) + int count, key; +{ + Function *orig_func; + CPPFunction *orig_attempt_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + rl_completion_entry_function = (Function *)history_completion_generator; + rl_attempted_completion_function = (CPPFunction *)NULL; + + if (rl_last_func == (Function *)dynamic_complete_history) + rl_complete_internal ('?'); + else + rl_complete_internal (TAB); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; +} + +#endif /* DYNAMIC_HISTORY_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static void +bash_complete_username (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_username_internal (TAB); +} + +static void +bash_possible_username_completions (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_username_internal ('?'); +} + +static void +bash_complete_username_internal (what_to_do) + int what_to_do; +{ + bash_specific_completion + (what_to_do, (Function *)username_completion_function); +} + +static void +bash_complete_filename (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_filename_internal (TAB); +} + +static void +bash_possible_filename_completions (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_filename_internal ('?'); +} + +static void +bash_complete_filename_internal (what_to_do) + int what_to_do; +{ + Function *orig_func, *orig_dir_func; + CPPFunction *orig_attempt_func; + char *orig_rl_completer_word_break_characters; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_dir_func = rl_directory_completion_hook; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; + rl_completion_entry_function = (Function *)filename_completion_function; + rl_attempted_completion_function = (CPPFunction *)NULL; + rl_directory_completion_hook = (Function *)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_directory_completion_hook = orig_dir_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; +} + +static void +bash_complete_hostname (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_hostname_internal (TAB); +} + +static void +bash_possible_hostname_completions (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_hostname_internal ('?'); +} + +static void +bash_complete_variable (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_variable_internal (TAB); +} + +static void +bash_possible_variable_completions (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_variable_internal ('?'); +} + +static void +bash_complete_command (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_command_internal (TAB); +} + +static void +bash_possible_command_completions (ignore, ignore2) + int ignore, ignore2; +{ + bash_complete_command_internal ('?'); +} + +static void +bash_complete_hostname_internal (what_to_do) + int what_to_do; +{ + bash_specific_completion + (what_to_do, (Function *)hostname_completion_function); +} + +static void +bash_complete_variable_internal (what_to_do) + int what_to_do; +{ + bash_specific_completion + (what_to_do, (Function *)variable_completion_function); +} + +static void +bash_complete_command_internal (what_to_do) + int what_to_do; +{ + bash_specific_completion + (what_to_do, (Function *)command_word_completion_function); +} + +static void +bash_specific_completion (what_to_do, generator) + int what_to_do; + Function *generator; +{ + Function *orig_func; + CPPFunction *orig_attempt_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + rl_completion_entry_function = generator; + rl_attempted_completion_function = (CPPFunction *)NULL; + + rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; +} + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ diff --git a/bashtypes.h b/bashtypes.h new file mode 100644 index 0000000..a725d61 --- /dev/null +++ b/bashtypes.h @@ -0,0 +1,34 @@ +/* bashtypes.h -- <sys/types.h> with special handling for crays. */ + +/* 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 (__BASHTYPES_H) +# define __BASHTYPES_H + +#if defined (CRAY) +# define word __word +#endif + +#include <sys/types.h> + +#if defined (CRAY) +# undef word +#endif + +#endif /* __BASHTYPES_H */ diff --git a/bracecomp.c b/bracecomp.c new file mode 100644 index 0000000..c07e15d --- /dev/null +++ b/bracecomp.c @@ -0,0 +1,166 @@ +/* bracecomp.c -- Complete a filename with the possible completions enclosed + in csh-style braces such that the list of completions is available to the + shell. */ + +/* Original version by tromey@cns.caltech.edu, Fri Feb 7 1992. */ + +/* 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 <stdio.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "shell.h" +#include <readline/readline.h> + +/* Find greatest common prefix of two strings. */ +static int +string_gcd (s1, s2) + char *s1, *s2; +{ + register int i; + + if (s1 == NULL || s2 == NULL) + return (0); + + for (i = 0; *s1 && *s2; ++s1, ++s2, ++i) + { + if (*s1 != *s2) + break; + } + + return (i); +} + +static char * +really_munge_braces (array, real_start, real_end, gcd_zero) + char **array; + int real_start, real_end, gcd_zero; +{ + int start, end, gcd; + char *result, *subterm; + int result_size, flag; + + flag = 0; + + if (real_start == real_end) + { + if (array[real_start]) + return (savestring (array[real_start] + gcd_zero)); + else + return (savestring (array[0])); + } + + result = (char *) xmalloc (result_size = 1); + *result = '\0'; + + for (start = real_start; start < real_end; start = end + 1) + { + gcd = strlen (array[start]); + for (end = start + 1; end < real_end; end++) + { + int temp; + + temp = string_gcd (array[start], array[end]); + + if (temp <= gcd_zero) + break; + + gcd = temp; + } + end--; + + if (gcd_zero == 0 && start == real_start && end != (real_end - 1)) + { + /* 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); + strcpy (result, "{"); + flag++; + } + + if (start == end) + subterm = savestring (array[start] + gcd_zero); + else + { + /* 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); + strncat (result, array[start] + gcd_zero, gcd - gcd_zero); + strcat (result, "{"); + subterm = really_munge_braces (array, start, end + 1, gcd); + subterm[strlen (subterm) - 1] = '}'; + } + + result_size += strlen (subterm) + 1; + result = (char *) xrealloc (result, result_size); + strcat (result, subterm); + strcat (result, ","); + free (subterm); + } + + if (gcd_zero == 0) + result[strlen (result) - 1] = flag ? '}' : '\0'; + return (result); +} + +static void +hack_braces_completion (names) + char **names; +{ + register int i; + char *temp; + + temp = really_munge_braces (names, 1, array_len (names), 0); + + for (i = 0; names[i]; ++i) + { + free (names[i]); + names[i] = NULL; + } + names[0] = temp; +} + +void +bash_brace_completion () +{ + Function *orig_ignore_func; + Function *orig_entry_func; + CPPFunction *orig_attempt_func; + + orig_ignore_func = rl_ignore_some_completions_function; + orig_attempt_func = rl_attempted_completion_function; + orig_entry_func = rl_completion_entry_function; + + rl_completion_entry_function = (Function *) filename_completion_function; + rl_attempted_completion_function = NULL; + rl_ignore_some_completions_function = (Function *) hack_braces_completion; + + rl_complete_internal (TAB); + + rl_ignore_some_completions_function = orig_ignore_func; + rl_attempted_completion_function = orig_attempt_func; + rl_completion_entry_function = orig_entry_func; +} diff --git a/braces.c b/braces.c new file mode 100644 index 0000000..2eb4de4 --- /dev/null +++ b/braces.c @@ -0,0 +1,371 @@ +/* braces.c -- code for doing word expansion in curly braces. */ + +/* 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. */ + +/* Stuff in curly braces gets expanded after variable and command + substitution, but before filename globbing. + + (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. */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (SHELL) +#include "shell.h" +#endif /* SHELL */ + +#include "general.h" +#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n') + +/* Basic idea: + + Segregate the text into 3 sections: preamble (stuff before an open brace), + postamble (stuff after the matching close brace) and amble (stuff after + preamble, and before postamble). Expand amble, and then tack on the + expansions to preamble. Expand postamble, and tack on the expansions to + the result so far. + */ + +/* The character which is used to separate arguments. */ +int brace_arg_separator = ','; + +static int brace_gobbler (); +static char **expand_amble (), **array_concat (); + +/* Return an array of strings; the brace expansion of TEXT. */ +char ** +brace_expand (text) + char *text; +{ + register int start; + char *preamble, *postamble, *amble; + char **tack, **result; + int i, c; + + /* Find the text of the preamble. */ + i = 0; + c = brace_gobbler (text, &i, '{'); + + preamble = (char *)xmalloc (i + 1); + strncpy (preamble, text, i); + preamble[i] = '\0'; + + 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 != '{') + return (result); + + /* Find the amble. This is the stuff inside this set of braces. */ + start = ++i; + c = brace_gobbler (text, &i, '}'); + + /* What if there isn't a matching close brace? */ + if (!c) + { +#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++) + { + if (text[j] == '\\') + { + j++; + continue; + } + + if (text[j] == brace_arg_separator) + { + free_array (result); + report_error ("Missing `}'"); + throw_to_top_level (); + } + } +#endif + free (preamble); /* Same as result[0]; see initialization. */ + result[0] = savestring (text); + return (result); + } + + amble = (char *)xmalloc (1 + (i - start)); + strncpy (amble, &text[start], (i - start)); + amble[i - start] = '\0'; + +#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); + } + } +#endif /* SHELL */ + + postamble = &text[i + 1]; + + tack = expand_amble (amble); + result = array_concat (result, tack); + free (amble); + free_array (tack); + + tack = brace_expand (postamble); + result = array_concat (result, tack); + free_array (tack); + + return (result); +} + +/* Expand the text found inside of braces. We simply try to split the + text at BRACE_ARG_SEPARATORs into separate strings. We then brace + expand each slot which needs it, until there are no more slots which + need it. */ +static char ** +expand_amble (text) + char *text; +{ + char **result, **partial; + char *tem; + int start, i, c; + + result = (char **)NULL; + + for (start = 0, i = 0, c = 1; c; start = ++i) + { + c = brace_gobbler (text, &i, brace_arg_separator); + tem = (char *)xmalloc (1 + (i - start)); + strncpy (tem, &text[start], (i - start)); + tem[i- start] = '\0'; + + partial = brace_expand (tem); + + if (!result) + result = partial; + else + { + register int lr = array_len (result); + register int lp = array_len (partial); + register int j; + + result = (char **)xrealloc (result, (1 + lp + lr) * sizeof (char *)); + + for (j = 0; j < lp; j++) + result[lr + j] = partial[j]; + + result[lr + j] = (char *)NULL; + free (partial); + } + free (tem); + } + return (result); +} + +/* Start at INDEX, and skip characters in TEXT. Set INDEX to the + index of the character matching SATISFY. This understands about + quoting. Return the character that caused us to stop searching; + this is either the same as SATISFY, or 0. */ +static int +brace_gobbler (text, indx, satisfy) + char *text; + int *indx; + int satisfy; +{ + register int i, c, quoted, level, pass_next; + + level = quoted = pass_next = 0; + + for (i = *indx; c = text[i]; i++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + + /* A backslash escapes the next character. This allows backslash to + escape the quote character in a double-quoted string. */ + if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`')) + { + pass_next = 1; + continue; + } + + if (quoted) + { + if (c == quoted) + quoted = 0; + continue; + } + + if (c == '"' || c == '\'' || c == '`') + { + quoted = c; + continue; + } + + if (c == satisfy && !level && !quoted) + { + /* We ignore an open brace surrounded by whitespace, and also + an open brace followed immediately by a close brace, that + was preceded with whitespace. */ + if (c == '{' && + ((!i || brace_whitespace (text[i - 1])) && + (brace_whitespace (text[i + 1]) || text[i + 1] == '}'))) + continue; +#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 */ + break; + } + + if (c == '{') + level++; + else if (c == '}' && level) + level--; + } + + *indx = i; + return (c); +} + +/* Return a new array of strings which is the result of appending each + string in ARR2 to each string in ARR1. The resultant array is + len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents) + are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2 + is returned. */ +static char ** +array_concat (arr1, arr2) + char **arr1, **arr2; +{ + register int i, j, len, len1, len2; + register char **result; + + if (!arr1) + return (copy_array (arr2)); + + if (!arr2) + return (copy_array (arr1)); + + len1 = array_len (arr1); + len2 = array_len (arr2); + + result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *)); + + len = 0; + for (i = 0; i < len1; i++) + { + int strlen_1 = strlen (arr1[i]); + + for (j = 0; j < len2; j++) + { + result[len] = + (char *)xmalloc (1 + strlen_1 + strlen (arr2[j])); + strcpy (result[len], arr1[i]); + strcpy (result[len] + strlen_1, arr2[j]); + len++; + } + free (arr1[i]); + } + free (arr1); + + result[len] = (char *)NULL; + return (result); +} + +#if defined (TEST) +#include <stdio.h> + +fatal_error (format, arg1, arg2) + char *format, *arg1, *arg2; +{ + report_error (format, arg1, arg2); + exit (1); +} + +report_error (format, arg1, arg2) + char *format, *arg1, *arg2; +{ + fprintf (stderr, format, arg1, arg2); + fprintf (stderr, "\n"); +} + +main () +{ + char example[256]; + + for (;;) + { + char **result; + int i; + + fprintf (stderr, "brace_expand> "); + + if ((!fgets (example, 256, stdin)) || + (strncmp (example, "quit", 4) == 0)) + break; + + if (strlen (example)) + example[strlen (example) - 1] = '\0'; + + result = brace_expand (example); + + for (i = 0; result[i]; i++) + printf ("%s\n", result[i]); + + free_array (result); + } +} + +/* + * Local variables: + * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o" + * end: + */ + +#endif /* TEST */ diff --git a/builtins.h b/builtins.h new file mode 100644 index 0000000..6d4d8e8 --- /dev/null +++ b/builtins.h @@ -0,0 +1,45 @@ +/* builtins.h -- What a builtin looks like, and where to find them. */ + +/* 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. */ + +#include "config.h" +#include "command.h" +#include "general.h" + +#if defined (ALIAS) +#include "alias.h" +#endif + +/* 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. */ + +/* The thing that we build the array of builtins out of. */ +struct builtin { + char *name; /* The name that the user types. */ + Function *function; /* The address of the invoked function. */ + int flags; /* One of the #defines above. */ + char **long_doc; /* NULL terminated array of strings. */ + char *short_doc; /* Short version of documenation. */ +}; + +/* Found in builtins.c, created by builtins/mkbuiltins. */ +extern int num_shell_builtins; /* Number of shell builtins. */ +extern struct builtin shell_builtins[]; diff --git a/builtins/ChangeLog b/builtins/ChangeLog new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/builtins/ChangeLog diff --git a/builtins/Makefile b/builtins/Makefile new file mode 100644 index 0000000..6472f7d --- /dev/null +++ b/builtins/Makefile @@ -0,0 +1,267 @@ +# 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/alias.def b/builtins/alias.def new file mode 100644 index 0000000..a878c70 --- /dev/null +++ b/builtins/alias.def @@ -0,0 +1,180 @@ +This file is alias.def, from which is created alias.c +It implements the builtins "alias" and "unalias" 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. + +$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. +$END + +#include "../config.h" + +#if defined (ALIAS) +# include <stdio.h> +# include "../shell.h" +# include "../alias.h" +# include "common.h" + +extern int interactive; +static void print_alias (); + +/* Hack the alias command in a Korn shell way. */ +alias_builtin (list) + WORD_LIST *list; +{ + int any_failed = 0; + + if (!list) + { + register int i; + ASSOC **alias_list; + + if (!aliases) + return (EXECUTION_FAILURE); + + alias_list = all_aliases (); + + if (!alias_list) + return (EXECUTION_FAILURE); + + for (i = 0; alias_list[i]; i++) + print_alias (alias_list[i]); + + free (alias_list); /* XXX - Do not free the strings. */ + } + else + { + while (list) + { + register char *value, *name = list->word->word; + register int offset; + + for (offset = 0; name[offset] && name[offset] != '='; offset++) + ; + + if (offset && name[offset] == '=') + { + name[offset] = '\0'; + value = name + offset + 1; + + add_alias (name, value); + } + else + { + ASSOC *t = find_alias (name); + if (t) + print_alias (t); + else + { + if (interactive) + builtin_error ("`%s' not found", name); + any_failed++; + } + } + list = list->next; + } + } + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} +#endif /* ALIAS */ + +$BUILTIN unalias +$FUNCTION unalias_builtin +$DEPENDS_ON ALIAS +$SHORT_DOC unalias [-a] [name ...] +Remove NAMEs from the list of defined aliases. If the -a option is given, +then remove all alias definitions. +$END + +#if defined (ALIAS) +/* Remove aliases named in LIST from the aliases database. */ +unalias_builtin (list) + register WORD_LIST *list; +{ + register ASSOC *alias; + int any_failed = 0; + + while (list && *list->word->word == '-') + { + register char *word = list->word->word; + + if (ISOPTION (word, 'a')) + { + delete_all_aliases (); + list = list->next; + } + else if (ISOPTION (word, '-')) + { + list = list->next; + break; + } + else + { + bad_option (word); + return (EXECUTION_FAILURE); + } + } + + while (list) + { + alias = find_alias (list->word->word); + + if (alias) + remove_alias (alias->name); + else + { + if (interactive) + builtin_error ("`%s' not an alias", list->word->word); + + any_failed++; + } + + list = list->next; + } + + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} + +/* Output ALIAS in such a way as to allow it to be read back in. */ +static void +print_alias (alias) + ASSOC *alias; +{ + char *value = single_quote (alias->value); + + printf ("alias %s=%s\n", alias->name, value); + free (value); + + fflush (stdout); +} +#endif /* ALIAS */ diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c new file mode 100644 index 0000000..95dcaac --- /dev/null +++ b/builtins/bashgetopt.c @@ -0,0 +1,136 @@ +/* bashgetopt.c -- `getopt' for use by the builtins. */ + +/* Copyright (C) 1992 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 <errno.h> +#include "shell.h" + +#include "bashansi.h" + +#define ERR(S, C) builtin_error("%s%c", (S), (C)) + +static int sp; + +char *list_optarg; +int list_optopt; + +static WORD_LIST *lhead = (WORD_LIST *)NULL; +WORD_LIST *lcurrent = (WORD_LIST *)NULL; +WORD_LIST *loptend; /* Points to the first non-option argument in the list */ + +int +internal_getopt(list, opts) +WORD_LIST *list; +char *opts; +{ + register int c; + register char *cp; + + if (!list) { + list_optarg = (char *)NULL; + loptend = (WORD_LIST *)NULL; /* No non-option arguments */ + return -1; + } + + if (list != lhead || !lhead) { + /* Hmmm.... called with a different word list. Reset. */ + sp = 1; + lcurrent = lhead = list; + loptend = (WORD_LIST *)NULL; + } + + if (sp == 1) { + if (!lcurrent || + (lcurrent->word->word[0] != '-' || lcurrent->word->word[1] == '\0')) { + lhead = (WORD_LIST *)NULL; + loptend = lcurrent; + return(-1); + } else if (lcurrent->word->word[0] == '-' && + lcurrent->word->word[1] == '-' && + lcurrent->word->word[2] == 0) { + lhead = (WORD_LIST *)NULL; + loptend = lcurrent->next; + return(-1); + } + } + + list_optopt = c = lcurrent->word->word[sp]; + + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + ERR("illegal option: -", c); + if (lcurrent->word->word[++sp] == '\0') { + lcurrent = lcurrent->next; + sp = 1; + } + list_optarg = NULL; + if (lcurrent) + loptend = lcurrent->next; + return('?'); + } + + if (*++cp == ':') { + /* Option requires an argument. */ + /* We allow -l2 as equivalent to -l 2 */ + if (lcurrent->word->word[sp+1] != '\0') { + list_optarg = &(lcurrent->word->word[sp+1]); + lcurrent = lcurrent->next; + } else if (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 { + /* No argument, just return the option. */ + if (lcurrent->word->word[++sp] == '\0') { + sp = 1; + lcurrent = lcurrent->next; + } + list_optarg = (char *)NULL; + } + + return(c); +} + +/* + * reset_internal_getopt -- force the in[ft]ernal getopt to reset + */ + +void +reset_internal_getopt () +{ + lhead = lcurrent = loptend = (WORD_LIST *)NULL; + sp = 1; +} + +void +report_bad_option () +{ + char s[3]; + + s[0] = '-'; + s[1] = list_optopt; + s[2] = '\0'; + bad_option (s); +} diff --git a/builtins/bashgetopt.h b/builtins/bashgetopt.h new file mode 100644 index 0000000..0360dbb --- /dev/null +++ b/builtins/bashgetopt.h @@ -0,0 +1,37 @@ +/* bashgetopt.h -- extern declarations for stuff defined in bashgetopt.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. */ + +/* See getopt.h for the explanation of these variables. */ + +#if !defined (__BASH_GETOPT_H) +# define __BASH_GETOPT_H + +extern char *list_optarg; + +extern int list_optopt; + +extern WORD_LIST *lcurrent; +extern WORD_LIST *loptend; + +extern int internal_getopt (); +extern void reset_internal_getopt (); +extern void report_bad_option (); + +#endif /* !__BASH_GETOPT_H */ diff --git a/builtins/bind.def b/builtins/bind.def new file mode 100644 index 0000000..cdcd6a3 --- /dev/null +++ b/builtins/bind.def @@ -0,0 +1,219 @@ +This file is bind.def, from which is created bind.c. +It implements the builtin "bind" 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 bind.c + +$BUILTIN bind +$DEPENDS_ON READLINE +$FUNCTION bind_builtin +$SHORT_DOC bind [-lvd] [-m keymap] [-f filename] [-q name] [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'. +Arguments we accept: + -m keymap Use `keymap' as the keymap for the duration of this + command. Acceptable keymap names are emacs, + 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. + -f filename Read key bindings from FILENAME. + -q function-name Query about which keys invoke the named function. +$END + +#include <stdio.h> +#include "../shell.h" +#if defined (READLINE) +#include <errno.h> +#if !defined (errno) +extern int errno; +#endif /* !errno */ +#include <readline/readline.h> +#include <readline/history.h> +#include "bashgetopt.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]" + +int +bind_builtin (list) + WORD_LIST *list; +{ + int return_code = EXECUTION_SUCCESS; + FILE *old_rl_outstream; + Keymap kmap, saved_keymap; + int lflag, dflag, fflag, vflag, qflag, mflag, opt; + char *initfile, *map_name, *fun_name; + + 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; + + if (!bash_readline_initialized) + initialize_readline (); + + /* Cannot use unwind_protect_pointer () on "FILE *", it is only + guaranteed to work for strings. */ + /* XXX -- see if we can use unwind_protect here */ + old_rl_outstream = rl_outstream; + rl_outstream = stdout; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "lvdf:q:m:")) != EOF) + { + switch (opt) + { + case 'l': + lflag++; + break; + + case 'v': + vflag++; + break; + + case 'd': + dflag++; + break; + + case 'f': + fflag++; + initfile = list_optarg; + break; + + case 'm': + mflag++; + map_name = list_optarg; + break; + + case 'q': + qflag++; + fun_name = list_optarg; + break; + + default: + builtin_error (USAGE); + BIND_RETURN (EX_USAGE); + } + } + + list = loptend; + + /* First, see if we need to install a special keymap for this + command. Then start on the arguments. */ + + if (mflag && map_name) + { + kmap = rl_get_keymap_by_name (map_name); + if (!kmap) + { + builtin_error ("`%s': illegal keymap name", map_name); + BIND_RETURN (EXECUTION_FAILURE); + } + } + + if (kmap) + { + saved_keymap = rl_get_keymap (); + rl_set_keymap (kmap); + } + + /* 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 (vflag) + rl_function_dumper (0); + + if (dflag) + rl_function_dumper (1); + + if (fflag && initfile) + { + if (rl_read_init_file (initfile) != 0) + { + builtin_error ("cannot read %s: %s", initfile, strerror (errno)); + BIND_RETURN (EXECUTION_FAILURE); + } + } + + if (qflag && fun_name) + return_code = query_bindings (fun_name); + + /* Process the rest of the arguments as binding specifications. */ + while (list) + { + rl_parse_and_bind (list->word->word); + list = list->next; + } + + bind_exit: + if (saved_keymap) + rl_set_keymap (saved_keymap); + + rl_outstream = old_rl_outstream; + return (return_code); +} + +static int +query_bindings (name) + char *name; +{ + Function *function; + char **keyseqs; + int j; + + function = rl_named_function (name); + if (!function) + { + builtin_error ("unknown function name `%s'", name); + return EXECUTION_FAILURE; + } + + keyseqs = rl_invoking_keyseqs (function); + + if (!keyseqs) + { + printf ("%s is not bound to any keys.\n", name); + return EXECUTION_FAILURE; + } + + printf ("%s can be invoked via ", name); + for (j = 0; j < 5 && keyseqs[j]; j++) + printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n"); + if (keyseqs[j]) + printf ("...\n"); + free_array (keyseqs); + return EXECUTION_SUCCESS; +} +#endif /* READLINE */ diff --git a/builtins/break.def b/builtins/break.def new file mode 100644 index 0000000..d72f9e3 --- /dev/null +++ b/builtins/break.def @@ -0,0 +1,110 @@ +This file is break.def, from which is created break.c. +It implements the builtins "break" and "continue" 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 break.c + +$BUILTIN break +$FUNCTION break_builtin +$SHORT_DOC break [n] +Exit from within a FOR, WHILE or UNTIL loop. If N is specified, +break N levels. +$END + +#include "../shell.h" + +extern char *this_command_name; + +static int check_loop_level (); + +/* The depth of while's and until's. */ +int loop_level = 0; + +/* Non-zero when a "break" instruction is encountered. */ +int breaking = 0; + +/* Non-zero when we have encountered a continue instruction. */ +int continuing = 0; + +/* Set up to break x levels, where x defaults to 1, but can be specified + as the first argument. */ +break_builtin (list) + WORD_LIST *list; +{ + int newbreak; + + if (!check_loop_level ()) + return (EXECUTION_FAILURE); + + newbreak = get_numeric_arg (list); + + if (newbreak <= 0) + return (EXECUTION_FAILURE); + + if (newbreak > loop_level) + newbreak = loop_level; + + breaking = newbreak; + + return (EXECUTION_SUCCESS); +} + +$BUILTIN continue +$FUNCTION continue_builtin +$SHORT_DOC continue [n] +Resume the next iteration of the enclosing FOR, WHILE or UNTIL loop. +If N is specified, resume at the N-th enclosing loop. +$END + +/* Set up to continue x levels, where x defaults to 1, but can be specified + as the first argument. */ +continue_builtin (list) + WORD_LIST *list; +{ + int newcont; + + if (!check_loop_level ()) + return (EXECUTION_FAILURE); + + newcont = get_numeric_arg (list); + + if (newcont <= 0) + return (EXECUTION_FAILURE); + + if (newcont > loop_level) + newcont = loop_level; + + continuing = newcont; + + return (EXECUTION_SUCCESS); +} + +/* Return non-zero if a break or continue command would be okay. + Print an error message if break or continue is meaningless here. */ +static int +check_loop_level () +{ +#if defined (BREAK_COMPLAINS) + if (!loop_level) + 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 new file mode 100644 index 0000000..824b30d --- /dev/null +++ b/builtins/builtin.def @@ -0,0 +1,67 @@ +This file is builtin.def, from which is created builtin.c. +It implements the builtin "builtin" 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 builtin.c + +$BUILTIN builtin +$FUNCTION builtin_builtin +$SHORT_DOC builtin [shell-builtin [arg ...]] +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 "../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. */ +builtin_builtin (list) + WORD_LIST *list; +{ + Function *function; + register char *command; + + if (!list) + return (EXECUTION_SUCCESS); + + command = (list->word->word); +#if defined (DISABLED_BUILTINS) + function = builtin_address (command); +#else /* !DISABLED_BUILTINS */ + function = find_shell_builtin (command); +#endif /* !DISABLED_BUILTINS */ + + if (!function) + { + builtin_error ("%s: not a shell builtin", command); + return (EXECUTION_FAILURE); + } + else + { + this_command_name = command; + list = list->next; + return ((*function) (list)); + } +} diff --git a/builtins/cd.def b/builtins/cd.def new file mode 100644 index 0000000..338f694 --- /dev/null +++ b/builtins/cd.def @@ -0,0 +1,689 @@ +This file is cd.def, from which is created cd.c. It implements the +builtins "cd", "pwd", "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 cd.c + +#include <stdio.h> +#include <sys/param.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include <errno.h> +#include <tilde/tilde.h> + +#include "../shell.h" +#include "../flags.h" +#include "../maxpath.h" +#include "common.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +static int change_to_directory (), cd_to_string (); + +$BUILTIN cd +$FUNCTION cd_builtin +$SHORT_DOC cd [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 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 +name. If that variable has a value, then cd to the value of that +variable. +$END + +/* 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 + restrictions properly. */ +int +cd_builtin (list) + WORD_LIST *list; +{ + char *dirname; + +#if defined (RESTRICTED_SHELL) + if (restricted) + { + builtin_error ("restricted"); + return (EXECUTION_FAILURE); + } +#endif /* RESTRICTED_SHELL */ + + if (list) + { + 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)) + { + 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); + return (EXECUTION_FAILURE); + } + goto bind_and_exit; + } + else + { + dirname = get_string_value ("HOME"); + + if (!dirname) + return (EXECUTION_FAILURE); + + if (!change_to_directory (dirname)) + { + file_error (dirname); + 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) + { + builtin_error ("%s", buffer); + free (buffer); + } + } + else + directory = get_working_directory ("pwd"); + + if (directory) + { + 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. + +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) + { + builtin_error ("No other directory"); + 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 == '-') + { + int num; + if (1 == sscanf (&(list->word->word)[1], "%d", &num)) + { + if (direction == '-') + num = directory_list_offset - num; + + if (num > directory_list_offset || num < 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); + } + 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); + + return (tt); + } + } + } + } + + /* 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 (cd_builtin (list) == EXECUTION_SUCCESS) + { + if (directory_list_offset == directory_list_size) + { + pushd_directory_list = (char **) + xrealloc (pushd_directory_list, + (directory_list_size += 10) * sizeof (char *)); + } + 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)) + { + 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; + } + 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); + 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 ("<no directory>"); + 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); +} +#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. +$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) + WORD_LIST *list; +{ + register int i; + int which = 0; + char direction = '+'; + + if (list) + { + direction = *(list->word->word); + + if ((direction != '+' && direction != '-') || + (1 != sscanf (&((list->word->word)[1]), "%d", &which))) + { + builtin_error ("bad arg `%s'", list->word->word); + return (EXECUTION_FAILURE); + } + } + + if (which > directory_list_offset || (!directory_list_offset && !which)) + { + if (!directory_list_offset) + builtin_error ("Directory stack empty"); + else + builtin_error ("Stack contains only %d directories", + directory_list_offset + 1); + return (EXECUTION_FAILURE); + } + + /* 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]); + } + 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--; + + /* 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); +} +#endif /* PUSHD_AND_POPD */ + +/* Do the work of changing to the directory NEWDIR. Handle symbolic + link following, etc. */ + +static int +change_to_directory (newdir) + char *newdir; +{ + char *t; + + if (!no_symbolic_links) + { + int chdir_return = 0; + char *tdir = (char *)NULL; + + if (!the_current_working_directory) + { + t = get_working_directory ("cd_links"); + FREE (t); + } + + if (the_current_working_directory) + t = make_absolute (newdir, the_current_working_directory); + else + t = savestring (newdir); + + /* TDIR is the canonicalized absolute pathname of the NEWDIR. */ + tdir = canonicalize_pathname (t); + + /* Use the canonicalized version of NEWDIR, or, if canonicalization + failed, use the non-canonical form. */ + if (tdir && *tdir) + free (t); + else + { + FREE (tdir); + + tdir = t; + } + + if (chdir (tdir) < 0) + { + int err; + + chdir_return = 0; + free (tdir); + + err = errno; + + /* We failed changing to the canonicalized directory name. Try + what the user passed verbatim. If we succeed, reinitialize + the_current_working_directory. */ + if (chdir (newdir) == 0) + { + chdir_return = 1; + if (the_current_working_directory) + { + free (the_current_working_directory); + the_current_working_directory = (char *)NULL; + } + + tdir = get_working_directory ("cd"); + FREE (tdir); + } + else + errno = err; + } + else + { + chdir_return = 1; + + FREE (the_current_working_directory); + the_current_working_directory = tdir; + } + + return (chdir_return); + } + else + { + if (chdir (newdir) < 0) + return (0); + else + return (1); + } +} + +/* 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 = make_word_list (make_word (name), NULL); + int result = (cd_builtin (tlist)); + dispose_words (tlist); + return (result); +} diff --git a/builtins/colon.def b/builtins/colon.def new file mode 100644 index 0000000..4ae5b65 --- /dev/null +++ b/builtins/colon.def @@ -0,0 +1,37 @@ +This file is colon.def, from which is created colon.c. +It implements the builtin ":" 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 colon.c + +$BUILTIN : +$DOCNAME colon_builtin +$FUNCTION colon_builtin +$SHORT_DOC : +No effect; the command does nothing. A zero exit code is returned. +$END + +/* Do nothing. This command is a no-op. */ +int +colon_builtin (ignore) + char *ignore; +{ + return (0); +} diff --git a/builtins/command.def b/builtins/command.def new file mode 100644 index 0000000..b84613e --- /dev/null +++ b/builtins/command.def @@ -0,0 +1,177 @@ +This file is command.def, from which is created command.c. +It implements the builtin "command" 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 command.c + +$BUILTIN command +$FUNCTION command_builtin +$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 +for PATH that is guaranteed to find all of the standard utilities. If +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 <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" +#include "bashgetopt.h" + +extern int subshell_environment; + +static void restore_path (); +static char *get_standard_path (); + +/* Run the commands mentioned in LIST without paying attention to shell + functions. */ +int +command_builtin (list) + WORD_LIST *list; +{ + int result, verbose = 0, use_standard_path = 0, opt; + char *old_path; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "pvV")) != -1) + { + switch (opt) + { + case 'p': + use_standard_path = 1; + break; + case 'V': + verbose = 2; + break; + case 'v': + verbose = 4; + break; + + default: + report_bad_option (); + builtin_error ("usage: command [-pvV] [command [arg...]]"); + return (EX_USAGE); + } + } + list = loptend; + + if (!list) + return (EXECUTION_SUCCESS); + + if (verbose) + { + int found, any_found = 0; + + while (list) + { + + found = describe_command (list->word->word, verbose, 0); + + if (!found) + builtin_error ("%s: not found", list->word->word); + + any_found += found; + list = list->next; + } + return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + } + + 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); + } + + run_unwind_frame ("command_builtin"); + + return (result); +} + +/* Restore the value of the $PATH variable after replacing it when + executing `command -p'. */ +static void +restore_path (var) + char *var; +{ + bind_variable ("PATH", var); + free (var); +} + +/* Return a value for PATH that is guaranteed to find all of the standard + utilities. This uses Posix.2 configuration variables, if present. It + uses a value defined in config.h as a last resort. */ +static char * +get_standard_path () +{ +#if defined (_CS_PATH) && !defined (hpux_7) && !defined (NetBSD) + char *p; + size_t len; + + len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0); + p = xmalloc ((int)len + 2); + *p = '\0'; + confstr (_CS_PATH, p, len); + return (p); +#else /* !_CSPATH || hpux_7 || NetBSD */ +# if defined (CS_PATH) + return (savestring (CS_PATH)); +# else + return (savestring (STANDARD_UTILS_PATH)); +# endif /* !CS_PATH */ +#endif /* !_CS_PATH || hpux_7 */ +} diff --git a/builtins/common.c b/builtins/common.c new file mode 100644 index 0000000..ff940b5 --- /dev/null +++ b/builtins/common.c @@ -0,0 +1,829 @@ +/* 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. */ + +#include <stdio.h> +#include <sys/types.h> +#include "../posixstat.h" +#if defined (HAVE_VFPRINTF) +#include <varargs.h> +#endif /* VFPRINTF */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" +#include "../unwind_prot.h" +#include "../maxpath.h" +#include "../jobs.h" +#include "../builtins.h" +#include "../input.h" +#include "../execute_cmd.h" +#include "hashcom.h" +#include "common.h" +#include <tilde/tilde.h> + +#if defined (HISTORY) +# include "../bashhist.h" +#endif + +extern int no_symbolic_links, interactive, interactive_shell; +extern int indirection_level, startup_state; +extern int last_command_exit_value; +extern int hashing_disabled; +extern int variable_context; +extern char *this_command_name, *shell_name; +extern COMMAND *global_command; +extern HASH_TABLE *hashed_filenames; + +/* 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); +} + +/* 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) +void +builtin_error (va_alist) + va_dcl +{ + char *format; + va_list args; + + if (this_command_name && *this_command_name) + fprintf (stderr, "%s: ", this_command_name); + + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + va_end (args); + fprintf (stderr, "\n"); +} +#else /* !HAVE_VFPRINTF */ +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 /* !HAVE_VFPRINTF */ + +/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is + non-zero, then discard whatever the existing arguments are, else + only discard the ones that are to be replaced. */ +void +remember_args (list, destructive) + WORD_LIST *list; + int destructive; +{ + register int i; + + for (i = 1; i < 10; i++) + { + if (destructive && dollar_vars[i]) + { + free (dollar_vars[i]); + dollar_vars[i] = (char *)NULL; + } + + if (list) + { + if (!destructive && dollar_vars[i]) + free (dollar_vars[i]); + + dollar_vars[i] = savestring (list->word->word); + list = list->next; + } + } + + /* If arguments remain, assign them to REST_OF_ARGS. + Note that copy_word_list (NULL) returns NULL, and + that dispose_words (NULL) does nothing. */ + if (destructive || list) + { + dispose_words (rest_of_args); + rest_of_args = copy_word_list (list); + } + + if (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 */ +/* */ +/* **************************************************************** */ + +static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; +static int dollar_arg_stack_slots = 0; +static int dollar_arg_stack_index = 0; + +void +push_context () +{ + push_dollar_vars (); + variable_context++; +} + +void +pop_context () +{ + pop_dollar_vars (); + kill_all_local_variables (); + variable_context--; +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (WORD_LIST **) + 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; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (!dollar_arg_stack || !dollar_arg_stack_index) + return; + + remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); + dispose_words (dollar_arg_stack[dollar_arg_stack_index]); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; +} + +void +dispose_saved_dollar_vars () +{ + if (!dollar_arg_stack || !dollar_arg_stack_index) + 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; + +/* Have the dollar variables been reset to new values since we last + checked? */ +dollar_vars_changed () +{ + return (changed_dollar_vars); +} + +void +set_dollar_vars_unchanged () +{ + changed_dollar_vars = 0; +} + +void +set_dollar_vars_changed () +{ + changed_dollar_vars = 1; +} + +/* Function called when one of the builtin commands detects a bad + option. */ +void +bad_option (s) + char *s; +{ + builtin_error ("unknown option: %s", s); +} + +/* 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; + +char * +get_working_directory (for_whom) + char *for_whom; +{ + if (no_symbolic_links) + { + if (the_current_working_directory) + free (the_current_working_directory); + + the_current_working_directory = (char *)NULL; + } + + if (!the_current_working_directory) + { + char *directory; + + the_current_working_directory = xmalloc (MAXPATHLEN); + directory = getwd (the_current_working_directory); + if (!directory) + { + 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); + + free (the_current_working_directory); + the_current_working_directory = (char *)NULL; + return (char *)NULL; + } + } + + return (savestring (the_current_working_directory)); +} + +/* Make NAME our internal idea of the current working directory. */ +void +set_working_directory (name) + char *name; +{ + if (the_current_working_directory) + free (the_current_working_directory); + + the_current_working_directory = savestring (name); +} + +#if defined (JOB_CONTROL) +/* Return the job spec found in LIST. */ +get_job_spec (list) + WORD_LIST *list; +{ + register char *word; + int job = NO_JOB; + int substring = 0; + + if (!list) + return (current_job); + + word = list->word->word; + + if (!*word) + return (current_job); + + if (*word == '%') + word++; + + if (digit (*word) && (sscanf (word, "%d", &job) == 1)) + return (job - 1); + + switch (*word) + { + case 0: + case '%': + case '+': + return (current_job); + + case '-': + return (previous_job); + + case '?': /* Substring search requested. */ + substring++; + word++; + goto find_string; + + default: + find_string: + { + register int i, wl = strlen (word); + for (i = 0; i < job_slots; i++) + { + if (jobs[i]) + { + register PROCESS *p = jobs[i]->pipe; + do + { + if ((substring && strindex (p->command, word)) || + (strncmp (p->command, word, wl) == 0)) + if (job != NO_JOB) + { + builtin_error ("ambigious job spec: %s", word); + return (DUP_JOB); + } + else + job = i; + + p = p->next; + } + while (p != jobs[i]->pipe); + } + } + return (job); + } + } +} +#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; +{ + 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); + +#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 (); + 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; + } + } + } + + 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 (jump_to_top_level) + longjmp (top_level, code); + + return (last_result); +} + +/* Return the address of the builtin named NAME. + DISABLED_OKAY means find it even if the builtin is disabled. */ +static Function * +builtin_address_internal (name, disabled_okay) + char *name; + int disabled_okay; +{ + int hi, lo, mid, j; + + hi = num_shell_builtins - 1; + lo = 0; + + while (lo <= hi) + { + mid = (lo + hi) / 2; + + j = shell_builtins[mid].name[0] - name[0]; + + if (j == 0) + j = strcmp (shell_builtins[mid].name, name); + + if (j == 0) + { + /* It must have a function pointer. It must be enabled, or we + must have explicitly allowed disabled functions to be found. */ + if (shell_builtins[mid].function && + ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay)) + return (shell_builtins[mid].function); + else + return ((Function *)NULL); + } + if (j > 0) + hi = mid - 1; + else + lo = mid + 1; + } + return ((Function *)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. */ +Function * +find_shell_builtin (name) + char *name; +{ + return (builtin_address_internal (name, 0)); +} + +/* Return the address of builtin with NAME, irregardless of its state of + enableness. */ +Function * +builtin_address (name) + char *name; +{ + return (builtin_address_internal (name, 1)); +} + +static int +shell_builtin_compare (sbp1, sbp2) + struct builtin *sbp1, *sbp2; +{ + int result; + + if ((result = sbp1->name[0] - sbp2->name[0]) == 0) + result = strcmp (sbp1->name, sbp2->name); + + return (result); +} + +/* Sort the table of shell builtins so that the binary search will work + in find_shell_builtin. */ +void +initialize_shell_builtins () +{ + qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin), + shell_builtin_compare); +} + +/* Return a new string which is the quoted version of STRING. This is used + by alias and trap. */ +char * +single_quote (string) + char *string; +{ + register int i, j, c; + char *result; + + result = (char *)xmalloc (3 + (3 * strlen (string))); + + result[0] = '\''; + + for (i = 0, j = 1; string && (c = string[i]); i++) + { + result[j++] = c; + + if (c == '\'') + { + result[j++] = '\\'; /* insert escaped single quote */ + result[j++] = '\''; + result[j++] = '\''; /* start new quoted string */ + } + } + + result[j++] = '\''; + result[j] = '\0'; + + return (result); +} + +char * +double_quote (string) + char *string; +{ + register int i, j, c; + char *result; + + result = (char *)xmalloc (3 + (3 * strlen (string))); + + result[0] = '"'; + + for (i = 0, j = 1; string && (c = string[i]); i++) + { + switch (c) + { + case '"': + case '$': + case '`': + case '\\': + result[j++] = '\\'; + default: + result[j++] = c; + break; + } + } + + result[j++] = '"'; + result[j] = '\0'; + + return (result); +} diff --git a/builtins/common.h b/builtins/common.h new file mode 100644 index 0000000..c7c99e7 --- /dev/null +++ b/builtins/common.h @@ -0,0 +1,69 @@ +/* common.h -- extern declarations for functions defined in common.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 (__COMMON_H) +# define __COMMON_H + +#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c) + +extern void builtin_error (); +extern void bad_option (); + +extern int get_numeric_arg (); + +extern void remember_args (); + +extern void no_args (); + +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 (); +extern int dollar_vars_changed (); +extern void set_dollar_vars_unchanged (), set_dollar_vars_changed (); + +/* Keeps track of the current working directory. */ +extern char *the_current_working_directory; +extern char *get_working_directory (); +extern void set_working_directory (); + +#if defined (JOB_CONTROL) +extern int get_job_spec (); +#endif + +extern int parse_and_execute (); +extern void parse_and_execute_cleanup (); + +extern void initialize_shell_builtins (); + +/* It's OK to declare a function as returning a Function * without + providing a definition of what a `Function' is. */ +extern Function *find_shell_builtin (); +extern Function *builtin_address (); + +extern char *single_quote (); +extern char *double_quote (); + +#endif /* !__COMMON_H */ diff --git a/builtins/declare.def b/builtins/declare.def new file mode 100644 index 0000000..17b7ea2 --- /dev/null +++ b/builtins/declare.def @@ -0,0 +1,290 @@ +This file is declare.def, from which is created declare.c. +It implements the builtins "declare" and "local" 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 declare.c + +$BUILTIN declare +$FUNCTION declare_builtin +$SHORT_DOC declare [-[frxi]] name[=value] ... +Declare variables and/or give them attributes. If no NAMEs are +given, then display the values of variables instead. + +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. + +Variables with the integer attribute have arithmetic evaluation (see +`let') done when the variable is assigned to. + +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] ... +Obsolete. See `declare'. +$END + +#include <stdio.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" + +extern int variable_context, array_needs_making; + +static int declare_internal (); + +/* Declare or change variable attributes. */ +int +declare_builtin (list) + register WORD_LIST *list; +{ + return (declare_internal (list, 0)); +} + +$BUILTIN local +$FUNCTION local_builtin +$SHORT_DOC local name[=value] ... +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. +$END +int +local_builtin (list) + register WORD_LIST *list; +{ + if (variable_context) + return (declare_internal (list, 1)); + else + { + builtin_error ("Can only be used in a function"); + return (EXECUTION_FAILURE); + } +} + +/* The workhorse function. */ +static int +declare_internal (list, local_var) + register WORD_LIST *list; + int local_var; +{ + int flags_on = 0, flags_off = 0; + int any_failed = 0; + + while (list) + { + register char *t = list->word->word; + int *flags; + + if (t[0] == '-' && t[1] == '-' && t[2] == '\0') + { + list = list->next; + break; + } + + if (*t != '+' && *t != '-') + break; + + if (*t == '+') + flags = &flags_off; + else + flags = &flags_on; + + t++; + + while (*t) + { + if (*t == 'f') + *flags |= att_function, t++; + else if (*t == 'x') + *flags |= att_exported, t++, array_needs_making = 1; + else if (*t == 'r') + *flags |= att_readonly, t++; + else if (*t == 'i') + *flags |= att_integer, t++; + else + { + builtin_error ("unknown option: `-%c'", *t); + return (EX_USAGE); + } + } + + list = list->next; + } + + /* If there are no more arguments left, then we just want to show + some variables. */ + if (!list) + { + /* Show local variables defined at this context level if this is + the `local' builtin. */ + if (local_var) + { + register SHELL_VAR **vlist; + register int i; + + vlist = map_over (variable_in_context, shell_variables); + + if (vlist) + { + for (i = 0; vlist[i]; i++) + print_assignment (vlist[i]); + + free (vlist); + } + } + else + { + if (!flags_on) + set_builtin ((WORD_LIST *)NULL); + else + set_or_show_attributes ((WORD_LIST *)NULL, flags_on); + } + + fflush (stdout); + return (EXECUTION_SUCCESS); + } + +#define NEXT_VARIABLE() free (name); list = list->next; continue + + /* There are arguments left, so we are making variables. */ + while (list) + { + char *value, *name = savestring (list->word->word); + int offset = assignment (name); + + if (offset) + { + name[offset] = '\0'; + value = name + offset + 1; + } + else + value = ""; + + if (legal_identifier (name) == 0) + { + builtin_error ("%s: not a legal variable name", name); + any_failed++; + NEXT_VARIABLE (); + } + + /* If VARIABLE_CONTEXT has a non-zero value, then we are executing + inside of a function. This means we should make local variables, + not global ones. */ + + if (variable_context) + 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'. */ + + /* There should be a way, however, to let people look at a particular + function definition by saying `typeset -f foo'. */ + + if (flags_on & att_function) + { + if (offset) + { + builtin_error ("Can't use `-f' to make functions"); + return (EXECUTION_FAILURE); + } + else + { + SHELL_VAR *find_function (), *funvar; + + funvar = find_function (name); + + if (funvar) + { + if (readonly_p (funvar) && (flags_off & att_readonly)) + { + builtin_error ("%s: readonly function", name); + any_failed++; + NEXT_VARIABLE (); + } + + if (flags_on == att_function && flags_off == 0) + { + char *result = named_function_string + (name, (COMMAND *)function_cell (funvar), 1); + printf ("%s\n", result); + } + else + { + funvar->attributes |= flags_on; + funvar->attributes &= ~flags_off; + } + } + else + any_failed++; + NEXT_VARIABLE (); + } + } + else + { + SHELL_VAR *var; + + var = find_variable (name); + + if (!var) + var = bind_variable (name, ""); + + if (readonly_p (var) && (flags_off & att_readonly)) + { + builtin_error ("%s: readonly variable", name); + any_failed++; + NEXT_VARIABLE (); + } + + var->attributes |= flags_on; + var->attributes &= ~flags_off; + + 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); + } + } + + stupidly_hack_special_variables (name); + + NEXT_VARIABLE (); + } + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} diff --git a/builtins/echo.def b/builtins/echo.def new file mode 100644 index 0000000..7539103 --- /dev/null +++ b/builtins/echo.def @@ -0,0 +1,168 @@ +This file is echo.def, from which is created echo.c. +It implements the builtin "echo" 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 echo.c +#include <stdio.h> +#include "../shell.h" + +$BUILTIN echo +$FUNCTION echo_builtin +$DEPENDS_ON V9_ECHO +$SHORT_DOC echo [-neE] [arg ...] +Output the ARGs. If -n is specified, the trailing newline is +suppressed. If the -e option is given, interpretation of the +following backslash-escaped characters is turned on: + \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 + \num the character whose ASCII code is NUM (octal). + +You can explicitly turn off the interpretation of the above characters +with the -E option. +$END + +$BUILTIN echo +$FUNCTION echo_builtin +$DEPENDS_ON !V9_ECHO +$SHORT_DOC echo [-n] [arg ...] +Output the ARGs. If -n is specified, the trailing newline is suppressed. +$END + +#if defined (V9_ECHO) +# define VALID_ECHO_OPTIONS "neE" +#else /* !V9_ECHO */ +# define VALID_ECHO_OPTIONS "n" +#endif /* !V9_ECHO */ + +/* 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_builtin (list) + WORD_LIST *list; +{ + int display_return = 1, do_v9 = 0; + +#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; +#endif /* DEFAULT_ECHO_TO_USG */ + + while (list && list->word->word[0] == '-') + { + register char *temp; + register int i; + + /* 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]); + + for (i = 0; temp[i]; i++) + { + if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0) + goto just_echo; + } + + if (!*temp) + goto just_echo; + + /* All of the options in TEMP are valid options to ECHO. + Handle them. */ + while (*temp) + { + if (*temp == 'n') + display_return = 0; +#if defined (V9_ECHO) + else if (*temp == 'e') + do_v9 = 1; + else if (*temp == 'E') + do_v9 = 0; +#endif /* V9_ECHO */ + else + goto just_echo; + + temp++; + } + list = list->next; + } + +just_echo: + + if (list) + { +#if defined (V9_ECHO) + if (do_v9) + { + 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(' '); + } + } + else +#endif /* V9_ECHO */ + print_word_list (list, " "); + } + if (display_return) + printf ("\n"); + fflush (stdout); + return (EXECUTION_SUCCESS); +} diff --git a/builtins/enable.def b/builtins/enable.def new file mode 100644 index 0000000..2aeae39 --- /dev/null +++ b/builtins/enable.def @@ -0,0 +1,156 @@ +This file is enable.def, from which is created enable.c. +It implements the builtin "enable" 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 enable.c + +$BUILTIN enable +$FUNCTION enable_builtin +$SHORT_DOC enable [-n] [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' found on your +path instead of the shell builtin version, you type `enable -n test'. +$END + +#include "../shell.h" +#include "../builtins.h" +#include "common.h" + +#define ENABLED 1 +#define DISABLED 2 + +static int enable_shell_command (); +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. */ +enable_builtin (list) + WORD_LIST *list; +{ + int result = 0, any_failed = 0; + int disable_p, all_p; + + disable_p = all_p = 0; + + while (list && list->word->word && list->word->word[0] == '-') + { + 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 + { + bad_option (arg); + return (EXECUTION_FAILURE); + } + } + + if (!list) + { + int filter; + + if (all_p) + filter = ENABLED | DISABLED; + else if (disable_p) + filter = DISABLED; + else + filter = ENABLED; + + list_some_builtins (filter); + } + else + { + while (list) + { + result = enable_shell_command (list->word->word, disable_p); + + if (!result) + { + builtin_error ("%s: not a shell builtin", list->word->word); + any_failed++; + } + list = list->next; + } + } + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +/* List some builtins. + FILTER is a mask with two slots: ENABLED and DISABLED. */ +static void +list_some_builtins (filter) + int filter; +{ + register int i; + + for (i = 0; i < num_shell_builtins; i++) + { + if (!shell_builtins[i].function) + 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); + } + } +} + +/* Enable the shell command NAME. If DISABLE_P is non-zero, then + disable NAME instead. */ +static int +enable_shell_command (name, disable_p) + char *name; + int disable_p; +{ + register int i; + int found = 0; + + for (i = 0; i < num_shell_builtins; i++) + { + if (!shell_builtins[i].function) + continue; + + if (STREQ (name, shell_builtins[i].name)) + { + found++; + + if (disable_p) + shell_builtins[i].flags &= ~BUILTIN_ENABLED; + else + shell_builtins[i].flags |= BUILTIN_ENABLED; + } + } + return (found); +} diff --git a/builtins/eval.def b/builtins/eval.def new file mode 100644 index 0000000..5c3eda8 --- /dev/null +++ b/builtins/eval.def @@ -0,0 +1,45 @@ +This file is eval.def, from which is created eval.c. +It implements the builtin "eval" 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 eval.c + +$BUILTIN eval +$FUNCTION eval_builtin +$SHORT_DOC eval [arg ...] +Read ARGs as input to the shell and execute the resulting command(s). +$END + +#include "../shell.h" + +/* Parse the string that these words make, and execute the command found. */ +int +eval_builtin (list) + WORD_LIST *list; +{ + int result; + + /* 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); +} diff --git a/builtins/exec.def b/builtins/exec.def new file mode 100644 index 0000000..f950afc --- /dev/null +++ b/builtins/exec.def @@ -0,0 +1,163 @@ +This file is exec.def, from which is created exec.c. +It implements the builtin "exec" 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 exec.c + +$BUILTIN exec +$FUNCTION exec_builtin +$SHORT_DOC exec [ [-] 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. +$END + +#include "../shell.h" +#include <sys/types.h> +#include "../posixstat.h" +#include <signal.h> +#include <errno.h> + +#include "../execute_cmd.h" +#include "common.h" +#include "../flags.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 +exec_builtin (list) + WORD_LIST *list; +{ + int exit_value = EXECUTION_FAILURE; + + maybe_make_export_env (); + + /* First, let the redirections remain. */ + dispose_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + + if (!list) + return (EXECUTION_SUCCESS); + else + { + /* Otherwise, execve the new command with args. */ + char *command, **args; + int dash_name = 0; + + 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++; + } + + if (!list) + return (EXECUTION_SUCCESS); + +#if defined (RESTRICTED_SHELL) + if (restricted) + { + builtin_error ("restricted"); + return (EXECUTION_FAILURE); + } +#endif /* RESTRICTED_SHELL */ + + args = make_word_array (list); + + /* 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; + } + + 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. */ + adjust_shell_level (-1); + maybe_make_export_env (); + +#if defined (HISTORY) + maybe_save_shell_history (); +#endif /* HISTORY */ + restore_original_signals (); + +#if defined (JOB_CONTROL) + if (subshell_environment == 0) + end_job_control (); +#endif /* JOB_CONTROL */ + + shell_execve (command, args, export_env); + + 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); + + failed_exec: + if (command) + free (command); + + if (subshell_environment || + (!interactive && !find_variable ("no_exit_on_failed_exec"))) + exit (exit_value); + + initialize_traps (); + reinitialize_signals (); + +#if defined (JOB_CONTROL) + restart_job_control (); +#endif /* JOB_CONTROL */ + + return (exit_value); + } +} diff --git a/builtins/exit.def b/builtins/exit.def new file mode 100644 index 0000000..25a3b63 --- /dev/null +++ b/builtins/exit.def @@ -0,0 +1,129 @@ +This file is exit.def, from which is created exit.c. +It implements the builtins "exit" and "logout" 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 exit.c + +$BUILTIN exit +$FUNCTION exit_builtin +$SHORT_DOC exit [n] +Exit the shell with a status of N. If N is omitted, the exit status +is that of the last command executed. +$END + +#include <stdio.h> +#include <sys/types.h> +#include "../shell.h" +#include "../jobs.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; + +int +exit_builtin (list) + WORD_LIST *list; +{ + if (interactive) + { + fprintf (stderr, login_shell ? "logout\n" : "exit\n"); + fflush (stderr); + } + + return (exit_or_logout (list)); +} + +$BUILTIN logout +$FUNCTION logout_builtin +$SHORT_DOC logout +Logout of a login shell. +$END + +/* How to logout. */ +int +logout_builtin (list) + WORD_LIST *list; +{ + if (!login_shell && interactive) + { + builtin_error ("Not login shell: use `exit'"); + return (EXECUTION_FAILURE); + } + else + return (exit_or_logout (list)); +} + +/* Clean up work for exiting or logging out. */ +Function *last_shell_builtin = (Function *)NULL; +Function *this_shell_builtin = (Function *)NULL; + +static int +exit_or_logout (list) + WORD_LIST *list; +{ + int exit_value; + +#if defined (JOB_CONTROL) + int exit_immediate_okay; + + exit_immediate_okay = (!interactive || + last_shell_builtin == exit_builtin || + last_shell_builtin == logout_builtin || + last_shell_builtin == jobs_builtin); + + /* Check for stopped jobs if the user wants to. */ + if (!exit_immediate_okay) + { + register int i; + for (i = 0; i < job_slots; i++) + if (jobs[i] && (jobs[i]->state == JSTOPPED)) + { + fprintf (stderr, "There are stopped jobs.\n"); + + /* This is NOT superfluous because EOF can get here without + going through the command parser. Set both last and this + so that either `exit', `logout', or ^D will work to exit + immediately if nothing intervenes. */ + this_shell_builtin = last_shell_builtin = exit_builtin; + return (EXECUTION_FAILURE); + } + } +#endif /* JOB_CONTROL */ + + /* 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; + + /* 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); + + last_command_exit_value = exit_value; + + /* Exit the program. */ + longjmp (top_level, EXITPROG); +} diff --git a/builtins/fc.def b/builtins/fc.def new file mode 100644 index 0000000..1f6db68 --- /dev/null +++ b/builtins/fc.def @@ -0,0 +1,691 @@ +This file is fc.def, from which is created fc.c. +It implements the builtin "fc" 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 fc.c + +$BUILTIN fc +$FUNCTION fc_builtin +$DEPENDS_ON HISTORY +$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd] + +FIRST and LAST can be numbers specifying the range, or FIRST can be a +string, which means the most recent command beginning with that +string. + + -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, + then the editor which corresponds to the current readline editing + mode, then vi. + + -l means list lines instead of editing. + -n means no line numbers listed. + -r means reverse the order of the lines (making it newest listed first). + +With the `fc -s [pat=rep ...] [command]' format, the command is +re-executed after the substitution OLD=NEW is performed. + +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. +$END + +#include <stdio.h> +#include "../bashansi.h" +#include "../shell.h" +#if defined (HISTORY) +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <errno.h> +#include "../builtins.h" +#include "../flags.h" +#include "../maxpath.h" +#include "../bashhist.h" +#include <readline/history.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 echo_input_at_read; + +extern int unlink (); + +/* **************************************************************** */ +/* */ +/* The K*rn shell style fc command (Fix Command) */ +/* */ +/* **************************************************************** */ + +/* fc builtin command (fix command) for Bash for those who + like K*rn-style history better than csh-style. + + fc [-e ename] [-nlr] [first] [last] + + FIRST and LAST can be numbers specifying the range, or FIRST can be + a string, which means the most recent command beginning with that + string. + + -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, + then the editor which corresponds to the current readline editing + mode, then vi. + + -l means list lines instead of editing. + -n means no line numbers listed. + -r means reverse the order of the lines (making it newest listed first). + + fc -e - [pat=rep ...] [command] + fc -s [pat=rep ...] [command] + + 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 void fc_replhist (), fc_addhist (); + +/* Data structure describing a list of global replacements to perform. */ +typedef struct repl { + struct repl *next; + char *pat; + 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) + +#define FREE_RLIST() \ + do { \ + for (rl = rlist; rl; ) { \ + REPL *r; \ + r = rl->next; \ + if (rl->pat) \ + free (rl->pat); \ + if (rl->rep) \ + free (rl->rep); \ + free (rl); \ + rl = r; \ + } \ + } while (0) + +/* String to execute on a file that we want to edit. */ +#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}" + +int +fc_builtin (list) + WORD_LIST *list; +{ + register int i; + register char *sep; + 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; + HIST_ENTRY **hlist; + char fn[MAXPATHLEN]; + + numbering = 1; + reverse = listing = execute = 0; + + /* Parse out the options and set which of the two forms we're in. */ + + while (list && *list->word->word == '-') + { + register char *s = &((list->word->word)[1]); + + if (!isletter (*s)) + 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); + } + } + list = list->next; + } + + if (ename && (*ename == '-') && (ename[1] == '\0')) + execute = 1; + + /* The "execute" form of the command (re-run, with possible string + substitutions). */ + if (execute) + { + while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL)) + { + *sep++ = '\0'; + rl = (REPL *)xmalloc (sizeof (REPL)); + rl->next = (REPL *)NULL; + rl->pat = savestring (list->word->word); + rl->rep = savestring (sep); + + if (rlist == NULL) + rlist = rl; + else + { + rl->next = rlist; + rlist = rl; + } + list = list->next; + } + + /* If we have a list of substitutions to do, then reverse it + to get the replacements in the proper order. */ + + if (rlist && rlist->next) + 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); + + if (command == NULL) + { + builtin_error ("no command found"); + if (rlist) + FREE_RLIST (); + + return (EXECUTION_FAILURE); + } + + if (rlist) + { + newcom = fc_dosubs (command, rlist); + free (command); + FREE_RLIST (); + command = newcom; + } + + printf ("%s\n", command); + fc_replhist (command); /* replace `fc -e -' with command */ + return (parse_and_execute (command, "fc", -1)); + } + + /* This is the second form of the command (the list-or-edit-and-rerun + form). */ + hlist = history_list (); + if (hlist == 0) + return (EXECUTION_SUCCESS); + for (i = 0; hlist[i]; i++); + + /* With the Bash implementation of history, the current command line + ("fc blah..." and so on) is already part of the history list by + the time we get to this point. This just skips over that command + and makes the last command that this deals with be the last command + the user entered before the fc. */ + + last_hist = i - 2; + + if (list) + { + histbeg = fc_gethnum (list->word->word, hlist); + list = list->next; + + if (list) + histend = fc_gethnum (list->word->word, hlist); + else + { + if (listing) + histend = last_hist; + else + histend = histbeg; + } + } + else + { + /* The default for listing is the last 16 history items. */ + if (listing) + { + histend = last_hist; + histbeg = histend - 16; + if (histbeg < 0) + histbeg = 0; + } + else + { + /* For editing, it is the last history command. */ + histbeg = histend = last_hist; + } + } + + /* We print error messages for line specifications out of range. */ + if ((histbeg < 0) || (histend < 0) || + (histbeg > last_hist) || (histend > last_hist)) + { + builtin_error ("history specification out of range"); + return (EXECUTION_FAILURE); + } + + if (histend < histbeg) + { + int t = histend; + + histend = histbeg; + histbeg = t; + reverse = 1; + } + + if (listing) + stream = stdout; + else + { + numbering = 0; + sprintf (fn, "/tmp/bash%d", (int)time ((long *) 0) + (int)getpid ()); + + stream = fopen (fn, "w"); + + if (!stream) + { + builtin_error ("cannot open temp file %s", fn); + return (EXECUTION_FAILURE); + } + } + + if (!reverse) + { + 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)); + } + } + + if (listing) + return (EXECUTION_SUCCESS); + + fclose (stream); + + /* Now edit the file of commands. */ + if (ename) + { + command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2); + sprintf (command, "%s %s", ename, fn); + } + else + { + command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn)); + sprintf (command, "%s %s", FC_EDIT_COMMAND, fn); + } + parse_and_execute (command, "fc", -1); + + /* Now reopen the file and execute the edited commands. */ + + stream = fopen (fn, "r"); + + if (stream == NULL) + { + builtin_error ("cannot reopen temp file %s", fn); + unlink (fn); + return (EXECUTION_FAILURE); + } + + retval = EXECUTION_SUCCESS; + first = 1; + + /* First, write the commands to the history file. This will not happen + when we call parse_and_execute, since parse_and_execute disables + the command line history while it executes. */ + + while ((line = fc_readline (stream)) != NULL) + { + if (line[0] == '\n') + { + free (line); + continue; /* Skip blank lines. */ + } + + if (first) + { + first = 0; + fc_replhist (line); + } + else + fc_addhist (line); + + free (line); + } + fclose (stream); + + /* Turn on the `v' flag while maybe_execute_file runs so the commands + will be echoed as they are read by the parser. */ + begin_unwind_frame ("fc builtin"); + add_unwind_protect (unlink, fn); + unwind_protect_int (echo_input_at_read); + echo_input_at_read = 1; + + retval = maybe_execute_file (fn, 0); + + run_unwind_frame ("fc builtin"); + + return (retval); +} + +/* 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. */ +static int +fc_gethnum (command, hlist) + char *command; + HIST_ENTRY **hlist; +{ + int sign = 1, n, clen; + register int i, j; + register char *s; + + /* Count history elements. */ + for (i = 0; hlist[i]; i++); + + /* With the Bash implementation of history, the current command line + ("fc blah..." and so on) is already part of the history list by + the time we get to this point. This just skips over that command + and makes the last command that this deals with be the last command + the user entered before the fc. */ + i -= 2; + + /* No specification defaults to most recent command. */ + if (command == NULL) + return (i); + + /* Otherwise, there is a specification. It can be a number relative to + the current position, or an absolute history number. */ + s = command; + + /* Handle possible leading minus sign. */ + if (s && (*s == '-')) + { + sign = -1; + s++; + } + + if (s && digit(*s)) + { + n = atoi (s); + n *= sign; + + /* Anything specified greater than the last history element that we + deal with is an error. */ + if (n > i + history_base) + return (-1); + + /* If the value is negative or zero, then it is an offset from + the current history item. */ + if (n < 0) + return (i + n + 1); + else if (n == 0) + return (i); + else + return (n - history_base); + } + + clen = strlen (command); + for (j = i; j >= 0; j--) + { + if (STREQN (command, histline (j), clen)) + return (j); + } + return (-1); +} + +/* Locate the most recent history line which begins with + COMMAND in HLIST, and return a malloc()'ed copy of it. */ +static char * +fc_gethist (command, hlist) + char *command; + HIST_ENTRY **hlist; +{ + int i; + + if (!hlist) + return ((char *)NULL); + + i = fc_gethnum (command, hlist); + + if (i >= 0) + return (savestring (histline (i))); + else + return ((char *)NULL); +} + +/* Read the edited history lines from STREAM and return them + one at a time. This can read unlimited length lines. The + caller should free the storage. */ +static char * +fc_readline (stream) + FILE *stream; +{ + register int c; + int line_len = 0, lindex = 0; + char *line = (char *)NULL; + + while ((c = getc (stream)) != EOF) + { + if ((lindex + 2) >= line_len) + line = (char *) xrealloc (line, (line_len += 128)); + + if (c == '\n') + { + line[lindex++] = '\n'; + line[lindex++] = '\0'; + return (line); + } + else + line[lindex++] = c; + } + + if (!lindex) + { + if (line) + free (line); + + return ((char *)NULL); + } + + if (lindex + 2 >= line_len) + line = (char *)xrealloc (line, lindex + 3); + + line[lindex++] = '\n'; /* Finish with newline if none in file */ + line[lindex++] = '\0'; + return (line); +} + +/* Perform the SUBS on COMMAND. + SUBS is a list of substitutions, and COMMAND is a simple string. + Return a pointer to a malloc'ed string which contains the substituted + command. */ +static char * +fc_dosubs (command, subs) + char *command; + REPL *subs; +{ + register char *new = savestring (command); + register REPL *r; + + for (r = subs; r; r = r->next) + { + register char *t; + + t = fc_replace (r->pat, r->rep, new); + 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 + history list. This way you can do `r' to your heart's content. */ +static void +fc_replhist (command) + char *command; +{ + register int i; + HIST_ENTRY **hlist, *histent, *discard; + char *data; + int n; + + if (!command || !*command) + return; + + hlist = history_list (); + + if (hlist == NULL) + return; + + for (i = 0; hlist[i]; i++); + i--; + + /* History_get () takes a parameter that should be + offset by history_base. */ + + histent = history_get (history_base + i); /* Don't free this */ + if (histent == NULL) + return; + + n = strlen (command); + + if (command[n - 1] == '\n') + command[n - 1] = '\0'; + + if (command && *command) + { + discard = remove_history (i); + if (discard) + { + if (discard->line) + free (discard->line); + free ((char *) discard); + } + maybe_add_history (command); /* Obeys HISTCONTROL setting. */ + } +} + +/* Add LINE to the history, after removing a single trailing newline. */ +static void +fc_addhist (line) + char *line; +{ + register int n; + + n = strlen (line); + + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + if (line && *line) + maybe_add_history (line); +} +#endif /* HISTORY */ diff --git a/builtins/fg_bg.def b/builtins/fg_bg.def new file mode 100644 index 0000000..e48af38 --- /dev/null +++ b/builtins/fg_bg.def @@ -0,0 +1,145 @@ +This file is fg_bg.def, from which is created fg_bg.c. +It implements the builtins "bg" and "fg" 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 fg_bg.c + +$BUILTIN fg +$FUNCTION fg_builtin +$DEPENDS_ON JOB_CONTROL +$SHORT_DOC fg [job_spec] +Place JOB_SPEC in the foreground, and make it the current job. If +JOB_SPEC is not present, the shell's notion of the current job is +used. +$END + +#include <sys/types.h> +#include <signal.h> +#include "../shell.h" +#include "../jobs.h" + +#if defined (JOB_CONTROL) +extern char *this_command_name; + +static int fg_bg (); + +/* How to bring a job into the foreground. */ +int +fg_builtin (list) + WORD_LIST *list; +{ + int fg_bit = 1; + register WORD_LIST *t = list; + + if (!job_control) + { + builtin_error ("no job control"); + return (EXECUTION_FAILURE); + } + + /* 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; + + return (fg_bg (list, fg_bit)); +} +#endif /* JOB_CONTROL */ + +$BUILTIN bg +$FUNCTION bg_builtin +$DEPENDS_ON JOB_CONTROL +$SHORT_DOC bg [job_spec] +Place JOB_SPEC in the background, as if it had been started with +`&'. If JOB_SPEC is not present, the shell's notion of the current +job is used. +$END + +#if defined (JOB_CONTROL) +/* How to put a job into the background. */ +int +bg_builtin (list) + WORD_LIST *list; +{ + if (!job_control) + { + builtin_error ("no job control"); + return (EXECUTION_FAILURE); + } + + return (fg_bg (list, 0)); +} + +/* How to put a job into the foreground/background. */ +static int +fg_bg (list, foreground) + WORD_LIST *list; + int foreground; +{ + sigset_t set, oset; + int job, status = EXECUTION_SUCCESS, old_async_pid; + + BLOCK_CHILD (set, oset); + job = get_job_spec (list); + + if (job < 0 || job >= job_slots || !jobs[job]) + { + if (job != DUP_JOB) + builtin_error ("No such job %s", list ? list->word->word : ""); + + goto failure; + } + + /* Or if jobs[job]->pgrp == shell_pgrp. */ + if (!(jobs[job]->flags & J_JOBCONTROL)) + { + builtin_error ("job %%%d started without job control", job + 1); + goto failure; + } + + if (!foreground) + { + old_async_pid = last_asynchronous_pid; + last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */ + } + + status = start_job (job, foreground); + + if (status >= 0) + { + /* win: */ + UNBLOCK_CHILD (oset); + return (status); + } + else + { + if (!foreground) + last_asynchronous_pid = old_async_pid; + + failure: + UNBLOCK_CHILD (oset); + return (EXECUTION_FAILURE); + } +} +#endif /* JOB_CONTROL */ diff --git a/builtins/getopt.c b/builtins/getopt.c new file mode 100644 index 0000000..7603430 --- /dev/null +++ b/builtins/getopt.c @@ -0,0 +1,283 @@ +/* getopt for BASH. + + Copyright (C) 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 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. */ + +#include <stdio.h> +#include "../memalloc.h" +#include "../shell.h" +#include "getopt.h" + +/* For communication from `sh_getopt' to the caller. + When `sh_getopt' finds an option that takes an argument, + the argument value is returned here. */ +char *sh_optarg = 0; + +/* 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 `sh_getopt'. + + On entry to `sh_getopt', zero means this is the first call; initialize. + + When `sh_getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `sh_optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int sh_optind = 0; + +/* Index of the current argument. */ +static int sh_curopt; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; +static int sh_charindex; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int sh_opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int sh_optopt = '?'; + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `sh_getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `sh_getopt' finds another option character, it returns that character, + updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `sh_getopt' returns `EOF'. + Then `sh_optind' is the index in ARGV of the first ARGV-element + that is not an option. + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `sh_opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `sh_optarg'. */ + +/* 1003.2 specifies the format of this message. */ +#define BADOPT(x) fprintf (stderr, "%s: illegal option -- %c\n", argv[0], x) +#define NEEDARG(x) fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], x) + +int +sh_getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + int option_index; + char c, *temp; + + sh_optarg = 0; + + if (sh_optind > argc || sh_optind < 0) + { + sh_optind = argc; + return (EOF); + } + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (sh_optind == 0) + { + sh_optind = 1; + 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 (sh_optind == argc) + return EOF; + + temp = argv[sh_optind]; + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, and return EOF. */ + if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0') + { + sh_optind++; + return EOF; + } + + /* If we have come to a non-option, either stop the scan or describe + it to the caller and pass it by. This makes the pseudo-option + `-' mean the end of options, but does not skip over it. */ + if (temp[0] != '-' || temp[1] == '\0') + return EOF; + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + nextchar = argv[sh_curopt = sh_optind] + 1; + sh_charindex = 1; + } + + /* Look at and handle the next option-character. */ + + 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 (sh_opterr) + BADOPT (c); + + return '?'; + } + + if (temp[1] == ':') + { + if (nextchar && *nextchar) + { + /* This is an option that requires an argument. */ + sh_optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + sh_optind++; + } + else if (sh_optind == argc) + { + if (sh_opterr) + NEEDARG (c); + + sh_optopt = c; + c = (optstring[0] == ':') ? ':' : '?'; + } + else + /* We already incremented `sh_optind' once; + increment it again when taking next ARGV-elt as argument. */ + sh_optarg = argv[sh_optind++]; + nextchar = (char *)NULL; + } + return c; +} + +void +sh_getopt_restore_state (argv) + char **argv; +{ + if (nextchar) + nextchar = argv[sh_curopt] + sh_charindex; +} + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `sh_getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_sh_optind = 0; + + while (1) + { + int this_option_sh_optind = sh_optind ? sh_optind : 1; + + c = sh_getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_sh_optind = this_option_sh_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", sh_optarg); + break; + + case '?': + break; + + default: + printf ("?? sh_getopt returned character code 0%o ??\n", c); + } + } + + if (sh_optind < argc) + { + printf ("non-option ARGV-elements: "); + while (sh_optind < argc) + printf ("%s ", argv[sh_optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/builtins/getopt.h b/builtins/getopt.h new file mode 100644 index 0000000..fa9878c --- /dev/null +++ b/builtins/getopt.h @@ -0,0 +1,57 @@ +/* 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. */ + +/* XXX THIS HAS BEEN MODIFIED FOR INCORPORATION INTO BASH XXX */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +/* 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 *sh_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, `sh_optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int sh_optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int sh_opterr; + +/* Set to an option character which was unrecognized. */ + +extern int sh_optopt; + +extern int sh_getopt (); +extern void sh_getopt_restore_state (); + +#endif /* _GETOPT_H */ diff --git a/builtins/getopts.def b/builtins/getopts.def new file mode 100644 index 0000000..0f2b82f --- /dev/null +++ b/builtins/getopts.def @@ -0,0 +1,300 @@ +This file is getopts.def, from which is created getopts.c. +It implements the builtin "getopts" 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 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. + +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 will place 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 shell +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 shell variable OPTARG. + +getopts reports errors in one of two ways. If the first character +of OPTSTRING is a colon, getopts uses silent error reporting. In +this mode, no error messages are printed. If an illegal option is +seen, getopts places the option character found into OPTARG. If a +required argument is not found, getopts places a ':' into NAME and +sets OPTARG to the option character found. If getopts is not in +silent mode, and an illegal option is seen, getopts places '?' into +NAME and unsets OPTARG. If a required option is not found, a '?' +is placed in NAME, OPTARG is unset, and a diagnostic message is +printed. + +If the shell variable OPTERR has the value 0, getopts disables the +printing of error messages, even if the first character of +OPTSTRING is not a colon. OPTERR has the value 1 by default. + +Getopts normally parses the positional parameters ($0 - $9), but if +more arguments are given, they are parsed instead. +$END + +#include <stdio.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" + +#if defined (GETOPTS_BUILTIN) +#include "getopt.h" + +#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; + +/* getopts_reset is magic code for when OPTIND is reset. N is the + value that has just been assigned to OPTIND. */ +void +getopts_reset (newind) + int newind; +{ + sh_optind = newind; +} + +/* Error handling is now performed as specified by Posix.2, draft 11 + (identical to that of ksh-88). The special handling is enabled if + the first character of the option string is a colon; this handling + disables diagnostic messages concerning missing option arguments + and illegal option characters. The handling is as follows. + + ILLEGAL OPTIONS: + name -> "?" + if (special_error) then + OPTARG = option character found + no error output + else + OPTARG unset + diagnostic message + fi + + MISSING OPTION ARGUMENT; + if (special_error) then + name -> ":" + OPTARG = option character found + else + name -> "?" + OPTARG unset + diagnostic message + fi + */ + +static int +dogetopts (argc, argv) + int argc; + char **argv; +{ + int ret, special_error, old_opterr = 0, i, n; + char strval[2], numval[16]; + char *optstr; /* list of options */ + char *name; /* variable to get flag val */ + char *t; + + if (argc < 3) + { + builtin_error("usage: getopts optstring name [arg]"); + return (EX_USAGE); + } + + /* argv[0] is "getopts". */ + + optstr = argv[1]; + name = argv[2]; + argc -= 2; + argv += 2; + + special_error = optstr[0] == ':'; + + if (special_error) + { + old_opterr = sh_opterr; + optstr++; + sh_opterr = 0; /* suppress diagnostic messages */ + } + + if (argc > 1) + { + sh_getopt_restore_state (argv); + t = argv[0]; + argv[0] = dollar_vars[0]; + ret = sh_getopt (argc, argv, optstr); + argv[0] = t; + } + else if (rest_of_args == (WORD_LIST *)NULL) + { + register int 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++); + v = (char **)xmalloc ((i + 1) * sizeof (char *)); + for (i = 0; i < 10 && dollar_vars[i]; i++) + v[i] = dollar_vars[i]; + for (words = rest_of_args; words; words = words->next, i++) + v[i] = words->word->word; + v[i] = (char *)NULL; + ret = sh_getopt (i, v, optstr); + free (v); + } + + if (special_error) + sh_opterr = old_opterr; + + /* Set the OPTIND variable in any case, to handle "--" skipping. */ + if (sh_optind < 10) + { + numval[14] = sh_optind + '0'; + numval[15] = '\0'; + i = 14; + } + else + { + numval[i = 15] = '\0'; + n = sh_optind; + do + { + numval[--i] = (n % 10) + '0'; + } + while (n /= 10); + } + bind_variable ("OPTIND", numval + i); + + /* 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 + NULL. If a required option argument was missing, OPTARG points + to a NULL string (that is, optarg[0] == 0). */ + if (ret == '?') + { + if (sh_optarg == NULL) + ret = G_ILLEGAL_OPT; + else if (sh_optarg[0] == '\0') + ret = G_ARG_MISSING; + } + + if (ret == G_EOF) + { + bind_variable (name, "?"); + return (EXECUTION_FAILURE); + } + + if (ret == G_ILLEGAL_OPT) + { + /* Illegal option encountered. */ + strval[0] = '?'; + strval[1] = '\0'; + bind_variable (name, strval); + + if (special_error) + { + strval[0] = (char) sh_optopt; + strval[1] = '\0'; + bind_variable ("OPTARG", strval); + } + else + makunbound ("OPTARG", shell_variables); + return (EXECUTION_SUCCESS); + } + + if (ret == G_ARG_MISSING) + { + /* Required argument missing. */ + if (special_error) + { + strval[0] = ':'; + strval[1] = '\0'; + bind_variable (name, strval); + + strval[0] = (char) sh_optopt; + strval[1] = '\0'; + bind_variable ("OPTARG", strval); + } + else + { + strval[0] = '?'; + strval[1] = '\0'; + bind_variable (name, strval); + makunbound ("OPTARG", shell_variables); + } + return (EXECUTION_SUCCESS); + } + + bind_variable ("OPTARG", sh_optarg); + + strval[0] = (char) ret; + strval[1] = '\0'; + bind_variable (name, strval); + + return (EXECUTION_SUCCESS); +} + +/* The getopts builtin. Build an argv, and call dogetopts with it. */ +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; + + ret = dogetopts (ac, av); + free ((char *)av); + return (ret); +} +#endif /* GETOPTS_BUILTIN */ diff --git a/builtins/hash.def b/builtins/hash.def new file mode 100644 index 0000000..f4d319b --- /dev/null +++ b/builtins/hash.def @@ -0,0 +1,222 @@ +This file is hash.def, from which is created hash.c. +It implements the builtin "hash" 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 hash.c + +$BUILTIN hash +$FUNCTION hash_builtin +$SHORT_DOC hash [-r] [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. +$END + +#include <sys/types.h> +#include "../posixstat.h" + +#include <stdio.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" +#include "../builtins.h" +#include "../flags.h" +#include "hashcom.h" +#include "common.h" +#include "../execute_cmd.h" + +extern int dot_found_in_search; + +void +initialize_filename_hashing () +{ + hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS); +} + +/* 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. */ +hash_builtin (list) + WORD_LIST *list; +{ + int expunge_hash_table = 0; + int any_failed = 0; + + if (hashing_disabled) + { + builtin_error ("hashing disabled"); + return (EXECUTION_FAILURE); + } + + while (list) + { + char *arg = list->word->word; + + if (ISOPTION (arg, '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 ...]"); + return (EX_USAGE); + } + else + break; + } + + /* 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) + { + /* 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"); + + return (EXECUTION_SUCCESS); + } + + if (expunge_hash_table) + { + int bucket = 0; + register BUCKET_CONTENTS *item_list, *prev; + + 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) + { + /* 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 (full_path && executable_file (full_path)) + remember_filename (word, full_path, dot_found_in_search, 0); + else + { + builtin_error ("%s: not found", word); + any_failed++; + } + } + if (full_path) + free (full_path); + + list = list->next; + } + + fflush (stdout); + + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} + +/* 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. */ +void +remember_filename (filename, full_pathname, check_dot, found) + char *filename, *full_pathname; + int check_dot, found; +{ + register BUCKET_CONTENTS *item; + + if (hashing_disabled) + 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)); + } + pathdata(item)->path = savestring (full_pathname); + pathdata(item)->check_dot = check_dot; + item->times_found = found; +} diff --git a/builtins/hashcom.h b/builtins/hashcom.h new file mode 100644 index 0000000..defe2fc --- /dev/null +++ b/builtins/hashcom.h @@ -0,0 +1,32 @@ +/* hashcom.h - Common defines for hashing filenames. */ + +/* 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 "../hash.h" + +#define FILENAME_HASH_BUCKETS 631 + +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. */ +} PATH_DATA; + +#define pathdata(x) ((PATH_DATA *)(x)->data) diff --git a/builtins/help.def b/builtins/help.def new file mode 100644 index 0000000..c9f1db8 --- /dev/null +++ b/builtins/help.def @@ -0,0 +1,134 @@ +This file is help.def, from which is created help.c. +It implements the builtin "help" 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 help.c + +$BUILTIN help +$FUNCTION 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 <stdio.h> +#include "../shell.h" +#include "../builtins.h" + +#if defined (USE_GLOB_LIBRARY) +# include <glob/glob.h> +#else +# define FNM_NOMATCH 1 +#endif /* USE_GLOB_LIBRARY */ + +/* 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. */ +help_builtin (list) + WORD_LIST *list; +{ + if (!list) + { + register int i, j; + char blurb[256]; + + 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"); + + for (i = 0; i < num_shell_builtins; 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); + + } + if (i % 2) + printf ("\n"); + } + else + { + int match_found = 0; + char *pattern = ""; + + if (glob_pattern_p (list->word->word)) + { + printf ("Shell commands matching keyword%s `", + list->next ? "s" : ""); + print_word_list (list, ", "); + printf ("'\n\n"); + } + + while (list) + { + register int i = 0, plen; + char *name; + + pattern = list->word->word; + plen = strlen (pattern); + + while (name = shell_builtins[i].name) + { + int doc_index; + + QUIT; + if ((strncmp (pattern, name, plen) == 0) || + (fnmatch (pattern, name, 0) != FNM_NOMATCH)) + { + printf ("%s: %s\n", name, shell_builtins[i].short_doc); + + 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++; + } + list = list->next; + } + + if (!match_found) + { + fprintf (stderr, "No help topics match `%s'. Try `help help'.\n", + pattern); + fflush (stderr); + return (EXECUTION_FAILURE); + } + } + fflush (stdout); + return (EXECUTION_SUCCESS); +} diff --git a/builtins/history.def b/builtins/history.def new file mode 100644 index 0000000..814e705 --- /dev/null +++ b/builtins/history.def @@ -0,0 +1,179 @@ +This file is history.def, from which is created history.c. +It implements the builtin "history" 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 history.c + +$BUILTIN history +$FUNCTION history_builtin +$DEPENDS_ON HISTORY +$SHORT_DOC history [n] [ [-awrn] [filename]] +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 +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. +$END + +#include "../shell.h" +#if defined (HISTORY) +#include <sys/types.h> +#include <sys/file.h> +#include "../filecntl.h" +#include "../posixstat.h" +#include "../bashhist.h" +#include <readline/history.h> + +/* History. Arg of -w FILENAME means write file, arg of -r FILENAME + means read file. Arg of N means only display that many items. */ + +history_builtin (list) + WORD_LIST *list; +{ + register int i; + int limited = 0, limit = 0; + HIST_ENTRY **hlist; + + while (list) + { + 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) + { + list = list->next; + break; + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_error ("usage: history [n] [-rwan [filename]]"); + return (EX_USAGE); + } + else + break; + } + + if (list) + { + limited = 1; + limit = get_numeric_arg (list); + } + + hlist = history_list (); + + if (hlist) + { + for (i = 0; hlist[i]; i++); + + if (limit < 0) + limit = -limit; + + if (!limited) + 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); + i++; + } + } + return (EXECUTION_SUCCESS); +} +#endif /* HISTORY */ diff --git a/builtins/inlib.def b/builtins/inlib.def new file mode 100644 index 0000000..023945b --- /dev/null +++ b/builtins/inlib.def @@ -0,0 +1,74 @@ +This file is inlib.def, from which is created inlib.c. +It implements the Apollo-specific builtin "inlib" 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 inlib.c +#include <stdio.h> +#include "../shell.h" + +$BUILTIN inlib +$FUNCTION inlib_builtin +$DEPENDS_ON apollo +$SHORT_DOC inlib pathname [pathname...] +Install a user-supplied library specified by pathname in the current +shell process. The library is used to resolve external references +in programs and libraries loaded after its installation. Note +that the library is not loaded into the address space unless it is +needed to resolve an external reference. The list of inlibed +libraries is passed to all children of the current shell. +$END + +#if defined (apollo) + +#include <apollo/base.h> +#include <apollo/loader.h> + +inlib_builtin (list) + WORD_LIST *list; +{ + status_$t status; + int return_value; + short len; + + if (!list) + { + builtin_error ("usage: inlib pathname [pathname...]"); + return (EX_USAGE); + } + + return_value = EXECUTION_SUCCESS; + + while (list) + { + len = (short)strlen (list->word->word); + loader_$inlib (list->word->word, len, &status); + + if (status.all != status_$ok) + { + builtin_error ("inlib failed for %s", list->word->word); + return_value = EXECUTION_FAILURE; + } + + list = list->next; + } + + return (return_value); +} +#endif /* apollo */ diff --git a/builtins/jobs.def b/builtins/jobs.def new file mode 100644 index 0000000..8a293da --- /dev/null +++ b/builtins/jobs.def @@ -0,0 +1,171 @@ +This file is jobs.def, from which is created jobs.c. +It implements the builtin "jobs" in Bash. + +Copyright (C) 1987, 1989, 1991, 1992 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 jobs.c + +$BUILTIN jobs +$FUNCTION jobs_builtin +$DEPENDS_ON JOB_CONTROL +$SHORT_DOC jobs [-lnp] [jobspec ...] | 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. +$END + +#include "../shell.h" + +#if defined (JOB_CONTROL) +#include <sys/types.h> +#include <signal.h> +#include "../jobs.h" + +#include "bashgetopt.h" + +extern int job_control, interactive_shell; +static int execute_list_with_replacements (); + +/* The `jobs' command. Prints outs a list of active jobs. If the + argument `-l' is given, then the process id's are printed also. + If the argument `-p' is given, print the process group leader's + 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. */ +int +jobs_builtin (list) + WORD_LIST *list; +{ + int form = JLIST_STANDARD, execute = 0; + int opt; + int any_failed = 0; + + if (!job_control && !interactive_shell) + return (EXECUTION_SUCCESS); + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "lpnx")) != -1) + { + switch (opt) + { + case 'l': + form = JLIST_LONG; + break; + case 'p': + form = JLIST_PID_ONLY; + break; + case 'n': + form = JLIST_CHANGED_ONLY; + break; + case 'x': + if (form != JLIST_STANDARD) + { + builtin_error ("Other options not allowed with `-x'"); + return (EXECUTION_FAILURE); + } + execute++; + break; + + default: + builtin_error ("usage: jobs [-lpn [jobspec]] [-x command [args]]"); + return (EX_USAGE); + } + } + + list = loptend; + + if (execute) + return (execute_list_with_replacements (list)); + + if (!list) + { + list_jobs (form); + 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); + any_failed++; + } + else if (job != DUP_JOB) + list_one_job ((JOB *)NULL, form, 0, job); + + UNBLOCK_CHILD (oset); + list = list->next; + } + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +static int +execute_list_with_replacements (list) + WORD_LIST *list; +{ + register WORD_LIST *l; + int job, result; + + /* First do the replacement of job specifications with pids. */ + for (l = list; l; l = l->next) + { + if (l->word->word[0] == '%') /* we have a winner */ + { + job = get_job_spec (l); + + /* A bad job spec is not really a job spec! Pass it through. */ + if (job < 0 || job >= job_slots || !jobs[job]) + continue; + + free (l->word->word); + l->word->word = itos (jobs[job]->pgrp); + } + } + + /* Next make a new simple command and execute it. */ + begin_unwind_frame ("jobs_builtin"); + { + COMMAND *command = (COMMAND *)NULL; + + add_unwind_protect (dispose_command, command); + + command = make_bare_simple_command (); + command->value.Simple->words = copy_word_list (list); + command->value.Simple->redirects = (REDIRECT *)NULL; + command->flags |= CMD_INHIBIT_EXPANSION; + command->value.Simple->flags |= CMD_INHIBIT_EXPANSION; + + result = execute_command (command); + } + + run_unwind_frame ("jobs_builtin"); + return (result); +} +#endif /* JOB_CONTROL */ diff --git a/builtins/kill.def b/builtins/kill.def new file mode 100644 index 0000000..53d5c8f --- /dev/null +++ b/builtins/kill.def @@ -0,0 +1,281 @@ +This file is kill.def, from which is created kill.c. +It implements the builtin "kill" 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 kill.c + +$BUILTIN kill +$FUNCTION kill_builtin +$DEPENDS_ON JOB_CONTROL +$SHORT_DOC kill [-s sigspec | -sigspec] [pid | job]... | -l [signum] +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 +be signal numbers for which names should be listed. Kill is a shell +builtin for two reasons: it allows job IDs to be used instead of +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 "../bashtypes.h" +#include "../shell.h" +#include "../trap.h" +#include "../jobs.h" +#include "common.h" +#include <errno.h> + +#if defined (JOB_CONTROL) +extern int interactive; +extern int posixly_correct; + +#if !defined (CONTINUE_AFTER_KILL_ERROR) +# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE) +#else +# define CONTINUE_OR_FAIL goto continue_killing +#endif /* CONTINUE_AFTER_KILL_ERROR */ + +/* Here is the kill builtin. We only have it so that people can type + kill -KILL %1? No, if you fill up the process table this way you + can still kill some. */ +int +kill_builtin (list) + WORD_LIST *list; +{ + int signal = SIGTERM; + int any_succeeded = 0, listing = 0, saw_signal = 0; + char *sigspec = "TERM", *word; + pid_t pid; + + if (!list) + return (EXECUTION_SUCCESS); + + /* Process options. */ + while (list) + { + word = list->word->word; + + if (ISOPTION (word, 'l')) + { + listing++; + list = list->next; + } + else if (ISOPTION (word, 's')) + { + list = list->next; + if (list) + { + sigspec = list->word->word; + if (sigspec[0] == '0' && !sigspec[1]) + signal = 0; + else + signal = decode_signal (sigspec); + list = list->next; + } + else + { + builtin_error ("-s requires an argument"); + return (EXECUTION_FAILURE); + } + } + else if (ISOPTION (word, '-')) + { + list = list->next; + break; + } + /* 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). */ + else if ((*word == '-') && !saw_signal) + { + sigspec = word + 1; + signal = decode_signal (sigspec); + saw_signal++; + list = list->next; + } + else + break; + } + + 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); + } + + /* OK, we are killing processes. */ + if (signal == NO_SIG) + { + builtin_error ("bad signal spec `%s'", sigspec); + return (EXECUTION_FAILURE); + } + + while (list) + { + word = list->word->word; + + if (*word == '-') + word++; + + if (all_digits (word)) + { + /* Use the entire argument in case of minus sign presence. */ + pid = (pid_t) atoi (list->word->word); + + if (kill_pid (pid, signal, 0) < 0) + goto signal_error; + else + any_succeeded++; + } + else if (*list->word->word != '%') + { + builtin_error ("No such pid %s", 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; + + BLOCK_CHILD (set, oset); + job = get_job_spec (list); + + if (job < 0 || job >= job_slots || !jobs[job]) + { + if (job != DUP_JOB) + builtin_error ("No such job %s", list->word->word); + UNBLOCK_CHILD (oset); + CONTINUE_OR_FAIL; + } + + /* Job spec used. Kill the process group. If the job was started + 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; + + UNBLOCK_CHILD (oset); + + if (kill_pid (pid, signal, 1) < 0) + { + signal_error: + if (errno == EPERM) + builtin_error ("(%d) - Not owner", (int)pid); + else if (errno == ESRCH) + builtin_error ("(%d) - No such pid", (int)pid); + else + builtin_error ("Invalid signal %d", signal); + CONTINUE_OR_FAIL; + } + else + any_succeeded++; + } + else + { + builtin_error ("bad process specification `%s'", list->word->word); + CONTINUE_OR_FAIL; + } + continue_killing: + list = list->next; + } + + if (any_succeeded) + return (EXECUTION_SUCCESS); + else + return (EXECUTION_FAILURE); +} +#endif /* JOB_CONTROL */ diff --git a/builtins/let.def b/builtins/let.def new file mode 100644 index 0000000..fdb3a6f --- /dev/null +++ b/builtins/let.def @@ -0,0 +1,77 @@ +This file is let.def, from which is created let.c. +It implements the builtin "let" 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. + +$BUILTIN let +$FUNCTION let_builtin +$PRODUCES let.c +$SHORT_DOC let arg [arg ...] +Each ARG is an arithmetic expression to be evaluated. 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 + ! logical NOT + * / % multiplication, division, remainder + + - addition, subtraction + <= >= < > comparison + == != equality inequality + = assignment + +Shell variables are allowed as operands. The name of the variable +is replaced by its value (coerced to a long integer) within +an expression. The variable need not have its integer attribute +turned on to be used in an expression. + +Operators are evaluated in order of precedence. Sub-expressions in +parentheses are evaluated first and may override the precedence +rules above. + +If the last ARG evaluates to 0, let returns 1; 0 is returned +otherwise. +$END + +#include "../shell.h" + +/* Arithmetic LET function. */ +let_builtin (list) + WORD_LIST *list; +{ + long ret = 0L; + + if (!list) + { + builtin_error ("argument (expression) expected"); + return (EXECUTION_FAILURE); + } + + while (list) + { + ret = evalexp (list->word->word); + list = list->next; + } + + if (ret == 0L) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c new file mode 100644 index 0000000..572d01e --- /dev/null +++ b/builtins/mkbuiltins.c @@ -0,0 +1,1311 @@ +/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from + a single source file called builtins.def. */ + +/* 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. */ + +#include "../bashansi.h" +#include "../config.h" +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include "../filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#define DOCFILE "builtins.texi" + +static char *xmalloc (), *xrealloc (); + +#if !defined (__STDC__) && !defined (strcpy) +extern char *strcpy (); +#endif /* !__STDC__ && !strcpy */ + +#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) + +/* Flag values that builtins can have. */ +#define BUILTIN_FLAG_SPECIAL 0x01 + +/* If this stream descriptor is non-zero, then write + texinfo documentation to it. */ +FILE *documentation_file = (FILE *)NULL; + +/* Non-zero means to only produce documentation. */ +int only_documentation = 0; + +/* Non-zero means to not do any productions. */ +int inhibit_production = 0; + +#if !defined (OLDCODE) +int no_long_document = 0; +#endif /* !OLDCODE */ + +/* The name of a directory to precede the filename when reporting + errors. */ +char *error_directory = (char *)NULL; + +/* The name of the structure file. */ +char *struct_filename = (char *)NULL; + +/* The name of the external declaration file. */ +char *extern_filename = (char *)NULL; + +/* Here is a structure for manipulating arrays of data. */ +typedef struct { + int size; /* Number of slots allocated to array. */ + int sindex; /* Current location in array. */ + int width; /* Size of each element. */ + int growth_rate; /* How fast to grow. */ + char **array; /* The array itself. */ +} ARRAY; + +/* Here is a structure defining a single BUILTIN. */ +typedef struct { + char *name; /* The name of this builtin. */ + char *function; /* The name of the function to call. */ + char *shortdoc; /* The short documentation for this builtin. */ + char *docname; /* Possible name for documentation string. */ + ARRAY *longdoc; /* The long documentation for this builtin. */ + ARRAY *dependencies; /* Null terminated array of #define names. */ + int flags; /* Flags for this builtin. */ +} BUILTIN_DESC; + +/* Here is a structure which defines a DEF file. */ +typedef struct { + char *filename; /* The name of the input def file. */ + ARRAY *lines; /* The contents of the file. */ + int line_number; /* The current line number. */ + char *production; /* The name of the production file. */ + FILE *output; /* Open file stream for PRODUCTION. */ + ARRAY *builtins; /* Null terminated array of BUILTIN_DESC *. */ +} DEF_FILE; + +/* The array of all builtins encountered during execution of this code. */ +ARRAY *saved_builtins = (ARRAY *)NULL; + +/* The Posix.2 so-called `special' builtins. */ +char *special_builtins[] = +{ + ":", ".", "source", "break", "continue", "eval", "exec", "exit", + "export", "readonly", "return", "set", "shift", "trap", "unset", + (char *)NULL +}; +static int is_special_builtin (); + + +/* 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. */ +main (argc, argv) + int argc; + char **argv; +{ + int arg_index = 1; + FILE *structfile, *externfile; + char *documentation_filename, *temp_struct_filename; + + structfile = externfile = (FILE *)NULL; + documentation_filename = DOCFILE; + temp_struct_filename = (char *)NULL; + + while (arg_index < argc && argv[arg_index][0] == '-') + { + char *arg = argv[arg_index++]; + + if (strcmp (arg, "-externfile") == 0) + extern_filename = argv[arg_index++]; + else if (strcmp (arg, "-structfile") == 0) + struct_filename = argv[arg_index++]; + else if (strcmp (arg, "-noproduction") == 0) + inhibit_production = 1; + else if (strcmp (arg, "-document") == 0) + documentation_file = fopen (documentation_filename, "w"); + else if (strcmp (arg, "-D") == 0) + { + int len; + + if (error_directory) + free (error_directory); + + error_directory = xmalloc (2 + strlen (argv[arg_index])); + strcpy (error_directory, argv[arg_index]); + len = strlen (error_directory); + + if (len && error_directory[len - 1] != '/') + strcat (error_directory, "/"); + + arg_index++; + } + else if (strcmp (arg, "-documentonly") == 0) + { + only_documentation = 1; + documentation_file = fopen (documentation_filename, "w"); + } +#if !defined (OLDCODE) + else if (strcmp (arg, "-nodocument") == 0) + no_long_document = 1; +#endif /* !OLDCODE */ + else + { + fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg); + exit (2); + } + } + + /* If there are no files to process, just quit now. */ + if (arg_index == argc) + exit (0); + + if (!only_documentation) + { + /* Open the files. */ + if (struct_filename) + { + temp_struct_filename = xmalloc (15); + sprintf (temp_struct_filename, "mk-%d", (int) getpid ()); + structfile = fopen (temp_struct_filename, "w"); + + if (!structfile) + file_error (temp_struct_filename); + } + + if (extern_filename) + { + externfile = fopen (extern_filename, "w"); + + if (!externfile) + file_error (extern_filename); + } + + /* Write out the headers. */ + write_file_headers (structfile, externfile); + } + + if (documentation_file) + { + fprintf (documentation_file, "@c Table of builtins created with %s.\n", + argv[0]); + fprintf (documentation_file, "@ftable @asis\n"); + } + + /* Process the .def files. */ + while (arg_index < argc) + { + register char *arg; + + arg = argv[arg_index++]; + + extract_info (arg, structfile, externfile); + } + + /* Close the files. */ + if (!only_documentation) + { + /* Write the footers. */ + write_file_footers (structfile, externfile); + + if (structfile) + { + write_longdocs (structfile, saved_builtins); + fclose (structfile); + link (temp_struct_filename, struct_filename); + unlink (temp_struct_filename); + } + + if (externfile) + fclose (externfile); + } + + if (documentation_file) + { + fprintf (documentation_file, "@end ftable\n"); + fclose (documentation_file); + } + + exit (0); +} + +/* **************************************************************** */ +/* */ +/* Array Functions and Manipulators */ +/* */ +/* **************************************************************** */ + +/* Make a new array, and return a pointer to it. The array will + contain elements of size WIDTH, and is initialized to no elements. */ +ARRAY * +array_create (width) + int width; +{ + ARRAY *array; + + array = (ARRAY *)xmalloc (sizeof (ARRAY)); + array->size = 0; + array->sindex = 0; + array->width = width; + + /* Default to increasing size in units of 20. */ + array->growth_rate = 20; + + array->array = (char **)NULL; + + return (array); +} + +/* Copy the array of strings in ARRAY. */ +ARRAY * +copy_string_array (array) + ARRAY *array; +{ + register int i; + ARRAY *copy; + + if (!array) + return (ARRAY *)NULL; + + copy = array_create (sizeof (char *)); + + copy->size = array->size; + copy->sindex = array->sindex; + copy->width = array->width; + + copy->array = (char **)xmalloc ((1 + array->sindex) * sizeof (char *)); + + for (i = 0; i < array->sindex; i++) + copy->array[i] = savestring (array->array[i]); + + copy->array[i] = (char *)NULL; + + return (copy); +} + +/* Add ELEMENT to ARRAY, growing the array if neccessary. */ +array_add (element, array) + char *element; + ARRAY *array; +{ + if (array->sindex + 2 > array->size) + array->array = (char **)xrealloc + (array->array, (array->size += array->growth_rate) * array->width); + +#if defined (HAVE_BCOPY) + bcopy (&element, &(array->array[array->sindex]), array->width); + array->sindex++; + bzero (&(array->array[array->sindex]), array->width); +#else + array->array[array->sindex++] = element; + array->array[array->sindex] = (char *)NULL; +#endif /* !HAVE_BCOPY */ +} + +/* Free an allocated array and data pointer. */ +array_free (array) + ARRAY *array; +{ + if (array->array) + free (array->array); + + free (array); +} + +/* **************************************************************** */ +/* */ +/* Processing a DEF File */ +/* */ +/* **************************************************************** */ + +/* The definition of a function. */ +typedef int Function (); + +/* Structure handles processor directives. */ +typedef struct { + char *directive; + Function *function; +} HANDLER_ENTRY; + +extern int + builtin_handler (), function_handler (), short_doc_handler (), + comment_handler (), depends_on_handler (), produces_handler (), + end_handler (), docname_handler (); + +HANDLER_ENTRY handlers[] = { + { "BUILTIN", builtin_handler }, + { "DOCNAME", docname_handler }, + { "FUNCTION", function_handler }, + { "SHORT_DOC", short_doc_handler }, + { "$", comment_handler }, + { "COMMENT", comment_handler }, + { "DEPENDS_ON", depends_on_handler }, + { "PRODUCES", produces_handler }, + { "END", end_handler }, + { (char *)NULL, (Function *)NULL } +}; + +/* Return the entry in the table of handlers for NAME. */ +HANDLER_ENTRY * +find_directive (directive) + char *directive; +{ + register int i; + + for (i = 0; handlers[i].directive; i++) + if (strcmp (handlers[i].directive, directive) == 0) + return (&handlers[i]); + + return ((HANDLER_ENTRY *)NULL); +} + +/* Non-zero indicates that a $BUILTIN has been seen, but not + the corresponding $END. */ +static int building_builtin = 0; + +/* Non-zero means to output cpp line and file information before + printing the current line to the production file. */ +int output_cpp_line_info = 0; + +/* The main function of this program. Read FILENAME and act on what is + found. Lines not starting with a dollar sign are copied to the + $PRODUCES target, if one is present. Lines starting with a dollar sign + are directives to this program, specifying the name of the builtin, the + function to call, the short documentation and the long documentation + strings. FILENAME can contain multiple $BUILTINs, but only one $PRODUCES + 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". */ +extract_info (filename, structfile, externfile) + char *filename; + FILE *structfile, *externfile; +{ + register int i; + DEF_FILE *defs; + struct stat finfo; + char *buffer, *line; + int fd; + + if (stat (filename, &finfo) == -1) + file_error (filename); + + fd = open (filename, O_RDONLY, 0666); + + if (fd == -1) + file_error (filename); + + buffer = xmalloc (1 + (int)finfo.st_size); + + if (read (fd, buffer, finfo.st_size) != finfo.st_size) + file_error (filename); + + close (fd); + + /* Create and fill in the initial structure describing this file. */ + defs = (DEF_FILE *)xmalloc (sizeof (DEF_FILE)); + defs->filename = filename; + defs->lines = array_create (sizeof (char *)); + defs->line_number = 0; + defs->production = (char *)NULL; + defs->output = (FILE *)NULL; + defs->builtins = (ARRAY *)NULL; + + /* Build the array of lines. */ + i = 0; + while (i < finfo.st_size) + { + array_add (&buffer[i], defs->lines); + + while (buffer[i] != '\n' && i < finfo.st_size) + i++; + buffer[i++] = '\0'; + } + + /* Begin processing the input file. We don't write any output + until we have a file to write output to. */ + output_cpp_line_info = 1; + + /* Process each line in the array. */ + for (i = 0; line = defs->lines->array[i]; i++) + { + defs->line_number = i; + + if (*line == '$') + { + register int j; + char *directive; + HANDLER_ENTRY *handler; + + /* Isolate the directive. */ + for (j = 0; line[j] && !whitespace (line[j]); j++); + + directive = xmalloc (j); + strncpy (directive, line + 1, j - 1); + directive[j -1] = '\0'; + + /* Get the function handler and call it. */ + handler = find_directive (directive); + + if (!handler) + { + line_error (defs, "Unknown directive `%s'", directive); + free (directive); + continue; + } + else + { + /* Advance to the first non-whitespace character. */ + while (whitespace (line[j])) + j++; + + /* Call the directive handler with the FILE, and ARGS. */ + (*(handler->function)) (directive, defs, line + j); + } + free (directive); + } + else + { + if (building_builtin) + add_documentation (defs, line); + else if (defs->output) + { + if (output_cpp_line_info) + { + /* If we're handed an absolute pathname, don't prepend + the directory name. */ + if (defs->filename[0] == '/') + fprintf (defs->output, "#line %d \"%s\"\n", + defs->line_number + 1, defs->filename); + else + fprintf (defs->output, "#line %d \"%s%s\"\n", + defs->line_number + 1, + error_directory ? error_directory : "./", + defs->filename); + output_cpp_line_info = 0; + } + + fprintf (defs->output, "%s\n", line); + } + } + } + + /* Close the production file. */ + if (defs->output) + fclose (defs->output); + + /* The file has been processed. Write the accumulated builtins to + the builtins.c file, and write the extern definitions to the + builtext.h file. */ + write_builtins (defs, structfile, externfile); + + free (buffer); + free_defs (defs); +} + +#define free_safely(x) if (x) free (x) + +static void +free_builtin (builtin) + BUILTIN_DESC *builtin; +{ + register int i; + + free_safely (builtin->name); + free_safely (builtin->function); + free_safely (builtin->shortdoc); + free_safely (builtin->docname); + + if (builtin->longdoc) + array_free (builtin->longdoc); + + if (builtin->dependencies) + { + for (i = 0; builtin->dependencies->array[i]; i++) + free (builtin->dependencies->array[i]); + array_free (builtin->dependencies); + } +} + +/* Free all of the memory allocated to a DEF_FILE. */ +free_defs (defs) + DEF_FILE *defs; +{ + register int i; + register BUILTIN_DESC *builtin; + + if (defs->production) + free (defs->production); + + if (defs->lines) + array_free (defs->lines); + + if (defs->builtins) + { + for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++) + { + free_builtin (builtin); + free (builtin); + } + array_free (defs->builtins); + } + free (defs); +} + +/* **************************************************************** */ +/* */ +/* The Handler Functions Themselves */ +/* */ +/* **************************************************************** */ + +/* Strip surrounding whitespace from STRING, and + return a pointer to the start of it. */ +char * +strip_whitespace (string) + char *string; +{ + while (whitespace (*string)) + string++; + + remove_trailing_whitespace (string); + return (string); +} + +/* Remove only the trailing whitespace from STRING. */ +remove_trailing_whitespace (string) + char *string; +{ + register int i; + + i = strlen (string) - 1; + + while (i > 0 && whitespace (string[i])) + i--; + + string[++i] = '\0'; +} + +/* Ensure that there is a argument in STRING and return it. + FOR_WHOM is the name of the directive which needs the argument. + DEFS is the DEF_FILE in which the directive is found. + If there is no argument, produce an error. */ +char * +get_arg (for_whom, defs, string) + char *for_whom, *string; + DEF_FILE *defs; +{ + char *new; + + new = strip_whitespace (string); + + if (!*new) + line_error (defs, "%s requires an argument", for_whom); + + return (savestring (new)); +} + +/* Error if not building a builtin. */ +must_be_building (directive, defs) + char *directive; + DEF_FILE *defs; +{ + if (!building_builtin) + line_error (defs, "%s must be inside of a $BUILTIN block", directive); +} + +/* Return the current builtin. */ +BUILTIN_DESC * +current_builtin (directive, defs) + char *directive; + DEF_FILE *defs; +{ + must_be_building (directive, defs); + return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]); +} + +/* Add LINE to the long documentation for the current builtin. + Ignore blank lines until the first non-blank line has been seen. */ +add_documentation (defs, line) + DEF_FILE *defs; + char *line; +{ + register BUILTIN_DESC *builtin; + + builtin = current_builtin ("(implied LONGDOC)", defs); + + remove_trailing_whitespace (line); + + if (!*line && !builtin->longdoc) + return; + + if (!builtin->longdoc) + builtin->longdoc = array_create (sizeof (char *)); + + array_add (line, builtin->longdoc); +} + +/* How to handle the $BUILTIN directive. */ +int +builtin_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + /* 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)); + + 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; + } + return (0); +} + +/* How to handle the $FUNCTION directive. */ +int +function_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + register BUILTIN_DESC *builtin; + + builtin = current_builtin (self, defs); + + if (builtin->function) + line_error (defs, "%s already has a function (%s)", + builtin->name, builtin->function); + else + builtin->function = get_arg (self, defs, arg); + + return (0); +} + +/* How to handle the $DOCNAME directive. */ +int +docname_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + register BUILTIN_DESC *builtin; + + builtin = current_builtin (self, defs); + + if (builtin->docname) + line_error (defs, "%s already had a docname (%s)", + builtin->name, builtin->docname); + else + builtin->docname = get_arg (self, defs, arg); + + return (0); +} + +/* How to handle the $SHORT_DOC directive. */ +short_doc_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + register BUILTIN_DESC *builtin; + + builtin = current_builtin (self, defs); + + if (builtin->shortdoc) + line_error (defs, "%s already has short documentation (%s)", + builtin->name, builtin->shortdoc); + else + builtin->shortdoc = get_arg (self, defs, arg); + + return (0); +} + +/* How to handle the $COMMENT directive. */ +comment_handler (self, defs) + char *self; + DEF_FILE *defs; +{ +} + +/* How to handle the $DEPENDS_ON directive. */ +depends_on_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + register BUILTIN_DESC *builtin; + char *dependent; + + builtin = current_builtin (self, defs); + dependent = get_arg (self, defs, arg); + + if (!builtin->dependencies) + builtin->dependencies = array_create (sizeof (char *)); + + array_add (dependent, builtin->dependencies); + + return (0); +} + +/* How to handle the $PRODUCES directive. */ +produces_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + /* If just hacking documentation, don't change any of the production + files. */ + if (only_documentation) + return (0); + + output_cpp_line_info++; + + if (defs->production) + line_error (defs, "%s already has a %s definition", defs->filename, self); + else + { + defs->production = get_arg (self, defs, arg); + + if (inhibit_production) + return (0); + + defs->output = fopen (defs->production, "w"); + + if (!defs->output) + file_error (defs->production); + + fprintf (defs->output, "/* %s, created from %s. */\n", + defs->production, defs->filename); + } + return (0); +} + +/* How to handle the $END directive. */ +end_handler (self, defs, arg) + char *self, *arg; + DEF_FILE *defs; +{ + must_be_building (self, defs); + building_builtin = 0; +} + +/* **************************************************************** */ +/* */ +/* Error Handling Functions */ +/* */ +/* **************************************************************** */ + +/* Produce an error for DEFS with FORMAT and ARGS. */ +line_error (defs, format, arg1, arg2) + DEF_FILE *defs; + char *format, *arg1, *arg2; +{ + if (defs->filename[0] != '/') + fprintf (stderr, "%s", error_directory ? error_directory : "./"); + fprintf (stderr, "%s:%d:", defs->filename, defs->line_number + 1); + fprintf (stderr, format, arg1, arg2); + fprintf (stderr, "\n"); + fflush (stderr); +} + +/* Print error message for FILENAME. */ +file_error (filename) + char *filename; +{ + perror (filename); + exit (2); +} + +/* **************************************************************** */ +/* */ +/* 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, "mkbuiltins: Out of virtual memory!\n"); + abort (); +} + +/* **************************************************************** */ +/* */ +/* Creating the Struct and Extern Files */ +/* */ +/* **************************************************************** */ + +/* Return a pointer to a newly allocated builtin which is + an exact copy of BUILTIN. */ +BUILTIN_DESC * +copy_builtin (builtin) + BUILTIN_DESC *builtin; +{ + BUILTIN_DESC *new; + + new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC)); + + new->name = savestring (builtin->name); + new->shortdoc = savestring (builtin->shortdoc); + new->longdoc = copy_string_array (builtin->longdoc); + new->dependencies = copy_string_array (builtin->dependencies); + + new->function = + builtin->function ? savestring (builtin->function) : (char *)NULL; + new->docname = + builtin->docname ? savestring (builtin->docname) : (char *)NULL; + + return (new); +} + +/* How to save away a builtin. */ +save_builtin (builtin) + BUILTIN_DESC *builtin; +{ + BUILTIN_DESC *newbuiltin; + + newbuiltin = copy_builtin (builtin); + + /* If this is the first builtin to be saved, create the array + to hold it. */ + if (!saved_builtins) + saved_builtins = array_create (sizeof (BUILTIN_DESC *)); + + array_add ((char *)newbuiltin, saved_builtins); +} + +/* Flags that mean something to write_documentation (). */ +#define STRING_ARRAY 1 +#define TEXINFO 2 + +char *structfile_header[] = { + "/* builtins.c -- the built in shell commands. */", + "", + "/* This file is manufactured by ./mkbuiltins, and should not be", + " edited by hand. See the source to mkbuiltins for details. */", + "", + "/* Copyright (C) 1987, 1991, 1992 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. */", + "", + "/* The list of shell builtins. Each element is name, function, enabled-p,", + " 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", + " expansion performed.", + "", + " Functions which need to look at only the simple commands (e.g.", + " the enable_builtin ()), should ignore entries where", + " (array[i].function == (Function *)NULL). Such entries are for", + " the list of shell reserved control structures, like `if' and `while'.", + " The end of the list is denoted with a NULL name field. */", + "", + "#include \"../builtins.h\"", + (char *)NULL + }; + +char *structfile_footer[] = { + " { (char *)0x0, (Function *)0x0, 0, (char **)0x0, (char *)0x0 }", + "};", + "", + "int num_shell_builtins =", + "\tsizeof (shell_builtins) / sizeof (struct builtin) - 1;", + (char *)NULL +}; + +/* Write out any neccessary opening information for + STRUCTFILE and EXTERNFILE. */ +write_file_headers (structfile, externfile) + FILE *structfile, *externfile; +{ + register int i; + + if (structfile) + { + for (i = 0; structfile_header[i]; i++) + fprintf (structfile, "%s\n", structfile_header[i]); + + fprintf (structfile, "#include \"%s\"\n", + extern_filename ? extern_filename : "builtext.h"); + fprintf (structfile, "\nstruct builtin shell_builtins[] = {\n"); + } + + if (externfile) + fprintf (externfile, + "/* %s - The list of builtins found in libbuiltins.a. */\n", + extern_filename ? extern_filename : "builtext.h"); +} + +/* Write out any necessary closing information for + STRUCTFILE and EXTERNFILE. */ +write_file_footers (structfile, externfile) + FILE *structfile, *externfile; +{ + register int i; + + /* Write out the footers. */ + if (structfile) + { + for (i = 0; structfile_footer[i]; i++) + fprintf (structfile, "%s\n", structfile_footer[i]); + } +} + +/* Write out the information accumulated in DEFS to + STRUCTFILE and EXTERNFILE. */ +write_builtins (defs, structfile, externfile) + DEF_FILE *defs; + FILE *structfile, *externfile; +{ + register int i; + + /* Write out the information. */ + if (defs->builtins) + { + register BUILTIN_DESC *builtin; + + for (i = 0; i < defs->builtins->sindex; i++) + { + builtin = (BUILTIN_DESC *)defs->builtins->array[i]; + + /* Write out any #ifdefs that may be there. */ + if (!only_documentation) + { + if (builtin->dependencies) + { + if (builtin->function) + write_ifdefs (externfile, builtin->dependencies->array); + write_ifdefs (structfile, builtin->dependencies->array); + } + + /* Write the extern definition. */ + if (externfile) + { + if (builtin->function) + fprintf (externfile, "extern int %s ();\n", + builtin->function); + + fprintf (externfile, "extern char *%s_doc[];\n", + builtin->docname ?builtin->docname : builtin->name); + } + + /* Write the structure definition. */ + if (structfile) + { + fprintf (structfile, " { \"%s\", ", builtin->name); + + if (builtin->function) + fprintf (structfile, "%s, ", builtin->function); + 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, + builtin->docname ? builtin->docname : builtin->name); + +#undef SPECIAL_FLAG_STRING +#undef NORMAL_FLAG_STRING + + fprintf + (structfile, " \"%s\" },\n", + builtin->shortdoc ? builtin->shortdoc : builtin->name); + + /* Save away this builtin for later writing of the + long documentation strings. */ + save_builtin (builtin); + } + + /* Write out the matching #endif, if neccessary. */ + if (builtin->dependencies) + { + if (externfile) + write_endifs (externfile, builtin->dependencies->array); + + if (structfile) + write_endifs (structfile, builtin->dependencies->array); + } + } + + if (documentation_file) + { + fprintf (documentation_file, "@item %s\n", builtin->name); + write_documentation + (documentation_file, builtin->longdoc->array, 0, TEXINFO); + } + } + } +} + +/* Write out the long documentation strings in BUILTINS to STREAM. */ +write_longdocs (stream, builtins) + FILE *stream; + ARRAY *builtins; +{ + register int i; + register BUILTIN_DESC *builtin; + + for (i = 0; i < builtins->sindex; i++) + { + builtin = (BUILTIN_DESC *)builtins->array[i]; + + if (builtin->dependencies) + write_ifdefs (stream, builtin->dependencies->array); + + /* Write the long documentation strings. */ + fprintf (stream, "char *%s_doc[] =", + builtin->docname ? builtin->docname : builtin->name); + write_documentation (stream, builtin->longdoc->array, 0, STRING_ARRAY); + + if (builtin->dependencies) + write_endifs (stream, builtin->dependencies->array); + + } +} + +/* Write an #ifdef string saying what needs to be defined (or not defined) + in order to allow compilation of the code that will follow. + STREAM is the stream to write the information to, + DEFINES is a null terminated array of define names. + If a define is preceded by an `!', then the sense of the test is + reversed. */ +write_ifdefs (stream, defines) + FILE *stream; + char **defines; +{ + register int i; + + if (!stream) + return; + + fprintf (stream, "#if "); + + for (i = 0; defines[i]; i++) + { + char *def = defines[i]; + + if (*def == '!') + fprintf (stream, "!defined (%s)", def + 1); + else + fprintf (stream, "defined (%s)", def); + + if (defines[i + 1]) + fprintf (stream, " && "); + } + fprintf (stream, "\n"); +} + +/* Write an #endif string saying what defines controlled the compilation + of the immediately preceding code. + STREAM is the stream to write the information to. + DEFINES is a null terminated array of define names. */ +write_endifs (stream, defines) + FILE *stream; + char **defines; +{ + register int i; + + if (!stream) + return; + + fprintf (stream, "#endif /* "); + + for (i = 0; defines[i]; i++) + { + fprintf (stream, "%s", defines[i]); + + if (defines[i + 1]) + fprintf (stream, " && "); + } + + fprintf (stream, " */\n"); +} + +/* Write DOCUMENTAION to STREAM, perhaps surrounding it with double-quotes + and quoting special characters in the string. */ +write_documentation (stream, documentation, indentation, flags) + FILE *stream; + char **documentation; + int indentation, flags; +{ + register int i, j; + register char *line; + int string_array = (flags & STRING_ARRAY); /* Mutually exclusive. */ + int texinfo = (flags & TEXINFO); + + if (!stream) + return; + + if (string_array) + fprintf (stream, " {\n"); + +#if !defined (OLDCODE) + /* XXX -- clean me up; for experiment only */ + if (no_long_document) + goto end_of_document; +#endif /* !OLDCODE */ + + for (i = 0; line = documentation[i]; i++) + { + /* Allow #ifdef's to be written out verbatim. */ + if (*line == '#') + { + if (string_array) + fprintf (stream, "%s\n", line); + continue; + } + + if (string_array) + fprintf (stream, " \""); + + if (indentation) + for (j = 0; j < indentation; j++) + fprintf (stream, " "); + + if (string_array) + { + for (j = 0; line[j]; j++) + { + switch (line[j]) + { + case '\\': + case '"': + fprintf (stream, "\\%c", line[j]); + break; + + default: + fprintf (stream, "%c", line[j]); + } + } + + fprintf (stream, "\",\n"); + } + else if (texinfo) + { + for (j = 0; line[j]; j++) + { + switch (line[j]) + { + case '@': + case '{': + case '}': + fprintf (stream, "@%c", line[j]); + break; + + default: + fprintf (stream, "%c", line[j]); + } + } + fprintf (stream, "\n"); + } + else + fprintf (stream, "%s\n", line); + } + +#if !defined (OLDCODE) +end_of_document: +#endif /* !OLDCODE */ + + if (string_array) + fprintf (stream, " (char *)NULL\n};\n"); +} + +static int +is_special_builtin (name) + char *name; +{ + register int i; + + for (i = 0; special_builtins[i]; i++) + if (strcmp (name, special_builtins[i]) == 0) + return 1; + return 0; +} diff --git a/builtins/psize.c b/builtins/psize.c new file mode 100644 index 0000000..03a4f6e --- /dev/null +++ b/builtins/psize.c @@ -0,0 +1,63 @@ +/* psize.c - Find pipe size. */ + +/* 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. */ + +/* 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 <stdio.h> +#include <sys/types.h> +#include <signal.h> +#include <errno.h> + +#include "../command.h" +#include "../general.h" +extern int errno; + +int nw; + +sighandler +sigpipe (sig) + int sig; +{ + fprintf (stderr, "%d\n", nw); + exit (0); +} + +main (argc, argv) + int argc; + char **argv; +{ + char buf[128]; + register int i; + + for (i = 0; i < 128; i++) + buf[i] = ' '; + + signal (SIGPIPE, sigpipe); + + nw = 0; + for (;;) + { + int n; + n = write (1, buf, 128); + nw += n; + } +} diff --git a/builtins/psize.sh b/builtins/psize.sh new file mode 100755 index 0000000..961becd --- /dev/null +++ b/builtins/psize.sh @@ -0,0 +1,24 @@ +#! /bin/sh +# +# psize.sh -- determine this system's pipe size, and write a define to +# pipesize.h so ulimit.c can use it. + +echo "/*" +echo " * pipesize.h" +echo " *" +echo " * This file is automatically generated by psize.sh" +echo " * Do not edit!" +echo " */" +echo "" + +./psize.aux 2>/tmp/pipesize | sleep 3 + +if [ -s /tmp/pipesize ]; then + echo "#define PIPESIZE `cat /tmp/pipesize`" +else + echo "#define PIPESIZE 512" +fi + +rm -f /tmp/pipesize + +exit 0 diff --git a/builtins/read.def b/builtins/read.def new file mode 100644 index 0000000..7b6dfc9 --- /dev/null +++ b/builtins/read.def @@ -0,0 +1,276 @@ +This file is read.def, from which is created read.c. +It implements the builtin "read" 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 read.c + +$BUILTIN read +$FUNCTION read_builtin +$SHORT_DOC read [-r] [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 +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. +$END + +#include <stdio.h> +#include "../shell.h" +#include "common.h" + +#define issep(c) (strchr (ifs_chars, (c)) != (char *)0) + +static int stream_close (); + +extern int interrupt_immediately; + +/* 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. */ +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; + SHELL_VAR *var; + + i = 0; /* Index into the string that we are reading. */ + raw_mode = 0; /* Not reading raw input be default. */ + + while (list) + { + if (ISOPTION (list->word->word, 'r')) + { + raw_mode = 1; + list = list->next; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_error ("usage: read [-r] [name ...]"); + 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); + } + + var = find_variable ("IFS"); + ifs_chars = var ? value_cell (var) : " \t\n"; + + input_string = xmalloc (size = 128); + + setbuf (input_stream, (char *)NULL); + + begin_unwind_frame ("read_builtin"); + add_unwind_protect (xfree, input_string); + add_unwind_protect (stream_close, input_stream); + interrupt_immediately++; + + 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) + { + if (i + 2 >= size) + input_string = xrealloc (input_string, size += 128); + + /* If the next character is to be accepted verbatim, a backslash + newline pair still disappears from the input. */ + if (pass_next) + { + if (c == '\n') + i--; /* back up over the CTLESC */ + else + input_string[i++] = c; + pass_next = 0; + continue; + } + + if (c == '\\' && !raw_mode) + { + pass_next++; + saw_escape++; + input_string[i++] = CTLESC; + continue; + } + + if (c == '\n') + break; + + if (c == CTLESC || c == CTLNUL) + { + saw_escape++; + input_string[i++] = CTLESC; + } + + input_string[i++] = c; + } + input_string[i] = '\0'; + + interrupt_immediately--; + discard_unwind_frame ("read_builtin"); + + fclose (input_stream); + + if (c == EOF) + { + retval = EXECUTION_FAILURE; + /* input_string[0] = '\0'; */ + } + else + retval = EXECUTION_SUCCESS; + + if (!list) + { + if (saw_escape) + { + t = dequote_string (input_string); + var = bind_variable ("REPLY", t); + free (t); + } + else + var = bind_variable ("REPLY", input_string); + var->attributes &= ~att_invisible; + free (input_string); + } + else + { + /* 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) + { + 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); + } + + /* 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) + { + t1 = dequote_string (t); + var = bind_variable (varname, t1); + free (t1); + } + else + var = bind_variable (varname, t); + } + else + { + t = (char *)0; + var = bind_variable (varname, ""); + } + + stupidly_hack_special_variables (varname); + var->attributes &= ~att_invisible; + + if (t) + free (t); + } + + if (legal_identifier (list->word->word) == 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); + 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; +{ + return (fclose (file)); +} diff --git a/builtins/reserved.def b/builtins/reserved.def new file mode 100644 index 0000000..4074ae0 --- /dev/null +++ b/builtins/reserved.def @@ -0,0 +1,154 @@ +This file is reserved.def, in which the shell reserved words are defined. +It has no direct C file production, but defines builtins for the Bash +builtin help command. + +Copyright (C) 1987, 1989, 1991, 1992 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. + +$BUILTIN for +$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done +The `for' loop executes a sequence of commands for each member in a +list of items. If `in WORDS ...;' is not present, then `in "$@"' is +assumed. For each element in WORDS, NAME is set to that element, and +the COMMANDS are executed. +$END + +$BUILTIN select +$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done +The WORDS are expanded, generating a list of words. The +set of expanded words is printed on the standard error, each +preceded by a number. If `in WORDS' is not present, `in "$@"' +is assumed. 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 the displayed words, then NAME is set +to that word. If the line is empty, WORDS and the prompt are +redisplayed. If EOF is read, the command completes. Any other +value read causes NAME to be set to null. The line read is saved +in the variable REPLY. COMMANDS are executed after each selection +until a break or return command is executed. +$END + +$BUILTIN case +$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac +Selectively execute COMMANDS based upon WORD matching PATTERN. The +`|' is used to separate multiple patterns. +$END + +$BUILTIN if +$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi +The if COMMANDS are executed. If the exit status is zero, then the then +COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed +in turn, and if the exit status is zero, the corresponding then COMMANDS +are executed and the if command completes. Otherwise, the else COMMANDS +are executed, if present. The exit status is the exit status of the last +command executed, or zero if no condition tested true. +$END + +$BUILTIN while +$SHORT_DOC while COMMANDS; do COMMANDS; done +Expand and execute COMMANDS as long as the final command in the +`while' COMMANDS has an exit status of zero. +$END + +$BUILTIN until +$SHORT_DOC until COMMANDS; do COMMANDS; done +Expand and execute COMMANDS as long as the final command in the +`until' COMMANDS has an exit status which is not zero. +$END + +$BUILTIN function +$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; } +Create a simple command invoked by NAME which runs COMMANDS. +Arguments on the command line along with NAME are passed to the +function as $0 .. $n. +$END + +$BUILTIN { ... } +$DOCNAME grouping_braces +$SHORT_DOC { COMMANDS } +Run a set of commands in a group. This is one way to redirect an +entire set of commands. +$END + +$BUILTIN % +$DOCNAME fg_percent +$SHORT_DOC %[DIGITS | WORD] [&] +This is similar to the `fg' command. Resume a stopped or background +job. If you specifiy DIGITS, then that job is used. If you specify +WORD, then the job whose name begins with WORD is used. Following the +job specification with a `&' places the job in the background. +$END + +$BUILTIN variables +$DOCNAME variable_help +$SHORT_DOC variables - Some variable names and meanings +BASH_VERSION The version numbers of this Bash. +CDPATH A colon separated list of directories to search + when the argument to `cd' is not found in the current + directory. +#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. +HISTSIZE The maximum number of history lines that a running + shell can access. +#endif /* HISTORY */ +HOME The complete pathname to your login directory. +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. +MAILCHECK How often, in seconds, Bash checks for new mail. +MAILPATH A colon-separated list of filenames which Bash checks + for new mail. +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. +TERM The name of the current terminal type. +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. + A value of `exact' means that the command word must + exactly match a command in the list of stopped jobs. A + value of `substring' means that the command word must + 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 + substitution character, usually `!'. The second is + 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. +#endif /* HISTORY */ +$END diff --git a/builtins/return.def b/builtins/return.def new file mode 100644 index 0000000..8340a44 --- /dev/null +++ b/builtins/return.def @@ -0,0 +1,57 @@ +This file is return.def, from which is created return.c. +It implements the builtin "return" 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 return.c + +$BUILTIN return + +$FUNCTION return_builtin +$SHORT_DOC return [n] +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 "../shell.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 + exit status is used. */ +int +return_builtin (list) + WORD_LIST *list; +{ + return_catch_value = get_numeric_arg (list); + + if (!list) + return_catch_value = last_command_exit_value; + + if (return_catch_flag) + longjmp (return_catch, 1); + else + { + builtin_error ("Can only `return' from a function"); + return (EXECUTION_FAILURE); + } +} diff --git a/builtins/set.def b/builtins/set.def new file mode 100644 index 0000000..a97168c --- /dev/null +++ b/builtins/set.def @@ -0,0 +1,528 @@ +This file is set.def, from which is created set.c. +It implements the "set" and "unset" builtins 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 set.c + +#include <stdio.h> +#include "../shell.h" +#include "../flags.h" + +#include "bashgetopt.h" + +extern int interactive; +extern int noclobber, no_brace_expansion, posixly_correct; +#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 ...] + -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. + -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 + 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 +#if defined (READLINE) + emacs use an emacs-style line editing interface +#endif /* READLINE */ + errexit same as -e +#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 + monitor same as -m + noclobber disallow redirection to existing files + 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 + verbose same as -v +#if defined (READLINE) + vi use a vi-style line editing interface +#endif /* READLINE */ + xtrace same as -x + -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. + -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 (BANG_HISTORY) + -H Enable ! style history substitution. This flag is on + by default. +#endif /* BANG_HISTORY */ + -C If set, disallow existing regular files to be overwritten + by redirection of output. + -P If set, do not follow symbolic links when executing commands + such as cd which change the current directory. + +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 ARGs are positional +parameters and are assigned, in order, to $1, $2, .. $n. If no +ARGs are given, all shell variables are printed. +$END + +/* An a-list used to match long options for set -o to the corresponding + option letter. */ +struct { + char *name; + int letter; +} o_options[] = { + { "allexport", 'a' }, + { "errexit", 'e' }, +#if defined (BANG_HISTORY) + { "histexpand", 'H' }, +#endif /* BANG_HISTORY */ + { "monitor", 'm' }, + { "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}, +}; + +#define MINUS_O_FORMAT "%-15s\t%s\n" + +void +list_minus_o_opts () +{ + register int i; + char *on = "on", *off = "off"; + + printf (MINUS_O_FORMAT, "braceexpand", (no_brace_expansion == 0) ? on : off); + printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); + + if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) + printf (MINUS_O_FORMAT, "ignoreeof", on); + else + printf (MINUS_O_FORMAT, "ignoreeof", off); + + printf (MINUS_O_FORMAT, "interactive-comments", + interactive_comments ? on : off); + + printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); + +#if defined (READLINE) + if (no_line_editing) + { + printf (MINUS_O_FORMAT, "emacs", off); + printf (MINUS_O_FORMAT, "vi", off); + } + 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); + } +#endif /* READLINE */ + + for (i = 0; o_options[i].name; i++) + { + 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); + } +} + +set_minus_o_option (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + int option_char = -1; + + if (STREQ (option_name, "braceexpand")) + { + if (on_or_off == FLAG_ON) + no_brace_expansion = 0; + else + no_brace_expansion = 1; + } + else if (STREQ (option_name, "noclobber")) + { + if (on_or_off == FLAG_ON) + bind_variable ("noclobber", ""); + else + unbind_variable ("noclobber"); + stupidly_hack_special_variables ("noclobber"); + } + else if (STREQ (option_name, "ignoreeof")) + { + unbind_variable ("ignoreeof"); + unbind_variable ("IGNOREEOF"); + if (on_or_off == FLAG_ON) + bind_variable ("IGNOREEOF", "10"); + stupidly_hack_special_variables ("IGNOREEOF"); + } + +#if defined (READLINE) + else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) + { + if (on_or_off == FLAG_ON) + { + rl_variable_bind ("editing-mode", option_name); + + 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); + } + } +#endif /* READLINE */ + else if (STREQ (option_name, "interactive-comments")) + interactive_comments = (on_or_off == FLAG_ON); + else if (STREQ (option_name, "posix")) + { + 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"); + } + } + else + { + 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) + { + bad_option (option_name); + return (EXECUTION_FAILURE); + } + } + return (EXECUTION_SUCCESS); +} + +/* 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. */ +set_builtin (list) + WORD_LIST *list; +{ + int on_or_off, flag_name, force_assignment = 0; + + if (!list) + { + 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); + } + + 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)) + { + char c; + + if (arg[0] != '-' && arg[0] != '+') + break; + + /* `-' or `--' signifies end of flag arguments. */ + if (arg[0] == '-' && + (!arg[1] || (arg[1] == '-' && !arg[2]))) + break; + + while (c = *++arg) + { + if (find_flag (c) == FLAG_UNKNOWN && c != 'o') + { + char s[2]; + s[0] = c; s[1] = '\0'; + bad_option (s); + if (c == '?') + printf ("usage: %s\n", USAGE_STRING); + 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) + { + char *string = 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]))) + { + list = list->next; + + /* `set --' unsets the positional parameters. */ + if (string[1] == '-') + force_assignment = 1; + + /* Until told differently, the old shell behaviour of + `set - [arg ...]' being equivalent to `set +xv [arg ...]' + stands. Posix.2 says the behaviour is marked as obsolescent. */ + else + { + change_flag ('x', '+'); + change_flag ('v', '+'); + } + + break; + } + + if ((on_or_off = *string) && + (on_or_off == '-' || on_or_off == '+')) + { + int i = 1; + while (flag_name = string[i++]) + { + if (flag_name == '?') + { + printf ("usage: %s\n", USAGE_STRING); + return (EXECUTION_SUCCESS); + } + else if (flag_name == 'o') /* -+o option-name */ + { + char *option_name; + WORD_LIST *opt; + + opt = list->next; + + if (!opt) + { + list_minus_o_opts (); + continue; + } + + option_name = opt->word->word; + + if (!option_name || !*option_name || (*option_name == '-')) + { + list_minus_o_opts (); + continue; + } + list = list->next; /* Skip over option name. */ + + 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); + return (EXECUTION_FAILURE); + } + } + } + } + else + { + break; + } + list = list->next; + } + + /* Assigning $1 ... $n */ + if (list || force_assignment) + remember_args (list, 1); + return (EXECUTION_SUCCESS); +} + +$BUILTIN unset +$FUNCTION unset_builtin +$SHORT_DOC unset [-f] [-v] [name ...] +For each NAME, remove the corresponding variable or function. Given +the `-v', unset will only act on variables. Given the `-f' flag, +unset will only act on functions. With neither flag, unset first +tries to unset a variable, and if that fails, then tries to unset a +function. Some variables (such as PATH and IFS) cannot be unset; also +see readonly. +$END + +unset_builtin (list) + WORD_LIST *list; +{ + int unset_function = 0, unset_variable = 0, opt; + int any_failed = 0; + char *name; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "fv")) != -1) + { + switch (opt) + { + case 'f': + unset_function = 1; + break; + case 'v': + unset_variable = 1; + break; + default: + return (EXECUTION_FAILURE); + } + } + + list = loptend; + + if (unset_function && unset_variable) + { + builtin_error ("cannot simultaneously unset a function and a variable"); + return (EXECUTION_FAILURE); + } + + while (list) + { + name = list->word->word; + + if (!unset_function && + find_name_in_list (name, non_unsettable_vars) > -1) + { + builtin_error ("%s: cannot unset", name); + any_failed++; + } + else + { + SHELL_VAR *var; + int tem; + + 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"); + any_failed++; + list = list->next; + continue; + } + + /* 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); + } + list = list->next; + } + + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} diff --git a/builtins/setattr.def b/builtins/setattr.def new file mode 100644 index 0000000..2340e1a --- /dev/null +++ b/builtins/setattr.def @@ -0,0 +1,253 @@ +This file is setattr.def, from which is created setattr.c. +It implements the builtins "export" and "readonly", 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 setattr.c + +#include "../shell.h" +#include "common.h" +#include "bashgetopt.h" + +extern int array_needs_making; +extern char *this_command_name; + +$BUILTIN export +$FUNCTION export_builtin +$SHORT_DOC export [-n] [-f] [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' +is given, a list of all names that are exported in this shell is +printed. An argument of `-n' says to remove the export property +from subsequent NAMEs. An argument of `--' disables further option +processing. +$END + +/* For each variable name in LIST, make that variable appear in the + environment passed to simple commands. If there is no LIST, then + 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. */ +export_builtin (list) + register WORD_LIST *list; +{ + return (set_or_show_attributes (list, att_exported)); +} + +$BUILTIN readonly +$FUNCTION readonly_builtin +$SHORT_DOC readonly [-n] [-f] [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 +processing. +$END + +/* For each variable name in LIST, make that variable readonly. Given an + empty LIST, print out all existing readonly variables. */ +readonly_builtin (list) + register WORD_LIST *list; +{ + return (set_or_show_attributes (list, att_readonly)); +} + +/* 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) + register WORD_LIST *list; + int attribute; +{ + register SHELL_VAR *var; + int assign, undo = 0, functions_only = 0, any_failed = 0, opt; + + /* Read arguments from the front of the list. */ + reset_internal_getopt (); + while ((opt = internal_getopt (list, "nfp")) != -1) + { + switch (opt) + { + case 'n': + undo = 1; + break; + case 'f': + functions_only = 1; + break; + case 'p': + break; + default: + builtin_error ("usage: %s [-nfp] [varname]", this_command_name); + return (EX_USAGE); + } + } + list = loptend; + + if (list) + { + if (attribute & att_exported) + array_needs_making = 1; + + /* Cannot undo readonly status. */ + if (undo && (attribute & att_readonly)) + attribute &= ~att_readonly; + + while (list) + { + register char *name = list->word->word; + + if (functions_only) + { + var = find_function (name); + if (!var) + { + builtin_error ("%s: not a function", name); + any_failed++; + } + else + { + if (undo) + var->attributes &= ~attribute; + else + var->attributes |= attribute; + } + list = list->next; + if (attribute == att_exported) + array_needs_making++; + continue; + } + + assign = assignment (name); + + if (assign) + name[assign] = '\0'; + if (legal_identifier (name) == 0) + { + builtin_error ("%s: not a legal variable name", name); + any_failed++; + list = list->next; + continue; + } + + if (assign) + { + 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); + 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 */ + list = list->next; + } + } + else + { + SHELL_VAR **variable_list; + register int i; + + if ((attribute & att_function) || functions_only) + { + variable_list = all_shell_functions (); + if (attribute != att_function) + attribute &= ~att_function; /* so declare -xf works, for example */ + } + else + variable_list = all_shell_variables (); + + if (variable_list) + { + for (i = 0; var = variable_list[i]; i++) + { + if ((var->attributes & attribute) && !invisible_p (var)) + { + char flags[6]; + + flags[0] = '\0'; + + if (exported_p (var)) + strcat (flags, "x"); + + if (readonly_p (var)) + strcat (flags, "r"); + + if (function_p (var)) + strcat (flags, "f"); + + if (integer_p (var)) + strcat (flags, "i"); + + if (flags[0]) + { + printf ("declare -%s ", flags); + + 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 (); + + printf ("%s\n", named_function_string + (var->name, function_cell (var), 1)); + } + } + } + } + free (variable_list); + } + } + return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); +} diff --git a/builtins/shift.def b/builtins/shift.def new file mode 100644 index 0000000..4d8fed0 --- /dev/null +++ b/builtins/shift.def @@ -0,0 +1,95 @@ +This file is shift.def, from which is created shift.c. +It implements the builtin "shift" 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 shift.c + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" + +$BUILTIN shift +$FUNCTION shift_builtin +$SHORT_DOC shift [n] +The positional parameters from $N+1 ... are renamed to $1 ... If N is +not given, it is assumed to be 1. +$END + +/* 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 + shifting. Return > 0 if `times' > $#, otherwise 0. */ +int +shift_builtin (list) + WORD_LIST *list; +{ + int times, number; + WORD_LIST *args; + + times = get_numeric_arg (list); + + if (!times) + return (EXECUTION_SUCCESS); + + 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) + { + builtin_error ("shift count must be <= $#"); + return (EXECUTION_FAILURE); + } + + while (times-- > 0) + { + register int count; + + if (dollar_vars[1]) + free (dollar_vars[1]); + + for (count = 1; count < 9; count++) + dollar_vars[count] = dollar_vars[count + 1]; + + if (rest_of_args) + { + WORD_LIST *temp = rest_of_args; + + dollar_vars[9] = savestring (temp->word->word); + rest_of_args = rest_of_args->next; + temp->next = (WORD_LIST *)NULL; + dispose_words (temp); + } + else + dollar_vars[9] = (char *)NULL; + } + + return (EXECUTION_SUCCESS); +} diff --git a/builtins/source.def b/builtins/source.def new file mode 100644 index 0000000..895e98b --- /dev/null +++ b/builtins/source.def @@ -0,0 +1,186 @@ +This file is source.def, from which is created source.c. +It implements the builtins "." and "source" 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 source.c + +$BUILTIN source +$FUNCTION source_builtin +$SHORT_DOC source filename +Read and execute commands from FILENAME and return. The pathnames +in $PATH are used to find the directory containing FILENAME. +$END +$BUILTIN . +$DOCNAME dot +$FUNCTION source_builtin +$SHORT_DOC . filename +Read and execute commands from FILENAME and return. The pathnames +in $PATH are used to find the directory containing FILENAME. +$END +/* source.c - Implements the `.' and `source' builtins. */ + +#include <sys/types.h> +#include <sys/file.h> +#include <errno.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" +#include "../posixstat.h" +#include "../filecntl.h" +#include "../execute_cmd.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; + +/* How many `levels' of sourced files we have. */ +int sourcelevel = 0; + +/* 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 + execution. If the script does not change the dollar vars, we restore + what we saved. If the dollar vars are changed in the script, we leave + the new values alone and free the saved values. */ +static void +maybe_pop_dollar_vars () +{ + if (dollar_vars_changed ()) + { + dispose_saved_dollar_vars (); + set_dollar_vars_unchanged (); + } + else + pop_dollar_vars (); +} + +/* Read and execute commands from the file passed as argument. Guess what. + 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. */ +source_builtin (list) + WORD_LIST *list; +{ + int result, return_val; + + /* Assume the best. */ + result = EXECUTION_SUCCESS; + + if (list) + { + 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++; + + set_dollar_vars_unchanged (); + + return_catch_flag++; + return_val = setjmp (return_catch); + + if (return_val) + parse_and_execute_cleanup (); + else + result = parse_and_execute (string, filename, -1); + + run_unwind_frame ("File Sourcing"); + + /* 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 + { + builtin_error ("filename argument required"); + result = EXECUTION_FAILURE; + } + return (result); +} diff --git a/builtins/suspend.def b/builtins/suspend.def new file mode 100644 index 0000000..48edc20 --- /dev/null +++ b/builtins/suspend.def @@ -0,0 +1,86 @@ +This file is suspend.def, from which is created suspend.c. +It implements the builtin "suspend" 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 suspend.c + +$BUILTIN suspend +$DEPENDS_ON JOB_CONTROL +$FUNCTION suspend_builtin +$SHORT_DOC suspend [-f] +Suspend the execution of this shell until it receives a SIGCONT +signal. The `-f' if specified says not to complain about this +being a login shell if it is; just suspend anyway. +$END + +#include <sys/types.h> +#include <signal.h> +#include "../shell.h" +#include "../jobs.h" + +#if defined (JOB_CONTROL) +extern int job_control; + +static SigHandler *old_cont, *old_tstp; + +/* Continue handler. */ +sighandler +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 */ +} + +/* Suspending the shell. If -f is the arg, then do the suspend + no matter what. Otherwise, complain if a login shell. */ +int +suspend_builtin (list) + WORD_LIST *list; +{ + if (!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) + { + builtin_error ("Can't 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); + return (EXECUTION_SUCCESS); +} + +#endif /* JOB_CONTROL */ diff --git a/builtins/test.def b/builtins/test.def new file mode 100644 index 0000000..2b1457b --- /dev/null +++ b/builtins/test.def @@ -0,0 +1,144 @@ +This file is test.def, from which is created test.c. +It implements the builtin "test" 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 test.c + +$BUILTIN test +$FUNCTION test_builtin +$SHORT_DOC test [expr] +Exits with a status of 0 (trueness) or 1 (falseness) depending on +the evaluation of EXPR. Expressions may be unary or binary. Unary +expressions are often used to examine the status of a file. There +are string operators as well, and numeric comparison operators. + +File operators: + + -b FILE True if file is block special. + -c FILE True if file is character special. + -d FILE True if file 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 is set-group-id. + -h FILE True if file is a symbolic link. Use "-L". + -L FILE True if file is a symbolic link. + -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 is a socket. + -t FD True if FD is opened on a terminal. + -u FILE True if the file is set-user-id. + -w FILE True if the file is writable by you. + -x FILE True if the file is executable by you. + -O FILE True if the file is effectively owned by you. + -G FILE True if the file is effectively owned by your group. + + FILE1 -nt FILE2 True if file1 is newer than (according to + modification date) file2. + + FILE1 -ot FILE2 True if file1 is older than file2. + + FILE1 -ef FILE2 True if file1 is a hard link to file2. + +String operators: + + -z STRING True if string is empty. + + -n STRING + or STRING True if string is not empty. + + STRING1 = STRING2 + True if the strings are equal. + STRING1 != STRING2 + True if the strings are not equal. + +Other operators: + + ! EXPR True if expr is false. + EXPR1 -a EXPR2 True if both expr1 AND expr2 are true. + EXPR1 -o EXPR2 True if either expr1 OR expr2 is true. + + arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne, + -lt, -le, -gt, or -ge. + +Arithmetic binary operators return true if ARG1 is equal, not-equal, +less-than, less-than-or-equal, greater-than, or greater-than-or-equal +than ARG2. +$END + +$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. +$END + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "../shell.h" +extern char *this_command_name; + +/* TEST/[ builtin. */ +int +test_builtin (list) + WORD_LIST *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) + { + if (this_command_name[0] == '[' && !this_command_name[1]) + builtin_error ("missing `]'"); + + 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); + + result = test_command (argc, argv); + free_array (argv); + return (result); +} diff --git a/builtins/times.def b/builtins/times.def new file mode 100644 index 0000000..9c42768 --- /dev/null +++ b/builtins/times.def @@ -0,0 +1,89 @@ +This file is times.def, from which is created times.c. +It implements the builtin "times" 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 times.c + +$BUILTIN times +$FUNCTION times_builtin +$SHORT_DOC times +Print the accumulated user and system times for processes run from +the shell. +$END + +#include "../shell.h" +#include <sys/types.h> + +#if defined (hpux) || defined (USGr4) || defined (XD88) || defined (USGr3) +# undef HAVE_RESOURCE +#endif /* hpux || USGr4 || XD88 || USGr3 */ + +#if defined (_POSIX_VERSION) || !defined (HAVE_RESOURCE) +# include <sys/times.h> +#else /* !_POSIX_VERSION && HAVE_RESOURCE */ +# include <sys/time.h> +# include <sys/resource.h> +#endif /* !_POSIX_VERSION && HAVE_RESOURCE */ + +/* Print the totals for system and user time used. The + information comes from variables in jobs.c used to keep + track of this stuff. */ +times_builtin (list) + WORD_LIST *list; +{ +#if !defined (_POSIX_VERSION) && defined (HAVE_RESOURCE) && defined (RUSAGE_SELF) + struct rusage self, kids; + + getrusage (RUSAGE_SELF, &self); + getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */ + + print_timeval (&self.ru_utime); + putchar (' '); + print_timeval (&self.ru_stime); + putchar ('\n'); + print_timeval (&kids.ru_utime); + putchar (' '); + print_timeval (&kids.ru_stime); + putchar ('\n'); + +#else /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */ +# if !defined (BrainDeath) + struct tms t; + + times (&t); + + /* 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. */ + + print_time_in_hz (t.tms_utime); + putchar (' '); + print_time_in_hz (t.tms_stime); + putchar ('\n'); + print_time_in_hz (t.tms_cutime); + putchar (' '); + print_time_in_hz (t.tms_cstime); + putchar ('\n'); +# endif /* BrainDeath */ +#endif /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */ + + return (EXECUTION_SUCCESS); +} diff --git a/builtins/trap.def b/builtins/trap.def new file mode 100644 index 0000000..b81651d --- /dev/null +++ b/builtins/trap.def @@ -0,0 +1,204 @@ +This file is trap.def, from which is created trap.c. +It implements the builtin "trap" 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 trap.c + +$BUILTIN trap +$FUNCTION trap_builtin +$SHORT_DOC trap [arg] [signal_spec] +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 <signal.h>, 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 $$". +$END + +#include <sys/types.h> +#include <signal.h> +#include "../shell.h" +#include "../trap.h" +#include "common.h" + +/* The trap command: + + trap <arg> <signal ...> + trap <signal ...> + trap -l + trap [--] + + Set things up so that ARG is executed when SIGNAL(s) N is recieved. + If ARG is the empty string, then ignore the SIGNAL(s). If there is + no ARG, then set the trap for SIGNAL(s) to its original value. Just + plain "trap" means to print out the list of commands associated with + each signal number. Single arg of "-l" means list the signal names. */ + +/* Possible operations to perform on the list of signals.*/ +#define SET 0 /* Set this signal to first_arg. */ +#define REVERT 1 /* Revert to this signals original value. */ +#define IGNORE 2 /* Ignore this signal. */ + +extern int interactive; + +trap_builtin (list) + WORD_LIST *list; +{ + register int i; + int list_signal_names = 0; + + while (list) + { + if (ISOPTION (list->word->word, '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]"); + return (EX_USAGE); + } + else + break; + } + + if (list_signal_names) + { + 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); + } + + if (list) + { + char *first_arg = list->word->word; + int operation = SET, any_failed = 0; + + if (signal_object_p (first_arg)) + operation = REVERT; + else + { + list = list->next; + if (*first_arg == '\0') + operation = IGNORE; + else if (first_arg[0] == '-' && !first_arg[1]) + operation = REVERT; + } + + 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++; + } + else + { + switch (operation) + { + case SET: + set_signal (sig, first_arg); + break; + + case REVERT: + restore_default_signal (sig); + + /* Signals that the shell treats specially need special + handling. */ + switch (sig) + { + case SIGINT: + if (interactive) + set_signal_handler (SIGINT, sigint_sighandler); + else + set_signal_handler (SIGINT, termination_unwind_protect); + break; + + case SIGQUIT: + /* Always ignore SIGQUIT. */ + set_signal_handler (SIGQUIT, SIG_IGN); + break; + case SIGTERM: +#if defined (JOB_CONTROL) + case SIGTTIN: + case SIGTTOU: + case SIGTSTP: +#endif /* JOB_CONTROL */ + if (interactive) + set_signal_handler (sig, SIG_IGN); + break; + } + break; + + case IGNORE: + ignore_signal (sig); + break; + } + } + list = list->next; + } + return ((!any_failed) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + } + + for (i = 0; i < NSIG; i++) + { + char *t, *p; + + p = trap_list[i]; + + if (p == (char *)DEFAULT_SIG) + continue; + + t = (p == (char *)IGNORE_SIG) ? (char *)NULL : single_quote (p); + printf ("trap -- %s %s\n", t ? t : "''", signal_name (i)); + if (t) + free (t); + } + return (EXECUTION_SUCCESS); +} diff --git a/builtins/type.def b/builtins/type.def new file mode 100644 index 0000000..aecc303 --- /dev/null +++ b/builtins/type.def @@ -0,0 +1,325 @@ +This file is type.def, from which is created type.c. +It implements the builtin "type" in Bash. + +Copyright (C) 1987, 1989, 1991, 1992 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 type.c + +$BUILTIN type +$FUNCTION type_builtin +$SHORT_DOC 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, 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 -all 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. +$END + +#include <stdio.h> +#include <sys/types.h> +#include "../posixstat.h" +#include "../shell.h" +#include "../execute_cmd.h" + +#if defined (ALIAS) +#include "../alias.h" +#endif /* ALIAS */ + +#include "common.h" + +extern STRING_INT_ALIST word_token_alist[]; + +/* 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 + execve, or if it is a builtin command, or an alias. Possible flag + arguments: + -type Returns the "type" of the object, one of + `alias', `keyword', `function', `builtin', + or `file'. + + -path Returns the pathname of the file if -type is + a file. + + -all Returns all occurrences of words, whether they + be a filename in the path, alias, function, + or builtin. + Order of evaluation: + alias + keyword + function + builtin + file + */ +type_builtin (list) + WORD_LIST *list; +{ + int path_only, type_only, all, verbose; + int successful_finds; + + 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]); + + if (flag[0] == 't' && (!flag[1] || strcmp (flag + 1, "ype") == 0)) + { + type_only = 1; + path_only = 0; + } + else if (flag[0] == 'p' && (!flag[1] || strcmp (flag + 1, "ath") == 0)) + { + path_only = 1; + type_only = 0; + } + else if (flag[0] == 'a' && (!flag[1] || strcmp (flag + 1, "ll") == 0)) + { + all = 1; + } + else + { + bad_option (flag); + builtin_error ("usage: type [-all | -path | -type ] name [name ...]"); + return (EX_USAGE); + } + list = list->next; + } + + if (type_only) + verbose = 1; + else if (!path_only) + verbose = 2; + else if (path_only) + verbose = 3; + else + verbose = 0; + + while (list) + { + int found; + + found = describe_command (list->word->word, verbose, all); + + if (!found && !path_only && !type_only) + builtin_error ("%s: not found", list->word->word); + + successful_finds += found; + list = list->next; + } + + fflush (stdout); + + if (successful_finds != 0) + return (EXECUTION_SUCCESS); + else + return (EXECUTION_FAILURE); +} + +/* + * Describe COMMAND as required by the type builtin. + * + * If VERBOSE == 0, don't print anything + * If VERBOSE == 1, print short description as for `type -t' + * If VERBOSE == 2, print long description as for `type' and `command -V' + * If VERBOSE == 3, print path name only for disk files + * If VERBOSE == 4, print string used to invoke COMMAND, for `command -v' + * + * ALL says whether or not to look for all occurrences of COMMAND, or + * return after finding it once. + */ +describe_command (command, verbose, all) + char *command; + int verbose, all; +{ + int found = 0, i, found_file = 0; + char *full_path = (char *)NULL; + SHELL_VAR *func; + +#if defined (ALIAS) + /* Command is an alias? */ + ASSOC *alias = find_alias (command); + + if (alias) + { + if (verbose == 1) + printf ("alias\n"); + else if (verbose == 2) + printf ("%s is aliased to `%s'\n", command, alias->value); + else if (verbose == 4) + { + char *x = single_quote (alias->value); + printf ("alias %s=%s\n", command, x); + free (x); + } + + found = 1; + + if (!all) + return (1); + } +#endif /* ALIAS */ + + /* Command is a shell reserved word? */ + i = find_reserved_word (command); + if (i >= 0) + { + if (verbose == 1) + printf ("keyword\n"); + else if (verbose == 2) + printf ("%s is a shell keyword\n", command); + else if (verbose == 4) + printf ("%s\n", command); + + found = 1; + + if (!all) + return (1); + } + + /* Command is a function? */ + func = find_function (command); + + if (func) + { + if (verbose == 1) + printf ("function\n"); + else if (verbose == 2) + { +#define PRETTY_PRINT_FUNC 1 + char *result; + + printf ("%s is a function\n", command); + + /* We're blowing away THE_PRINTED_COMMAND here... */ + + result = named_function_string (command, + (COMMAND *) function_cell (func), + PRETTY_PRINT_FUNC); + printf ("%s\n", result); +#undef PRETTY_PRINT_FUNC + } + else if (verbose == 4) + printf ("%s\n", command); + + found = 1; + + if (!all) + return (1); + } + + /* Command is a builtin? */ + if (find_shell_builtin (command)) + { + if (verbose == 1) + printf ("builtin\n"); + else if (verbose == 2) + printf ("%s is a shell builtin\n", command); + else if (verbose == 4) + printf ("%s\n", command); + + found = 1; + + if (!all) + return (1); + } + + /* Command is a disk file? */ + /* If the command name given is already an absolute command, just + check to see if it is executable. */ + if (absolute_program (command)) + { + int f = file_status (command); + if (f & FS_EXECABLE) + { + if (verbose == 1) + printf ("file\n"); + else if (verbose == 2) + printf ("%s is %s\n", command, command); + else if (verbose == 3 || verbose == 4) + printf ("%s\n", command); + + /* There's no use looking in the hash table or in $PATH, + because they're not consulted when an absolute program + name is supplied. */ + return (1); + } + } + + /* If the user isn't doing "-all", then we might care about + whether the file is present in our hash table. */ + if (!all) + { + if ((full_path = find_hashed_filename (command)) != (char *)NULL) + { + if (verbose == 1) + printf ("file\n"); + else if (verbose == 2) + printf ("%s is hashed (%s)\n", command, full_path); + else if (verbose == 3 || verbose == 4) + printf ("%s\n", full_path); + + return (1); + } + } + + /* Now search through $PATH. */ + while (1) + { + if (!all) + full_path = find_user_command (command); + else + full_path = + user_command_matches (command, FS_EXEC_ONLY, found_file); + /* XXX - should that be FS_EXEC_PREFERRED? */ + + if (!full_path) + break; + + found_file++; + found = 1; + + if (verbose == 1) + printf ("file\n"); + else if (verbose == 2) + printf ("%s is %s\n", command, full_path); + else if (verbose == 3 || verbose == 4) + printf ("%s\n", full_path); + + free (full_path); + full_path = (char *)NULL; + + if (!all) + break; + } + + return (found); +} diff --git a/builtins/ulimit.def b/builtins/ulimit.def new file mode 100644 index 0000000..1947c36 --- /dev/null +++ b/builtins/ulimit.def @@ -0,0 +1,731 @@ +This file is ulimit.def, from which is created ulimit.c. +It implements the builtin "ulimit" 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 ulimit.c + +$BUILTIN ulimit +$FUNCTION ulimit_builtin +$DEPENDS_ON !MINIX +$SHORT_DOC ulimit [-SHacdfmstpnuv [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 use the `soft' resource limit + -H use the `hard' resource limit + -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 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 +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 <stdio.h> +#include <sys/types.h> +#include <sys/param.h> +#include <errno.h> +#include "../shell.h" +#include "pipesize.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_RESOURCE) +# include <sys/time.h> +# include <sys/resource.h> +#else +# include <sys/times.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +/* Check for the most basic symbols. If they aren't present, this + system's <sys/resource.h> isn't very useful to us. */ +#if !defined (RLIMIT_FSIZE) || defined (GETRLIMIT_MISSING) +# undef HAVE_RESOURCE +#endif + +#if !defined (RLIMTYPE) +# define RLIMTYPE long +# define string_to_rlimtype string_to_long +# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") +#endif + +static void print_long (); + +/* **************************************************************** */ +/* */ +/* Ulimit builtin and Hacks. */ +/* */ +/* **************************************************************** */ + +/* Block size for ulimit operations. */ +#define ULIMIT_BLOCK_SIZE ((long)1024) + +#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 + +#define u_ALL_LIMITS 0x7ff + +#if !defined (RLIM_INFINITY) +# 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 */ + +#define LIMIT_HARD 0x01 +#define LIMIT_SOFT 0x02 + +static RLIMTYPE shell_ulimit (); +static RLIMTYPE pipesize (); +static RLIMTYPE open_files (); + +#if defined (HAVE_RESOURCE) +static RLIMTYPE getmaxvm (); +#endif /* HAVE_RESOURCE */ + +static void print_specific_limits (); +static void print_all_limits (); + +static char t[2]; + +/* 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; +{ +# if defined (HAVE_SETDTABLESIZE) + if (cmd == u_NUM_OPEN_FILES) + return (1); +# endif /* HAVE_SETDTABLSIZE */ + + return ((current > new) || (current_user.uid == 0)); +} +#endif /* !HAVE_RESOURCE */ + +/* Report or set limits associated with certain per-process resources. + See the help documentation in builtins.c for a full description. + + Rewritten by Chet Ramey 6/30/91. */ +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; + + c = mode = verbose_print = opt_eof = 0; + limit = (RLIMTYPE)-1; + + do + { + cmd = setting = all_limits = specific_limits = 0; + block_factor = ULIMIT_BLOCK_SIZE; + + /* read_options: */ + if (list && !opt_eof && *list->word->word == '-') + { + 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); + } + } + } + + 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) + { + print_specific_limits (cmd, mode); + continue; + } + + current_limit = shell_ulimit (cmd, real_limit, 0, mode); + + 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 + { + 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"); + } + } + while (list); + + return (EXECUTION_SUCCESS); +} + +/* The ulimit that we call from within Bash. + + 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. + + Systems without BSD resource limits can specify only u_FILE_SIZE. + This includes most USG systems. + + Chet Ramey supplied the BSD resource limit code. */ +static RLIMTYPE +shell_ulimit (which, newlim, setting, mode) + int which, setting, mode; + RLIMTYPE newlim; +{ +#if defined (HAVE_RESOURCE) + struct rlimit limit; + int cmd; + + if (mode == 0) + mode |= LIMIT_SOFT; +#endif + + switch (which) + { +#if !defined (HAVE_RESOURCE) + + case u_FILE_SIZE: + if (!setting) + { + /* 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 */ + } + 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; +#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 */ + + /* 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 ()); + + 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)); + + case u_MAX_VIRTUAL_MEM: + if (setting) + { + errno = EINVAL; + return ((RLIMTYPE)-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: + errno = EINVAL; + return ((RLIMTYPE)-1); + } +} + +#if defined (HAVE_RESOURCE) +static RLIMTYPE +getmaxvm (mode) + int mode; +{ + 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); + else + maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max; + + if (getrlimit (RLIMIT_STACK, &rl) < 0) + return ((RLIMTYPE)-1); + else + maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max; + + /* Protect against overflow. */ + return ((maxdata / 1024L) + (maxstack / 1024L)); +#endif /* !RLIMIT_VMEM */ +} +#endif /* HAVE_RESOURCE */ + +static RLIMTYPE +open_files (mode) + int mode; +{ +#if !defined (RLIMIT_NOFILE) + return ((RLIMTYPE)getdtablesize ()); +#else + struct rlimit rl; + + getrlimit (RLIMIT_NOFILE, &rl); + if (mode & LIMIT_SOFT) + return (rl.rlim_cur); + else + return (rl.rlim_max); +#endif +} + +static RLIMTYPE +pipesize () +{ +#if defined (PIPE_BUF) + /* This is defined on Posix systems. */ + return ((RLIMTYPE) PIPE_BUF); +#else +# if defined (PIPESIZE) + /* This is defined by running a program from the Makefile. */ + return ((RLIMTYPE) PIPESIZE); +# else + errno = EINVAL; + return ((RLIMTYPE)-1); +# 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; +{ + 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); +} + +static void +print_specific_bsd_limits (cmd, mode) + int cmd, mode; +{ + register int i; + + 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); + } + +#if defined (HAVE_RESOURCE) + if (cmd & u_MAX_VIRTUAL_MEM) + { + printf ("%-25s", "virtual memory (kbytes)"); + print_rlimtype (getmaxvm (mode), 1); + } +#endif /* HAVE_RESOURCE */ +} + +static void +print_all_limits (mode) + int mode; +{ + if (mode == 0) + mode |= LIMIT_SOFT; + + print_specific_limits (u_ALL_LIMITS, mode); +} diff --git a/builtins/umask.def b/builtins/umask.def new file mode 100644 index 0000000..1d84aa9 --- /dev/null +++ b/builtins/umask.def @@ -0,0 +1,288 @@ +This file is umask.def, from which is created umask.c. +It implements the builtin "umask" 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 umask.c + +$BUILTIN umask +$FUNCTION umask_builtin +$SHORT_DOC umask [-S] [mode] +The user file-creation mask is set to MODE. If MODE is omitted, or if +`-S' is supplied, the current value of the mask is printed. The `-S' +option makes the output symbolic; otherwise an octal number is output. +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 <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include "../shell.h" +#include "../posixstat.h" +#include "common.h" + +/* **************************************************************** */ +/* */ +/* UMASK Builtin and Helpers */ +/* */ +/* **************************************************************** */ + +static void print_symbolic_umask (); +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. */ +umask_builtin (list) + WORD_LIST *list; +{ + int print_symbolically = 0; + + while (list) + { + if (ISOPTION (list->word->word, 'S')) + { + list = list->next; + 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]"); + return (EX_USAGE); + } + else + break; + } + + if (list) + { + int new_umask; + + if (digit (*list->word->word)) + { + new_umask = 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) + { + builtin_error ("`%s' is not an octal number from 000 to 777", + list->word->word); + return (EXECUTION_FAILURE); + } + } + else + { + new_umask = symbolic_umask (list); + if (new_umask == -1) + return (EXECUTION_FAILURE); + } + umask (new_umask); + if (print_symbolically) + print_symbolic_umask (new_umask); + } + else /* Display the UMASK for this user. */ + { + int old_umask; + + old_umask = umask (022); + umask (old_umask); + + if (print_symbolically) + print_symbolic_umask (old_umask); + else + printf ("%03o\n", old_umask); + } + fflush (stdout); + return (EXECUTION_SUCCESS); +} + +/* Print the umask in a symbolic form. In the output, a letter is + printed if the corresponding bit is clear in the umask. */ +static void +print_symbolic_umask (um) + int um; +{ + char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ + int i; + + i = 0; + if ((um & S_IRUSR) == 0) + ubits[i++] = 'r'; + if ((um & S_IWUSR) == 0) + ubits[i++] = 'w'; + if ((um & S_IXUSR) == 0) + ubits[i++] = 'x'; + ubits[i] = '\0'; + + i = 0; + if ((um & S_IRGRP) == 0) + gbits[i++] = 'r'; + if ((um & S_IWGRP) == 0) + gbits[i++] = 'w'; + if ((um & S_IXGRP) == 0) + gbits[i++] = 'x'; + gbits[i] = '\0'; + + i = 0; + if ((um & S_IROTH) == 0) + obits[i++] = 'r'; + if ((um & S_IWOTH) == 0) + obits[i++] = 'w'; + if ((um & S_IXOTH) == 0) + obits[i++] = 'x'; + obits[i] = '\0'; + + printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits); +} + +/* Set the umask from a symbolic mode string similar to that accepted + by chmod. If the -S argument is given, then print the umask in a + symbolic form. */ +static int +symbolic_umask (list) + WORD_LIST *list; +{ + int um, umc, c; + int who, op, perm, mask; + char *s; + + /* Get the initial umask. Don't change it yet. */ + um = umask (022); + umask (um); + + /* All work below is done with the complement of the umask -- its + more intuitive and easier to deal with. It is complemented + again before being returned. */ + umc = ~um; + + s = list->word->word; + + for (;;) + { + who = op = perm = mask = 0; + + /* Parse the `who' portion of the symbolic mode clause. */ + while (member (*s, "agou")) + { + switch (c = *s++) + { + case 'u': + who |= S_IRWXU; + continue; + case 'g': + who |= S_IRWXG; + continue; + case 'o': + who |= S_IRWXO; + continue; + case 'a': + who |= S_IRWXU | S_IRWXG | S_IRWXO; + continue; + default: + break; + } + } + + /* The operation is now sitting in *s. */ + op = *s++; + switch (op) + { + case '+': + case '-': + case '=': + break; + default: + builtin_error ("bad symbolic mode operator: %c", op); + return (-1); + } + + /* Parse out the `perm' section of the symbolic mode clause. */ + while (member (*s, "rwx")) + { + c = *s++; + + switch (c) + { + case 'r': + perm |= S_IRUGO; + break; + + case 'w': + perm |= S_IWUGO; + break; + + case 'x': + perm |= S_IXUGO; + break; + } + } + + /* Now perform the operation or return an error for a + bad permission string. */ + if (!*s || *s == ',') + { + if (who) + perm &= who; + + switch (op) + { + case '+': + umc |= perm; + break; + + case '-': + umc &= ~perm; + break; + + case '=': + umc &= ~who; + umc |= perm; + break; + + default: + builtin_error ("bad operation character: %c", op); + return (-1); + } + + if (!*s) + { + um = ~umc & 0777; + break; + } + else + s++; /* skip past ',' */ + } + else + { + builtin_error ("bad character in symbolic mode: %c", *s); + return (-1); + } + } + return (um); +} diff --git a/builtins/wait.def b/builtins/wait.def new file mode 100644 index 0000000..f613179 --- /dev/null +++ b/builtins/wait.def @@ -0,0 +1,132 @@ +This file is wait.def, from which is created wait.c. +It implements the builtin "wait" 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. + + +$BUILTIN wait +$FUNCTION wait_builtin +$DEPENDS_ON JOB_CONTROL +$PRODUCES wait.c +$SHORT_DOC wait [n] +Wait for the specified process and report its termination status. If +N is not given, all currently active child processes are waited for, +and the return code is zero. N may be a process ID or a job +specification; if a job spec is given, all processes in the job's +pipeline are waited for. +$END + +$BUILTIN wait +$FUNCTION wait_builtin +$DEPENDS_ON !JOB_CONTROL +$SHORT_DOC wait [n] +Wait for the specified process and report its termination status. If +N is not given, all currently active child processes are waited for, +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 <sys/types.h> +#include <signal.h> +#include "../shell.h" +#include "../jobs.h" + +extern int interrupt_immediately; + +/* Wait for the pid in LIST to stop or die. If no arguments are given, then + 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. */ +wait_builtin (list) + WORD_LIST *list; +{ + int status = EXECUTION_SUCCESS; + + begin_unwind_frame ("wait_builtin"); + unwind_protect_int (interrupt_immediately); + interrupt_immediately++; + + /* We support jobs or pids. + wait <pid-or-job> [pid-or-job ...] */ + + /* But wait without any arguments means to wait for all of the shell's + currently active background processes. */ + if (!list) + { + wait_for_background_pids (); + status = EXECUTION_SUCCESS; + goto return_status; + } + + while (list) + { + pid_t pid; + char *w; + + w = list->word->word; + if (digit (*w)) + { + if (all_digits (w + 1)) + { + pid = (pid_t)atoi (w); + status = wait_for_single_pid (pid); + } + else + { + builtin_error ("`%s' is not a pid or legal job spec", w); + status = EXECUTION_FAILURE; + goto return_status; + } + } +#if defined (JOB_CONTROL) + else if (job_control && *w) + /* Must be a job spec. Check it out. */ + { + int job; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + job = get_job_spec (list); + + if (job < 0 || job >= job_slots || !jobs[job]) + { + if (job != DUP_JOB) + builtin_error ("No such job %s", list->word->word); + UNBLOCK_CHILD (oset); + status = 127; /* As per Posix.2, section 4.70.2 */ + list = list->next; + continue; + } + + /* Job spec used. Wait for the last pid in the pipeline. */ + UNBLOCK_CHILD (oset); + status = wait_for_job (job); + } +#endif /* JOB_CONTROL */ + else + { + builtin_error ("`%s' is not a pid or legal job spec", w); + status = EXECUTION_FAILURE; + } + list = list->next; + } + return_status: + run_unwind_frame ("wait_builtin"); + return (status); +} diff --git a/command.h b/command.h new file mode 100644 index 0000000..cffc15f --- /dev/null +++ b/command.h @@ -0,0 +1,215 @@ +/* command.h -- The structures used internally to represent commands, and + the extern declarations of the functions used to create them. */ + +/* 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 (_COMMAND_H) +#define _COMMAND_H + +#include "stdc.h" + +/* Instructions describing what kind of thing to do for a redirection. */ +enum r_instruction { + r_output_direction, r_input_direction, r_inputa_direction, + r_appending_to, r_reading_until, r_duplicating_input, + r_duplicating_output, r_deblank_reading_until, r_close_this, + r_err_and_out, r_input_output, r_output_force, + r_duplicating_input_word, r_duplicating_output_word +}; + +/* 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 }; + +/* 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. */ +} WORD_DESC; + +/* A linked list of words. */ +typedef struct word_list { + struct word_list *next; + WORD_DESC *word; +} WORD_LIST; + + +/* **************************************************************** */ +/* */ +/* Shell Command Structs */ +/* */ +/* **************************************************************** */ + +/* What a redirection descriptor looks like. If FLAGS is IS_DESCRIPTOR, + then we use REDIRECTEE.DEST, else we use the file specified. */ + +typedef union { + long dest; /* Place to redirect REDIRECTOR to, or ... */ + WORD_DESC *filename; /* filename to redirect to. */ +} REDIRECTEE; + +typedef struct redirect { + struct redirect *next; /* Next element, or NULL. */ + int redirector; /* Descriptor to be redirected. */ + int flags; /* Flag value for `open'. */ + enum r_instruction instruction; /* What to do with the information. */ + REDIRECTEE redirectee; /* File descriptor or filename */ + char *here_doc_eof; /* The word that appeared in <<foo. */ +} REDIRECT; + +/* An element used in parsing. A single word or a single redirection. + This is an ephemeral construct. */ +typedef struct element { + WORD_DESC *word; + REDIRECT *redirect; +} ELEMENT; + +/* Possible values for command->flags. */ +#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */ +#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */ +#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */ +#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */ +#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 */ + +/* What a command looks like. */ +typedef struct command { + enum command_type type; /* FOR CASE WHILE IF CONNECTION or SIMPLE. */ + int flags; /* Flags controlling execution environment. */ + int line; /* line number the command starts on */ + REDIRECT *redirects; /* Special redirects for FOR CASE, etc. */ + union { + struct for_com *For; + struct case_com *Case; + struct while_com *While; + struct if_com *If; + struct connection *Connection; + struct simple_com *Simple; + struct function_def *Function_def; + struct group_com *Group; +#if defined (SELECT_COMMAND) + struct select_com *Select; +#endif + } value; +} COMMAND; + +/* Structure used to represent the CONNECTION type. */ +typedef struct connection { + int ignore; /* Unused; simplifies make_command (). */ + COMMAND *first; /* Pointer to the first command. */ + COMMAND *second; /* Pointer to the second command. */ + int connector; /* What separates this command from others. */ +} CONNECTION; + +/* Structures used to represent the CASE command. */ + +/* Pattern/action structure for CASE_COM. */ +typedef struct pattern_list { + struct pattern_list *next; /* Clause to try in case this one failed. */ + WORD_LIST *patterns; /* Linked list of patterns to test. */ + COMMAND *action; /* Thing to execute if a pattern matches. */ +} PATTERN_LIST; + +/* The CASE command. */ +typedef struct case_com { + int flags; /* See description of CMD flags. */ + WORD_DESC *word; /* The thing to test. */ + PATTERN_LIST *clauses; /* The clauses to test against, or NULL. */ +} CASE_COM; + +/* FOR command. */ +typedef struct for_com { + int flags; /* See description of CMD flags. */ + WORD_DESC *name; /* The variable name to get mapped over. */ + WORD_LIST *map_list; /* The things to map over. This is never NULL. */ + COMMAND *action; /* The action to execute. + During execution, NAME is bound to successive + members of MAP_LIST. */ +} FOR_COM; + +#if defined (SELECT_COMMAND) +/* KSH SELECT command. */ +typedef struct select_com { + int flags; /* See description of CMD flags. */ + WORD_DESC *name; /* The variable name to get mapped over. */ + WORD_LIST *map_list; /* The things to map over. This is never NULL. */ + COMMAND *action; /* The action to execute. + During execution, NAME is bound to the member of + MAP_LIST chosen by the user. */ +} SELECT_COM; +#endif /* SELECT_COMMAND */ + +/* IF command. */ +typedef struct if_com { + int flags; /* See description of CMD flags. */ + COMMAND *test; /* Thing to test. */ + COMMAND *true_case; /* What to do if the test returned non-zero. */ + COMMAND *false_case; /* What to do if the test returned zero. */ +} IF_COM; + +/* WHILE command. */ +typedef struct while_com { + int flags; /* See description of CMD flags. */ + COMMAND *test; /* Thing to test. */ + COMMAND *action; /* Thing to do while test is non-zero. */ +} WHILE_COM; + +/* The "simple" command. Just a collection of words and redirects. */ +typedef struct simple_com { + int flags; /* See description of CMD flags. */ + WORD_LIST *words; /* The program name, the arguments, + variable assignments, etc. */ + REDIRECT *redirects; /* Redirections to perform. */ + 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. */ +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. */ +} FUNCTION_DEF; + +/* A command that is `grouped' allows pipes to take effect over + the entire command structure. */ +typedef struct group_com { + int ignore; /* See description of CMD flags. */ + COMMAND *command; +} GROUP_COM; + +extern COMMAND *global_command; + +/* Forward declarations of functions declared in copy_cmd.c. */ + +extern WORD_DESC *copy_word __P((WORD_DESC *)); +extern WORD_LIST *copy_word_list __P((WORD_LIST *)); +extern REDIRECT *copy_redirect __P((REDIRECT *)); +extern REDIRECT *copy_redirects __P((REDIRECT *)); +extern COMMAND *copy_command __P((COMMAND *)); + +#endif /* _COMMAND_H */ diff --git a/config.h b/config.h new file mode 100644 index 0000000..8fd2ba3 --- /dev/null +++ b/config.h @@ -0,0 +1,186 @@ +/* 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 <unistd.h> +# 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.mini b/config.h.mini new file mode 100644 index 0000000..3acc84e --- /dev/null +++ b/config.h.mini @@ -0,0 +1,194 @@ +/* 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 <unistd.h> +#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/configure b/configure new file mode 100755 index 0000000..53e10b6 --- /dev/null +++ b/configure @@ -0,0 +1,8 @@ +#!/bin/sh +# +# 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. +# +echo "Bash is configured to auto configure." +exit 0 diff --git a/copy_cmd.c b/copy_cmd.c new file mode 100644 index 0000000..991bbc9 --- /dev/null +++ b/copy_cmd.c @@ -0,0 +1,305 @@ +/* copy_command.c -- copy a COMMAND structure. This is needed + primarily for making function definitions, but I'm not sure + that anyone else will need it. */ + +/* 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. */ + +#include <stdio.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "shell.h" + +WORD_DESC * +copy_word (word) + WORD_DESC *word; +{ + WORD_DESC *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 + the new chain. */ +WORD_LIST * +copy_word_list (list) + WORD_LIST *list; +{ + WORD_LIST *new_list = NULL; + + while (list) + { + 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 *)); +} + +static PATTERN_LIST * +copy_case_clause (clause) + PATTERN_LIST *clause; +{ + PATTERN_LIST *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); +} + +static PATTERN_LIST * +copy_case_clauses (clauses) + PATTERN_LIST *clauses; +{ + PATTERN_LIST *new_list = (PATTERN_LIST *)NULL; + + while (clauses) + { + PATTERN_LIST *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 *)); +} + +/* Copy a single redirect. */ +REDIRECT * +copy_redirect (redirect) + REDIRECT *redirect; +{ + 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!!!! */ + case r_appending_to: + case r_output_direction: + case r_input_direction: + case r_inputa_direction: + case r_err_and_out: + case r_input_output: + case r_output_force: + case r_duplicating_input_word: + case r_duplicating_output_word: + new_redirect->redirectee.filename = + copy_word (redirect->redirectee.filename); + break; + } + return (new_redirect); +} + +REDIRECT * +copy_redirects (list) + REDIRECT *list; +{ + REDIRECT *new_list = NULL; + + while (list) + { + REDIRECT *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)); + new_for->flags = com->flags; + new_for->name = copy_word (com->name); + new_for->map_list = copy_word_list (com->map_list); + new_for->action = copy_command (com->action); + 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)); + + new_group->command = copy_command (com->command); + return (new_group); +} + +static CASE_COM * +copy_case_command (com) + CASE_COM *com; +{ + CASE_COM *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); + return (new_case); +} + +static WHILE_COM * +copy_while_command (com) + WHILE_COM *com; +{ + WHILE_COM *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); + return (new_while); +} + +static IF_COM * +copy_if_command (com) + IF_COM *com; +{ + IF_COM *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); + new_if->false_case = copy_command (com->false_case); + return (new_if); +} + +static SIMPLE_COM * +copy_simple_command (com) + SIMPLE_COM *com; +{ + SIMPLE_COM *new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); + + new_simple->flags = com->flags; + new_simple->words = copy_word_list (com->words); + new_simple->redirects = copy_redirects (com->redirects); + new_simple->line = com->line; + return (new_simple); +} + +static FUNCTION_DEF * +copy_function_def (com) + FUNCTION_DEF *com; +{ + FUNCTION_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); +} + +/* Copy the command structure in COMMAND. Return a pointer to the + copy. Don't you forget to dispose_command () on this pointer + later! */ +COMMAND * +copy_command (command) + COMMAND *command; +{ + COMMAND *new_command = (COMMAND *)NULL; + + 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->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; +#endif + + 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); + break; + } + } + return (new_command); +} diff --git a/cpp-Makefile b/cpp-Makefile new file mode 100644 index 0000000..9e1e2e8 --- /dev/null +++ b/cpp-Makefile @@ -0,0 +1,1553 @@ +/* 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 <sys/stream.h> +STREAM = -DHAVE_SYS_STREAM_H +#endif /* HAVE_SYS_STREAM_H */ + +#if defined (HAVE_SYS_PTEM_H) +/**/# This system has <sys/ptem.h> +PTEM = -DHAVE_SYS_PTEM_H +#endif /* HAVE_SYS_PTEM_H */ + +#if defined (HAVE_SYS_PTE_H) +/**/# This system has <sys/pte.h> +PTE = -DHAVE_SYS_PTE_H +#endif /* HAVE_SYS_PTE_H */ + +/**/# This system has <unistd.h>. +#if defined (HAVE_UNISTD_H) +UNISTD = -DHAVE_UNISTD_H +#endif + +/**/# This system has <stdlib.h> +#if defined (HAVE_STDLIB_H) +STDLIB = -DHAVE_STDLIB_H +#endif + +/**/# This system has <limits.h> +#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 <sys/resource.h> +RESOURCE = -DHAVE_RESOURCE +#endif + +#if defined (HAVE_SYS_PARAM) +/**/# This system has <sys/param.h> +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 <sys/wait.h> +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 new file mode 100644 index 0000000..f420fe1 --- /dev/null +++ b/dispose_cmd.c @@ -0,0 +1,207 @@ +/* dispose_command.c -- dispose of a COMMAND structure. */ + +/* 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. */ + +#include "shell.h" + +/* Dispose of the command structure passed. */ +void +dispose_command (command) + COMMAND *command; +{ + if (!command) return; + + if (command->redirects) + dispose_redirects (command->redirects); + + 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: + { + register SELECT_COM *c = command->value.Select; + 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); + free (command->value.Group); + break; + } + + case cm_case: + { + register CASE_COM *c = command->value.Case; + PATTERN_LIST *t, *p = c->clauses; + + dispose_word (c->word); + + while (p) + { + dispose_words (p->patterns); + dispose_command (p->action); + t = p; + p = p->next; + free (t); + } + free (c); + break; + } + + case cm_until: + case cm_while: + { + register WHILE_COM *c = command->value.While; + + dispose_command (c->test); + dispose_command (c->action); + free (c); + break; + } + + case cm_if: + { + register IF_COM *c = command->value.If; + dispose_command (c->test); + dispose_command (c->true_case); + dispose_command (c->false_case); + free (c); + break; + } + + case cm_simple: + { + register SIMPLE_COM *c = command->value.Simple; + dispose_words (c->words); + dispose_redirects (c->redirects); + free (c); + break; + } + + case cm_connection: + { + register CONNECTION *c = command->value.Connection; + dispose_command (c->first); + dispose_command (c->second); + free (c); + break; + } + + case cm_function_def: + { + register FUNCTION_DEF *c = command->value.Function_def; + dispose_word (c->name); + dispose_command (c->command); + free (c); + break; + } + + default: + report_error ("Attempt to free unknown command type `%d'.\n", command->type); + break; + } + free (command); +} + +/* How to free a WORD_DESC. */ +void +dispose_word (word) + WORD_DESC *word; +{ + if (word->word) + free (word->word); + free (word); +} + +/* How to get rid of a linked list of words. A WORD_LIST. */ +void +dispose_words (list) + WORD_LIST *list; +{ + WORD_LIST *t; + while (list) + { + t = list; + list = list->next; + dispose_word (t->word); + free (t); + } +} + +/* How to dispose of an array of pointers to char. */ +void +dispose_word_array (array) + char **array; +{ + register int count; + + for (count = 0; array[count]; count++) + free (array[count]); + + free (array); +} + +/* How to dispose of an list of redirections. A REDIRECT. */ +void +dispose_redirects (list) + REDIRECT *list; +{ + register REDIRECT *t; + + while (list) + { + t = list; + list = list->next; + switch (t->instruction) + { + case r_reading_until: + case r_deblank_reading_until: + free (t->here_doc_eof); + /* ... */ + case r_output_direction: + case r_input_direction: + case r_inputa_direction: + case r_appending_to: + case r_err_and_out: + case r_input_output: + case r_output_force: + case r_duplicating_input_word: + case r_duplicating_output_word: + dispose_word (t->redirectee.filename); + break; + } + free (t); + } +} diff --git a/dispose_cmd.h b/dispose_cmd.h new file mode 100644 index 0000000..11166dd --- /dev/null +++ b/dispose_cmd.h @@ -0,0 +1,32 @@ +/* dispose_cmd.h -- Functions appearing in dispose_cmd.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 (_DISPOSE_CMD_H_) +#define _DISPOSE_CMD_H_ + +#include "stdc.h" + +extern void dispose_command __P((COMMAND *)); +extern void dispose_word __P((WORD_DESC *)); +extern void dispose_words __P((WORD_LIST *)); +extern void dispose_word_array __P((char **)); +extern void dispose_redirects __P((REDIRECT *)); + +#endif /* !_DISPOSE_CMD_H_ */ diff --git a/documentation/FAQ b/documentation/FAQ new file mode 100644 index 0000000..c44bc47 --- /dev/null +++ b/documentation/FAQ @@ -0,0 +1,795 @@ +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 + $(<file) + one-dimensional arrays and appropriate expansions + variables: ERRNO, FPATH, COLUMNS, LINES, EDITOR, VISUAL + extended pattern matching with egrep-style pattern lists + co-processes (|&, >&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) +$(<file) $(cat file) +arrays no good subsitute yet +((...)) let "..." +time use external command; GNU time is particularly useful + use time bash -c '...' for complicated constructs +extended patterns no good substitute +coprocesses named pipe pairs (one for read, one for write) +typeset +f declare -f | + sed -n 's:^declare -[a-z]* \([^ ]*\).*$:\1:p' +cd, print, whence function subsitutes in examples/functions/kshenv +autoloaded functions examples/functions/autoload is the same as typeset -fu +read var?prompt [ -t 0 ] && echo -n prompt >&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 new file mode 100644 index 0000000..fb437eb --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,103 @@ +# 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/README b/documentation/README new file mode 100644 index 0000000..c20007d --- /dev/null +++ b/documentation/README @@ -0,0 +1,32 @@ +This directory contains the bash documentation. + +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 +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 rest of this file explains how to use the `builtins.1' man page. + +For each command in the list of builtins create a file in man/man1 called: + +${command}.1 + +eg. +for.1 +type.1 +alias.1 +etc. + +All these files are identical as follows: + +jaws@jaws(264)$ cat alias.1 +.so man1/builtins.1 +jaws@jaws(265)$ + +Make sure you adjust the .so line in builtins.1 to reflect where you +put it. diff --git a/documentation/article.ms b/documentation/article.ms new file mode 100644 index 0000000..027f876 --- /dev/null +++ b/documentation/article.ms @@ -0,0 +1,1114 @@ +.de SE \" start example +.sp .5 +.RS +.ft CR +.nf +.. +.de EE \" end example +.fi +.sp .5 +.RE +.ft R +.. +.TL +Bash \- The GNU shell* +.AU +Chet Ramey +Case Western Reserve University +chet@po.cwru.edu +.FS +*An earlier version of this article appeared in The Linux Journal. +.FE +.NH 1 +Introduction +.PP +.B Bash +is the shell, or command language interpreter, +that will appear in the GNU operating system. +The name is an acronym for +the \*QBourne-Again SHell\*U, a pun on Steve Bourne, the author +of the direct ancestor of the current +.UX +shell \fI/bin/sh\fP, +which appeared in the Seventh Edition Bell Labs Research version +of \s-1UNIX\s+1. +.PP +Bash is an \fBsh\fP\-compatible shell that incorporates useful +features from the Korn shell (\fBksh\fP) and the C shell (\fBcsh\fP), +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. +.PP +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 portable. It currently runs +on nearly every version of +.UX +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 \s-1UNIX\s+1-like systems such as QNX and Minix +are part of the distribution. +.PP +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. +.NH 1 +What's POSIX, anyway? +.PP +.I POSIX +is a name originally coined by Richard Stallman for a family of open +system standards based on \s-1UNIX\s+1. There are a number of aspects of \s-1UNIX\s+1 +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. +.PP +The POSIX Shell and Utilities standard has been developed by IEEE Working +Group 1003.2 (POSIX.2).\(dd +.FS +\(ddIEEE, \fIIEEE Standard for Information Technology -- Portable +Operating System Interface (POSIX) Part 2: Shell and Utilities\fP, +1992. +.FE +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. +There are four primary areas of work in the 1003.2 standard: +.IP \(bu +Aspects of the shell's syntax and command language. +A number of special builtins such as +.B cd +and +.B exec +are being specified as part of the shell, since their +functionality usually cannot be implemented by a separate executable; +.IP \(bu +A set of utilities to be called by shell scripts and applications. +Examples are programs like +.I sed, +.I tr, +and +.I awk. +Utilities commonly implemented as shell builtins +are described in this section, such as +.B test +and +.B kill . +An expansion of this section's scope, termed the User Portability +Extension, or UPE, has standardized interactive programs such as +.I vi +and +.I mailx; +.IP \(bu +A group of functional interfaces to services provided by the +shell, such as the traditional \f(CRsystem()\fP +C library function. There are functions to perform shell word +expansions, perform filename expansion (\fIglobbing\fP), obtain values +of POSIX.2 system configuration variables, retrieve values of +environment variables (\f(CRgetenv()\fP\^), and other services; +.IP \(bu +A suite of \*Qdevelopment\*U utilities such as +.I c89 +(the POSIX.2 version of \fIcc\fP), +and +.I yacc. +.PP +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 +.I 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 +.B eval +and +.B 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 +.B read +and +.B test . +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 \fIvi\fP-style line editing commands +have been standardized; \fIemacs\fP editing commands were left +out due to objections. +.PP +While POSIX.2 includes much of what the shell has traditionally +provided, some important things have been omitted as being +\*Qbeyond its scope.\*U There is, for instance, no mention of +a difference between a +.I login +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 +.I .profile . +.NH 1 +Basic Bash features +.PP +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 (\fIfor\fP, \fIif\fP, \fIwhile\fP, etc.). +All of the Bourne shell builtins, including those not specified in +the POSIX.2 standard, appear in Bash. Shell \fIfunctions\fP, +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 +.B PS1 , +.B IFS , +and +.B PATH . +Bash implements essentially 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. +.PP +The Korn Shell (\fBksh\fP) is a descendent of the Bourne shell written +at AT&T Bell Laboratories by David Korn\(dg. 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 +.B RANDOM +and +.B REPLY , +the +.B typeset +builtin, +the ability to remove substrings from variables based on patterns, +and shell arithmetic. +.FS +\(dgMorris Bolsky and David Korn, \fIThe KornShell Command and +Programming Language\fP, Prentice Hall, 1989. +.FE +.B RANDOM +expands to a random number each time it is referenced; assigning a +value to +.B RANDOM +seeds the random number generator. +.B REPLY +is the default variable used by the +.B read +builtin when no variable names are supplied as arguments. +The +.B typeset +builtin is used to define variables and give them attributes +such as \fBreadonly\fP. +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 available, +with the same precedence rules: +.SE +$ echo $((3 + 5 * 32)) +163 +.EE +.LP +For interactive use, Bash implements ksh-style aliases and builtins +such as +.B fc +(discussed below) and +.B jobs . +Bash aliases allow a string to be substituted for a command name. +They can be used to create a mnemonic for a \s-1UNIX\s+1 command +name (\f(CRalias del=rm\fP), to expand a single word to a complex command +(\f(CRalias news='xterm -g 80x45 -title trn -e trn -e -S1 -N &'\fP), or to +ensure that a command is invoked with a basic set of options +(\f(CRalias ls="/bin/ls -F"\fP). +.PP +The C shell (\fBcsh\fP)\(dg, originally written by Bill Joy while at +Berkeley, is widely used and quite popular for its interactive +facilities. Bash includes a csh-compatible history expansion +mechanism (\*Q! history\*U), brace expansion, access to a stack +of directories via the +.B pushd , +.B popd , +and +.B dirs +builtins, and tilde expansion, to generate users' home directories. +Tilde expansion has also been adopted by both the Korn Shell and +POSIX.2. +.FS +\(dgBill Joy, An Introduction to the C Shell, \fIUNIX User's Supplementary +Documents\fP, University of California at Berkeley, 1986. +.FE +.PP +There were certain areas in which POSIX.2 felt standardization +was necessary, but no existing implementation provided the proper +behavior. The working group invented and standardized functionality +in these areas, which Bash implements. The +.B command +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 \*Q!\*U was added +to negate the return value of a command or pipeline; it was nearly +impossible to express \*Qif not x\*U cleanly using the sh language. +There exist multiple incompatible implementations of the +.B test +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 arguments are given to +.B test , +and leaves the behavior undefined when more arguments are supplied. +Bash uses the POSIX.2 algorithm, which was conceived by David Korn. +.NH 2 +Features not in the Bourne Shell +.PP +There are a number of minor differences between Bash and the +version of sh present on most other versions of \s-1UNIX\s+1. 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 \*Q!\*U reserved word, the +.B command +builtin, the ability of the +.B read +builtin to correctly return a line ending with a backslash, symbolic +arguments to the +.B umask +builtin, variable substring removal, a way to get the length of a variable, +and the new algorithm for the +.B test +builtin from the POSIX.2 standard, none of which appear in sh. +.PP +Bash also implements the \*Q$(...)\*U command substitution syntax, +which supersedes the sh `...` construct. +The \*Q$(...)\*U construct expands to the output of the command +contained within the +parentheses, with trailing newlines removed. The sh syntax is +accepted for backwards compatibility, but the \*Q$(...)\*U form +is preferred because its quoting rules are much simpler and it +is easier to nest. +.PP +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 functions, 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. +.PP +Bash has closed +a long-standing shell security hole by not using the +.B $IFS +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 \*Q.\*U command using the +\fBreturn\fP 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. +.NH 1 +Bash-specific Features +.PP +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. +.NH 2 +Startup Files +.PP +Bash executes startup files differently than other shells. The Bash +behavior is a compromise between the csh principle of startup files +with fixed names executed for each shell and the sh +\*Qminimalist\*U behavior. An interactive instance of Bash started +as a login shell reads and executes +.I ~/.bash_profile +(the file .bash_profile in the user's home directory), if it exists. +An interactive non-login shell reads and executes +.I ~/.bashrc . +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 +.B $ENV , +if set, as the name of a startup file. The ksh practice of reading +.B $ENV +for every shell, with the accompanying difficulty 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 complex. Ease of use won out here. Interestingly, +the next release of ksh will change to reading +.B $ENV +only for interactive shells. +.NH 2 +New Builtin Commands +.PP +There are a few builtins which are new or have been extended in Bash. +The +.B enable +builtin allows builtin commands to be turned on and off arbitrarily. +To use the version of +.I echo +found in a user's search path rather than the Bash builtin, +\f(CRenable -n echo\fP suffices. The +.B help +builtin provides +quick synopses of the shell facilities without requiring +access to a manual page. +.B Builtin +is similar to +.B command +in that it bypasses shell functions and directly executes builtin +commands. Access to a csh-style stack of directories is provided +via the +.B pushd , +.B popd , +and +.B dirs +builtins. +.B Pushd +and +.B popd +insert and remove directories from the stack, respectively, and +.B dirs +lists the stack contents. On systems that allow fine-grained control +of resources, the +.B ulimit +builtin can be used to tune these settings. +.B Ulimit +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 +.B suspend +command will stop the shell process when job control is active; most +other shells do not allow themselves to be stopped like that. +.B Type, +the Bash answer to +.B which +and +.B whence, +shows what will happen when a word is typed as a command: +.SE +$ 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 +} +.EE +.LP +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 +.B command +utility. +.NH 2 +Editing and Completion +.PP +One area in which Bash shines is command line editing. Bash uses the +.I readline +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. +.PP +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 inputrc +file, which defaults to the file +.I ~/.inputrc , +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 bindings +that perform history expansion or shell word expansions on the current +input line. +.PP +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 converted to meta-prefixed key sequences (a +meta-prefixed key sequence consists of the character with the +eighth bit zeroed, preceded by the +.I meta-prefix +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 readline wants to +ring the terminal's bell. All of these variables can be set in +the inputrc file. +.PP +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 readline, +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 +.B $PATH +and double-quote the current or previous word: +.SE +# Macros that are convenient for shell interaction +$if Bash +# edit the path +"\eC-xp": "PATH=${PATH}\ee\eC-e\eC-a\eef\eC-f" +# prepare to type a quoted word -- insert open and close double +# quotes and move to just after the open quote +"\eC-x\e"": "\e"\e"\eC-b" +# Quote the current or previous word +"\eC-xq": "\eeb\e"\eef\e"" +$endif +.EE +.LP +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. +.PP +Bash implements the +.B bind +builtin for more dyamic control of readline than the startup file +permits. +.B Bind +is used in several ways. In +.I list +mode, it can display the current key bindings, list all the +readline editing directives 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 +.I batch +mode, it reads a series of key bindings directly from a file and +passes them to readline. In its most common usage, +.B bind +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 bind . +.PP +The readline library also provides an interface for \fIword completion\fP. +When the +.I completion +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 possible 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 character 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 completely 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 generally quite +good at determining what type of completion to attempt. +.NH 2 +History +.PP +Access to the list of commands previously entered (the \fIcommand history\fP) +is provided jointly by Bash and the readline library. Bash provides +variables (\fB$HISTFILE\fP, \fB$HISTSIZE\fP, and \fB$HISTCONTROL\fP) +and the +.B history +and +.B fc +builtins to manipulate the history list. +The value of +.B $HISTFILE +specifes the file where Bash writes the command history on exit and +reads it on startup. +.B $HISTSIZE +is used to limit the number of commands saved in the history. +.B $HISTCONTROL +provides a crude form of control over which commands are saved on +the history list: a value of +.I ignorespace +means to not save commands which begin with a space; a value of +.I ignoredups +means to not save commands identical to the last command saved. +\fB$HISTCONTROL\fP was named \fB$history_control\fP in earlier +versions of Bash; the old name is still accepted for backwards +compatibility. The +.B history +command can read or write files containing the history list +and display the current list contents. The +.B fc +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 history list for +a portion of the current input line or a string typed by the user. +Finally, the +.I history +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 +(\*Qbang history\*U, so called because the exclamation point +introduces a history substitution): +.SE +$ 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 +.EE +.LP +The command history is only +saved when the shell is interactive, so it is not available for use +by shell scripts. +.NH 2 +New Shell Variables +.PP +There are a number of convenience variables that Bash interprets +to make life easier. These include +.B FIGNORE , +which is a set of filename suffixes identifying files to exclude when +completing filenames; +.B HOSTTYPE , +which is automatically set to a string describing the type of +hardware on which Bash is currently executing; +.B command_oriented_history , +which directs Bash to save all lines of a multiple-line +command such as a \fIwhile\fP or \fIfor\fP loop in a single +history entry, allowing easy re-editing; and +.B IGNOREEOF , +whose value indicates the number of consecutive EOF characters that +an interactive shell will read before exiting \- an easy way to keep +yourself from being logged out accidentally. The +.B auto_resume +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. +.NH 2 +Brace Expansion +.PP +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 implements \fIbrace expansion\fP, 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 +.I preamble , +followed by a pair of braces enclosing a series of comma-separated +strings, and an optional +.I postamble . +The preamble is prepended to each string within the braces, and the +postamble is then appended to each resulting string: +.SE +$ echo a{d,c,b}e +ade ace abe +.EE +.LP +As this example demonstrates, the results of brace expansion are not +sorted, as they are by filename expansion. +.NH 2 +Process Substitution +.PP +On systems that can support it, Bash provides a facility known as +\fIprocess substitution\fP. Process substitution is similar to command +substitution in that its specification includes a command to execute, +but the shell does not collect 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 +.I /dev/fd +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: +.SE +$ cmp <(old_prog) <(new_prog) +.EE +.NH 2 +Prompt Customization +.PP +One of the more popular interactive features that Bash provides is +the ability to customize the prompt. Both +.B $PS1 +and +.B $PS2, +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., +.B $SHLVL , +which indicates how deeply the current shell is nested). +Bash specially interprets characters in the prompt string +preceded by a backslash. Some of these backslash escapes are +replaced with +the current time, the date, the current working directory, +the username, and the command number or history 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 \fIsu\fP. +Before printing each primary prompt, Bash expands the variable +.B $PROMPT_COMMAND +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: +.SE +$ PS1='\eu@\eh [\et] \eW($SHLVL:\e!)\e$ ' +chet@odin [21:03:44] documentation(2:636)$ cd .. +chet@odin [21:03:54] src(2:637)$ +.EE +.LP +The string being assigned is surrounded by single quotes so that if +it is exported, the value of +.B $SHLVL +will be updated by a child shell: +.SE +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)$ +.EE +.LP +The \fP\e$\fP escape is displayed +as \*Q\fB$\fP\*U when running as a normal user, but as \*Q\fB#\fP\*U when +running as root. +.NH 2 +File System Views +.PP +Since Berkeley introduced symbolic links in 4.2 BSD, one of their most +annoying properties has been the \*Qwarping\*U to a completely +different area of the file system when using +.B cd , +and the resultant non-intuitive behavior of \*Q\fBcd ..\fP\*U. +The \s-1UNIX\s+1 kernel treats symbolic links +.I physically . +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 component. In either case, the symbolic link +is visible. If the link value is an absolute pathname, +the user finds himself in a completely different part of the file +system. +.PP +Bash provides a +.I logical +view of the file system. In this default mode, command and filename +completion and builtin commands such as +.B cd +and +.B pushd +which change the current working directory transparently follow +symbolic links as if they were directories. +The +.B $PWD +variable, which holds the shell's idea of the current working directory, +depends on the path used to reach the directory rather than its +physical location in the local file system hierarchy. For example: +.SE +$ 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 +.EE +.LP +One problem with this, of +course, arises when programs that do not understand the shell's logical +notion of the file system interpret \*Q..\*U differently. This generally +happens when Bash completes filenames containing \*Q..\*U according to a +logical hierarchy which does not correspond to their physical location. +For users who find this troublesome, a corresponding +.I physical +view of the file system is available: +.SE +$ cd /usr/local/bin +$ pwd +/usr/local/bin +$ set -o physical +$ pwd +/net/share/sun4/local/bin +.EE +.NH 2 +Internationalization +.PP +One of the most significant improvements in version 1.13 of Bash was the +change to \*Qeight-bit cleanliness\*U. Previous versions used the +eighth bit of characters to mark whether or not they were +quoted when performing word expansions. 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 manipulate files with \*Qodd\*U 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 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 family of character sets, used by many European countries. +.NH 2 +POSIX Mode +.PP +Although Bash is intended to be POSIX.2 conformant, there are areas in +which the default behavior is not compatible with the standard. For +users who wish to operate in a strict POSIX.2 environment, Bash +implements a \fIPOSIX mode\fP. When this mode is active, Bash modifies +its default operation where it differs from POSIX.2 to match the +standard. POSIX mode is entered when Bash is started with the +.B -posix +option. This feature is also available as an option to the +\fBset\fP builtin, \fBset -o posix\fP. +For compatibility with other GNU software that attempts to be POSIX.2 +compliant, Bash also enters POSIX mode if the variable +.B $POSIXLY_CORRECT +is set when Bash is started or assigned a value during execution. +.B $POSIX_PEDANTIC +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 +.B $ENV +rather than the \*Qnormal\*U startup files, and does not allow +reserved words to be aliased. +.NH 1 +New Features and Future Plans +.PP +There are several features introduced in the current +version of Bash, version 1.14, and a number under consideration +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. +.NH 2 +New Features in Bash-1.14 +.PP +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. +.PP +Readline has a few new +variables, several new bindable commands, and some additional +emacs mode default key bindings. 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 directory names. +The history expansion facilities are now nearly +completely csh-compatible: missing modifiers have been added and +history substitution has been extended. +.PP +Several of the features described earlier, such as +.B "set -o posix" +and +.B $POSIX_PEDANTIC , +are new in version 1.14. +There is a new shell variable, +.B OSTYPE , +to which Bash assigns a value that identifies the +version of \s-1UNIX\s+1 it's +running on (great for putting architecture-specific binary directories +into the \fB$PATH\fP). +Two variables have been renamed: +.B $HISTCONTROL +replaces +.B $history_control , +and +.B $HOSTFILE +replaces +.B $hostname_completion_file . +In both cases, the old names are accepted for backwards +compatibility. The ksh +.I select +construct, which allows the generation of simple menus, +has been implemented. New capabilities have been added +to existing variables: +.B $auto_resume +can now take values of +.I exact +or +.I substring , +and +.B $HISTCONTROL +understands the value +.I ignoreboth , +which combines the two previously acceptable values. The +.B dirs +builtin has acquired options to print out specific members of the +directory stack. The +.B $nolinks +variable, which forces a physical view of the file system, +has been superseded by the +.B \-P +option to the +.B set +builtin (equivalent to \fBset -o physical\fP); the variable is retained +for backwards compatibility. The version string contained in +.B $BASH_VERSION +now includes an indication of the patch level as well as the +\*Qbuild version\*U. +Some little-used features have +been removed: the +.B bye +synonym for +.B exit +and the +.B $NO_PROMPT_VARS +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. +.PP +The documentation has been thoroughly overhauled: +there is a new manual page on the readline library and the \fIinfo\fP +file has been updated to reflect the current version. +As always, as many bugs as possible have been fixed, although some +surely remain. +.NH 2 +Other Features +.PP +There are a few features that I hope to include in later Bash releases. +Some are based on work already done in other shells. +.PP +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 \fIvarname\fP=( ... ) to assign a list of words directly to +an array and a mechanism to allow +the +.B read +builtin to read a list of values directly into an array, would be +desirable. Given those extensions, the ksh +.B "set \-A" +syntax may not be worth supporting (the +.B \-A +option assigns a list of values to an array, but is a rather +peculiar special case). +.PP +Some shells include a means of \fIprogrammable\fP word +completion, where the user specifies on a per-command basis how the +arguments of the command are to be treated when completion 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. +.PP +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 +.B HISTIGNORE , +which would contain a colon-separated list of commands. Lines beginning +with these commands, after the restrictions of +.B $HISTCONTROL +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 +.B $HISTIGNORE . +.PP +One thing that newer shells such as +.B wksh +(also known as +.B dtksh ) +provide is a command to dynamically load code +implementing additional builtin commands into a running shell. +This new builtin would take an object file or shared library +implementing the \*Qbody\*U of the +builtin (\fIxxx_builtin()\fP for those familiar with Bash internals) +and a structure containing 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 +.B help +command (possibly present in the shared object as well). It would +manage the details of extending the internal table of builtins. +.PP +A few other builtins would also be desirable: two are the POSIX.2 +.B getconf +command, which prints the values of system configuration variables +defined by POSIX.2, and a +.B disown +builtin, which causes a shell running +with job control active to \*Qforget about\*U one or more +background jobs in its internal jobs table. Using +.B getconf , +for example, a user could retrieve a value for +.B $PATH +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. +.PP +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. +.NH 1 +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, +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 +much. The grammar presented in Bourne's paper describing +the shell distributed with the Seventh Edition of \s-1UNIX\s+1\(dg +is so far off that it does not allow the command \f(CWwho|wc\fP. +In fact, as Tom Duff states: +.QP +Nobody really knows what the +Bourne shell's grammar is. Even examination of the source code is +little help.\(dd +.FS +\(dgS. R. Bourne, \*QUNIX Time-Sharing System: The UNIX Shell\*U, +\fIBell System Technical Journal\fP, 57(6), July-August, 1978, pp. 1971-1990. +.FE +.FS +\(ddTom Duff, \*QRc \- A Shell for Plan 9 and \s-1UNIX\s+1 systems\*U, +\fIProc. of the Summer 1990 EUUG Conference\fP, London, July, 1990, +pp. 21-33. +.FE +.LP +The POSIX.2 standard includes a \fIyacc\fP 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 \*Qlegal\*U sh constructs which Bash flags as +syntax errors. Complete sh compatibility is a tough nut. +.PP +The shell is bigger and slower than I would like, though the current +version is substantially faster than previously. The readline library +could stand a substantial rewrite. A hand-written parser to replace +the current \fIyacc\fP-generated one would probably result in a speedup, +and would solve one glaring problem: the shell could parse +commands in \*Q$(...)\*U constructs +as they are entered, rather than reporting errors when the construct +is expanded. +.PP +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 specially to +enable functionality available another way (\fB$notify\fP vs. +\fBset -o notify\fP and \fB$nolinks\fP vs. \fBset -o physical\fP, for +instance); the special treatment of the variable name should probably +be removed. A few more things could stand removal; the +.B $allow_null_glob_expansion +and +.B $glob_dot_filenames +variables are of particularly questionable value. +The \fB$[...]\fP arithmetic evaluation syntax is redundant now that +the POSIX-mandated \fB$((...))\fP construct has been implemented, +and could be deleted. +It would be nice if the text output by the +.B help +builtin were external to the shell rather than compiled into it. +The behavior enabled by +.B $command_oriented_history , +which causes the shell to attempt to save all lines of a multi-line +command in a single history entry, should be made the default and +the variable removed. +.NH 1 +Availability +.PP +As with all other +GNU software, Bash is available for anonymous FTP from +.I prep.ai.mit.edu:/pub/gnu +and from other GNU software mirror sites. The current version is in +.I bash-1.14.1.tar.gz +in that directory. Use +.I archie +to find the nearest archive site. The +latest version is always available for FTP from +.I bash.CWRU.Edu:/pub/dist. +Bash documentation is available for FTP from +.I bash.CWRU.Edu:/pub/bash. +.PP +The Free Software Foundation sells tapes and CD-ROMs +containing Bash; send electronic mail to +\f(CRgnu@prep.ai.mit.edu\fP or call \f(CR+1-617-876-3296\fP +for more information. +.PP +Bash is also distributed with several versions of \s-1UNIX\s+1-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. +.FS +*BSD/386 is a trademark of Berkeley Software Design, Inc. +.FE +.PP +The Linux distribution deserves special mention. There are two +configurations included in the standard Bash distribution: a +\*Qnormal\*U configuration, in which all of the standard features +are included, and a \*Qminimal\*U configuration, which omits job +control, aliases, history and command line editing, the directory +stack and +.B pushd/popd/dirs, +process substitution, prompt string special character decoding, and the +.I select +construct. This minimal version is designed to be a drop-in replacement +for the traditional \s-1UNIX\s+1 /bin/sh, and is included as the Linux +/bin/sh in several packagings. +.NH 1 +Conclusion +.PP +Bash is a worthy successor to sh. +It is sufficiently portable +to run on nearly every version of \s-1UNIX\s+1 from +4.3 BSD to SVR4.2, and several \s-1UNIX\s+1 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. diff --git a/documentation/article.ps b/documentation/article.ps new file mode 100644 index 0000000..3cf5f39 --- /dev/null +++ b/documentation/article.ps @@ -0,0 +1,1368 @@ +%!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 F1<ad50>72 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 F1<ad41>2.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 new file mode 100644 index 0000000..38cd71f --- /dev/null +++ b/documentation/article.txt @@ -0,0 +1,1111 @@ + + + + + + + + + + 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.1 b/documentation/bash.1 new file mode 100644 index 0000000..9a04b1a --- /dev/null +++ b/documentation/bash.1 @@ -0,0 +1,5371 @@ +.\" +.\" MAN PAGE COMMENTS to +.\" +.\" Chet Ramey +.\" Information Network Services +.\" Case Western Reserve University +.\" chet@ins.CWRU.Edu +.\" +.\" Last Change: Fri May 5 10:44:39 EDT 1995 +.\" +.\" bash_builtins, strip all but Built-Ins section +.if \n(zZ=1 .ig zZ +.TH BASH 1 "1995 May 5" GNU +.\" +.\" There's some problem with having a `@' +.\" in a tagged paragraph with the BSD man macros. +.\" It has to do with `@' appearing in the }1 macro. +.\" This is a problem on 4.3 BSD and Ultrix, but Sun +.\" appears to have fixed it. +.\" If you're seeing the characters +.\" `@u-3p' appearing before the lines reading +.\" `possible-hostname-completions +.\" and `complete-hostname' down in READLINE, +.\" then uncomment this redefinition. +.\" +.de }1 +.ds ]X \&\\*(]B\\ +.nr )E 0 +.if !"\\$1"" .nr )I \\$1n +.}f +.ll \\n(LLu +.in \\n()Ru+\\n(INu+\\n()Iu +.ti \\n(INu +.ie !\\n()Iu+\\n()Ru-\w\\*(]Xu-3p \{\\*(]X +.br\} +.el \\*(]X\h|\\n()Iu+\\n()Ru\c +.}f +.. +.\" +.\" File Name macro. This used to be `.PN', for Path Name, +.\" but Sun doesn't seem to like that very much. +.\" +.de FN +\fI\|\\$1\|\fP +.. +.SH NAME +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. +.SH DESCRIPTION +.B Bash +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 +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). +.SH OPTIONS +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 +.B \-c +flag is present, then commands are read from +.IR string . +If there are arguments after the +.IR string , +they are assigned to the positional parameters, starting with +.BR $0 . +.TP +.B \-i +If the +.B \-i +flag is present, the shell is +.IR interactive . +.TP +.B \-s +If the +.B \-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. +.TP +.B \- +A single +.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. +.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. +.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 +.FN /etc/profile +or any of the personal initialization files +.IR ~/.bash_profile , +.IR ~/.bash_login , +or +.IR ~/.profile . +By default, +.B bash +normally reads these files when it is invoked as a login shell (see +.SM +.B INVOCATION +below). +.TP +\fB\-rcfile\fP \fIfile\fP +Execute commands from +.I file +instead of the standard personal initialization file +.IR ~/.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 +below). +.TP +.B \-nolineediting +Do not use the GNU +.I readline +library to read command lines if interactive. +.TP +.B \-posix +Change the behavior of bash where the default operation differs +from the Posix 1003.2 standard to match the standard +.PD +.SH ARGUMENTS +If arguments remain after option processing, and neither the +.B \-c +nor the +.B \-s +option has been supplied, the first argument is assumed to +be the name of a file containing shell commands. If +.B bash +is invoked in this fashion, +.B $0 +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. +.SH DEFINITIONS +.PD 0 +.TP +.B blank +A space or tab. +.TP +.B word +A sequence of characters considered as a single unit by the shell. +Also known as a +.BR token . +.TP +.B name +A +.I word +consisting only of alphanumeric characters and underscores, and +beginning with an alphabetic character or an underscore. Also +referred to as an +.BR identifier . +.TP +.B metacharacter +A character that, when unquoted, separates words. One of the following: +.br +.RS +.PP +.if t \fB| & ; ( ) < > space tab\fP +.if n \fB| & ; ( ) < > space tab\fP +.RE +.PP +.TP +.B control operator +A \fItoken\fP that performs a control function. It is one of the following +symbols: +.RS +.PP +.if t \fB\(bv\|\(bv & && ; ;; ( ) | <newline>\fP +.if n \fB|| & && ; ;; ( ) | <newline>\fP +.RE +.PD +.SH "RESERVED WORDS" +\fIReserved words\fP 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 +.SM +.B SHELL GRAMMAR +below) or the third word of a +.B case +or +.B for +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 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 +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. +.PP +The return value of a \fIsimple command\fP is its exit status, or +128+\fIn\^\fP if the command is terminated by signal +.IR n . +.SS Pipelines +.PP +A \fIpipeline\fP is a sequence of one or more commands separated by +the character +.BR | . +The format for a pipeline is: +.RS +.PP +[ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ] +.RE +.PP +The standard output of +.I command +is connected to the standard input of +.IR command2 . +This connection is performed before any redirections specified by the +command (see +.SM +.B REDIRECTION +below). +.PP +If the reserved word +.B ! +precedes a pipeline, the exit status of that +pipeline is the logical NOT of the exit status of the last command. +Otherwise, the status of the pipeline is the exit status of the last +command. The shell waits for all commands in the pipeline to +terminate before returning a value. +.PP +Each command in a pipeline is executed as a separate process (i.e., in a +subshell). +.SS Lists +.PP +A \fIlist\fP is a sequence of one or more pipelines separated by one +of the operators +.BR ; , +.BR & , +.BR && , +or +.BR \(bv\|\(bv , +and terminated by one of +.BR ; , +.BR & , +or +.BR <newline> . +.PP +Of these list operators, +.B && +and +.B \(bv\|\(bv +have equal precedence, followed by +.B ; +and +.BR &, +which have equal precedence. +.PP +If a command is terminated by the control operator +.BR & , +the shell executes the command in the \fIbackground\fP +in a subshell. The shell does not wait for the command to +finish, and the return status is 0. Commands separated by a +.B ; +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. +.PP +The control operators +.B && +and +.B \(bv\|\(bv +denote AND lists and OR lists, respectively. +An AND list has the form +.RS +.PP +\fIcommand\fP \fB&&\fP \fIcommand2\fP +.RE +.PP +.I command2 +is executed if, and only if, +.I command +returns an exit status of zero. +.PP +An OR list has the form +.RS +.PP +\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 +AND and OR lists is the exit status of the last command +executed in the list. +.SS Compound Commands +.PP +A \fIcompound command\fP is one of the following: +.TP +(\fIlist\fP) +\fIlist\fP is executed in a subshell. Variable assignments and builtin +commands that affect the shell's environment do not remain in effect +after the command completes. The return status is the exit status of +\fIlist\fP. +.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. +.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 +in turn, and \fIlist\fP is executed each time. If the \fBin\fP +\fIword\fP is omitted, the \fBfor\fP command executes \fIlist\fP +once for each positional parameter that is set (see +.SM +.B PARAMETERS +below). +.TP +\fBselect\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 set of expanded words is printed on the standard +error, each preceded by a number. If the \fBin\fP +\fIword\fP is omitted, the positional parameters are printed (see +.SM +.B PARAMETERS +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 +the displayed words, then the value of +.I name +is set to that word. If the line is empty, the words and prompt +are displayed again. If EOF is read, the command completes. Any +other value read causes +.I name +to be set to null. The line read is saved in the variable +.BR REPLY . +The +.I list +is executed after each selection until a +.B break +or +.B return +command is executed. +The exit status of +.B select +is the exit status of the last command executed in +.IR list , +or zero if no commands were executed. +.TP +\fBcase\fP \fIword\fP \fBin\fP [ \fIpattern\fP [ \fB|\fP \fIpattern\fP ] \ +... ) \fIlist\fP ;; ] ... \fBesac\fP +A \fBcase\fP command first expands \fIword\fP, and tries to match +it against each \fIpattern\fP in turn, using the same matching rules +as for pathname expansion (see +.B Pathname Expansion +below). 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 +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 +The +.B if +.I list +is executed. If its exit status is zero, the +\fBthen\fP \fIlist\fP is executed. Otherwise, each \fBelif\fP +\fIlist\fP is executed in turn, and if its exit status is zero, +the corresponding \fBthen\fP \fIlist\fP is executed and the +command completes. Otherwise, the \fBelse\fP \fIlist\fP is +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 +.TP +\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 +an exit status of zero. The \fBuntil\fP command is identical +to the \fBwhile\fP command, except that the test is negated; +the +.B do +.I list +is executed as long as the last command in +.I list +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 +none was executed. +.TP +[ \fBfunction\fP ] \fIname\fP () { \fIlist\fP; } +This defines a function named \fIname\fP. The \fIbody\fP of the +function is the +.I list +of commands between { and }. This list +is executed whenever \fIname\fP is specified as the +name of a simple command. The exit status of a function is +the exit status of the last command executed in the body. (See +.SM +.B FUNCTIONS +below.) +.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 +.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. +.SH QUOTING +\fIQuoting\fP 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. +.PP +Each of the \fImetacharacters\fP listed above under +.SM +.B DEFINITIONS +has special meaning to the shell and must be quoted if they are to +represent themselves. There are three quoting mechanisms: the +.IR "escape character" , +single quotes, and double quotes. +.PP +A non-quoted backslash (\fB\e\fP) is the +.IR "escape character" . +It preserves the literal value of the next character that follows, +with the exception of <newline>. If a \fB\e\fP<newline> pair +appears, and the backslash is not quoted, the \fB\e\fP<newline> +is treated as a line continuation (that is, it is effectively ignored). +.PP +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. +.PP +Enclosing characters in double quotes preserves the literal value +of all characters within the quotes, with the exception of +.BR $ , +.BR ` , +and +.BR \e . +The characters +.B $ +and +.B ` +retain their special meaning within double quotes. The backslash +retains its special meaning only when followed by one of the following +characters: +.BR $ , +.BR ` , +\^\fB"\fP\^, +.BR \e , +or +.BR <newline> . +A double quote may be quoted within double quotes by preceding it with +a backslash. +.PP +The special parameters +.B * +and +.B @ +have special meaning when in double +quotes (see +.SM +.B PARAMETERS +below). +.SH PARAMETERS +A +.I parameter +is an entity that stores values, somewhat like a +variable in a conventional programming language. It can be a +.IR name , +a number, or one of the special characters listed below under +.BR "Special Parameters" . +For the shell's purposes, a +.I variable +is a parameter denoted by a +.IR name . +.PP +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 +.B unset +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.PP +A +.I variable +may be assigned to by a statement of the form +.RS +.PP +\fIname\fP=[\fIvalue\fP] +.RE +.PP +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 +.B \-i +attribute set (see +.B declare +below in +.SM +.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 +of \fB"$@"\fP as explained below under +.BR "Special Parameters" . +Pathname expansion is not performed. +.SS Positional Parameters +.PP +A +.I 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 +.B 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 (see +.SM +.B FUNCTIONS +below). +.PP +When a positional parameter consisting of more than a single +digit is expanded, it must be enclosed in braces (see +.SM +.B EXPANSION +below). +.SS Special Parameters +.PP +The shell treats several parameters specially. These parameters may +only be referenced; assignment to them is not allowed. +.PD 0 +.TP +.B * +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 +.SM +.B IFS +special variable. That is, ``\fB$*\fP'' is equivalent +to ``\fB$1\fP\fIc\fP\fB$2\fP\fIc\fP\fB...\fP'', where +.I c +is the first character of the value of the +.SM +.B IFS +variable. If +.SM +.B IFS +is null or unset, the parameters are separated by spaces. +.TP +.B @ +Expands to the positional parameters, starting from one. When the +expansion occurs within double quotes, each parameter expands as a +separate word. That is, `` +.BR $@ '' +is equivalent to +``\fB$1\fP'' ``\fB$2\fP'' ... +When there are no positional parameters, ``\fB$@\fP'' and +.B $@ +expand to nothing (i.e., they are removed). +.TP +.B # +Expands to the number of positional parameters in decimal. +.TP +.B ? +Expands to the status of the most recently executed foreground +pipeline. +.TP +.B \- +Expands to the current option flags as specified upon invocation, +by the +.B set +builtin command, or those set by the shell itself +(such as the +.B \-i +flag). +.TP +.B $ +Expands to the process ID of the shell. In a () subshell, it +expands to the process ID of the current shell, not the +subshell. +.TP +.B ! +Expands to the process ID of the most recently executed background +(asynchronous) command. +.TP +.B 0 +Expands to the name of the shell or shell script. This is set at +shell initialization. If +.B bash +is invoked with a file of commands, +.B $0 +is set to the name of that file. If +.B bash +is started with the +.B \-c +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 +.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 +the environment exported to that command. +.PD +.SS Shell Variables +.PP +The following variables are set by the shell: +.PP +.PD 0 +.TP +.B PPID +The process ID of the shell's parent. +.TP +.B PWD +The current working directory as set by the +.B cd +command. +.TP +.B OLDPWD +The previous working directory as set by the +.B cd +command. +.TP +.B REPLY +Set to the line of input read by the +.B read +builtin command when no arguments are supplied. +.TP +.B UID +Expands to the user ID of the current user, initialized at shell startup. +.TP +.B EUID +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 +.BR bash . +.TP +.B BASH_VERSION +Expands to the version number of this instance of +.BR bash . +.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 +generated. The sequence of random numbers may be initialized by assigning +a value to +.SM +.BR RANDOM . +If +.SM +.B RANDOM +is unset, it loses its special properties, even if it is +subsequently reset. +.TP +.B SECONDS +Each time this parameter is +referenced, the number of seconds since shell invocation is returned. If a +value is assigned to +.SM +.BR SECONDS , +the value returned upon subsequent +references is +the number of seconds since the assignment plus the value assigned. +If +.SM +.B SECONDS +is unset, it loses its special properties, even if it is +subsequently reset. +.TP +.B LINENO +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. +If +.SM +.B LINENO +is unset, it loses its special properties, even if it is +subsequently reset. +.TP +.B HISTCMD +The history number, or index in the history list, of the current +command. If +.SM +.B HISTCMD +is unset, it loses its special properties, even if it is +subsequently reset. +.TP +.B OPTARG +The value of the last option argument processed by the +.B getopts +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.TP +.B OPTIND +The index of the next argument to be processed by the +.B getopts +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.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. +.TP +.B OSTYPE +Automatically set to a string that +describes the operating system on which +.B bash +is executing. The default is system-dependent. +.PD +.PP +The following variables are used by the shell. In some cases, +.B bash +assigns a default value to a variable; these cases are noted +below. +.PP +.PD 0 +.TP +.B IFS +The +.I Internal Field Separator +that is used +for word splitting after expansion and to +split lines into words with the +.B read +builtin command. The default value is +``<space><tab><newline>''. +.TP +.B PATH +The search path for commands. It +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, +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:.''. +.TP +.B HOME +The home directory of the current user; the default argument for the +\fBcd\fP builtin command. +.TP +.B CDPATH +The search path for the +.B cd +command. This is a colon-separated +list of directories in which the shell looks for destination directories +specified by the +.B cd +command. A sample value is +``.:~:/usr''. +.TP +.B ENV +If this parameter is set when \fBbash\fP is executing a shell script, +its value is interpreted as a filename containing commands to +initialize the shell, as in +.IR .bashrc . +The value of +.SM +.B ENV +is subjected to parameter expansion, command substitution, and arithmetic +expansion before being interpreted as a pathname. +.SM +.B PATH +is not used to search for the resultant pathname. +.TP +.B MAIL +If this parameter is set to a filename and the +.SM +.B MAILPATH +variable is not set, +.B bash +informs the user of the arrival of mail in the specified file. +.TP +.B MAILCHECK +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. +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 +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!"' +.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''. +.TP +.B PS2 +The value of this parameter is expanded +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 +command (see +.SM +.B SHELL GRAMMAR +above). +.TP +.B PS4 +The value of this parameter is expanded +and the value is printed before each command +.B bash +displays during an execution trace. The first character of +.SM +.B PS4 +is replicated multiple times, as necessary, to indicate multiple +levels of indirection. The default is ``\fB+ \fP''. +.TP +.B HISTSIZE +The number of commands to remember in the command history (see +.SM +.B HISTORY +below). The default value is 500. +.TP +.B HISTFILE +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 +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. +.TP +.B OPTERR +If set to the value 1, +.B bash +displays error messages generated by the +.B getopts +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.SM +.B OPTERR +is initialized to 1 each time the shell is invoked or a shell +script is executed. +.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 +.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 +.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. +.TP +.B 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. +.B Bash +terminates after waiting for that number of seconds if input does +not arrive. +.TP +.B FCEDIT +The default editor for the +.B fc +builtin command. +.TP +.B FIGNORE +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 +.SM +.B FIGNORE +is excluded from the list of matched filenames. A sample +value is ``.o:~''. +.TP +.B INPUTRC +The filename for the 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 +.B space +character are not entered on the history list. If set to +a value of +.IR ignoredups , +lines matching the last history line are not entered. +A value of +.I ignoreboth +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. +.TP +.B histchars +The two or three characters which control history expansion +and tokenization (see +.SM +.B HISTORY EXPANSION +below). The first character is the +.IR "history expansion character" , +that is, the character which signals the start of a history +expansion, normally `\fB!\fP'. +The second character is the +.IR "quick substitution" +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 +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 +hostname. The file may be changed interactively; the next +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 +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 +.I name +of a stopped job, in this context, is the command line used to +start it. +If set to the value +.IR exact , +the string supplied must match the name of a stopped job exactly; +if set to +.IR substring , +the string supplied needs to match a substring of the name of a +stopped job. The +.I substring +value provides functionality analogous to the +.B %? +job id (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. +.PD +.SH EXPANSION +Expansion is performed on the command line after it has been split into +words. There are seven kinds of expansion performed: +.IR "brace expansion" , +.IR "tilde expansion" , +.IR "parameter and variable expansion" , +.IR "command substitution" , +.IR "arithmetic expansion" , +.IR "word splitting" , +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 +expansion. +.PP +On systems that can support it, there is an additional expansion +available: \fIprocess substitution\fP. +.PP +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 +.SM +.BR PARAMETERS ). +.SS Brace Expansion +.PP +.I "Brace expansion" +is a mechanism by which arbitrary strings +may be generated. This mechanism is similar to +\fIpathname expansion\fP, but the filenames generated +need not exist. Patterns to be brace expanded take +the form of an optional +.IR preamble , +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 +within the braces, and the postamble is then appended +to each resulting string, expanding left to right. +.PP +Brace expansions may be nested. The results of each expanded +string are not sorted; left to right order is preserved. +For example, a\fB{\fPd,c,b\fB}\fPe expands into `ade ace abe'. +.PP +Brace expansion is performed before any other expansions, +and any characters special to other expansions are preserved +in the result. It is strictly textual. +.B Bash +does not apply any syntactic interpretation to the context of the +expansion or the text between the braces. +.PP +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. +.PP +This construct is typically used as shorthand when the common +prefix of the strings to be generated is longer than in the +above example: +.RS +.PP +mkdir /usr/local/src/bash/{old,new,dist,bugs} +.RE +or +.RS +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. +.B sh +does not treat opening or closing braces specially when they +appear as part of a word, and preserves them in the output. +.B Bash +removes braces from words as a consequence of brace +expansion. For example, a word entered to +.B sh +as \fIfile{1,2}\fP +appears identically in the output. The same word is +output as +.I file1 file2 +after expansion by +.BR bash . +If strict compatibility with +.B sh +is desired, start +.B bash +with the +.B \-nobraceexpansion +flag (see +.SM +.B OPTIONS +above) +or disable brace expansion with the +.B +o braceexpand +option to the +.B set +command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.SS Tilde Expansion +.PP +If a word begins with a tilde character (`\fB~\fP'), all of the characters +preceding the first slash (or all characters, if there is no slash) +are treated as a possible \fIlogin name\fP. If this \fIlogin name\fP +is the null string, the tilde is replaced with the value of the +parameter +.SM +.BR HOME . +If +.SM +.B HOME +is unset, the home directory of +the user executing the shell is substituted instead. +.PP +If a `+' follows the tilde, the value of +.SM +.B PWD +replaces the tilde and `+'. If +a `\-' follows, the value of +.SM +.B OLDPWD +is substituted. +If the value following the tilde is a valid \fIlogin name\fP, +the tilde and \fIlogin name\fP are replaced with the home directory +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 +.B : +or +.BR = . +In these cases, tilde substitution is also performed. Consequently, one +may use pathnames with tildes in assignments to +.SM +.BR PATH , +.SM +.BR MAILPATH , +and +.SM +.BR CDPATH , +and the shell assigns the expanded value. +.SS Parameter Expansion +.PP +The `\fB$\fP' 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. +.PP +.PD 0 +.TP +${\fIparameter\fP} +The value of \fIparameter\fP is substituted. The braces are required +when +.I parameter +is a positional parameter with more than one digit, +or when +.I parameter +is followed by a character which is not to be +interpreted as part of its name. +.PD +.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. +.PP +.PD 0 +.TP +${\fIparameter\fP\fB:\-\fP\fIword\fP} +\fBUse Default Values\fP. If +.I parameter +is unset or null, the expansion of +.I word +is substituted. Otherwise, the value of +.I parameter +is substituted. +.TP +${\fIparameter\fP\fB:=\fP\fIword\fP} +\fBAssign Default Values\fP. +If +.I parameter +is unset or null, the expansion of +.I word +is assigned to +.IR parameter . +The value of +.I parameter +is then substituted. Positional parameters and special parameters may +not be assigned to in this way. +.TP +${\fIparameter\fP\fB:?\fP\fIword\fP} +\fBDisplay Error if Null or Unset\fP. +If +.I parameter +is null or unset, the expansion of \fIword\fP (or a message to that effect +if +.I word +is not present) is written to the standard error and the shell, if it +is not interactive, exits. Otherwise, the value of \fIparameter\fP is +substituted. +.TP +${\fIparameter\fP\fB:+\fP\fIword\fP} +\fBUse Alternate Value\fP. +If +.I parameter +is null or unset, nothing is substituted, otherwise the expansion of +.I word +is substituted. +.TP +${\fB#\fP\fIparameter\fP} +The length in characters of the value of \fIparameter\fP is substituted. +If \fIparameter\fP is +.B * +or +.BR @ , +the length substituted is the length of +.B * +expanded within double quotes. +.TP +.PD 0 +${\fIparameter\fP\fB#\fP\fIword\fP} +.TP +${\fIparameter\fP\fB##\fP\fIword\fP} +.PD +The +.I word +is expanded to produce a pattern just as in pathname +expansion. If the pattern matches the beginning 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). +.TP +.PD 0 +${\fIparameter\fP\fB%\fP\fIword\fP} +.TP +${\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 +.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). +.SS Command Substitution +.PP +\fICommand substitution\fP allows the output of a command to replace +the command name. There are two forms: +.PP +.RS +.PP +\fB$(\fP\fIcommand\fP\|\fB)\fP +.RE +or +.RS +\fB`\fP\fIcommand\fP\fB`\fP +.RE +.PP +. 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, +backslash retains its literal meaning except when followed by +.BR $ , +.BR ` , +or +.BR \e . +When using the $(\^\fIcommand\fP\|) form, all characters between the +parentheses make up the command; none are treated specially. +.PP +Command substitutions may be nested. To nest when using the old form, +escape the inner backquotes with backslashes. +.PP +If the substitution appears within double quotes, word splitting and +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: +.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. +.PP +The evaluation is performed according to the rules listed below under +.SM +.BR "ARITHMETIC EVALUATION" . +If +.I expression +is invalid, +.B bash +prints a message indicating failure and no substitution occurs. +.SS Process Substitution +.PP +\fIProcess substitution\fP is supported on systems that support named +pipes (\fIFIFOs\fP) or the \fB/dev/fd\fP method of naming open files. +It takes the form of +\fB<(\fP\fIlist\^\fP\fB)\fP +or +\fB>(\fP\fIlist\^\fP\fB)\fP. +The process \fIlist\fP is run with its input or output connected to a +\fIFIFO\fP or some file in \fB/dev/fd\fP. The name of this file is +passed as an argument to the current command as the result of the +expansion. If the \fB>(\fP\fIlist\^\fP\fB)\fP form is used, writing to +the file will provide input for \fIlist\fP. If the +\fB<(\fP\fIlist\^\fP\fB)\fP form is used, the file passed as an +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" . +.SS Word Splitting +.PP +The shell scans the results of +parameter expansion, +command substitution, +and +arithmetic expansion +that did not occur within double quotes for +.IR "word splitting" . +.PP +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 +.SM +.B IFS +is exactly +.BR <space><tab><newline> , +the default, then +any sequence of +.SM +.B IFS +characters serves to delimit words. If +.SM +.B IFS +has a value other than the default, then sequences of +the whitespace characters +.B space +and +.B tab +are ignored at the beginning and end of the +word, as long as the whitespace character is in the +value of +.SM +.BR IFS +(an +.SM +.B IFS +whitespace character). +Any character in +.SM +.B IFS +that is not +.SM +.B IFS +whitespace, along with any adjacent +.SM +.B IFS +whitespace characters, delimits a field. +A sequence of +.SM +.B IFS +whitespace characters is also treated as a delimiter. +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 +.I parameters +that have no values, are removed. +.PP +Note that if no expansion occurs, no splitting +is performed. +.SS Pathname Expansion +.PP +After word splitting, +unless the +.B \-f +option has been set, +.B bash +scans each +.I word +for the characters +.BR * , +.BR ? , +and +.BR [ . +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, +the word is removed. +When a pattern is used for pathname generation, +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 +.B ``.'' +character is not treated specially. +.PP +The special pattern characters have the following meanings: +.PP +.PD 0 +.TP +.B * +Matches any string, including the null string. +.TP +.B ? +Matches any single character. +.TP +.B [...] +Matches any one of the enclosed characters. A pair of characters +separated by a minus sign denotes a +.IR range ; +any character lexically between those two characters, inclusive, +is matched. If the first character following the +.B [ +is a +.B ! +or a +.B ^ +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. +.PD +.SS Quote Removal +.PP +After the preceding expansions, all unquoted occurrences of the +characters +.BR \e , +.BR ` , +and \^\f3"\fP\^ are removed. +.SH REDIRECTION +Before a command is executed, its input and output +may be +.I 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 +.I simple command +or may follow a +.IR command . +Redirections are processed in the order they appear, from +left to right. +.PP +In the following descriptions, if the file descriptor number is +omitted, and the first character of the redirection operator is +.BR < , +the redirection refers to the standard input (file descriptor +0). If the first character of the redirection operator is +.BR > , +the redirection refers to the standard output (file descriptor +1). +.PP +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 pathname expansion. If it expands to more +than one word, +.B bash +reports an error. +.PP +Note that the order of redirections is significant. For example, +the command +.RS +.PP +ls \fB>\fP dirlist 2\fB>&\fP1 +.RE +.PP +directs both standard output and standard error to the file +.IR dirlist , +while the command +.RS +.PP +ls 2\fB>&\fP1 \fB>\fP dirlist +.RE +.PP +directs only the standard output to file +.IR dirlist , +because the standard error was duplicated as standard output +before the standard output was redirected to +.IR dirlist . +.SS Redirecting Input +.PP +Redirection of input causes the file whose name results from +the expansion of +.I word +to be opened for reading on file descriptor +.IR n , +or the standard input (file descriptor 0) if +.I n +is not specified. +.PP +The general format for redirecting input is: +.RS +.PP +[\fIn\fP]\fB<\fP\fIword\fP +.RE +.SS Redirecting Output +.PP +Redirection of output causes the file whose name results from +the expansion of +.I word +to be opened for writing on file descriptor +.IR n , +or the standard output (file descriptor 1) if +.I n +is not specified. If the file does not exist it is created; +if it does exist it is truncated to zero size. +.PP +The general format for redirecting output is: +.RS +.PP +[\fIn\fP]\fB>\fP\fIword\fP +.RE +.PP +If the redirection operator is +.BR >| , +then the value of the +.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.) +.SS Appending Redirected Output +.PP +Redirection of output in this fashion +causes the file whose name results from +the expansion of +.I word +to be opened for appending on file descriptor +.IR n , +or the standard output (file descriptor 1) if +.I n +is not specified. If the file does not exist it is created. +.PP +The general format for appending output is: +.RS +.PP +[\fIn\fP]\fB>>\fP\fIword\fP +.RE +.PP +.SS Redirecting Standard Output and Standard Error +.PP +.B 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 +.I word +with this construct. +.PP +There are two formats for redirecting standard output and +standard error: +.RS +.PP +\fB&>\fP\fIword\fP +.RE +and +.RS +\fB>&\fP\fIword\fP +.RE +.PP +Of the two forms, the first is preferred. +This is semantically equivalent to +.RS +.PP +\fB>\fP\fIword\fP 2\fB>&\fP1 +.RE +.SS Here Documents +.PP +This type of redirection instructs the shell to read input from the +current source until a line containing only +.I 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. +.PP +The format of here-documents is as follows: +.RS +.PP +.nf +\fB<<\fP[\fB\-\fP]\fIword\fP + \fIhere-document\fP +\fIdelimiter\fP +.fi +.RE +.PP +No parameter expansion, command substitution, pathname +expansion, or arithmetic expansion is performed on +.IR word . +If any characters in +.I word +are quoted, the +.I delimiter +is the result of quote removal on +.IR 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 +.B \e<newline> +is ignored, and +.B \e +must be used to quote the characters +.BR \e , +.BR $ , +and +.BR ` . +.PP +If the redirection operator is +.BR <<\- , +then all leading tab characters are stripped from input lines and the +line containing +.IR delimiter . +This allows +here-documents within shell scripts to be indented in a +natural fashion. +.SS "Duplicating File Descriptors" +.PP +The redirection operator +.RS +.PP +[\fIn\fP]\fB<&\fP\fIword\fP +.RE +.PP +is used to duplicate input file descriptors. +If +.I word +expands to one or more digits, the file descriptor denoted by +.I n +is made to be a copy of that file descriptor. If +.I word +evaluates to +.BR \- , +file descriptor +.I n +is closed. If +.I n +is not specified, the standard input (file descriptor 0) is used. +.PP +The operator +.RS +.PP +[\fIn\fP]\fB>&\fP\fIword\fP +.RE +.PP +is used similarly to duplicate output file descriptors. If +.I n +is not specified, the standard output (file descriptor 1) is used. +As a special case, if \fIn\fP is omitted, and \fIword\fP does not +expand to one or more digits, the standard output and standard +error are redirected as described previously. +.SS "Opening File Descriptors for Reading and Writing" +.PP +The redirection operator +.RS +.PP +[\fIn\fP]\fB<>\fP\fIword\fP +.RE +.PP +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 +.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 +that may be set and unset with the +.B alias +and +.B unalias +builtin commands (see +.SM +.B 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 +.I metacharacters +listed above, with the exception that the alias name may not +contain \fI=\fP. The first word of the replacement text is tested +for aliases, but a word that is identical to an alias being expanded +is not expanded a second time. This means that one may alias +.B ls +to +.BR "ls \-F" , +for instance, and +.B bash +does not try to recursively expand the replacement text. +If the last character of the alias value is a +.IR blank , +then the next command +word following the alias is also checked for alias expansion. +.PP +Aliases are created and listed with the +.B alias +command, and removed with the +.B unalias +command. +.PP +There is no mechanism for using arguments in the replacement text, +as in +.BR csh . +If arguments are needed, a shell function should be used. +.PP +Aliases are not expanded when the shell is not interactive. +.PP +The rules concerning the definition and use of aliases are +somewhat confusing. +.B 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 +.B alias +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 . +.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 +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 +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 +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 . +.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 . +.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 +actions are taken. +.PP +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 +.SM +.BR FUNCTIONS . +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. +.PP +If the name is neither a shell function nor a builtin, +and contains no slashes, +.B bash +searches each element of the +.SM +.B 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. +.PP +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 given, if any. +.PP +If this execution fails because the file is not in executable +format, and the file is not a directory, it is assumed to be +a \fIshell script\fP, a file +containing shell commands. A subshell is spawned to execute +it. This subshell reinitializes 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 +.B hash +below under +.SM +\fBSHELL BUILTIN COMMANDS\fP) +are retained by the child. +.PP +If the program is a file beginning with +.BR #! , +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 themselves. The arguments to the +interpreter consist of a single optional argument following the +interpreter name on the first line of the program, followed +by the name of the program, followed by the command +arguments, if any. +.SH ENVIRONMENT +When a program is invoked it is given an array of strings +called the +.IR environment . +This is a list of +\fIname\fP\-\fIvalue\fP pairs, of the form +.IR "name\fR=\fPvalue" . +.PP +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 +.I export +to child processes. Executed commands inherit the environment. +The +.B export +and +.B 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 +.B unset +command, plus any additions via the +.B export +and +.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 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. +.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 PROMPTING +When executing interactively, +.B bash +displays the primary prompt +.SM +.B PS1 +when it is ready to read a command, and the secondary prompt +.SM +.B PS2 +when it needs more input to complete a command. +.B Bash +allows these prompt strings to be customized by inserting a number of +backslash-escaped special characters that are decoded as follows: +.RS +.PD 0 +.TP +.B \et +the current time in HH:MM:SS format +.TP +.B \ed +the date in "Weekday Month Date" format (e.g., "Tue May 26") +.TP +.B \en +newline +.TP +.B \es +the name of the shell, the basename of +.B $0 +(the portion following the final slash) +.TP +.B \ew +the current working directory +.TP +.B \eW +the basename of the current working directory +.TP +.B \eu +the username of the current user +.TP +.B \eh +the hostname +.TP +.B \e# +the command number of this command +.TP +.B \e! +the history 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 +.TP +.B \e\e +a backslash +.TP +.B \e[ +begin a sequence of non-printing characters, which could be used to +embed a terminal control sequence into the prompt +.TP +.B \e] +end a sequence of non-printing characters +.PD +.RE +.PP +The command number and the history number are usually different: +the history number of a command is its position in the history +list, which may include commands restored from the history file +(see +.SM +.B 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. +.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. +A vi-style line editing interface is also available. +.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 +means Control\-N. Similarly, +.I meta +keys are denoted by M\-\fIkey\fR, so M\-x means Meta\-X. (On keyboards +without a +.I meta +key, M\-\fIx\fP means ESC \fIx\fP, i.e., press the Escape key +then the +.I x +key. This makes ESC the \fImeta prefix\fP. +The combination M\-C\-\fIx\fP means ESC\-Control\-\fIx\fP, +or press the Escape key +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 +.SM +.BR INPUTRC , +if set, is used instead of +.IR ~/.inputrc . +Other programs that use this library may add their own commands +and bindings. +.PP +For example, placing +.RS +.PP +M\-Control\-u: universal\-argument +.RE +or +.RS +C\-Meta\-u: universal\-argument +.RE +into the +.FN ~/.inputrc +would make M\-C\-u execute the readline command +.IR universal\-argument . +.PP +The following symbolic character names are recognized: +.IR RUBOUT , +.IR DEL , +.IR ESC , +.IR LFD , +.IR NEWLINE , +.IR RET , +.IR RETURN , +.IR SPC , +.IR SPACE , +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. +.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 +prefixes, or as a key sequence. +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 +.RS +Control-u: universal\-argument +.br +Meta-Rubout: backward-kill-word +.br +Control-o: ">&output" +.RE +.LP +In the above example, +.I C-u +is bound to the function +.BR universal\-argument , +.I M-DEL +is bound to the function +.BR backward\-kill\-word , +and +.I C-o +is bound to run the macro +expressed on the right hand side (that is, to insert the text +.I >&output +into the line). +.PP +In the second form, \fB"keyseq"\fP:\fIfunction-name\fP or \fImacro\fP, +.B keyseq +differs from +.B 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. +.sp +.RS +"\eC-u": universal\-argument +.br +"\eC-x\eC-r": re\-read\-init\-file +.br +"\ee[11~": "Function Key 1" +.RE +.PP +In this example, +.I C-u +is again bound to the function +.BR universal\-argument . +.I "C-x C-r" +is bound to the function +.BR re\-read\-init\-file , +and +.I "ESC [ 1 1 ~" +is bound to insert the text +.BR "Function Key 1" . +The full set of escape sequences is +.RS +.TP +.B \eC\- +control prefix +.TP +.B \eM- +meta prefix +.TP +.B \ee +an escape character +.TP +.B \e\e +backslash +.TP +.B \e" +literal " +.TP +.B \e' +literal ' +.RE +.PP +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 '. +.PP +.B Bash +allows the current readline key bindings to be displayed or modified +with the +.B bind +builtin command. The editing mode may be switched during interactive +use by using the +.B \-o +option to the +.B set +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.PP +Readline has variables that can be used to further customize its +behavior. A variable may be set in the +.I inputrc +file with a statement of the form +.RS +.PP +\fBset\fP \fIvariable\-name\fP \fIvalue\fP +.RE +.PP +Except where noted, readline variables can take the values +.B On +or +.BR Off . +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 +\fBvisible\fP, readline uses a visible bell if one is available. +If set to \fBaudible\fP, readline attempts to ring the terminal's bell. +.TP +.B comment\-begin (``#'') +The string that is inserted in \fBvi\fP mode when the +.B vi\-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. +.TP +.B completion\-query\-items (100) +This determines when the user is queried about viewing +the number of possible completions +generated by the \fBpossible\-completions\fP 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. +.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 +.IR emacs ; +the value of +.B editing\-mode +also affects the default keymap. +.TP +.B show\-all\-if\-ambiguous (Off) +This alters the default behavior of the completion functions. If +set to +.BR on , +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. +.PD +.PP +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. +.IP \fB$if\fP +The +.B $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. +.RS +.IP \fBmode\fP +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 +readline is starting out in emacs mode. +.IP \fBterm\fP +The \fBterm=\fP 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 +.B = +is tested against the full name of the terminal and the portion +of the terminal name before the first \fB\-\fP. This allows +.I sun +to match both +.I sun +and +.IR sun\-cmd , +for instance. +.IP \fBapplication\fP +The \fBapplication\fP construct is used to include +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 +a specific program. For instance, the following command adds a +key sequence that quotes the current or previous word in Bash: +.RS +.nf +\fB$if\fP Bash +# Quote the current or previous word +"\eC-xq": "\eeb\e"\eef\e"" +\fB$endif\fP +.fi +.RE +.RE +.IP \fB$endif\fP +This command, as you saw in the previous example, terminates an +\fB$if\fP command. +.IP \fB$else\fP +Commands in this branch of the \fB$if\fP directive are executed if +the test fails. +.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. +.PP +The following is a list of the names of the commands and the default +key sequences to which they are bound. +.SS Commands for Moving +.PP +.PD 0 +.TP +.B beginning\-of\-line (C\-a) +Move to the start of the current line. +.TP +.B end\-of\-line (C\-e) +Move to the end of the line. +.TP +.B forward\-char (C\-f) +Move forward a character. +.TP +.B backward\-char (C\-b) +Move back a character. +.TP +.B forward\-word (M\-f) +Move forward to the end of the next word. Words are composed of +alphanumeric characters (letters and digits). +.TP +.B backward\-word (M\-b) +Move back to the start of this, or the previous, word. Words are +composed of alphanumeric characters (letters and digits). +.TP +.B 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. +.TP +.B redraw\-current\-line +Refresh the current line. By default, this is unbound. +.PD +.SS Commands for Manipulating the History +.PP +.PD 0 +.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 +.SM +.B HISTCONTROL +variable. If the line is a modified history +line, then restore the history line to its original state. +.TP +.B previous\-history (C\-p) +Fetch the previous command from the history list, moving back in +the list. +.TP +.B next\-history (C\-n) +Fetch the next command from the history list, moving forward in the +list. +.TP +.B beginning\-of\-history (M\-<) +Move to the first line in the history. +.TP +.B end\-of\-history (M\->) +Move to the end of the input history, i.e., the line currently being +entered. +.TP +.B 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. +.TP +.B 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. +.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. +.TP +.B non\-incremental\-forward\-search\-history (M\-n) +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. +.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. +.TP +.B yank\-nth\-arg (M\-C\-y) +Insert the first argument to the previous command (usually +the second word on the previous line) at point (the current +cursor position). With an argument +.IR n , +insert the \fIn\fPth word from the previous command (the words +in the previous command begin with word 0). A negative argument +inserts the \fIn\fPth word from the end of the previous command. +.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. +.TP +.B 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. See +.SM +.B HISTORY EXPANSION +below for a description of history expansion. +.TP +.B history\-expand\-line (M\-^) +Perform history expansion on the current line. See +.SM +.B HISTORY EXPANSION +below for a description of history expansion. +.TP +.B insert\-last\-argument (M\-.\^, M\-_\^) +A synonym for \fByank\-last\-arg\fP. +.TP +.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. +.PD +.SS Commands for Changing Text +.PP +.PD 0 +.TP +.B 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 +.BR C\-d , +then return +.SM +.BR EOF . +.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. +.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) +Insert a tab character. +.TP +.B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...) +Insert the character typed. +.TP +.B transpose\-chars (C\-t) +Drag the character before point forward over the character at point. +Point moves forward as well. If point is at the end of the line, then +transpose the two characters before point. Negative arguments don't work. +.TP +.B 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. +.TP +.B upcase\-word (M\-u) +Uppercase the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.TP +.B downcase\-word (M\-l) +Lowercase the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.TP +.B capitalize\-word (M\-c) +Capitalize the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.PD +.SS Killing and Yanking +.PP +.PD 0 +.TP +.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) +Kill backward to the beginning of the line. +.TP +.B unix\-line\-discard (C\-u) +Kill backward from point to the beginning of the line. +.\" There is no real difference between this and backward-kill-line +.TP +.B kill\-whole\-line +Kill all characters on the current line, no matter where the +cursor is. By default, this is unbound. +.TP +.B 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 \fBforward\-word\fP. +.TP +.B backward\-kill\-word (M\-Rubout) +Kill the word behind the cursor. Word boundaries are the same as +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. +.TP +.B delete\-horizontal\-space +Delete all spaces and tabs around point. By default, this is unbound. +.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 +.B yank +or +.BR yank\-pop . +.PD +.SS Numeric Arguments +.PP +.PD 0 +.TP +.B 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. +.TP +.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. +.PD +.SS Completing +.PP +.PD 0 +.TP +.B complete (TAB) +Attempt to perform completion on the text before point. +.B Bash +attempts completion treating the text as a variable (if the +text begins with \fB$\fP), username (if the text begins with +\fB~\fP), hostname (if the text begins with \fB@\fP), or +command (including aliases and functions) in turn. If none +of these produces a match, filename completion is attempted. +.TP +.B possible\-completions (M-?) +List the possible completions of the text before point. +.TP +.B insert\-completions +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. +.TP +.B complete\-filename (M\-/) +Attempt filename completion on the text before point. +.TP +.B possible\-filename\-completions (C\-x /) +List the possible completions of the text before point, +treating it as a filename. +.TP +.B complete\-username (M\-~) +Attempt completion on the text before point, treating +it as a username. +.TP +.B possible\-username\-completions (C\-x ~) +List the possible completions of the text before point, +treating it as a username. +.TP +.B complete\-variable (M\-$) +Attempt completion on the text before point, treating +it as a shell variable. +.TP +.B possible\-variable\-completions (C\-x $) +List the possible completions of the text before point, +treating it as a shell variable. +.TP +.B complete\-hostname (M\-@) +Attempt completion on the text before point, treating +it as a hostname. +.TP +.B possible\-hostname\-completions (C\-x @) +List the possible completions of the text before point, +treating it as a hostname. +.TP +.B 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. +.TP +.B possible\-command\-completions (C\-x !) +List the possible completions of the text before point, +treating it as a command name. +.TP +.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. +.TP +.B 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 (see +.B Brace Expansion +above). +.PD +.SS Keyboard Macros +.PP +.PD 0 +.TP +.B start\-kbd\-macro (C-x (\^) +Begin saving the characters typed into the current keyboard macro. +.TP +.B end\-kbd\-macro (C-x )\^) +Stop saving the characters typed into the current keyboard macro +and save the definition. +.TP +.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 +.SS Miscellaneous +.PP +.PD 0 +.TP +.B 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. +.TP +.B abort (C\-g) +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. +.TP +.B prefix\-meta (ESC) +Metafy the next character typed. +.SM +.B ESC +.B f +is equivalent to +.BR Meta\-f . +.TP +.B undo (C\-_, C\-x C\-u) +Incremental undo, separately remembered for each line. +.TP +.B revert\-line (M\-r) +Undo all changes made to this line. This is like typing the +.B undo +command enough times to return the line to its initial state. +.TP +.B tilde\-expand (M\-~) +Perform tilde expansion on the current word. +.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 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, +the list of commands previously typed. The text of the last +.SM +.B 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 (see +.SM +.B EXPANSION +above) but after history expansion is performed, subject to the +values of the shell variables +.B command_oriented_history +and +.SM +.BR HISTCONTROL . +On startup, the history is initialized from the file named by +the variable +.SM +.B HISTFILE +(default \fI~/.bash_history\fP). +.SM +.B HISTFILE +is truncated, if necessary, to contain no more than +.SM +.B HISTFILESIZE +lines. +The builtin command +.B fc +(see +.SM +.B SHELL BUILTIN COMMANDS +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 +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 +.SM +.BR HISTFILE . +If +.SM +.B HISTFILE +is unset, or if the history file is unwritable, the history is +not saved. +.SH "HISTORY EXPANSION" +.PP +The shell supports a history expansion feature that +is similar to the history expansion in +.BR csh. +This section describes what syntax features are available. This +feature is enabled by default for interactive shells, and can be +disabled using the +.B \+H +option to the +.B set +builtin command (see +.SM +.B SHELL BUILTIN COMMANDS +below). Non-interactive shells do not perform history expansion. +.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. +.PP +The shell allows control of the various characters used by the +history expansion mechanism (see the description of +.B histchars +above under +.BR "Shell Variables" ). +.SS Event Designators +.PP +An event designator is a reference to a command line entry in the +history list. +.PP +.PD 0 +.TP +.B ! +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 . +.TP +.B !\-\fIn\fR +Refer to the current command line minus +.IR n . +.TP +.B !\fIstring\fR +Refer to the most recent command starting with +.IR string . +.TP +.B !?\fIstring\fR\fB[?]\fR +Refer to the most recent command containing +.IR string . +.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 +.I string1 +with +.IR string2 . +Equivalent to +``!!:s/\fIstring1\fP/\fIstring2\fP/'' +(see \fBModifiers\fP below). +.TP +.B !# +The entire command line typed so far. +.PD +.SS Word Designators +.PP +A +.B : +separates the event specification from the word +designator. It can be omitted if the word designator begins with a +.BR ^ , +.BR $ , +.BR * , +or +.BR % . +Words are numbered from the beginning of the line, +with the first word being denoted by a 0 (zero). +.PP +.PD 0 +.TP +.B 0 (zero) +The zeroth word. For the shell, this is the command +word. +.TP +.I n +The \fIn\fRth word. +.TP +.B ^ +The first argument. That is, word 1. +.TP +.B $ +The last argument. +.TP +.B % +The word matched by the most recent `?\fIstring\fR?' search. +.TP +.I x\fB\-\fPy +A range of words; `\-\fIy\fR' abbreviates `0\-\fIy\fR'. +.TP +.B * +All of the words but the zeroth. This is a synonym +for `\fI1\-$\fP'. It is not an error to use +.B * +if there is just one +word in the event; the empty string is returned in that case. +.TP +.B x* +Abbreviates \fIx\-$\fP. +.TP +.B x\- +Abbreviates \fIx\-$\fP like \fBx*\fP, but omits the last word. +.PD +.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 `:'. +.PP +.PD 0 +.PP +.TP +.B h +Remove a trailing pathname component, leaving only the head. +.TP +.B r +Remove a trailing suffix of the form \fI.xxx\fP, leaving the +basename. +.TP +.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 +.B q +Quote the substituted words, escaping further substitutions. +.TP +.B x +Quote the substituted words as with +.BR q , +but break into words at +.B blanks +and newlines. +.TP +.B s/\fIold\fP/\fInew\fP/ +Substitute +.I new +for the first occurrence of +.I old +in the event line. Any delimiter can be used in place of /. The +final delimiter is optional if it is the last character of the +event line. The delimiter may be quoted in +.I old +and +.I new +with a single backslash. If & appears in +.IR new , +it is replaced by +.IR old . +A single backslash will quote the &. +.TP +.B & +Repeat the previous substitution. +.TP +.B g +Cause changes to be applied over the entire event line. This is +used in conjunction with `\fB:s\fP' (e.g., `\fB:gs/\fIold\fP/\fInew\fP/\fR') +or `\fB:&\fP'. If used with +`\fB:s\fP', any delimiter can be used +in place of /, and the final delimiter is optional +if it is the last character of the event line. +.PD +.SH "ARITHMETIC EVALUATION" +The shell allows arithmetic expressions to be evaluated, under +certain circumstances (see the \fBlet\fP builtin command and +\fBArithmetic Expansion\fP). +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. +.PP +.PD 0 +.TP +.B \- + +unary minus and plus +.TP +.B ! ~ +logical and bitwise negation +.TP +.B * / % +multiplication, division, remainder +.TP +.B + \- +addition, subtraction +.TP +.B << >> +left and right bitwise shifts +.TP +.B <= >= < > +comparison +.TP +.B == != +equality and inequality +.TP +.B & +bitwise AND +.TP +.B ^ +bitwise exclusive OR +.TP +.B | +bitwise OR +.TP +.B && +logical AND +.TP +.B || +logical OR +.TP +.B = *= /= %= += \-= <<= >>= &= ^= |= +assignment +.PD +.PP +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. +.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. +.PP +Operators are evaluated in order of precedence. Sub-expressions in +parentheses are evaluated first and may override the precedence +rules above. +.SH "SHELL BUILTIN COMMANDS" +.\" start of bash_builtins +.zZ +.PD 0 +.TP +\fB:\fP [\fIarguments\fP] +.PD +No effect; the command does nothing beyond expanding +.I arguments +and performing any specified +redirections. A zero exit code is returned. +.TP +.PD 0 +\fB .\| \fP \fIfilename\fP [\fIarguments\fP] +.TP +\fBsource\fP \fIfilename\fP [\fIarguments\fP] +.PD +Read and execute commands from +.I filename +in the current +shell environment and return the exit status of the last command +executed from +.IR filename . +If +.I filename +does not contain a slash, pathnames in +.SM +.B PATH +are used to find the directory containing +.IR filename . +The file searched for in +.SM +.B PATH +need not be executable. The current directory is +searched if no file is found in +.SM +.BR PATH . +If any \fIarguments\fP are supplied, they become the positional +parameters when \fIfile\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. +.TP +\fBbg\fP [\fIjobspec\fP] +Place \fIjobspec\fP in the background, as if it had been started with +.BR & . +If \fIjobspec\fP is not present, the shell's notion of the +\fIcurrent job\fP is used. +.B bg +.I jobspec +returns 0 unless run when job control is disabled or, when run with +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] +.TP +\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 +.PD +Display current +.B readline +key and function bindings, or bind a key sequence to a +.B readline +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 +following meanings: +.RS +.PD 0 +.TP +.B \-m \fIkeymap\fP +Use +.I keymap +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. +.TP +.B \-l +List the names of all \fBreadline\fP functions +.TP +.B \-v +List current function names and bindings +.TP +.B \-d +Dump function names and bindings in such a way that they can be re-read +.TP +.B \-f \fIfilename\fP +Read key bindings from \fIfilename\fP +.TP +.B \-q \fIfunction\fP +Query about which keys invoke the named \fIfunction\fP +.PD +.PP +The return value is 0 unless an unrecognized option is given or an +error occurred. +.RE +.TP +\fBbreak\fP [\fIn\fP] +Exit from within a +.BR for , +.BR while , +or +.B until +loop. If \fIn\fP is specified, break \fIn\fP levels. +.I n +must be \(>= 1. If +.I n +is greater than the number of enclosing loops, all enclosing loops +are exited. The return value is 0 unless the shell is not executing +a loop when +.B break +is executed. +.TP +\fBbuiltin\fP \fIshell\-builtin\fP [\fIarguments\fP] +Execute the specified shell builtin, passing it +.IR arguments , +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 \fBcd\fP builtin is +commonly redefined this way. The return status is false if +.I shell\-builtin +is not a shell builtin command. +.TP +\fBcd\fP [\fIdir\fP] +Change the current directory to \fIdir\fP. The variable +.SM +.B HOME +is the +default +.IR dir . +The variable +.SM +.B CDPATH +defines the search path for +the directory containing +.IR dir . +Alternative directory names 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 +.I dir +begins with a slash (/), +then +.SM +.B CDPATH +is not used. An argument of +.B \- +is equivalent to +.SM +.BR $OLDPWD . +The return value is true if the directory was successfully changed; +false otherwise. +.TP +\fBcommand\fP [\fB-pVv\fP] \fIcommand\fP [\fIarg\fP ...] +Run +.I command +with +.I args +suppressing the normal shell function lookup. Only builtin +commands or commands found in the +.SM +.B PATH +are executed. If the +.B \-p +option is given, the search for +.I command +is performed using a default value for +.B PATH +that is guaranteed to find all of the standard utilities. +If either the +.B \-V +or +.B \-v +option is supplied, a description of +.I command +is printed. The +.B \-v +option causes a single word indicating the command or pathname +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 +.B \-v +option is supplied, the exit status is 0 if +.I command +was found, and 1 if not. If neither option is supplied and +an error occurred or +.I command +cannot be found, the exit status is 127. Otherwise, the exit status of the +.B command +builtin is the exit status of +.IR command . +.TP +\fBcontinue\fP [\fIn\fP] +Resume the next iteration of the enclosing +.BR for , +.BR while , +or +.B until +loop. +If +.I n +is specified, resume at the \fIn\fPth enclosing loop. +.I n +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 +shell is not executing a loop when +.B continue +is executed. +.TP +.PD 0 +\fBdeclare\fP [\fB\-frxi\fP] [\fIname\fP[=\fIvalue\fP]] +.TP +\fBtypeset\fP [\fB\-frxi\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. +.RS +.PD 0 +.TP +.B \-f +Use function names only +.TP +.B \-r +Make \fIname\fPs readonly. These names cannot then be assigned values +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 +.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 turn off readonly status for a readonly variable, +or an attempt is made to display a non-existant 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 pushd +command; the +.B popd +command moves back up through the list. +.RS +.PD 0 +.TP +.B +n +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 +shown by +.B dirs +when invoked without options, starting with zero. +.TP +.B \-l +produces a longer listing; the default listing format uses a +tilde to denote the home directory. +.PD +.PP +The return value is 0 unless an +illegal option is supplied or \fIn\fP indexes beyond the end +of the directory stack. +.RE +.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 +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. +.RS +.PD 0 +.TP +.B \ea +alert (bell) +.TP +.B \eb +backspace +.TP +.B \ec +suppress trailing newline +.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 \ennn +the character whose ASCII code is \fInnn\fP (octal) +.PD +.RE +.TP +\fBenable\fP [\fB\-n\fP] [\fB\-all\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. +If \fB\-n\fP is used, each \fIname\fP +is disabled; otherwise, +\fInames\fP are enabled. For example, to use the +.B test +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 +indication of whether or not each is enabled. +.B enable +accepts +.B \-a +as a synonym for +.BR \-all . +The return value is 0 unless a +.I name +is not a shell builtin. +.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 +.IR args , +or only null arguments, +.B eval +returns true. +.TP +\fBexec\fP [[\fB\-\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 \- , +the shell places a dash in the zeroth arg passed to +.IR command . +This is what login does. If the file +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. +If +.I command +is not specified, any redirections take effect in the current shell, +and the return status is 0. +.TP +\fBexit\fP [\fIn\fP] +Cause the shell to exit +with a status of \fIn\fP. If +.I n +is omitted, the exit status +is that of the last command executed. +A trap on +.SM +.B EXIT +is executed before the shell terminates. +.TP +.PD 0 +\fBexport\fP [\fB\-nf\fP\^] [\fIname\fP[=\fIword\fP]] ... +.TP +.B export \-p +.PD +The supplied +.I names +are marked for automatic export to the environment of +subsequently executed commands. If the +.B \-f +option is given, +the +.I names +refer to functions. +If no +.I names +are given, or if the +.B \-p +option is supplied, a list +of all names that are exported in this shell is printed. +The +.B \-n +option causes the export property to be removed from the +named variables. An argument of +.B \-\- +disables option checking for the rest of the arguments. +.B export +returns an exit status of 0 unless an illegal option is +encountered, +one of the \fInames\fP is not a legal shell variable name, or +.B \-f +is supplied with a +.I name +that is not a function. +.TP +.PD 0 +\fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-nlr\fP] [\fIfirst\fP] [\fIlast\fP] +.TP +\fBfc\fP \fB\-s\fP [\fIpat\fP=\fIrep\fP] [\fIcmd\fP] +.PD +Fix Command. In the first form, a range of commands from +.I first +to +.I last +is selected from the history list. +.I First +and +.I last +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 negative number is used as an offset from the current +command number). If +.I last +is not specified it is set to +the current command for listing (so that +.B fc \-l \-10 +prints the last 10 commands) and to +.I first +otherwise. +If +.I first +is not specified it is set to the previous +command for editing and \-16 for listing. +.sp 1 +The +.B \-n +flag suppresses +the command numbers when listing. The +.B \-r +flag reverses the order of +the commands. If the +.B \-l +flag is given, +the commands are listed on +standard output. Otherwise, the editor given by +.I ename +is invoked +on a file containing those commands. If +.I ename +is not given, the +value of the +.SM +.B FCEDIT +variable is used, and +the value of +.SM +.B EDITOR +if +.SM +.B FCEDIT +is not set. If neither variable is set, +.FN vi +is used. When editing is complete, the edited commands are +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'' +re-executes the last command. +.sp 1 +If the first form is used, the return value is 0 unless an illegal +option is encountered or +.I first +or +.I last +specify history lines out of range. +If the +.B \-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 +.I cmd +does not specify a valid history line, in which case +.B fc +returns failure. +.TP +\fBfg\fP [\fIjobspec\fP] +Place +.I jobspec +in the foreground, and make it the current job. If +.I jobspec +is not present, the shell's notion of the \fIcurrent job\fP 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 +.I jobspec +does not specify a valid job or +.I jobspec +specifies a job that was started without job control. +.TP +\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIargs\fP] +.B getopts +is used by shell procedures to parse positional parameters. +.I 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, +.B getopts +places the next option in the shell variable +.IR name , +initializing +.I name +if it does not exist, +and the index of the next argument to be processed into the +variable +.SM +.BR OPTIND . +.SM +.B OPTIND +is initialized to 1 each time the shell or a shell script +is invoked. When an option requires an argument, +.B getopts +places that argument into the variable +.SM +.BR OPTARG . +The shell does not reset +.SM +.B OPTIND +automatically; it must be manually reset between multiple +calls to +.B getopts +within the same shell invocation if a new set of parameters +is to be used. +.sp 1 +.B getopts +can report errors in two ways. If the first character of +.I optstring +is a colon, +.I silent +error reporting is used. In normal operation diagnostic messages +are printed when illegal options or missing option arguments are +encountered. +If the variable +.SM +.B OPTERR +is set to 0, no error message will be displayed, even if the first +character of +.I optstring +is not a colon. +.sp 1 +If an illegal option is seen, +.B getopts +places ? into +.I name +and, if not silent, +prints an error message and unsets +.SM +.BR OPTARG . +If +.B getopts +is silent, +the option character found is placed in +.SM +.B OPTARG +and no diagnostic message is printed. +.sp 1 +If a required argument is not found, and +.B getopts +is not silent, +a question mark (\^\fB?\fP\^) is placed in +.IR name , +.B OPTARG +is unset, and a diagnostic message is printed. +If +.B getopts +is silent, then a colon (\^\fB:\fP\^) is placed in +.I name +and +.SM +.B OPTARG +is set to the option character found. +.sp 1 +.B getopts +normally parses the positional parameters, but if more arguments are +given in +.IR args , +.B getopts +parses those instead. +.B 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. +.TP +\fBhash\fP [\fB\-r\fP] [\fIname\fP] +For each +.IR name , +the full pathname of the command is determined +and remembered. 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 +.I name +is not found or an illegal option is supplied. +.TP +\fBhelp\fP [\fIpattern\fP] +Display helpful information about builtin commands. If +.I pattern +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 +.IR pattern . +.TP +.PD 0 +\fBhistory\fP [\fIn\fP] +.TP +\fBhistory\fP \fB\-rwan\fP [\fIfilename\fP] +.\".TP +.\"\fBhistory\fP \fB\-s\fP \fIargs\fP +.PD +With no options, display the command +history list with line numbers. Lines listed +with a +.B * +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 +name of the history file; if not, the value of +.SM +.B HISTFILE +is used. Options, if supplied, have the following meanings: +.RS +.PD 0 +.TP +.B \-a +Append the ``new'' history lines (history lines entered since the +beginning of the current \fBbash\fP session) to the history file +.TP +.B \-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 \fBbash\fP session. +.TP +.B \-r +Read the contents of the history file +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. +.PD +.PP +The return value is 0 unless an illegal option is encountered or an +error occurs while reading or writing the history file. +.RE +.TP +.PD 0 +\fBjobs\fP [\fB\-lnp\fP] [ \fIjobspec\fP ... ] +.TP +\fBjobs\fP \fB\-x\fP \fIcommand\fP [ \fIargs\fP ... ] +.PD +The first form lists the active jobs. The +.B \-l +option lists process IDs +in addition to the normal information; the +.B \-p +option lists only the process ID of the job's process group +leader. The +.B \-n +option displays only jobs that have changed status since +last notified. 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 +If the +.B \-x +option is supplied, +.B jobs +replaces any +.I jobspec +found in +.I command +or +.I args +with the corresponding process group ID, and executes +.I command +passing it +.IR args , +returning its exit status. +.TP +.PD 0 +\fBkill\fP [\fB-s sigspec\fP | \fB\-sigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... +.TP +\fBkill\fP \fB\-l\fP [\fIsignum\fP] +.PD +Send the signal named by +.I sigspec +to the processes named by +.I pid +or +.IR jobspec . +.I sigspec +is either a signal name such as +.SM +.B SIGKILL +or a signal number. If +.I sigspec +is a signal name, the name is case insensitive and may be +given with or without the +.SM +.B SIG +prefix. +If +.I sigspec +is not present, then +.SM +.B SIGTERM +is assumed. An argument of +.B \-l +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. +.B kill +returns true if at least one signal was successfully sent, or false +if an error occurs or an illegal option is encountered. +.TP +\fBlet\fP \fIarg\fP [\fIarg\fP ...] +Each +.I arg +is an arithmetic expression to be evaluated (see +.SM +.BR "ARITHMETIC EVALUATION" ). +If the last +.I arg +evaluates to 0, +.B let +returns 1; 0 is returned otherwise. +.TP +\fBlocal\fP [\fIname\fP[=\fIvalue\fP] ...] +For each argument, create a local variable named +.IR name , +and assign it +.IR value . +When +.B local +is used within a function, it causes the variable +.I name +to have a visible scope restricted to that function and its children. +With no operands, +.B local +writes a list of local variables to the standard output. It is +an error to use +.B local +when not within a function. The return status is 0 unless +.B local +is used outside a function, or an illegal +.I name +is supplied. +.TP +.B logout +Exit a login shell. +.TP +\fBpopd\fP [\fB+/\-n\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. +.RS +.PD 0 +.TP +.B +n +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 +shown by +.BR dirs , +starting with zero. For example: ``popd -0'' +removes the last directory, ``popd -1'' the next to last. +.PD +.PP +If the +.B popd +command is successful, a +.B dirs +is performed as well, and the return status is 0. +.B popd +returns false if an illegal option is encountered, the directory stack +is empty, a non-existent directory stack entry is specified, or the +directory change fails. +.RE +.TP +.PD 0 +\fBpushd\fP [\fIdir\fP] +.TP +\fBpushd\fP \fB+/\-n\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. +.RS +.PD 0 +.TP +.B +n +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 +Rotates the stack so that the \fIn\fPth directory +(counting from the right) is at the top. +.TP +.B dir +adds +.I dir +to the directory stack at the top, making it the +new current working directory. +.PD +.PP +If the +.B pushd +command is successful, a +.B dirs +is performed as well. +If the first form is used, +.B pushd +returns 0 unless the cd to +.I dir +fails. With the second form, +.B 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. +.RE +.TP +\fBpwd\fP +Print the absolute pathname of the current working directory. +The path printed contains no symbolic links if the +.B \-P +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. +.TP +\fBread\fP [\fB\-r\fP] [\fIname\fP ...] +One line is read from the standard input, and the first word +is assigned to the first +.IR name , +the second word to the second +.IR name , +and so on, with leftover words assigned to the last +.IR name . +Only the +characters in +.SM +.B IFS +are recognized as word delimiters. 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 ...] +.TP +\fBreadonly -p\fP +.PD +The given +\fInames\fP are marked readonly and the values of these +\fInames\fP +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 +.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 +.B \-f +is supplied with a +.I name +that is not a function. +.TP +\fBreturn\fP [\fIn\fP] +Causes a function to exit with the return value specified by +.IR n . +If +.I 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 +.B . +(\fBsource\fP) command, it causes the shell to stop executing +that script and return either +.I n +or the exit status of the last command executed within the +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 ...] +.RS +.PD 0 +.TP 8 +.B \-a +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). +.TP 8 +.B \-e +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 +command that fails is part of an +.I until +or +.I while +loop, +part of an +.I if +statement, part of a +.B && +or +.B \(bv\|\(bv +list, or if the command's return value is +being inverted via +.BR ! . +.TP 8 +.B \-f +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. +.TP 8 +.B \-k +All keyword arguments 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 +by default for interactive shells on systems that support +it (see +.SM +.B JOB CONTROL +above). Background processes run in a separate process +group and a line containing their exit status is printed +upon their completion. +.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 +interactive shells. +.TP 8 +.B \-o \fIoption-name\fP +The \fIoption-name\fP can be one of the following: +.RS +.TP 8 +.B allexport +Same as +.BR \-a . +.TP 8 +.B braceexpand +The shell performs brace expansion (see +.B Brace Expansion +above). This is on by default. +.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 +option. +.TP 8 +.B errexit +Same as +.BR \-e . +.TP 8 +.B histexpand +Same as +.BR \-H . +.TP 8 +.B ignoreeof +The effect is as if the shell command `IGNOREEOF=10' 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). +.TP 8 +.B monitor +Same as +.BR \-m . +.TP 8 +.B noclobber +Same as +.BR \-C . +.TP 8 +.B noexec +Same as +.BR \-n . +.TP 8 +.B noglob +Same as +.BR \-f . +.TP 8 +.B nohash +Same as +.BR \-d . +.TP 8 +.B notify +Same as +.BR \-b . +.TP 8 +.B nounset +Same as +.BR \-u . +.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. +.TP 8 +.B privileged +Same as +.BR \-p . +.TP 8 +.B verbose +Same as +.BR \-v . +.TP 8 +.B vi +Use a vi-style command line editing interface. +.TP 8 +.B xtrace +Same as +.BR \-x . +.PP +If no \fIoption-name\fP is supplied, the values of the current options are +printed. +.RE +.TP 8 +.B \-p +Turn on +.I privileged +mode. In this mode, the +.B $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. +.TP 8 +.B \-t +Exit after reading and executing one command. +.TP 8 +.B \-u +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. +.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 +.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. +.TP 8 +.B \-C +The effect is as if the shell command `noclobber=' had been executed +(see +.B Shell Variables +above). +.TP 8 +.B \-H +Enable +.B ! +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 +.B cd +which change the current directory. The physical directory is +used instead. +.TP 8 +.B \-\- +If no arguments follow this flag, then the positional parameters are +unset. Otherwise, the positional parameters are set to the +\fIarg\fPs, even if some of them begin with a +.BR \- . +.TP 8 +.B \- +Signal the end of options, cause all remaining \fIarg\fPs to be +assigned to the positional parameters. The +.B \-x +and +.B \-v +options are turned off. +If there are no \fIarg\fPs, +the positional parameters remain unchanged. +.PD +.PP +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 +.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 +unless an illegal option is encountered. +.RE +.TP +\fBshift\fP [\fIn\fP] +The positional parameters from \fIn\fP+1 ... are renamed to +.B $1 +.B .... +Parameters represented by the numbers \fB$#\fP +down to \fB$#\fP\-\fIn\fP+1 are unset. +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 +.I n +is greater than +.B $# +or less than 0; otherwise 0. +.TP +\fBsuspend\fP [\fB\-f\fP] +Suspend the execution of this shell until it receives a +.SM +.B SIGCONT +signal. The +.B \-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 +.B \-f +is not supplied, or if job control is not enabled. +.TP +.PD 0 +\fBtest\fP \fIexpr\fP +.TP +\fB[\fP \fIexpr\fP \fB]\fP +Return a status of 0 (true) or 1 (false) depending on +the evaluation of the conditional expression +.IR expr . +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 \fIfile\fP +is of the form /dev/fd/\fIn\fP, then file descriptor \fIn\fP is +checked. +.RS +.PD 0 +.TP +.B \-b \fIfile\fP +True if \fIfile\fP exists and is block special. +.TP +.B \-c \fIfile\fP +True if \fIfile\fP exists and is character special. +.TP +.B \-d \fIfile\fP +True if \fIfile\fP exists and is a directory. +.TP +.B \-e \fIfile\fP +True if \fIfile\fP exists. +.TP +.B \-f \fIfile\fP +True if \fIfile\fP exists and is a regular file. +.TP +.B \-g \fIfile\fP +True if \fIfile\fP exists and is set-group-id. +.TP +.B \-k \fIfile\fP +True if \fIfile\fP has its ``sticky'' bit set. +.TP +.B \-L \fIfile\fP +True if \fIfile\fP exists and is a symbolic link. +.TP +.B \-p \fIfile\fP +True if \fIfile\fP exists and is a named pipe. +.TP +.B \-r \fIfile\fP +True if \fIfile\fP exists and is readable. +.TP +.B \-s \fIfile\fP +True if \fIfile\fP exists and has a size greater than zero. +.TP +.B \-S \fIfile\fP +True if \fIfile\fP exists and is a socket. +.TP +.B \-t \fIfd\fP +True if +.I fd +is opened on a terminal. +.TP +.B \-u \fIfile\fP +True if \fIfile\fP exists and its set-user-id bit is set. +.TP +.B \-w \fIfile\fP +True if \fIfile\fP exists and is writable. +.TP +.B \-x \fIfile\fP +True if \fIfile\fP exists and is executable. +.TP +.B \-O \fIfile\fP +True if \fIfile\fP exists and is owned by the effective user id. +.TP +.B \-G \fIfile\fP +True if \fIfile\fP exists and is owned by the effective group id. +.TP +\fIfile1\fP \-\fBnt\fP \fIfile2\fP +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. +.TP +\fIfile1\fP \fB\-ef\fP \fIfile\fP +True if \fIfile1\fP and \fIfile2\fP have the same device and +inode numbers. +.TP +.B \-z \fIstring\fP +True if the length of \fIstring\fP is zero. +.TP +.B \-n \fIstring\fP +.TP +\fIstring\fP +True if the length of +.I string +is non\-zero. +.TP +\fIstring1\fP \fB=\fP \fIstring2\fP +True if the strings are equal. +.TP +\fIstring1\fP \fB!=\fP \fIstring2\fP +True if the strings are not equal. +.TP +.B ! \fIexpr\fP +True if +.I expr +is false. +.TP +\fIexpr1\fP \-\fBa\fP \fIexpr2\fP +True if both +.I expr1 +AND +.I expr2 +are true. +.TP +\fIexpr1\fP \-\fBo\fP \fIexpr2\fP +True if either +.I expr1 +OR +.I expr2 +is true. +.TP +.I arg1 \fBOP\fP arg2 +.SM +.B OP +is one of +.BR \-eq , +.BR \-ne , +.BR \-lt , +.BR \-le , +.BR \-gt , +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. +.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 . +.PD +.RE +.TP +.B times +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] +The command +.I arg +is to be read and executed when the shell receives +signal(s) +.IR sigspec . +If +.I arg +is absent or +.BR \- , +all specified signals are +reset to their original values (the values they had +upon entrance to the shell). If +.I arg +is the null string this +signal is ignored by the shell and by the +commands it invokes. +.I sigspec +is either +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 +.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. +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 +.B trap +returns true. +.TP +\fBtype\fP [\fB\-all\fP] [\fB\-type\fP | \fB\-path\fP] \fIname\fP [\fIname\fP ...] +With no options, +indicate how each +.I name +would be interpreted if used as a command name. +If the +.B \-type +flag is used, +.B type +prints a phrase which is one of +.IR alias , +.IR keyword , +.IR function , +.IR builtin , +or +.I file +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. +If the +.B \-path +flag is used, +.B type +either returns the name of the disk file +that would be executed if +.I name +were specified as a command name, +or nothing if +.B \-type +would not return +.IR file . +If a command is hashed, +.B \-path +prints the hashed value, not necessarily the file that appears +first in +.SM +.BR PATH . +If the +.B \-all +flag is used, +.B type +prints all of the places that contain +an executable named +.IR name . +This includes aliases and functions, +if and only if the +.B \-path +flag is not also used. +The table of hashed commands is not consulted +when using +.BR \-all . +.B type +accepts +.BR \-a , +.BR \-t , +and +.B \-p +in place of +.BR \-all , +.BR \-type , +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 +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 +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 +.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. +Other options are interpreted as follows: +.RS +.PD 0 +.TP +.B \-a +all current limits are reported +.TP +.B \-c +the maximum size of core files created +.TP +.B \-d +the maximum size of a process's data segment +.TP +.B \-f +the maximum size of files created by the shell +.TP +.B \-m +the maximum resident set size +.TP +.B \-s +the maximum stack size +.TP +.B \-t +the maximum amount of cpu time in seconds +.TP +.B \-p +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) +.TP +.B \-u +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 +.I limit +is given, it is the new value of the specified resource (the +.B \-a +option is display only). +If no option is given, then +.B \-f +is assumed. Values are in 1024-byte increments, except for +.BR \-t , +which is in seconds, +.BR \-p , +which is in units of 512-byte blocks, +and +.B \-n +and +.BR \-u , +which are unscaled values. The return status is 0 +unless an illegal option is encountered, a non-numeric argument +other than \fBunlimited\fP is supplied as \fIlimit\fP, or an +error occurs while setting a new limit. +.RE +.TP +\fBumask\fP [\fB\-S\fP] [\fImode\fP] +The user file-creation mask is set to +.IR mode . +If +.I mode +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 +.IR chmod (1). +If +.I mode +is omitted, or if the +.B \-S +option is supplied, 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 +no \fImode\fP argument was supplied, and false otherwise. +.TP +\fBunalias\fP [\-\fBa\fP] [\fIname\fP ...] +Remove \fIname\fPs from the list of defined aliases. If +.B \-a +is supplied, all alias definitions are removed. The return +value is true unless a supplied +.I name +is not a defined alias. +.TP +\fBunset\fP [\-\fBfv\fP] [\fIname\fP ...] +For each +.IR name , +remove the corresponding variable or, given the +.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 +.SM +.BR RANDOM , +.SM +.BR SECONDS , +.SM +.BR LINENO , +or +.SM +.B HISTCMD +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. +.TP +\fBwait\fP [\fIn\fP] +Wait for the specified process and return its termination +status. +.I n +may be a process +ID or a job specification; if a job spec is given, all processes +in that job's pipeline are waited for. If +.I n +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 +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. +.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 +.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 +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. +.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. +.SH "SEE ALSO" +.PD 0 +.TP +\fIBash Features\fP, Brian Fox and Chet Ramey +.TP +\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey +.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) +.TP +\fIemacs\fP(1), \fIvi\fP(1) +.TP +\fIreadline\fP(3) +.PD +.SH FILES +.PD 0 +.TP +.FN /bin/bash +The \fBbash\fP executable +.TP +.FN /etc/profile +The systemwide initialization file, executed for login shells +.TP +.FN ~/.bash_profile +The personal initialization file, executed for login shells +.TP +.FN ~/.bashrc +The individual per-interactive-shell startup file +.TP +.FN ~/.inputrc +Individual \fIreadline\fP initialization file +.PD +.SH AUTHORS +.RS +Brian Fox, Free Software Foundation (primary author) +.br +bfox@ai.MIT.Edu +.PP +Chet Ramey, Case Western Reserve University +.br +chet@ins.CWRU.Edu +.SH BUG REPORTS +If you find a bug in +.B 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 +.B bash +that you have. +.PP +Once you have determined that a bug actually exists, use the +.I 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 \fPbug-bash\fP@\fIprep.ai.MIT.Edu\fP or posted to the Usenet +newsgroup +.BR gnu.bash.bug . +.PP +ALL bug reports should include: +.PP +.PD 0 +.TP 20 +The version number of \fBbash\fR +.TP +The hardware and operating system +.TP +The compiler used to compile +.TP +A description of the bug behaviour +.TP +A short script or `recipe' which exercises the bug +.PD +.PP +.I bashbug +inserts the first three items automatically into the template +it provides for filing a bug report. +.PP +Comments and bug reports concerning +this manual page should be directed to +.IR chet@ins.CWRU.Edu . +.SH BUGS +.PP +It's too big and too slow. +.PP +There are some subtle differences between +.B bash +and traditional versions of +.BR sh , +mostly because of the +.SM +.B POSIX +specification. +.PP +Aliases are confusing in some uses. +.zZ diff --git a/documentation/bash.ps b/documentation/bash.ps new file mode 100644 index 0000000..c3a4643 --- /dev/null +++ b/documentation/bash.ps @@ -0,0 +1,3959 @@ +%!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 F2<ad63>108 280.8 Q F3(string)4.166 E F0 .504(If the)158 280.8 +R F2<ad63>3.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 F2<ad69>108 304.8 Q F0(If the)158 304.8 Q F2<ad69>2.5 E F0 +(\215ag is present, the shell is)2.5 E F3(inter)2.5 E(active)-.15 E F0(.).18 E +F2<ad73>108 316.8 Q F0 .305(If the)158 316.8 R F2<ad73>2.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 F2<ad>108 352.8 Q F0 +3.373(As)158 352.8 S(ingle)172.483 352.8 Q F2<ad>3.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 F2<ad>2.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 F2<adad>2.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 F2<ad>2.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 +F2<ad72>108 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 F2<ad76>108 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 F2<ad63>2.516 E +F0 .016(nor the)2.516 F F2<ad73>2.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.666<efef>144 +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.666<efef>2.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(<newline>)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.666<efef>3.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.666<efef>2.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.666<efef>2.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 <ne)-.15 F 2.524(wline>. If)-.25 F(a)2.524 E F3(\\)2.524 E F0(<ne) +A .024(wline> pair appears, and the backslash is not quoted, the)-.25 F F3(\\) +108 218.4 Q F0(<ne)A +(wline> 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(<newline>)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 F3<ad69>2.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 F1<ad>108 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 +F1<ad69>2.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 F1<ad63>3.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(`<space><tab><ne)-.74 E(wline>')-.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 F1<ad62>2.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 F1<ad50>2.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 F1<ad43>2.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 +(<space><tab><newline>)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 F4<ad66>2.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 +<ad>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 F1<ad>A 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(\\<new-)3.27 E(line>)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 F2<ad>3.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<ad66> +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 F2<ad66>2.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 F1<ad>2.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 +F0<ad>A 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 +F1<ad6b>3.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<ad>.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<ad72> +.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 F1<ad6f>2.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 F1<ad>2.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<ad72>.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 F2<ad>A 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.5<ad2b>108 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 F2<ad6d>A 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 F2<ad6d>A 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 F2<ad6d>A 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 F2<ad6d>144 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 F2<ad6c>144 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 F2<ad76>144 268.8 Q F0 +(List current function names and bindings)180 268.8 Q F2<ad64>144 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 F2<ad66>144 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 +F2<ad71>144 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 SF<b3>2.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 F2<ad>3.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 F2<ad70>3.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 F2<ad56>2.731 E F0(or)2.731 E F2<ad76>2.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 F2<ad76>2.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 F2<ad56>2.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 F2<adad>2.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 F2<ad56>3.849 E F0(or)3.849 E F2<ad76> +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 F3<b3>3.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 +F1<ad66>144 144 Q F0(Use function names only)180 144 Q F1<ad72>144 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 F1<ad78>144 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 F1<ad69>144 +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 +F1<ad6e>144 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 F1<ad6c>144 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 F1<ad6e>2.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 F1<ad65>2.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 F1<ad45>3.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 F1<ad6e>A 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<ad6e> +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 +F1<ad6e>2.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 F1<ad61>2.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 F1<ad>A 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 F1<ad>3.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 F1<ad66>2.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 F1<ad70>144 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 F1<ad6e>3.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 F1<adad>3.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 F1<ad66>2.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 +F1<ad65>A 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 +<ad6e>2.921 E F0 .421(\215ag suppresses the command numbers when listing.)2.921 +F(The)5.421 E F1<ad72>2.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 +<ad6c>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 F1<ad65>2.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 F1<ad72>A 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 F1<ad72>2.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 F1<adad>2.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 F1<ad61>144 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 F1<ad6e>144 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 F1<ad72>144 662.4 Q F0 +(Read the contents of the history \214le and use them as the current history) +180 662.4 Q F1<ad77>144 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 F1<ad6c>2.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 F1<ad70>3.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<ad6e> +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<ad78> +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 F1<ad6c>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 268.8 S .814 +(uments are supplied).18 F(when)144 280.8 Q F1<ad6c>2.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 F1<adad>2.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 F1<ad6e>144 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 F1<ad6e>144 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 F1<ad50>3.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 F1<ad72>A 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 F1<ad72>2.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 +<ad66>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 F1<ad66>3.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 F1<ad70>3.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<adad> +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 F1<ad66>2.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 F1<ad61>144 +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 F1<ad62>144 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<ad65> +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.666<efef>3.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 +F1<ad66>144 540 Q F0(Disable pathname e)184 540 Q(xpansion.)-.15 E F1<ad68>144 +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 F1<ad6b>144 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 F1<ad6d>144 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 F1<ad6e>144 +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 F1<ad6f>144 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 F1<ad61>2.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 F1<ad65>2.5 E F0(.)A F1(histexpand)184 168 Q +F0(Same as)224 180 Q F1<ad48>2.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 F1<ad6d>2.5 E F0(.)A F1 +(noclob)184 276 Q(ber)-.1 E F0(Same as)224 288 Q F1<ad43>2.5 E F0(.)A F1 +(noexec)184 300 Q F0(Same as)224 300 Q F1<ad6e>2.5 E F0(.)A F1(noglob)184 312 Q +F0(Same as)224 312 Q F1<ad66>2.5 E F0(.)A F1(nohash)184 324 Q F0(Same as)9.43 E +F1<ad64>2.5 E F0(.)A F1(notify)184 336 Q F0(Same as)224 336 Q F1<ad62>2.5 E F0 +(.)A F1(nounset)184 348 Q F0(Same as)6.66 E F1<ad75>2.5 E F0(.)A F1(ph)184 360 +Q(ysical)-.15 E F0(Same as)5.14 E F1<ad50>2.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 F1<ad70>2.5 E F0(.)A F1 -.1(ve)184 420 S +(rbose).1 E F0(Same as)7.33 E F1<ad76>2.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 F1<ad78>2.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 F1<ad70>144 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 F1<ad74>144 +516 Q F0(Exit after reading and e)184 516 Q -.15(xe)-.15 G(cuting one command.) +.15 E F1<ad75>144 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 F1<ad76>144 564 Q F0(Print shell input lines as the)184 564 Q 2.5(ya)-.15 +G(re read.)306.63 564 Q F1<ad78>144 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<ad6c> +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 F1<ad64>144 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 F1<ad43>144 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 F1<ad48>144 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 F1<ad50>144 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 SF<adad>144 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 F1<ad>2.5 E F0(.)A +F1<ad>144 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 F1<ad78>3.445 E F0(and)3.445 E F1<ad76>3.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 F0<ad>A 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 F1<ad66>A 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 F1<ad66>2.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 F1<ad66>2.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 F1<ad62>144 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 F1<ad63>144 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 F1<ad64>144 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 F1<ad65>144 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 +<ad66>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 F1<ad67>144 +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 F1<ad6b>144 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 F1<ad4c>144 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 F1<ad70>144 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 F1<ad72>144 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 F1<ad73>144 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 F1<ad53>144 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 F1<ad74>144 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<ad75> +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 F1<ad77>144 +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 F1<ad78>144 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 F1<ad4f>144 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<ad47> +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 F0<ad>2.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 F0<ad>2.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 SF<ad7a>144 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 +<ad6e>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<ad> +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 F0<ad>2.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 F1<ad6c>2.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 F1<ad6c>A 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 F1<ad>4.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 F1<ad6c>2.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 F1<adad>3.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<ad61> +3.286 E F0(,)A F1<ad74>3.286 E F0 3.286(,a)C(nd)335.698 590.4 Q F1<ad70>3.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 F1<adad>3.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 SF<ad61>144 84 Q F0(all current limits are reported)180 84 +Q F1<ad63>144 96 Q F0(the maximum size of core \214les created)180 96 Q F1 +<ad64>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 F1<ad66>144 120 Q F0 +(the maximum size of \214les created by the shell)180 120 Q F1<ad6d>144 132 Q +F0(the maximum resident set size)180 132 Q F1<ad73>144 144 Q F0 +(the maximum stack size)180 144 Q F1<ad74>144 156 Q F0 +(the maximum amount of cpu time in seconds)180 156 Q F1<ad70>144 168 Q F0 +(the pipe size in 512-byte blocks \(this may not be set\))180 168 Q F1<ad6e>144 +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 F1<ad75>144 204 Q F0 +(the maximum number of processes a)180 204 Q -.25(va)-.2 G +(ilable to a single user).25 E F1<ad76>144 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 +<adad>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<ad61> +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 F1<ad66>144 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 F1<ad74>2.931 E F0 2.931(,w)C .431(hich is in seconds,) +421.315 256.8 R F1<ad70>2.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 F1<ad6e>3.327 E F0(and)3.327 E +F1<ad75>3.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 F1<ad53>A 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 F1<ad53>2.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 F1<ad53>2.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 F1<adad>2.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 F1<ad61>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 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 F1<ad66>2.773 E F0 .273(option, function.)2.773 F .272 +(An ar)5.272 F(gument)-.18 E(of)144 463.2 Q F1<adad>2.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 F1<ad>2.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 F1<ad69>2.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 F2<ad72>2.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 new file mode 100644 index 0000000..c23f298 --- /dev/null +++ b/documentation/bash.txt @@ -0,0 +1,3960 @@ + + + +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: + || & && ; ;; ( ) | <newline> + + + + +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 <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 _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 <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). + + 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 <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 (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 + ``<space><tab><newline>''. + 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 + <space><tab><newline>, 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 \<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 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 new file mode 100644 index 0000000..553c107 --- /dev/null +++ b/documentation/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 "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 new file mode 100644 index 0000000..ebac7d1 --- /dev/null +++ b/documentation/builtins.ps @@ -0,0 +1,1367 @@ +%!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 F2<ad6d>A 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 F2<ad6d>A 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 +F2<ad6d>A 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 F2<ad6d>144 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 F2<ad6c>144 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 F2<ad76>144 624 Q F0 +(List current function names and bindings)180 624 Q F2<ad64>144 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 F2<ad66>144 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 +<ad71>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<b3> +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<ad> +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 F1<ad70>3.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 F1<ad56>2.732 E F0(or)2.732 E F1<ad76>2.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 F1<ad76>2.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 F1<ad56>2.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 F1<adad>2.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 F1<ad56>3.848 E F0(or)3.848 E F1<ad76> +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 F3<b3>3.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 F1<ad66>144 +528 Q F0(Use function names only)180 528 Q F1<ad72>144 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 F1<ad78>144 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 F1<ad69>144 +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 +SF<ad6e>144 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 F1<ad6c>144 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 F1<ad6e>2.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 F1<ad65>2.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 F1<ad45>3.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 F1<ad6e>A 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 +<ad6e>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 F1<ad6e>2.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 F1<ad61>2.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 F1<ad>A 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 F1<ad>3.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 F1<ad66>2.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 F1<ad70>144 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 F1<ad6e>3.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 F1<adad>3.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 F1<ad66>2.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 F1<ad65>A/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 +<ad6e>2.92 E F0 .42(\215ag suppresses the command numbers when listing.)2.92 F +(The)5.421 E F1<ad72>2.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<ad6c> +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 F1<ad65>2.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 F1<ad72>A 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 F1<ad72>2.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 F1<adad>2.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 F1<ad61>144 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 F1<ad6e>144 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 F1<ad72>144 362.4 Q F0 +(Read the contents of the history \214le and use them as the current history) +180 362.4 Q F1<ad77>144 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 F1<ad6c>2.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 F1<ad70>3.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<ad6e> +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<ad78> +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 +<ad6c>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 F1<ad6c>2.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 F1<adad>2.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 F1<ad6e>144 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 F1<ad6e>144 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 F1<ad50>3.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 F1<ad72>A 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 F1<ad72>2.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 +<ad66>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 F1<ad66>3.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 F1<ad70>3.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<adad> +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 F1<ad66>2.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 F1<ad61>144 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 F1<ad62>144 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<ad65> +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.666<efef>3.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 F1<ad66>144 220.8 Q F0 +(Disable pathname e)184 220.8 Q(xpansion.)-.15 E F1<ad68>144 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 F1<ad6b>144 +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 F1<ad6d>144 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 F1<ad6e>144 +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 F1<ad6f>144 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 F1<ad61>2.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 +F1<ad65>2.5 E F0(.)A F1(histexpand)184 484.8 Q F0(Same as)224 496.8 Q F1<ad48> +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 F1<ad6d>2.5 E F0(.)A F1(noclob)184 592.8 +Q(ber)-.1 E F0(Same as)224 604.8 Q F1<ad43>2.5 E F0(.)A F1(noexec)184 616.8 Q +F0(Same as)224 616.8 Q F1<ad6e>2.5 E F0(.)A F1(noglob)184 628.8 Q F0(Same as) +224 628.8 Q F1<ad66>2.5 E F0(.)A F1(nohash)184 640.8 Q F0(Same as)9.43 E F1 +<ad64>2.5 E F0(.)A F1(notify)184 652.8 Q F0(Same as)224 652.8 Q F1<ad62>2.5 E +F0(.)A F1(nounset)184 664.8 Q F0(Same as)6.66 E F1<ad75>2.5 E F0(.)A F1(ph)184 +676.8 Q(ysical)-.15 E F0(Same as)5.14 E F1<ad50>2.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 F1<ad70>2.5 E F0(.)A F1 -.1 +(ve)184 108 S(rbose).1 E F0(Same as)7.33 E F1<ad76>2.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 F1<ad78>2.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 F1<ad70>144 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 F1<ad74>144 +204 Q F0(Exit after reading and e)184 204 Q -.15(xe)-.15 G(cuting one command.) +.15 E F1<ad75>144 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 F1<ad76>144 252 Q F0(Print shell input lines as the)184 252 Q 2.5(ya)-.15 +G(re read.)306.63 252 Q F1<ad78>144 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 +<ad6c>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 F1<ad64>144 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 F1<ad43>144 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 F1<ad48>144 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 F1<ad50>144 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 F1<adad>144 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 F1<ad>2.5 E F0(.)A F1<ad>144 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 +<ad78>3.445 E F0(and)3.445 E F1<ad76>3.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 F0<ad>A 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 F1<ad66>A 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 +<ad66>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 F1<ad66>2.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 SF<ad62>144 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 F2<ad63>144 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 F2<ad64>144 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 F2<ad65>144 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 +<ad66>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 F2<ad67>144 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 F2<ad6b>144 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 F2<ad4c>144 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 F2<ad70>144 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 F2<ad72>144 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 F2<ad73>144 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 +<ad53>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 F2<ad74>144 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 F2<ad75>144 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 F2<ad77>144 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 F2<ad78>144 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 F2<ad4f>144 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 F2<ad47>144 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 F0<ad>2.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 F0<ad>2.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 F2<ad7a>144 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 F2<ad6e>144 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<ad> +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 F0<ad>2.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 F2<ad6c>2.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 F2<ad6c>A 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 F2<ad>4.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 F2<ad6c>2.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 F2<adad>3.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<ad61> +3.286 E F0(,)A F1<ad74>3.286 E F0 3.286(,a)C(nd)335.698 244.8 Q F1<ad70>3.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 F1<adad>3.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 F1<ad61>144 393.6 Q F0 +(all current limits are reported)180 393.6 Q F1<ad63>144 405.6 Q F0 +(the maximum size of core \214les created)180 405.6 Q F1<ad64>144 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 F1<ad66>144 429.6 Q F0 +(the maximum size of \214les created by the shell)180 429.6 Q F1<ad6d>144 441.6 +Q F0(the maximum resident set size)180 441.6 Q F1<ad73>144 453.6 Q F0 +(the maximum stack size)180 453.6 Q F1<ad74>144 465.6 Q F0 +(the maximum amount of cpu time in seconds)180 465.6 Q F1<ad70>144 477.6 Q F0 +(the pipe size in 512-byte blocks \(this may not be set\))180 477.6 Q F1<ad6e> +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 F1<ad75>144 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 F1<ad76>144 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 +<adad>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 F1<ad61>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 F1<ad66>144 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 +<ad74>2.931 E F0 2.931(,w)C .431(hich is in seconds,)421.315 566.4 R F1<ad70> +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 F1<ad6e>3.327 E F0(and)3.327 E +F1<ad75>3.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 F1<ad53>A 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 F1<ad53>2.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 F1<ad53>2.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 F1<adad>2.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 +<ad61>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 F1<ad66>2.773 E F0 .273(option, function.)2.773 F .272 +(An ar)5.272 F(gument)-.18 E(of)144 148.8 Q F1<adad>2.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 new file mode 100644 index 0000000..3df6380 --- /dev/null +++ b/documentation/builtins.txt @@ -0,0 +1,1188 @@ + + + +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 Binary files differnew file mode 100644 index 0000000..21e5327 --- /dev/null +++ b/documentation/features.dvi diff --git a/documentation/features.info b/documentation/features.info new file mode 100644 index 0000000..6398445 --- /dev/null +++ b/documentation/features.info @@ -0,0 +1,3011 @@ +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 new file mode 100644 index 0000000..b8b52cc --- /dev/null +++ b/documentation/features.ps @@ -0,0 +1,3825 @@ +%!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 D<EA07E0EA1C38EA381CEA300CEA700EEA6006A2EAE0 +07AAEA6006A2EA700EEA300CEA381CEA1C38EA07E010187F9713>48 +D<12035AB4FC1207B3A2EA7FF80D187D9713>I<EA0F80EA1060EA2030EA4038EA803CEA +C01C12E01240EA003C1338A21370136013C0EA018013001202EA040412081210EA3008EA +3FF8127F12FF0E187E9713>I<EA07E0EA1838EA201CEA601EEA700EEA201E1200131CA2 +13381370EA07E0EA0038131C130E130FA212E0A212C0EA400EEA601CEA1838EA07E01018 +7F9713>I<1318A21338137813F813B8EA01381202A212041208121812101220124012C0 +B5FCEA0038A6EA03FF10187F9713>I<EA3018EA3FF013E01380EA2000A5EA2FC0EA3060 +EA2030EA00381318131CA2124012E0A2EA8018EA40381330EA30E0EA0F800E187E9713> +I<EA01F8EA0704EA0C06EA180E123013001270126012E0EAE3E0EAE418EAE80CEAF00EEA +E0061307A31260A2EA7006EA300EEA180CEA0C38EA07E010187F9713>I<1240EA7FFF13 +FEA2EA4004EA80081310A2EA00201340A21380120113005AA25A1206A2120EA512041019 +7E9813>I<EA07E0EA1818EA300CEA20061260A21270EA780CEA3E18EA1F30EA07C0EA03 +E0EA0CF8EA307CEA601E130FEAC0071303A3EA6002EA2004EA1818EA07E010187F9713> +I<EA07E0EA1C30EA3018EA700CEA600EEAE006A21307A31260EA700FEA3017EA1827EA07 +C7EA00071306130E130C12701318EA6030EA3060EA0F8010187F9713>I<39FFE1FFC039 +0E001C00AB380FFFFC380E001CAC39FFE1FFC01A1A7F991D>72 D<39FFE01FC0390E000F +00140C14085C5C5C495A0102C7FC5B130C131C132E1347EB8380EA0F03380E01C06D7EA2 +147080A280141E141F39FFE07FC01A1A7F991E>75 D<B5FC380E01C0EB0070147880A55C +1470EB01C0D80FFFC7FC380E0380EB00C0801470A31478A31540143CEC1C8039FFE00F00 +1A1A7F991C>82 D<39FF801FE0391E00070014066C13046C130CEB800800035BEA01C06D +5A00001360EB7040EB78801338011DC7FC131F130EAAEBFFC01B1A7F991D>89 +D<EA1FC0EA38707FEA101C1200A2EA03FCEA1E1C1238127012E01480A2133CEA705F381F +8F0011107F8F13>97 D<EA07F8EA1C1C1238EA700813005AA612701304EA3808EA1C18EA +07E00E107F8F11>99 D<133F1307A9EA03E7EA0C17EA180F487E127012E0A6126012706C +5AEA1C373807C7E0131A7F9915>I<EA07C0EA1C30EA30181270EA600C12E0EAFFFCEAE0 +00A41260EA7004EA3808EA1C18EA07E00E107F8F11>I<EA0FCF3818718038303000EA70 +38A4EA30306C5AEA2FC00060C7FCA21270EA3FF013FC6C7EEA600FEAC003A4EA6006EA38 +1CEA07E011187F8F13>103 D<12FC121CA9137CEA1D87381E0380A2121CAB38FF9FF014 +1A809915>I<1218123CA212181200A612FC121CAE12FF081A80990A>I<12FC121CA9EB1F +C0EB0F00130C5B13205B13E0121DEA1E70EA1C7813387F131E7F148038FF9FE0131A8099 +14>107 D<12FC121CB3A6EAFF80091A80990A>I<EAFC7CEA1D87381E0380A2121CAB38FF +9FF01410808F15>110 D<EA07E0EA1C38EA300CEA700EEA6006EAE007A6EA6006EA700E +EA381CEA1C38EA07E010107F8F13>I<EAFCFCEA1D07381E0380381C01C0A2EB00E0A6EB +01C01480381E0300EA1D06EA1CF890C7FCA6B47E1317808F15>I<EAFC78EA1D9CEA1E1C +1308EA1C00ABEAFF800E10808F0F>114 D<EA1F20EA60E0EA402012C0A2EAF000127FEA +3FC0EA1FE0EA00F0EA8070133012C01320EAF040EA8F800C107F8F0F>I<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 +D<EA01801203EA06005A121C121812385AA35AA91270A37E1218121C120C7EEA03801201 +091D799914>40 D<128012C01260123012381218121C120EA31207A9120EA3121C121812 +381230126012C01280081D7C9914>I<127012F812FCA2127C120C1218123012E012C006 +0A798414>44 D<EAFFFEA30F037E8C14>I<127012F8A312700505798414>I<EA07C0EA0F +E0EA1C70EA3838EA3018EA701CA2EAE00EA9EA701CA2EA3838A2EA1C70EA0FE0EA07C00F +177E9614>48 D<1203A25A5A123F12F712471207AEEA7FF0A20C177C9614>I<EA0FC0EA +1FF0EA3838EA701CEAE00EA312401200131CA213381330137013E0EA01C0EA030012065A +EA180E1230EA7FFEA20F177E9614>I<EA0FC0EA1FF0EA3838EA701CA212201200131813 +381370EA0FE013F0EA0038131C130EA2124012E0A2EA701CEA7838EA3FF0EA0FC00F177E +9614>I<137813F8EA01B8A2EA0338A21206120E120C121C12381230127012E0B51280A2 +38003800A548B4FCA211177F9614>I<127012F8A312701200A6127012F8A31270051079 +8F14>58 D<130E133E137C13F0EA03E0EA07C0EA1F00123E12F85A7E123E7EEA07C0EA03 +E0EA00F0137C133E130E0F137E9414>60 D<124012E012F8127C121EEA0F80EA07C0EA01 +F0EA00F8133E131E133E13F8EA01F0EA07C0EA0F80EA1E00127C5A12E012400F157E9514 +>62 D<EA1FE0EA3FF8EA701CEAE00EA21240EA003C137013E0EA01C0EA0380A41300C7FC +A41203EA0780A2EA03000F177E9614>I<EA01C0487EA21360A2EA0770A4EA0630EA0E38 +A4487EEA1FFCA2EA1C1CA2487EA238FE3F80A211177F9614>65 D<EAFFF013FCEA381E13 +0E1307A4130E131EEA3FFCA2EA381E130E1307A5130E131EEAFFFC13F810177F9614>I< +3801F180EA07FFEA0E1FEA1C071238EA7003A348C7FCA738700380A338380700121CEA0E +0EEA07FCEA01F011177F9614>I<EAFFE013F8EA383C7F130E7FA3EB0380A8EB0700A213 +0E131E5BEAFFF813E011177F9614>I<B5FCA2EA3807A490C7FCA21338A2EA3FF8A2EA38 +38A290C7FCA3EB0380A4B5FCA211177F9614>I<B51280A2EA3803A490C7FCA21338A2EA +3FF8A2EA3838A290C7FCA7B4FCA211177F9614>I<EA03C6EA0FFEEA1C3EEA181E1238EA +700EA21260EAE000A4137FA2130E12601270A2EA381E1218EA1C3EEA0FFEEA03CE10177F +9614>I<38FE3F80A238380E00A8EA3FFEA2EA380EA938FE3F80A211177F9614>I<EAFFF8 +A2EA0700B3EAFFF8A20D177D9614>I<EAFE3FA2EA381C5B137813705B12395BEA3B80EA +3FC07F123EEA3CF01370EA387813387FA27FA238FE1F80A211177F9614>75 +D<B4FCA21238AF1307A4B5FCA210177E9614>I<38FC1F80A2007C1300EA7637A4EA7777 +A2EA7367A313E7EA71C7A2EA7007A638F80F80A211177F9614>I<38FE3F80A2383E0E00 +123BA4138E1239A213CEA31238A213EE136EA4133E12FEA211177F9614>I<EA1FF0EA7F +FCEA783CEA701CEAE00EAFEA701CEA783CEA7FFCEA1FF00F177E9614>I<EAFFF013FCEA +381E130E1307A5130E131EEA3FFC13F0EA3800A812FEA210177F9614>I<EAFFE013F8EA +383C131C7FA45B133CEA3FF85BEA38387FA51480EB1DC0A238FE0F80EB070012177F9614 +>82 D<EA0FCCEA1FFCEA307CEA603CEAE01CA313001270127EEA3FE0EA0FF0EA01F8EA00 +1C131E130E126012E0A2EAF01CEAF838EAFFF0EAC7E00F177E9614>I<387FFF80B5FCEA +E1C3A43801C000AFEA0FF8A211177F9614>I<38FE0FE0A238380380B0381C0700A2EA0E +0EEA07FCEA01F01317809614>I<38FC1F80A238380E00A3EA3C1EEA1C1CA46C5AA4EA06 +30EA0770A3EA0360A213E0A26C5A11177F9614>I<38FC1F80A238700700A7EA31C6EA33 +E6EA3BEE136EA5EA1B6CA2EA1A2CEA1E3CA311177F9614>I<38FC1F80A238380E00EA3C +1EEA1C1CEA1E3CEA0E38A26C5AA2EA036013E0A26C5AA8EA07F0A211177F9614>89 +D<EA7FFE12FFEAE01CA21338A2EA007013E0A2EA01C0A2EA0380EA0700A2120EA25AEA38 +0EA21270A2EAFFFEA20F177E9614>I<EAFFE0A2EAE000B3A7EAFFE0A20B1D799914>I<12 +04121FEA7FC0EAF1E012E00B057C9614>94 D<EA1FC0EA7FF0EA7078EA2018EA001CA2EA +07FC121FEA3C1C127012E0A3EA707C383FFF80EA0F8F11107E8F14>97 +D<12FCA2121CA513F8EA1DFEEA1F07EA1E03001C1380EB01C0A6EB0380001E1300EA1F0E +EA1DFCEA0CF81217809614>I<EA03F8EA0FFEEA1C0EEA3804EA7000126012E0A4126012 +70EA380EEA1C1EEA0FFCEA03F00F107E8F14>I<137EA2130EA5EA07CEEA0FFEEA1C3EEA +301EEA700E12E0A61270EA301EEA383E381FEFC0EA07CF12177F9614>I<EA07E0EA0FF0 +EA1C38EA301CEA700CEAE00EA2EAFFFEA2EAE00012601270EA380EEA1C1EEA0FFCEA03F0 +0F107E8F14>I<13FCEA01FEEA038EEA07041300A3EA7FFE12FFEA0700ACEAFFF8A20F17 +7F9614>I<EA07CF381FFF80EA383B38301800EA701CA3EA3018EA3838EA3FF0EA37C000 +70C7FCA2EA3FF86C7E487EEA700F38E00380A438700700EA3C1EEA1FFCEA07F011197F8F +14>I<12FCA2121CA51378EA1DFEEA1F86EA1E07121CAA38FF8FE0A21317809614>I<1206 +120FA21206C7FCA4B4FCA21207ACEAFFF8A20D187C9714>I<136013F0A213601300A4EA +1FF0A2EA0070B2EA40E0EAE0C0EA7F80EA3F000C207E9714>I<12FCA2121CA5EBFF80A2 +EB1C005B5B5BEA1DC0EA1FE0A2EA1E70EA1C38133C131C7F38FF1F80A21117809614>I< +EAFF80A21203B3EAFFFEA20F177E9614>I<EAFB8EEAFFDF383CF380A2EA38E3AA38FEFB +E013791310808F14>I<EAFC78EAFDFEEA1F86EA1E07121CAA38FF8FE0A21310808F14>I< +EA07C0EA1FF0EA3C78EA701CA2EAE00EA6EA701CEA783CEA3C78EA1FF0EA07C00F107E8F +14>I<EAFCF8EAFDFEEA1F07EA1E03001C1380EB01C0A6EB0380001E1300EA1F0EEA1DFC +EA1CF890C7FCA6B47EA21218808F14>I<EA03E7EA0FF7EA1C1FEA300F1270487EA6EA70 +0F1230EA1C3FEA0FF7EA07C7EA0007A6EB3FE0A213187F8F14>I<EAFE1FEB7F80EA0EE3 +380F810090C7FCA2120EA8EAFFF0A211107F8F14>I<EA0FD8EA3FF8EA603812C0A2EAF0 +00EA7F80EA3FF0EA07F8EA001CEA600612E012F0EAF81CEAFFF8EACFE00F107E8F14>I< +1206120EA4EA7FFC12FFEA0E00A8130EA3131CEA07F8EA01F00F157F9414>I<EAFC3FA2 +EA1C07AB131F380FFFE0EA03E71310808F14>I<38FE3F80A2383C1E00EA1C1CA36C5AA3 +EA0630EA0770A36C5AA311107F8F14>I<38FE3F80A238700700EA380EA3EA39CEA3EA1B +6C121AA3EA1E7CA2EA0E3811107F8F14>I<EA7E3FA2EA1E3CEA0E78EA07705B12036C5A +12037FEA0770EA0E781338487E38FE3F80A211107F8F14>I<38FE3F80A2381C0E005BA2 +120E5BA212071330A2EA0370A25B1201A25BA3485A12730077C7FC127E123C11187F8F14 +>I<EA3FFF5AEA700E131C1338EA007013E0EA01C0EA0380EA0700120EEA1C0712381270 +B5FCA210107F8F14>I<EA1C10EA3F38EAE7E0EA41C00D047D9614>126 +D E /Ff 51 122 df<903907FC0FE090393FFF3FF89039FC03FC783A03F007F0FC3807E0 +0F15E0D80FC0147802071300A7B71280A23A0FC007E000B3A239FFFC7FFFA226267FA524 +>11 D<EB07FCEB3FFF9038FE0780D803F013C03807E00FA2EA0FC0A3EC030091C7FCA3EC +7FE0B6FCA2380FC007B3A239FFFC7FFEA21F267FA522>I<123C127E12FFA4127E123C08 +087C8711>46 D<131C133C13FC12FFA21200B3AA387FFFFCA216237CA21F>49 +D<48B4FC000713C0381E07F0383803F8386001FC387C00FE12FE14FF147FA2127C003813 +FFC7FC14FEA2EB01FC14F8EB03F0EB07E01480EB0F00131E5B1370EBE003EA01C0380380 +07380700061206380FFFFE5A5A4813FCB5FCA218237DA21F>I<48B4FC000713E0381E03 +F0383801F8003C13FC387E00FEA3123EEA1C01000013FCA2EB03F8EB07F0EB0FC03801FF +00A2380007E0EB01F014F8EB00FC14FE14FFA21210127C12FEA214FEA2387C01FC007013 +F8383E07F0380FFFC00001130018237DA21F>I<14381478A214F8130113031307130613 +0C131C13381330136013E0EA01C01380EA03005A120E5A12185A12705AB612C0A2390001 +F800A790387FFFC0A21A237EA21F>I<0018130C001F137CEBFFF814F014E014C01480EB +FC000018C7FCA513FF001B13E0381F03F0381C00F8000813FCC7127EA3147FA2127812FC +A3147E5A006013FC1270383801F8381E07E03807FFC03801FE0018237DA21F>I<EB1FC0 +EB7FF03801F0383803E00C3807803E000F137EEA1F005AA2007E133C1400A338FE3FC0EB +7FF0EB80F800FF13FCEB007C147E5A147FA4127EA4003E137E123F6C137C380F80F83807 +C1F03803FFC038007F0018237DA21F>I<1230123C003FB512C0A215804814005C5C3860 +0018A200E05B485B5CC6485AA249C7FC1306130EA25BA2133CA25BA213F8A41201A66C5A +13601A257DA41F>I<EBFF80000313E0380F01F8381C007C48133C141E1278A2127C127E +387F803C13E0383FF878381FFDF0EBFFC07E000313E014F8000F13FCEA1E1F383C07FEEA +7803EB00FF48133F141F140FA3140E1278141C6C1338381F80F03807FFE0000113001823 +7DA21F>I<141CA2143EA3147FA24A7EA39038019FC0A29038031FE0140F01077FEB0607 +A2010C7F1403011C7FEB1801A2496C7EA2017FB5FCA29039E0007F8049133FA248488015 +1F00038190C7120FA2486E7ED8FFF090B51280A229257EA42E>65 +D<B612E015FC3903F0007FED3F80ED1FC0ED0FE0A216F0A21507150FA216E0151F16C0ED +7F80913801FE0090B512F815FF9039F0003FC0ED0FE0ED07F016F8150316FCA616F81507 +ED0FF0ED1FE0ED7FC0B7120015F826257EA42C>I<9138FF8008010FEBF01890393FC03C +789039FE0006F8D801F81303484813014848130048481478121F48481438A2007F151890 +C8FCA2481500A97E16187F123FA26C6C1430120F6C6C14606C6C14C06C6CEB0180D800FE +EB070090383FC01E90380FFFF8010013C025257DA42C>I<B612E015FC3903F800FFED1F +C0ED07E06F7E6F7E82150082A2167FA31780AA1700A316FEA24B5A5E4B5A4B5AED1FC0ED +FF80B648C7FC15E029257EA42F>I<B7FCA23903F8007FED0F8015071503A21501A3ED00 +C01406A21600A2140E141EEBFFFEA2EBF81E140E1406A21660A291C7FC16C0A415011503 +A2ED0F80153FB7FCA223257EA428>I<B612FEA23803F800151F8181A281A3ED01801403 +A292C7FCA25C5C90B5FCA2EBF80F8080A491C8FCAAB512F0A221257EA427>I<B500E0B5 +12E0A23B03F80003F800AF90B6FCA29038F80003B0B500E0B512E0A22B257EA430>72 +D<B512E0A23803F800B3AFB512E0A213257EA417>I<B539E007FF80A2D803F8C7EA7800 +16605E4B5A0307C7FC150E15185D5D5DEC03804AC8FC140E141F4A7E147FECDFC09038FB +8FE09038FF0FF0EBFC07496C7E816E7E1400157F82153F6F7E6F7E8215076F7E82B539E0 +3FFFC0A22A257EA430>75 D<B512F0A2D803F8C7FCB3A31503A31506A3150EA2151E153E +157CEC03FCB6FCA220257EA425>I<D8FFF8EDFFF86D5C0003EEFE00017EEC037EA36D14 +06A26D6C130CA26D6C1318A26D6C1330A36D6C1360A26D6C13C0A2903900FC0180A29138 +7E0300A3EC3F06A2EC1F8CA2EC0FD8A2EC07F0A36E5AEA07803CFFFC01C01FFFF8A23525 +7EA43A>I<D8FFF8903807FFE07FD803FE9038003C006D14187F6D7E6D7E806D7E6D7E13 +036D7E6D7E80EC7F80EC3FC0141FEC0FE015F0EC07F8EC03FC1401EC00FE157F1698ED3F +D8ED1FF8150F15071503A2150115001678486C1438D8FFFC1418A22B257EA430>I<B67E +15F83903F801FEEC007F6F7E6F7EA282A55EA24B5A4BC7FCEC01FE90B512F815C09038F8 +03F06E7E6E7E157EA2157FA482A31760ED3FC017C0ED1FE1B539E00FFF80923801FE002B +257EA42E>82 D<01FF1380000713E3380F80F7381E001F48130F481307140312F81401A2 +7E91C7FCB4FCEA7FE013FE383FFFE014F86C13FE00077F6C1480C67E010313C0EB003FEC +0FE01407A200C01303A315C07E6C13076C14806CEB0F0038FFC03E38E3FFF838803FE01B +257DA422>I<007FB612F8A2397E00FE010078EC00780070153800601518A200E0151C16 +0C5AA4C71400B3A390B512FEA226247EA32B>I<B53B81FFFE01FFF0A23D07F0001FC000 +0F007013066C6C010F5CA26F7E6C6C5EA26D496C1338000017304B7E017F01195CA29138 +8030FE013F5E829139C0607F01011F5E03E0138190280FE0C03F83C7FCA29139F1801FC3 +010715C617E69139FB000FEE010315EC02FF14FC6D486D5AA24A130301005DA24A130102 +785CA202306D5A3C257FA43F>87 D<B539C001FFE0A2D807F8C7EA1C006C6C141816386C +6C14306C6C5C16E06D6C5B6D6C485A1503D91FE090C7FC90380FF006150E903807F80C6D +6C5A15386D6C5A903800FF6015E06E5A6E5AAE90380FFFFCA22B257FA42E>89 +D<EA07FF001F13E0383E03F0383F00F880147E121EC7FCA3EB1FFE3803FE7EEA0FC0EA1F +00123E127E5AA314BEEA7E01383F073E391FFE1FE03807F00F1B187E971E>97 +D<EAFFC0A2120FACEBC1FCEBCFFF9038FC0FC09038F007E09038C003F0A2EC01F8A215FC +A815F8A2EC03F013E09038F007E090381C1F80390E0FFF00380C03F81E267FA522>I<EB +7FE03803FFF83807C07C381F80FC13005A007E1378140012FEA8127E127F6C130CEA1F80 +EBC0183807E0703803FFE038007F0016187E971B>I<ECFFC0A2140FAC137F3803FFCF38 +0FE0FF381F803F383F000FA2127EA212FEA8127EA27E141F381F803F380FC0EF3903FFCF +FC3800FE0F1E267EA522>I<137F3803FFC03807C1F0380F80F8EA1F0048137C127E147E +12FEA2B512FEA248C7FCA3127EA214067E6C130C380F80183807E0703803FFE038007F80 +17187E971C>I<EB1FC0EB7FF0EA01F83803E1F8120713C1380FC0F01400A7B5FCA2EA0F +C0B3A2EAFFFEA215267EA513>I<3901FF07C00007EBDFE0380F83F1EA1F01393E00F800 +007E7FA6003E5B6C485A380F83E0EBFFC0001190C7FC0030C8FCA21238123C383FFFE06C +13FC806C7F481480383C003F48EB0FC000F81307A4007CEB0F806CEB1F00381F807E3807 +FFF8C613C01B247E971F>I<EAFFC0A2120FAC14FE9038C3FF809038CE0FC013D89038D0 +07E013E0A213C0AF39FFFC7FFEA21F267EA522>I<120FEA1F80EA3FC0A4EA1F80EA0F00 +C7FCA7EA7FC0A2120FB3A2EAFFF8A20D277EA611>I<131E133FEB7F80A4EB3F00131E90 +C7FCA73801FF80A2EA001FB3A8127800FC13005B133EEA787CEA3FF8EA0FE0113283A613 +>I<EAFFC0A2120FACEC1FF0A2EC0780EC0E005C14305CEBC1C0EBC38013C713DFEBFFC0 +EBE7E0EBC3F0138180EB80FC147E80A2EC1F80EC0FC039FFF83FF8A21D267FA520>I<EA +FFC0A2120FB3B0EAFFFCA20E267EA511>I<26FF80FE137F903A83FF81FFC03B0F8E0FC7 +07E0019813CC903A9007E803F001A013F0A201C013E0AF3BFFFC7FFE3FFFA230187E9733 +>I<38FF80FE903883FF80390F8E0FC0139890389007E013A0A213C0AF39FFFC7FFEA21F +187E9722>I<EB7F803803FFF03807C0F8381F807E48487EA2007EEB1F80A200FE14C0A8 +007E1480A26CEB3F00A2381F807E6C6C5A3803FFF038007F801A187E971F>I<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 df<EB03E0EB1C181338EB703C13E014383801C000A5485A387FFFF03803 +8070A4380700E0A6380E01C0A6381C0380001E13C038FF0FF016207E9F19>12 +D<903803F03F90391E09E0809039380F80C09039701F01E0EBE03E021E13C02601C01CC7 +FCA548485A007FB612803903803803A43A0700700700A6000EEBE00EA64848485A001EEB +E01E3AFF8FF8FFC023207E9F26>14 D<EC0801EC1803A2EC3006A34A5AA24A5AA349485A +A349485A001FB612C04815E03A000C018000A24948C7FCA3EB3006A2495AB712806C1500 +26018030C7FCA348485AA200065BA348485AA34848C8FCA2EA100223297D9F26>35 +D<EAFFF0A20C027E8A0F>45 D<13181338EA01F8EA0E701200A513E0A6EA01C0A6EA0380 +A6EA07001380EAFFFC0E1E7B9D17>49 D<EB3F80EBC1E038010070000213785AA2000F13 +7C1380A2EB00781206C712F814F0EB01E014C0EB0380EB0700130E5B5B13605B485A3803 +00201206000813405A383FFFC0481380B5FC161E7E9D17>I<120E121FA2121E120C1200 +AA1230127812F81278127008147C930D>58 D<001FB512FE4814FFC9FCA8B612FC6C14F8 +200C7D9023>61 D<3807FF803800F8001378A25BA6485AA6485AA6485AA648C7FC7FEAFF +F0111F7E9E10>73 D<3A07FF803FE03A00F8001F000178130C5D4913205D5D4AC7FC1402 +140848485A5C146014F013E1EBE4F83803C878EBD07CEBE03CEBC03E141E141F48487E81 +140781140381380F00016D487E39FFF00FFE231F7E9E23>75 D<EB01FCEB0E0790383801 +C090387000E0484813F048481378485A153C48C7FC5A001E143E123E123C127CA448147C +A3157815F81278EC01F0007C14E01403003C14C0001CEB0780001EEB0F006C131E380780 +383801C0E038007F801F217C9F23>79 D<0007B5FC3900F803C090387800F015785B157C +A41578484813F815F0EC01E0EC03C0EC0F00EBFFFCD803C0C7FCA6485AA648C8FC7FEAFF +F81E1F7E9E1F>I<EB1F82EB7066EBC01E3801800EEA030048130C00061304120EA3000F +1300A27FEA07F013FF6C13C06C13E038003FF0EB03F813001478143CA200401338A31430 +00601370146000F013C038E8018038C60300EA81FC17217E9F19>83 +D<3A03FFC0FFC03A007F003E00013C1318013E1310011E5B011F5B6D5B0281C7FCEB0783 +14C2EB03C414E8EB01F0A2130080A2EB017CEB023CEB043EEB0C1EEB081F497E13200140 +7FEB8007000180EB0003000780391F8007F039FFC01FFE221F7F9E22>88 +D<EA07F8EA0C0CEA1E061307121C1200A313FFEA07C7EA1E07EA3C0E127800F01310A313 +1EEB2E2038784F40381F878014147D9317>97 D<1207123F120F7EA2120EA65A137CEA1D +83381E0180001C13C0EB00E05A14F0A5387001E0A214C013031480EB0700EAE80EEACC38 +EA83E014207B9F19>I<13FEEA0383380E0780121C0038130090C7FC12785AA45AA37E5B +EA70026C5AEA1C18EA07E011147D9314>I<1438EB01F8EB00781438A21470A614E013FC +EA0382EA0601121CEA3C00383801C0127812F0A438E00380A412F0EA700738380F00381C +37803807C7E015207D9F19>I<13F8EA070EEA0E07121C383803801278127012F0A2B5FC +00F0C7FC5AA46C5AEA7002EA3004EA1C18EA07E011147D9314>I<EB07C0EB1C60EB30F0 +1360EBE0E0EBC0001201A5485AEA3FFCEA0380A448C7FCA6120EA65A121EEAFFC014207F +9F0E>I<140EEB3E11EBE1A33801C1C2380381E0EA07801301120FA3380703C01480EB87 +00EA04FC48C7FCA21218121CEA0FFF14C014E0381800F04813305A5AA3006013606C13C0 +381C0700EA07FC181F809417>I<13E0120712011200A2485AA6485AEB8F80EB90E013A0 +EBC0601380000713E01300A5380E01C0A6381C0380001E13C038FF8FF014207E9F19>I< +EA01C0EA03E0A213C0EA0180C7FCA6EA0380121F12071203A2EA0700A6120EA65A121EEA +FF800B1F7F9E0C>I<EB0380EB07C0A21480EB030090C7FCA61307137F130F7FA2130EA6 +5BA65BA65B1260EAF0605BEA6180003FC7FC1228839E0E>I<13E0120712011200A2485A +A6485AEB81FCEB80F014C0EB81801400EA07045B13181338137C131C120E7FA2130F7F14 +80EA1C03381E07C038FF8FF016207E9F18>I<13E0120712011200A2EA01C0A6EA0380A6 +EA0700A6120EA65A121EEAFF800B207F9F0C>I<390387C07C391F9861863907A0720739 +03C03403EB80380007EB7807EB0070A5000EEBE00EA64848485A001EEBE01E3AFFCFFCFF +C022147E9326>I<38038F80381F90E0EA07A03803C0601380000713E01300A5380E01C0 +A6381C0380001E13C038FF8FF014147E9319>I<13FCEA0387380E0180381C00C04813E0 +A24813F012F0A438E001E0A214C0130300F0138038700700EA380E6C5AEA07E014147D93 +17>I<EBE3E03807EC383800F01C497E140F48487E1580A53903800F00A2140E141E141C +5C38074070EB61C0011FC7FC90C8FCA3120EA4121EEAFFC0191D809319>I<EBFC203803 +8260EA0702381E01E0123C003813C0127812F0A438E00380A212F0A21307127038380F00 +EA1C37EA07C7EA0007A3130EA4131EEBFFC0131D7D9318>I<EA038E381FB380EA07C712 +03EB8300EA078090C7FCA5120EA65A121EEAFFC011147E9312>I<EA01F9EA0607EA0803 +12181301EA3802EA3C00121F13F0EA07FCEA01FEEA001FEA40071303A212601306EAF004 +EAC818EA87E010147F9312>I<1380EA0100A35A5A5A121EEAFFF8EA0E00A45AA65A1310 +A41320A2EA1840EA0F800D1C7C9B12>I<381C0380EAFC1FEA3C07EA1C03A238380700A6 +EA700EA4131EA25BEA305E381F9F8011147B9319>I<38FF83F8381E00E0001C13C01480 +121E380E01005B13025B12075BA25BEA039013A013E05B5B120190C7FC15147C9318>I< +39FF9FE1FC393C078070391C030060148015401580EA0E0790380D81001309EB19C21311 +380F21C4EA0720EB40C814E8EB80F0A26C485A1460000213401E147C9321>I<381FF0FF +3803C0780001137014403800E0C0EBE180EB73001376133CA2131C132E134E1387EA0107 +380203801204380C01C0383C03E038FE07FC18147F9318>I<390FF83F803901E00E00EB +C00C140813E000005B143014205C13705CA20171C7FC1339133A133E133C133813181310 +A25BA25BEA70C0EAF08000F1C8FC12E61278191D809318>I E /Fh +44 122 df<EC3FF8903803FFFE90390FF80F8090393FC001C090397F0007E001FE130F00 +014A7E5B1203A26F5A6F5A0301C7FC92C8FCA5B712F0A33903FC001F150FB3A7267FFFE1 +B51280A329327FB12D>12 D<B512F8A715077F921B>45 D<EB01C01303130F137FEA1FFF +B5FC13BFEAE03F1200B3B1007FB512F0A31C2E7AAD28>49 D<EB3FE03801FFFE0007EBFF +80D80F8013C0391E003FE00038EB1FF0007CEB0FF8007EEB07FCB4FC018013FEA21403A2 +EA7F00003E1307C7FC15FCA2EC0FF8A215F0EC1FE015C0EC3F80EC7F00147E14F8495A49 +5A495A49C7FC011E130E5B133849131E49131C485A48C7123C48B512FC5A5A5A4814F8B6 +FCA31F2E7CAD28>I<EB1FF890B5FC000314C03907E01FF0390F0007F8D81F807FEA3FC0 +6E7EA4EA1F80380F0007C75BA25D4A5A4A5AEC3F8002FFC7FCEB3FF8ECFF809038001FE0 +6E7E6E7E6E7E816E7EA21680A3121C123E127FEAFF801600A24A5AEA7F00007E495A003C +5C391FC01FF06CB512C0000391C7FC38003FF8212E7DAD28>I<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 D<B712C016FC16FFD801FEC77FEE7FE0707E161F +707EA2831607A4160FA25FA24C5A4C5A4C5A4B485ADB1FFEC7FC90B65AEEFF8049C7EA3F +E0EE0FF0EE07FCA2707E83821880A718005E5F16074C5A4C5AEEFFF0B812C094C7FC16F8 +31317DB039>I<913A03FF800180023FEBF00349B5EAFC0701079038003F0FD91FF8EB07 +9FD93FC0EB01FFD9FF807F4848C8127F4848153F0007161F49150F485A001F1607A2485A +1703127FA24992C7FCA212FFA9127FA27FEF0380123FA26C7E1707000F17006C7E6D150E +0003161E6C6C151C6C6C6C1478D93FC05CD91FF8EB03E0D907FFEB3F800101D9FFFEC7FC +D9003F13F80203138031317CB03A>I<B812F0A3C6903880003FEE07F816031600A21778 +A21738A3171C1507A31700A25D5D5D91B5FCA3EC803F818181A21707A392C7120EA4171E +A2173CA2177C17FC16011607163FB812F8A330317EB035>69 D<B812E0A3C6903880007F +EE0FF016031601A21600A21770A31738A21507A21700A35D5D5D91B5FCA3EC803F818181 +A592C8FCACB612C0A32D317EB033>I<B6D8807FB512C0A3C60180C7387FC000B391B7FC +A30280C7127FB3A3B6D8807FB512C0A33A317EB03F>72 D<B61280A3C6EB8000B3B3A7B6 +1280A319317EB01E>I<017FB512C0A39039001FF000B3AF121C123E127FEAFF80A25D14 +3FD87F005B007E5C003C49C7FC381F01FE3807FFF8C613C022317DB02A>I<B6D88003B5 +FCA3C60180C7EA1F80051EC7FC5F5F5FEE01C0EE07804CC8FC161E5E5E16E0ED03C04B5A +4BC9FC151E153E157F5D02837F02877F91388F7FE0EC9E3F9138BC1FF002F07F4A6C7EEC +C0074A6C7E826F7F81707E83163F707E707E831607707E83707F8284B6D8801FEBFF80A3 +39317EB03F>I<B67EA3000190C9FCB3A9EE0380A416071700A25EA35E5E5E5E4B5A150F +B7FCA329317DB030>I<90391FF8018090B51203000314C73907F007EF390F8000FF48C7 +127F003E141F150F5A150712FCA215037EA26C91C7FC13C0EA7FF0EBFF806C13F8ECFF80 +6C14F06C806C806C14FFC6FC013F1480010114C0D9001F13E01401EC003FED1FF0150F15 +07126000E01403A316E07EA26CEC07C07EB4EC0F8001C0EB1F00D8FBFC13FE00F1B512F8 +D8E03F5BD8C003138024317CB02D>83 D<007FB8FCA39039C00FF801D87E00EC003F007C +82007882A200708200F01780A3481603A5C792C7FCB3AA017FB6FCA331307DAF38>I<B6 +D88003B51280A3C60180C73807C000715AB3AE137F4DC7FC80013F150EA26D6C5C6D6C5C +6D6C5C6D6C495A903A00FF801FC0023FB55A020F49C8FC020013E039317EB03E>I<B500 +FC91B5FCA3000390C8EA03C06C17806E14076C170080017F150EA26E141E013F151C6E14 +3C011F153880010F5D8001075DA26E130101035D6E13036D5D15806D4AC7FCA26F5A027F +130EEDE01E023F131CEDF03C021F133815F8020F5BA2EDFCF002075B15FF6E5BA26E5BA2 +6E90C8FCA3157EA2153CA238317EB03D>I<EBFFF0000313FF390F803F809038C00FE048 +6C6C7EA26E7ED80FC07FEA0780C7FCA414FF131FEBFFE33803FC03EA0FF0EA1FC0123FEA +7F80A2EAFF00A31407A2387F800D393FC01DFE3A1FE078FFF03907FFE07FC6EB803F2420 +7E9F27>97 D<EA01F812FFA3120F1207ADEC3FE0ECFFFC9038FBE07F9039FF001F8049EB +0FC04914E049EB07F016F8A2ED03FCA316FEA816FCA3ED07F8A216F06DEB0FE06D14C001 +E7EB3F809039C3C0FE00903880FFF89038003FC027327EB12D>I<EB0FFF017F13C03901 +FC01F03803F0033907E007F8120FEA1FC0003FEB03F0EC01E04848C7FCA312FFA8127FA3 +6C6C131CA2001F14386C7E000714703903F001E03901FC07C039007FFF00EB0FF81E207D +9F24>I<ED0FC0EC07FFA3EC007F153FADEB07F8EB3FFF9038FE07BF3903F801FF3907E0 +007F120F4848133F123FA2485AA312FFA8127FA36C7EA2121F6C6C137F000714FF2603F0 +0313E03A01FC0F3FFE38007FFEEB0FF027327DB12D>I<EB0FFC90387FFF803901FC0FC0 +3903F003E03907E001F0000F14F8391FC000FC003F14FEA24848137E157FA212FFA290B6 +FCA20180C7FCA4127FA36C6C1307121F150E6C7E6C6C131C6C6C13783900FE03E090383F +FFC0903807FE0020207E9F25>I<EB01FE90380FFF8090381FC3C090387F07E09038FE0F +F0120113FC1203EC07E0EC018091C7FCA8B512FCA3D803FCC7FCB3A8387FFFF0A31C327E +B119>I<90391FF007C09039FFFE3FE03A01F83F79F03907E00FC3000F14E19039C007E0 +E0001FECF000A2003F80A5001F5CA2000F5CEBE00F00075C2603F83FC7FC3806FFFE380E +1FF090C9FC121EA2121F7F90B57E6C14F015FC6C806C801680000F15C0003FC7127F007E +EC1FE0007C140F00FC1407A4007EEC0FC0003E1580003F141FD80FC0EB7E003907F803FC +0001B512F0D8001F90C7FC242F7E9F28>I<EA01F812FFA3120F1207ADEC07F8EC3FFEEC +783F02C013809039F9801FC0EBFB0001FE14E05BA35BB3B500C3B5FCA328327DB12D>I< +EA03C0487E487E487EA46C5A6C5A6C5AC8FCA9EA01F8127FA31207B3A7B51280A311337D +B217>I<EA01F812FFA3120F1207B3B3A6B512C0A312327DB117>108 +D<2703F007F8EB1FE000FFD93FFEEBFFF8913A783F01E0FC02C090388300FE280FF1801F +C6137F2607F30013CC01F602F8148001FC5CA3495CB3B500C3B5380FFFFCA33E207D9F43 +>I<3903F007F800FFEB3FFEEC783F02C013803A0FF1801FC03807F30001F614E013FCA3 +5BB3B500C3B5FCA328207D9F2D>I<EB07FC90387FFFC03901FC07F03903F001F848486C +7E4848137E001F147F003F158049133F007F15C0A300FF15E0A8007F15C0A36C6CEB7F80 +A2001F15006C6C13FE00075C3903F803F83901FE0FF039007FFFC0D907FCC7FC23207E9F +28>I<3901F83FE000FFEBFFFC9038FBE07F9039FF003F80D807FEEB1FC049EB0FE04914 +F0ED07F8A216FC1503A216FEA816FC1507A216F8A2ED0FF06D14E06DEB1FC06DEB3F8090 +39FBC0FE009038F8FFF8EC3FC091C8FCABB512C0A3272E7E9F2D>I<3803F03F00FFEB7F +C09038F1C3E01487390FF30FF0EA07F6A29038FC07E0EC03C091C7FCA25BB2B512E0A31C +207E9F21>114 D<3801FF86000713FEEA1F00003C133E48131E140E12F8A36C90C7FCB4 +7E13FC387FFFC06C13F0806C7F00077F00017FEA003F01001380143F0060131F00E0130F +A27E15007E6C131E6C131C38FF807838F3FFF038C07F8019207D9F20>I<131CA5133CA3 +137CA213FC120112031207381FFFFEB5FCA2D803FCC7FCB0EC0380A71201EC0700EA00FE +EB7F0EEB3FFCEB07F0192E7FAD1F>I<D801F8EB07E000FFEB03FFA3000FEB003F000714 +1FB3153FA20003147FA26C6CEBDFF03A00FE039FFF90387FFF1FEB0FFC28207D9F2D>I< +B5EB1FFCA3D80FF8EB03C0000715806D1307000315007F0001140E7F6C5CA2EC803C017F +1338ECC078013F1370ECE0F0011F5B14F1010F5B14F9903807FB80A214FF6D90C7FCA26D +5AA26D5AA21478A226207E9F2B>I<3A7FFF807FFCA33A03FC000F006C6C131E6C6C5BEC +803890387FC078013F5B90381FE1E090380FF3C0ECFF806D90C7FC6D5A13016D7E81815B +903803DFE09038078FF08190380F07FC90381E03FEEB3C01496C7E4914804848EB7FC000 +03EC3FE026FFFC01B5FCA328207F9F2B>120 D<B5EB1FFCA3D80FF8EB03C0000715806D +1307000315007F0001140E7F6C5CA2EC803C017F1338ECC078013F1370ECE0F0011F5B14 +F1010F5B14F9903807FB80A214FF6D90C7FCA26D5AA26D5AA21478A21470A214F05C1301 +007C5BEAFE035C49C8FC5BEAFC1EEA787CEA3FF0EA0FC0262E7E9F2B>I +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 D<B51280A611067F9016>I<121C127FA2EAFF80A3EA7F00A2121C09097B +8813>I<130E131E137EEA07FE12FFA212F81200B3ABB512FEA317277BA622>49 +D<EBFF80000713F04813FC381E03FE393800FF80007C133F00FE14C06C131F15E0140FA2 +127E003C131FC7FC15C0A2EC3F801500147E5C5C495A495AEB078049C7FC131E4913E013 +705B3901C001C0EA0380EA0600000FB5FC5A5A5AB61280A31B277DA622>I<EB7F803803 +FFF04813FC380F81FE381F007FEA3F80EC3F80A3121F1300C7EA7F00A2147E5C495AEB07 +F0EBFFC0A2EB01F8EB007E801580EC1FC0A215E0A2123C127EB4FCA215C0143F48148000 +7CEB7F00383F01FE6CB45A000713F0C613801B277DA622>I<140FA25C5C5C5C5BA2EB03 +BFEB073F130E131C133C1338137013E0EA01C0EA038012071300120E5A5A5A12F0B612F8 +A3C7EA7F00A890381FFFF8A31D277EA622>I<00181303381F801FEBFFFE5C5C5C14C091 +C7FC001CC8FCA7EB7FC0381DFFF8381F80FC381E003F1208C7EA1F8015C0A215E0A21218 +127C12FEA315C05A0078EB3F80A26CEB7F00381F01FE6CB45A000313F0C613801B277DA6 +22>I<EB07F8EB3FFE90B5FC3901FC07803903F00FC03807C01FEA0F80121F130048EB0F +8091C7FC127EA3EAFE02EB1FF0EB3FFCEB603EEB801F00FF14809038000FC0A24814E0A4 +127EA4123E003F14C07EEC1F80D80F8013003807E07E6CB45A6C5B38003FC01B277DA622 +>I<1238123E003FB512F0A34814E015C0158015003870000EA25C485B5C5CC6485AA249 +5A130791C7FC5B5B131E133EA2137E137CA213FCA41201A76C5A13701C297CA822>I<EB +3FC03801FFF04813FC3807C07E48C67E001E7FEC0F80123EA2123F138001C01300EBF01F +381FFC1E6D5A380FFFF86C13E06C7F6C13FC8000077FD80F0F1380D81E0713C0EA3E0139 +7C007FE0141F48130F14071403A315C0127C007EEB07806CEB0F00381FC03F380FFFFC00 +035B38007FC01B277DA622>I<EB7F803801FFF000077F380FC0FC381F803E48487E007E +1480A2140F00FE14C0A315E0A5007E131FA26C133F6C132F380F80CF3807FF8F0001130F +EA0008010013C0A3EC1F80123E127FEC3F00143E147E007E5B383E03F8381FFFE06C1380 +D801FEC7FC1B277DA622>I<121C127FA2EAFF80A3EA7F00A2121CC7FCA9121C127FA2EA +FF80A3EA7F00A2121C091B7B9A13>I<48B4FC000F13E0381E03F0383801F8387800FC00 +FC13FE7EA3127C003813FCEA0001EB03F8EB07E0EB0FC01480EB1E00A25B1338A25BA790 +C7FCA5137013F8487E487EA36C5A6C5A1370172A7CA920>63 D<EC0780A24A7EA34A7EA2 +4A7EA3EC77F8A2ECF7FC14E3A2903801C1FEA201037F1480A249486C7EA24980010E133F +A2496D7EA2013FB57EA39039700007F8A201F080491303000181491301A2000381D8FFFE +013F13FCA32E297EA833>65 D<B612F815FF16C03A03F8001FE0ED0FF0ED07F8150316FC +A21501A3150316F8A2ED07F0150FED1FC0EDFF8090B5EAFE00EDFFC09039F8000FF0ED03 +F8ED01FC16FE1500A216FFA616FE1501ED03FC1507ED1FF8B712E016C0EDFE0028297DA8 +30>I<91387FE003903907FFFC07011FEBFF0F90397FF00F9F9039FF0001FFD801FC7F48 +48147F4848143F4848141F485A160F485A1607127FA290C9FC5AA97E7F1607123FA26C7E +160E6C7E6C6C141C6C6C143C6C6C14786CB4EB01F090397FF007C0011FB512800107EBFE +009038007FF028297CA831>I<B612FCEDFF8016E03A03FC001FF8ED03FCED00FE167FEE +3F80EE1FC0A2EE0FE0A2EE07F0A417F8AA17F0A3EE0FE0A217C0161FEE3F80EE7F005EED +03FCED1FF8B75A168003FCC7FC2D297EA834>I<B712E0A33903FC001FED07F01501A215 +001670A3913801C0781638A302031300A2140F90B5FCA3EBFC0F1403A20201130EA3161C +91C7FCA3163C1638167816F815011503151FB712F0A327297EA82C>I<B712C0A33903FC +003FED0FE015031501A21500A316F0913801C070A316001403A2140F90B5FCA3EBFC0F14 +03A21401A491C8FCA9B512FCA324297EA82A>I<91387FE003903907FFFC07011FEBFF0F +90397FF00F9F9039FF0001FFD801FC7F484880484880484880485A82485A82127FA290CA +FC5AA892B512F87E7F03001300123FA26C7EA26C7E6C7E6C7E6C7E6CB45B90387FF00701 +1FB5129F0107EBFE0F9039007FF0032D297CA835>I<B5D8F00FB5FCA3D803FCC7EA3FC0 +AF90B7FCA301FCC7123FB1B5D8F00FB5FCA330297EA835>I<B512F0A33803FC00B3B1B5 +12F0A314297EA819>I<90B512F8A301001300B3A91218127EB4FCA35C387E01FC007C5B +383E07F0380FFFE0000390C7FC1D297EA823>I<B500F0EBFFFEA3D803FCC7EA0F00161E +5E5E16E0ED03C04B5A4BC7FC151E5D15F04A5A4A5A1407140F4A7EEC7FF04A7EEBFDE790 +38FFC3FCEC83FE9038FE01FF497E6F7E826F7E151F6F7E8215076F7E6F7E8281EE7F80B5 +39F00FFFFEA32F297EA835>I<B512FCA3D803FCC8FCB3A3ED01C0A415031680A21507A2 +150FA2151F157F913801FF00B7FCA322297EA828>I<D8FFFE92383FFF80A26D5D0003EF +E000A2D9BF8014EFA2D99FC0EB01CFA2D98FE0EB038FA3D987F0EB070FA2D983F8130EA2 +D981FC131CA3D980FE1338A2027F1370A291383F80E0A391381FC1C0A291380FE380A291 +3807F700A3EC03FEA26E5AA26E5AD8FFFE0203B51280A2157039297DA840>I<D8FFFCEC +7FFF7F7F00036DEB01C080EBBFE0139F80EB8FF8EB87FCEB83FEEB81FF01801380147F15 +C0EC3FE0EC1FF0EC0FF8EC07FC140315FEEC01FF6E1381ED7FC1ED3FE1ED1FF1150F16F9 +ED07FDED03FF8181167FA2163F161F160F1607D8FFFE14031601A230297EA835>I<ECFF +C0010F13FC90383F807F9039FE001FC0D801F8EB07E048486D7E48486D7E000F8148486D +7EA24848147FA2007F168090C8123FA34816C0AA6C16806D147FA2003F1600A26C6C14FE +A26C6C495A6C6C495A6C6C495A6C6C495A6C6C495A90263FC0FFC7FC90380FFFFC010013 +C02A297CA833>I<B612F815FF16C03A03FC003FE0ED07F0ED03F816FC150116FEA716FC +150316F8ED07F0ED3FE090B61280EDFE0001FCC8FCB0B512F0A327297EA82E>I<ECFFC0 +010F13FC90383FC0FF9039FE001FC048486D7ED803F0EB03F000078148486D7E48486D7E +A24848147FA2007F1680A290C8123FA24816C0AA6C16806D147FA2003F1600A26C6C14FE +143E3A0FE07F81FC00079038C1C1F83A03F18063F0D801F9EB67E0D800FFEB3FC090263F +C07FC7FC90380FFFFC01004913C0EC003C811601ED1F8316FF6F1380A21700816F5A6F5A +6F5A2A357CA833>I<B612E015FE6F7E3A03FC003FE0ED0FF06F7E6F7E150182A65E4B5A +1507ED0FE0ED3FC090B500FEC7FCA29039FC00FF80ED3FC06F7E6F7E6F7EA9170EA21503 +923801FC1CB538F000FEEE7FF8EE0FE02F297EA832>I<9038FF80600003EBF0E0000F13 +F8381F80FD383F001F003E1307481303A200FC1301A214007EA26C140013C0EA7FFCEBFF +E06C13F86C13FE80000714806C14C0C6FC010F13E0EB007FEC1FF0140F140700E01303A4 +6C14E0A26C13076C14C0B4EB0F80EBE03F39E3FFFE0000E15B38C01FF01C297CA825>I< +007FB71280A39039807F807FD87C00140F00781507A20070150300F016C0A2481501A5C7 +91C7FCB3A490B612C0A32A287EA72F>I<B500F0EBFFFEA3D803FCC7EA0380B3AA0001ED +07007F0000150E137F6D143CD91FC05B90390FF003F06DB55A01001480DA1FFCC7FC2F29 +7EA834>I<B500F0EB7FFFA3D803FEC7EA01C00001ED0380A26D14076C16006E5B017F14 +0E80013F5CA26E133C011F14386E1378010F14708001075CA26D6C485AA2ECFE0301015C +ECFF076D91C7FC1587EC7F8EA215DEEC3FDC15FC6E5AA26E5AA36E5AA26E5AA230297FA8 +33>I<B53CE07FFFE01FFFC0A32803FC0003FCC7EA7000A26D6D7E000160A26D6E13016C +604B138002801503017F5F4B13C0D93FC0013F49C7FCA2913AE00E1FE00F011F160E17F0 +9126F01C0F131E010F161C033C13F8902707F838075BA2037813FC902703FC70035BA291 +3AFEE001FEF001015E02FF14FF4B7E6D5EA26E486D5AA36EC76CC8FCA2023E80021E141E +A242297FA845>I<B500F0EB3FFFA3D803FEC7EA03C06C6C15806C6DEB07005E6D6C130E +6E5B013F143C6D6C13386E5B010F14F06D6C5B6E485A01031303D901FF5B0387C7FC6D13 +8FEC7FCE15FC143F6E5A5D140FAE0103B512C0A330297FA833>89 +D<EAFFE0A4EAF000B3B3B0EAFFE0A40B3C7AAC13>91 D<3803FF80000F13F0381F01FC38 +3F80FE147F801580EA1F00C7FCA4EB3FFF3801FC3FEA0FE0EA1F80EA3F00127E5AA4145F +007E13DF393F839FFC381FFE0F3803FC031E1B7E9A21>97 D<EAFFE0A3120FACEBE1FE90 +38EFFF809038FE07E09038F803F09038F001F89038E000FCA2157EA2157FA8157EA315FC +A29038F001F89038F803F090389C0FE090380FFF80390E01FC00202A7EA925>I<EB3FF0 +3801FFFC3803F03E380FC07FEA1F80EA3F00A248133E007E90C7FCA212FEA7127EA2127F +6CEB03801380001FEB0700380FE00E3803F83C3801FFF838003FC0191B7E9A1E>I<EC7F +F0A31407ACEB3F873801FFF73807F03F380FC00F381F8007EA3F00A2127EA312FEA8127E +A27EA2381F800F380FC01F3907E07FFF3801FFE738007F87202A7EA925>I<EB3FC03801 +FFF03803E07C380F803E001F7F130048EB0F80127E15C0A200FE1307A2B6FCA248C8FCA3 +127EA2127F6CEB01C07E390F8003803907C007003803F01E3800FFFCEB3FE01A1B7E9A1F +>I<EB07F8EB3FFCEB7E3E3801FC7FEA03F813F01207143E1400A7B512C0A33807F000B3 +A3387FFF80A3182A7EA915>I<9038FF80F00003EBE3F8390FC1FE1C391F007C7C48137E +003EEB3E10007EEB3F00A6003E133E003F137E6C137C380FC1F8380BFFE00018138090C8 +FC1238A2123C383FFFF814FF6C14C06C14E06C14F0121F383C0007007CEB01F8481300A4 +007CEB01F0A2003FEB07E0390FC01F806CB5120038007FF01E287E9A22>I<EAFFE0A312 +0FAC147E9038E1FF809038E30FC001E413E0EBE80701F813F013F0A213E0B039FFFE3FFF +A3202A7DA925>I<1207EA0F80EA1FC0EA3FE0A3EA1FC0EA0F80EA0700C7FCA7EAFFE0A3 +120FB3A3EAFFFEA30F2B7EAA12>I<EAFFE0A3120FACEC1FFCA3EC0780EC0F00141E5C5C +14E0EBE3C013E7EBEFE0EBFFF08013F3EBE1FCEBC0FE147FA2EC3F80EC1FC0EC0FE0A2EC +07F039FFFC1FFFA3202A7FA923>107 D<EAFFE0A3120FB3B2EAFFFEA30F2A7EA912>I<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 +D<EA4010EAE038EAF078EAE038AAEA60300D0E7B9C18>I<EA0306EA078FA6387FFFC0B5 +12E0A26C13C0380F1E00A6387FFFC0B512E0A26C13C0381E3C00A6EA0C18131C7E9B18> +I<13C01201A3EA03F0EA0FFCEA3FFEEA7DCFEA71C738E1C38013C7A338F1C0001279123F +6C7EEA0FF8EA01FC13DE13CF13C73861C38012F1A212E1EBC7001271EA79DEEA3FFEEA1F +F8EA07E0EA01C0A3120011247D9F18>I<EA3803387C0780A2EAEE0F1400A25B131EA213 +3EEA7C3CA2EA387CEA0078A213F85B12015BA212035BA21207EB8380EB87C0120FEB0EE0 +A2121F121EA2123E383C07C0A23818038013247E9F18>I<EA01C0EA07E0487EEA0E7048 +7EA4EB73F813F313E3380FC1C0EBC38013831303381F0700EA3F87EA7B8EEA71CEEAE1FC +12E0137CEB7870A2EA70FE387FFFE0EA3FC7380F03C0151C7F9B18>I<1238127CA2127E +123E120EA3121CA2123812F812F012C0070E789B18>I<137013F0EA01E0EA03C0EA0780 +EA0F00121E121C5AA25AA45AA81270A47EA27E121E7EEA0780EA03C0EA01F0120013700C +24799F18>I<126012F012787E7E7EEA07801203EA01C0A2EA00E0A41370A813E0A4EA01 +C0A2EA03801207EA0F00121E5A5A5A12600C247C9F18>I<EA01C0A4EA41C138F1C780EA +FDDF387FFF00EA1FFCEA07F0A2EA1FFCEA7FFF38FDDF80EAF1C73841C100EA01C0A41114 +7D9718>I<136013F0A7387FFFC0B512E0A26C13C03800F000A7136013147E9718>I<121C +123E127E127F123F121F1207120E121E127C12F81260080C788518>I<387FFFC0B512E0 +A26C13C013047E8F18>I<1230127812FCA2127812300606778518>I<1303EB0780A2130F +14005B131EA2133E133C137C1378A213F85B12015B12035BA212075B120F90C7FCA25A12 +1E123E123CA2127C127812F85AA2126011247D9F18>I<EA01F0EA07FC487EEA1F1FEA1C +0738380380007813C0EA7001A238E000E0A9EAF001007013C0A2EA780300381380381C07 +00EA1F1FEA0FFE6C5AEA01F0131C7E9B18>I<EA01801203A21207120F123F12FF12FB12 +431203B0EA7FFCEAFFFEEA7FFC0F1C7B9B18>I<EA03F0EA0FFEEA3FFF387C0F80387003 +C0EAE00138F000E0A21260C7FCA2EB01C0A21303EB0780EB0F00131E5B5B5B485AEA07C0 +485A381E00E05AEA7FFFB5FC7E131C7E9B18>I<EA07F8EA1FFE487E38780780EB03C013 +0112301200EB0380A2EB0F00EA03FF5B7F38000780EB03C01301EB00E0A312F0A2EB01C0 +1303387C0780383FFF006C5AEA03F8131C7E9B18>I<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>I<EA0FF0EA3FFC48B4FC +EA700F38F00380A2EA600738000F00133E5BEA01F05B485AA55BC8FCA5EA0380487EA36C +5A111C7D9B18>I<137CEA01FEEA07FF380F8780381E03C0EA3C1DEA387F3870FFE0EA71 +E313C112E1EAE380A638E1C1C0127113E33870FF8038387F00EA3C1C381E00E0EA0F8338 +07FFC00001138038007E00131C7E9B18>I<137013F8A213D8A2EA01DCA3138CEA038EA4 +EA0707A5380FFF80A3EA0E03381C01C0A3387F07F000FF13F8007F13F0151C7F9B18>I< +EA7FFCB5FC6C1380381C03C01301EB00E0A4130114C01307381FFF80140014C0EA1C03EB +00E014F01470A414F014E01303387FFFC0B51280387FFE00141C7F9B18>I<EBF8E0EA03 +FEEA07FFEA0F07EA1E03EA3C01EA38005AA214005AA8127014E0A27E123C381E01C0EA0F +073807FF803803FE00EA00F8131C7E9B18>I<EA7FF8EAFFFE6C7E381C0F80EB03C0A2EB +01E01300A214F01470A814F014E0A2130114C01303EB0F80387FFF00485AEA7FF8141C7F +9B18>I<B512F0A3381C0070A41400A2130EA3EA1FFEA3EA1C0EA390C7FCA21438A5B512 +F8A3151C7F9B18>I<B512F8A3381C0038A41400A21307A3EA1FFFA3EA1C07A390C7FCA7 +EAFFC0A3151C7F9B18>I<3801F1C0EA03FDEA0FFFEA1F0FEA1C03123813011270A290C7 +FC5AA5EB0FF0131F130F387001C0A213031238A2EA1C07EA1F0FEA0FFFEA03FDEA01F114 +1C7E9B18>I<387F07F038FF8FF8387F07F0381C01C0A9EA1FFFA3EA1C01AA387F07F038 +FF8FF8387F07F0151C7F9B18>I<EA7FFFB512806C1300EA01C0B3A4EA7FFFB512806C13 +00111C7D9B18>I<387F07F038FF87F8387F07F0381C03C0EB07801400130E131E5B1338 +5B13F0121DA2EA1FB8A2131C121EEA1C0EA27FA2EB0380A2EB01C0387F03F038FF87F838 +7F03F0151C7F9B18>75 D<EAFFC0A3001CC7FCB114E0A5B5FCA3131C7E9B18>I<38FC01 +F8EAFE03A2383B06E0A4138EA2EA398CA213DCA3EA38D8A213F81370A21300A638FE03F8 +A3151C7F9B18>I<387E07F038FF0FF8387F07F0381D81C0A313C1121CA213E1A3136113 +71A213311339A31319A2131D130DA3EA7F07EAFF87EA7F03151C7F9B18>I<EA0FFE383F +FF804813C0EA7803EA700100F013E0EAE000B0EAF001007013C0EA7C07EA7FFF6C138038 +0FFE00131C7E9B18>I<EAFFFEEBFF8014C0EA1C03EB01E013001470A514E01301EB03C0 +EA1FFF1480EBFE00001CC7FCA8B47EA3141C7F9B18>I<EA0FFE383FFF804813C0EA7803 +EA700100F013E0EAE000AE1370A2EAF079387039C0EA783FEA7FFF6C1380380FFE00EA00 +0FEB0780A2EB03C01301A213227E9B18>I<EA7FF8EAFFFE6C7E381C0F80130314C01301 +A313031480130F381FFF005BA2EA1C0F7FEB0380A5149CA3387F01F8EAFF81387F00F016 +1C7F9B18>I<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>I<EAFFF8A3EAE000B3ACEAFFF8A3 +0D24779F18>I<126012F0A27E1278127C123CA2123E121E121F7EA27F12077F1203A27F +12017F12007F1378A2137C133C133E131EA2131F7F14801307A2EB030011247D9F18>I< +EAFFF8A3EA0038B3ACEAFFF8A30D247F9F18>I<EA0180EA07C0EA1FF0EA7EFCEAF83EEA +E00E0F067C9B18>I<387FFFC0B512E0A26C13C013047E7F18>I<1206121E123E12381270 +A212E0A312F812FC127CA21238070E789E18>I<EA0FF0EA1FFC487EEA3C0FEA18073800 +0380A213FF1207121FEA7F03127812E0A3EAF007EA780F383FFFF8EA1FFDEA07F015147E +9318>I<127E12FE127E120EA5133EEBFF80000F13C0EBC1E01380EB0070120E1438A600 +0F1370A2EB80E013C1EBFFC0000E138038063E00151C809B18>I<EA01FEEA07FF001F13 +80EA3E073838030048C7FCA25AA61270EB01C01238EA3E03381FFF8000071300EA01FC12 +147D9318>I<EB1F80133F131F1303A5EA03E3EA0FFBEA1FFFEA3C1FEA380FEA70071303 +12E0A6EA7007A2EA380FEA3C1F381FFFF0380FFBF83803E3F0151C7E9B18>I<EA01F0EA +07FCEA1FFEEA3E0F38380780EA7003A238E001C0A2B5FCA300E0C7FC1270EB01C01238EA +3E07381FFF8000071300EA01F812147D9318>I<EB1F80EB7FC0EBFFE013E13801C0C014 +00A3387FFFC0B5FCA23801C000AEEA7FFFA3131C7F9B18>I<3801E1F03807FFF85A381E +1E30381C0E00487EA5EA1C0EEA1E1EEA1FFC5BEA39E00038C7FC7EEA1FFEEBFFC04813E0 +387801F038700070481338A4007813F0EA7E03381FFFC06C13803801FC00151F7F9318> +I<127E12FE127E120EA5133EEBFF80000F13C013C1EB80E01300120EAB387FC7FC38FFE7 +FE387FC7FC171C809B18>I<EA0380EA07C0A3EA0380C7FCA4EA7FC012FF127F1201AEB5 +FCA3101D7C9C18>I<1338137CA313381300A4EA0FFCA3EA001CB3A4EA6038EAF078EAFF +F0EA7FE0EA3F800E277E9C18>I<127E12FE127E120EA5EB3FF0A3EB0780EB0F00131E5B +5B5BEA0FF87F139C130EEA0E0F7FEB038014C0387FC7F812FF127F151C7F9B18>I<EAFF +C0A31201B3A4B51280A3111C7D9B18>I<38F9C1C038FFF7F013FF383E3E38EA3C3CA2EA +3838AB38FE3E3EEB7E7EEB3E3E1714809318>I<EA7E3E38FEFF80007F13C0EA0FC1EB80 +E01300120EAB387FC7FC38FFE7FE387FC7FC1714809318>I<EA01F0EA0FFE487E383E0F +80EA3803387001C0A238E000E0A5EAF001007013C0EA7803383C0780EA3E0F381FFF006C +5AEA01F013147E9318>I<EA7E3E38FEFF80007F13C0380FC1E01380EB0070120E1438A6 +000F1370A2EB80E013C1EBFFC0000E1380EB3E0090C7FCA7EA7FC0487E6C5A151E809318 +>I<3801F380EA07FBEA1FFFEA3E1FEA380FEA7007A2EAE003A6EA7007A2EA380FEA3C1F +EA1FFFEA0FFBEA03E3EA0003A7EB1FF0EB3FF8EB1FF0151E7E9318>I<38FF0FC0EB3FE0 +EB7FF0EA07F0EBE060EBC0005BA290C7FCA9EAFFFC7F5B14147E9318>I<EA07F7EA3FFF +5AEA780FEAE007A3007CC7FCEA7FE0EA1FFCEA03FEEA001F38600780EAE003A212F038F8 +0F00B5FC13FCEAE7F011147D9318>I<487E1203A4387FFFC0B5FCA238038000A9144014 +E0A33801C1C013FF6C1380EB3E0013197F9818>I<387E07E0EAFE0FEA7E07EA0E00AC13 +01EA0F033807FFFC6C13FE3801FCFC1714809318>I<387F8FF000FF13F8007F13F0381C +01C0380E0380A338070700A3138FEA038EA3EA01DCA3EA00F8A2137015147F9318>I<38 +FF07F8138F1307383800E0A4381C01C0137113F9A213D9EA1DDD000D1380A3138DEA0F8F +A23807070015147F9318>I<387F8FF0139F138F380F0700EA078EEA039EEA01DC13F812 +00137013F07FEA01DCEA039E138EEA0707000E1380387F8FF000FF13F8007F13F015147F +9318>I<387F8FF000FF13F8007F13F0380E01C0EB0380A21207EB0700A2EA0387A2138E +EA01CEA213CC120013DC1378A31370A313F05B1279EA7BC0EA7F806CC7FC121E151E7F93 +18>I<383FFFF05AA2387001E0EB03C0EB078038000F00131E5B13F8485AEA03C0485A38 +0F0070121E5A5AB512F0A314147F9318>I<EB07E0131F137FEB780013E0AB1201EA7FC0 +485AA26C7EEA01E01200AB1378EB7FE0131F130713247E9F18>I<126012F0B3B0126004 +24769F18>I<127CB4FC13C01203C67EAB7FEB7FC0EB3FE0A2EB7FC0EBF0005BABEA03C0 +12FF90C7FC127C13247E9F18>I<EA060CEA1F1EEA3FBEEAFBF8EAF1F0EA60C00F067C9B +18>I E /Fl 82 124 df<90381F83E09038F06E303901C07878380380F8903800F03048 +EB7000A7B612803907007000B2383FE3FF1D20809F1B>11 D<133FEBE0C0EA01C0380381 +E0EA0701A290C7FCA6B512E0EA0700B2383FC3FC1620809F19>I<EB3FE013E0EA01C1EA +0381EA0700A8B5FCEA0700B2383FE7FC1620809F19>I<90381F81F89038F04F043901C0 +7C06390380F80FEB00F05A0270C7FCA6B7FC3907007007B23A3FE3FE3FE02320809F26> +I<127012F8A71270AA1220A51200A5127012F8A3127005217CA00D>33 +D<EA7038EAF87CEAFC7EA2EA743AEA0402A3EA0804A2EA1008A2EA2010EA40200F0E7F9F +17>I<127012F812FCA212741204A31208A21210A212201240060E7C9F0D>39 +D<13401380EA01005A12061204120C5AA212381230A212701260A412E0AC1260A4127012 +30A212381218A27E120412067E7EEA008013400A2E7BA112>I<7E12407E12307E120812 +0C7EA212077EA213801201A413C0AC1380A412031300A25A1206A25A120812185A12205A +5A0A2E7EA112>I<127012F012F8A212781208A31210A31220A21240050E7C840D>44 +D<EAFFF0A20C02808A0F>I<127012F8A3127005057C840D>I<144014C0EB0180A3EB0300 +A31306A25BA35BA35BA25BA35BA3485AA348C7FCA21206A35AA35AA25AA35AA35AA2122D +7EA117>I<EA03F0EA0E1C487EEA1806EA380738700380A400F013C0AD00701380A3EA78 +0700381300EA1806EA1C0E6C5AEA03F0121F7E9D17>I<13801203120F12F31203B3A6EA +07C0EAFFFE0F1E7C9D17>I<EA03F0EA0C1CEA100E487E00401380128000F013C0EAF803 +A3EA200712001480A2EB0F00130E5B5B5B13605B485A48C7FC000613405A5A00101380EA +3FFF5AB5FC121E7E9D17>I<EA03F0EA0C1CEA100EEA200F007813801307A2EA380F1200 +1400A2131E131C1370EA07F0EA003C130E130FEB0780A214C0122012F8A300F013801240 +EB0F00EA200EEA183CEA07F0121F7E9D17>I<1306A2130EA2131E132EA2134E138EA2EA +010E1202A212041208A212101220A2124012C0B512F038000E00A7EBFFE0141E7F9D17> +I<EA1803EA1FFE5B5B13E00010C7FCA6EA11F0EA161CEA180EEA10071480EA0003A214C0 +A3127012F0A200E013801240EB0700EA20066C5AEA0838EA07E0121F7E9D17>I<137CEA +0182EA0701380E0380EA0C0712183838030090C7FC12781270A2EAF1F0EAF21CEAF406EA +F807EB0380A200F013C0A51270A214801238EB07001218EA0C0E6C5AEA01F0121F7E9D17 +>I<1240387FFFE014C0A23840008038800100A21302485AA25B5BA25BA21360A213E05B +1201A41203A76C5A131F7E9D17>I<EA03F0EA0C0CEA1006EA3003382001801260A31270 +38780300123EEA3F06EA1FC8EA0FF0EA03F8487EEA0C7EEA103F38300F80EA6007EB01C0 +12C01300A31480EA600100201300EA1002EA0C0CEA03F0121F7E9D17>I<EA03F0EA0E18 +487E487E13071270EB038012F0A214C0A5EA7007A21238EA180BEA0E13EA03E338000380 +A3EB07001230EA7806130EEA700CEA2018EA1070EA0FC0121F7E9D17>I<127012F8A312 +701200AA127012F8A3127005147C930D>I<127012F8A312701200AA127012F012F8A212 +781208A31210A31220A21240051D7C930D>I<EA0FE0EA103CEA601EEA400EEAE00F12F0 +A21260EA001E131C13381370136013C01380A2EA0100A6C7FCA5EA0380EA07C0A3EA0380 +10207E9F15>63 D<5B497EA3497EA3EB09E0A3EB10F0A3EB2078A3497EA2EBC03EEB801E +A248B5FCEB000FA20002EB0780A348EB03C0A2120C001E14E039FF801FFE1F207F9F22> +65 D<B512E0380F0078141EA2801580A515005C141E147CEBFFF0EB007C141FEC0F80EC +07C0140315E0A515C014071580EC0F00143EB512F01B1F7E9E20>I<90380FE010903838 +1C309038E002703803C00139078000F048C71270121E15305A1510127C127800F81400A9 +1278007C1410123CA26C1420A27E6C6C13406C6C13803900E00300EB380CEB0FF01C217E +9F21>I<B512F83807801EEC0780EC03C0EC01E0EC00F015701578A2153CA3153EA8153C +A2157C1578A215F0EC01E0EC03C0EC0780EC1E00B512F81F1F7F9E23>I<B61280380F00 +0F14031401140015C01540A314401500A214C0130113FF130113001440A3EC0020A31540 +A315C01401EC0380140FB6FC1B1F7E9E1F>I<B61280380780071401A2140015C01540A4 +EC2000A3146014E013FF138014601420A391C7FCA87FEAFFFE1A1F7F9E1E>I<90380FE0 +109038381C309038E002703803C00139078000F048C71270121E15305A1510127C127800 +F81400A7EC3FFEEC01F000781300127C123CA27EA27E6C7E3903C001703900E002309038 +380C1090380FF0001F217E9F24>I<39FFF07FF8390F000780AD90B5FCEB0007AF39FFF0 +7FF81D1F7E9E22>I<EAFFF0EA0F00B3ABEAFFF00C1F7E9E10>I<3807FFC038003E00131E +B3A3122012F8A3EAF01CEA403CEA6038EA1070EA0FC012207F9E17>I<39FFF007FC390F +0003E0EC0180150014025C5C5C5C5C5C49C7FC5B497E130FEB13C0EB21E01341EB80F0EB +0078A28080A280EC0780A2EC03C015E015F039FFF01FFE1F1F7E9E23>I<EAFFF8EA0F80 +90C7FCB21402A414061404A2140C141C147CB512FC171F7E9E1C>I<B46CEB07FE000715 +C0A2D805C0130BA2D804E01313A301701323A26D1343A36D1383A290380E0103A3EB0702 +A3EB0384A2EB01C8A3EB00F0A21460121FD8FFE0EB7FFE271F7F9E2A>I<B4EB0FF8390F +8003E0EC0080EA0BC0EA09E0A2EA08F01378A27F7FA27FEB0780A2EB03C0EB01E0A2EB00 +F01478A2143C141EA2140F1407A214031401123E38FF80001D1F7E9E22>I<EB1FE0EB70 +383801C00E48487E39070003804814C0001EEB01E048EB00F0A2007C14F8A20078147800 +F8147CA900781478007C14F8A2003C14F0003E1301001E14E06CEB03C06C148039038007 +003801E01E38007038EB1FE01E217E9F23>I<B512E0380F007C141E80EC0780A215C0A4 +1580A2EC0F00141E147CEBFFE090C8FCAEEAFFF01A1F7E9E1F>I<EB1FE0EB70383801C0 +0E48487E39070003804814C0001EEB01E0003E14F0003C1300007C14F8A20078147800F8 +147CA900781478007C14F8A2003C14F0383E0781391E0841E0390F1023C0000714803903 +9017003801D01E3900783804EB1FF8EB001CEC0C0CEC0E1CEC0FF8A2140715F0EC01E01E +297E9F23>I<B57E380F00F0143C8080A21580A41500A2141E5C14F0EBFF80EB01C0EB00 +70A280143CA3143EA31504143F141FEC0F0839FFF00788C7EA01F01E207E9E21>I<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>I<EA0804 +EA1008EA2010A2EA4020A2EA8040A3EAB85CEAFC7EA2EA7C3EEA381C0F0E7A9F17>I<12 +FFA21203B3B3A512FFA2082D80A10D>I<120812101220A21240A21280A312B812FCA212 +7C1238060E7D9F0D>96 D<EA1FE0EA3030EA7818131CEA300E1200A313FEEA078EEA1E0E +1238127800F01310A3131E127838386720380F83C014147E9317>I<121C12FC121CAA13 +7CEA1D87381E0180EB00C0001C13E01470A21478A6147014F014E0001E13C0381A018038 +198700EA107C15207E9F19>I<EA01FCEA0706EA1C0F123813060078C7FC127012F0A612 +70127800381380A2381C0100EA0706EA01F811147F9314>I<EB01C0130F1301AAEA01F1 +EA070DEA0C03EA180112381278127012F0A61270A21238EA1803120CEA070D3801F1F815 +207F9F19>I<EA03F0EA0E1C487E487EA21270EB038012F0A2B5FC00F0C7FCA31270A26C +1380A2381C0100EA0706EA01F811147F9314>I<137CEA01C6EA030F1207EA0E061300A7 +EAFFF0EA0E00B2EA7FE01020809F0E>I<14E03803E330EA0E3CEA1C1C38380E00EA780F +A5EA380E6C5AEA1E38EA33E00020C7FCA21230A2EA3FFE381FFF8014C0383001E0386000 +70481330A4006013606C13C0381C03803803FC00141F7F9417>I<121C12FC121CAA137C +1386EA1D03001E1380A2121CAE38FF8FF014207E9F19>I<1238127CA31238C7FCA6121C +12FC121CB1EAFF80091F7F9E0C>I<13E0EA01F0A3EA00E01300A61370EA07F012001370 +B3A31260EAF06013C0EA6180EA3F000C28829E0E>I<121C12FC121CAAEB1FE0EB0780EB +060013045B5B5B136013E0EA1DF0EA1E70EA1C38133C131C7F130F7F148014C038FF9FF0 +14207E9F18>I<121C12FC121CB3ABEAFF8009207F9F0C>I<391C3E03E039FCC30C30391D +039038391E01E01CA2001C13C0AE3AFF8FF8FF8021147E9326>I<EA1C7CEAFC86EA1D03 +001E1380A2121CAE38FF8FF014147E9319>I<EA01F8EA070E381C0380383801C0A23870 +00E0A200F013F0A6007013E0A2383801C0A2381C038038070E00EA01F814147F9317>I< +EA1C7CEAFD87381E018014C0381C00E014F014701478A6147014F014E0381E01C0EB0380 +381D8700EA1C7C90C7FCA8B47E151D7E9319>I<3801F04038070CC0EA0E02EA1C03EA38 +011278127012F0A6127012781238EA1C03EA0C05EA0709EA01F1EA0001A8EB0FF8151D7F +9318>I<EA1CF0EAFD18EA1E3CA21318EA1C00AEEAFFC00E147E9312>I<EA0FC8EA3038EA +6018EAC008A3EAE000127CEA3FE0EA1FF0EA07F8EA003CEA800E130612C0A21304EAE00C +EAD818EA87E00F147F9312>I<1202A31206A2120EA2123EEAFFF8EA0E00AB1304A5EA07 +081203EA01F00E1C7F9B12>I<381C0380EAFC1FEA1C03AE1307120CEA061B3803E3F014 +147E9319>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382A2EA01C4 +A213E4EA00E8A21370A3132015147F9318>I<39FF9FE1FC393C078070391C030060EC80 +20000E1440A214C0D80704138014E0A239038861001471A23801D032143A143E3800E01C +A2EB6018EB40081E147F9321>I<38FF87F8381E03C0380E0180EB0300EA0702EA0384EA +01C813D8EA00F01370137813F8139CEA010E1202EA060738040380000C13C0003C13E038 +FE07FC16147F9318>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382 +A2EA01C4A213E4EA00E8A21370A31320A25BA3EAF080A200F1C7FC1262123C151D7F9318 +>I<EA7FFFEA700E1260EA401C133813781370EA00E0120113C0EA038012071301120E12 +1EEA1C03EA3802EA7006130EEAFFFE10147F9314>I<B512FC1601808C17>I +E /Fm 9 118 df<B87E17F817FF8428007FE0000313E004007FEF3FF8717EA2717EA284 +83A64D5AA34D5A4D5A60EFFFE04C5B040F90C7FC91B612FCA2EFFF8002E0C713E0EF3FF8 +EF0FFC84717E711380A27113C0A219E0A819C05F19805F4D13004D5A4D5A4CB45AB95A18 +C095C7FC17F03B3B7CBA45>66 D<B912C0A43A007FF000079338007FE0173F170F1707A2 +1703A21701A418F0EE7800A41800A216F8A21501150791B5FCA4ECF00715011500A21678 +A693C8FCAEB612FEA4343B7CBA3D>70 D<EB3FFE48B512E0000714F8390FE007FC9038F0 +01FE486C6C7E6F7E82153F6C48806C5A6C5AC8FCA491B5FC131F90387FF83F3803FF8038 +07FC00EA0FF0485A123F485AA2485AA4157F6C7E15DF3A3FE0039FF03B1FF80F0FFFE038 +07FFFE0001497E39003FE0002B267DA52F>97 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 new file mode 100644 index 0000000..bc1d2b3 --- /dev/null +++ b/documentation/features.texi @@ -0,0 +1,1907 @@ +\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.3 b/documentation/readline.3 new file mode 100644 index 0000000..bbe9d91 --- /dev/null +++ b/documentation/readline.3 @@ -0,0 +1,1216 @@ +.\" +.\" MAN PAGE COMMENTS to +.\" +.\" Chet Ramey +.\" Information Network Services +.\" Case Western Reserve University +.\" chet@ins.CWRU.Edu +.\" +.\" Last Change: Wed Jul 20 16:13:11 EDT 1994 +.\" +.TH READLINE 3 "1994 July 26" GNU +.\" +.\" File Name macro. This used to be `.PN', for Path Name, +.\" but Sun doesn't seem to like that very much. +.\" +.de FN +\fI\|\\$1\|\fP +.. +.SH NAME +readline \- get a line from a user with editing +.SH SYNOPSIS +.LP +.nf +.ft B +#include <readline.h> +#include <history.h> +.ft +.fi +.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. +.SH DESCRIPTION +.LP +.B readline +will read a line from the terminal +and return it, using +.B prompt +as a prompt. If +.B prompt +is null, no prompt is issued. The line returned is allocated with +.IR malloc (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. +.LP +.B 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. +.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 +returns the text of the line read. A blank line +returns the empty string. If +.B EOF +is encountered while reading a line, and the line is empty, +.B NULL +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 +keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n +means Control\-N. Similarly, +.I meta +keys are denoted by M\-\fIkey\fR, so M\-x means Meta\-X. (On keyboards +without a +.I meta +key, M\-\fIx\fP means ESC \fIx\fP, i.e., press the Escape key +then the +.I x +key. This makes ESC the \fImeta prefix\fP. +The combination M\-C\-\fIx\fP means ESC\-Control\-\fIx\fP, +or press the Escape key +then hold the Control key while pressing the +.I x +key.) +.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. +.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 +.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. +Each program using this library may add its own commands +and bindings. +.PP +For example, placing +.RS +.PP +M\-Control\-u: universal\-argument +.RE +or +.RS +C\-Meta\-u: universal\-argument +.RE +into the +.FN ~/.inputrc +would make M\-C\-u execute the readline command +.IR universal\-argument . +.PP +The following symbolic character names are recognized while +processing key bindings: +.IR RUBOUT , +.IR DEL , +.IR ESC , +.IR LFD , +.IR NEWLINE , +.IR RET , +.IR RETURN , +.IR SPC , +.IR SPACE , +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 +.SS 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 +prefixes, or as a key sequence. +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 +.RS +Control\-u: universal\-argument +.br +Meta\-Rubout: backward\-kill\-word +.br +Control\-o: ">&output" +.RE +.LP +In the above example, +.I C\-u +is bound to the function +.BR universal\-argument , +.I M-DEL +is bound to the function +.BR backward\-kill\-word , +and +.I C\-o +is bound to run the macro +expressed on the right hand side (that is, to insert the text +.I >&output +into the line). +.PP +In the second form, \fB"keyseq"\fP:\fIfunction\-name\fP or \fImacro\fP, +.B keyseq +differs from +.B 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. +.sp +.RS +"\eC\-u": universal\-argument +.br +"\eC\-x\eC\-r": re\-read\-init\-file +.br +"\ee[11~": "Function Key 1" +.RE +.PP +In this example, +.I C-u +is again bound to the function +.BR universal\-argument . +.I "C-x C-r" +is bound to the function +.BR re\-read\-init\-file , +and +.I "ESC [ 1 1 ~" +is bound to insert the text +.BR "Function Key 1" . +The full set of escape sequences is +.RS +.TP +.B \eC- +control prefix +.TP +.B \eM- +meta prefix +.TP +.B \ee +an escape character +.TP +.B \e\e +backslash +.TP +.B \e" +literal " +.TP +.B \e' +literal ' +.RE +.PP +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 '. +.PP +.B Bash +allows the current readline key bindings to be displayed or modified +with the +.B bind +builtin command. The editing mode may be switched during interactive +use by using the +.B \-o +option to the +.B set +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 +any other means to incorporate new bindings. +.SS Variables +.PP +Readline has variables that can be used to further customize its +behavior. A variable may be set in the +.I inputrc +file with a statement of the form +.RS +.PP +\fBset\fP \fIvariable\-name\fP \fIvalue\fP +.RE +.PP +Except where noted, readline variables can take the values +.B On +or +.BR Off . +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 +\fBvisible\fP, readline uses a visible bell if one is available. +If set to \fBaudible\fP, readline attempts to ring the terminal's bell. +.TP +.B comment\-begin (``#'') +The string that is inserted in \fBvi\fP mode when the +.B vi\-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. +.TP +.B completion\-query\-items (100) +This determines when the user is queried about viewing +the number of possible completions +generated by the \fBpossible\-completions\fP 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. +.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 +.IR emacs ; +the value of +.B editing\-mode +also affects the default keymap. +.TP +.B show\-all\-if\-ambiguous (Off) +This alters the default behavior of the completion functions. If +set to +.BR on , +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. +.PD +.SS Conditional Constructs +.PP +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. +.IP \fB$if\fP +The +.B $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. +.RS +.IP \fBmode\fP +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 +readline is starting out in emacs mode. +.IP \fBterm\fP +The \fBterm=\fP 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 +.B = +is tested against the full name of the terminal and the portion +of the terminal name before the first \fB\-\fP. This allows +.I sun +to match both +.I sun +and +.IR sun\-cmd , +for instance. +.IP \fBapplication\fP +The \fBapplication\fP construct is used to include +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 +a specific program. For instance, the following command adds a +key sequence that quotes the current or previous word in Bash: +.RS +.nf +\fB$if\fP bash +# Quote the current or previous word +"\eC-xq": "\eeb\e"\eef\e"" +\fB$endif\fP +.fi +.RE +.RE +.IP \fB$endif\fP +This command, as you saw in the previous example, terminates an +\fB$if\fP command. +.IP \fB$else\fP +Commands in this branch of the \fB$if\fP directive are executed if +the test fails. +.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. +.SS Commands for Moving +.PP +.PD 0 +.TP +.B beginning\-of\-line (C\-a) +Move to the start of the current line. +.TP +.B end\-of\-line (C\-e) +Move to the end of the line. +.TP +.B forward\-char (C\-f) +Move forward a character. +.TP +.B backward\-char (C\-b) +Move back a character. +.TP +.B forward\-word (M\-f) +Move forward to the end of the next word. Words are composed of +alphanumeric characters (letters and digits). +.TP +.B backward\-word (M\-b) +Move back to the start of this, or the previous, word. Words are +composed of alphanumeric characters (letters and digits). +.TP +.B 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. +.TP +.B redraw\-current\-line +Refresh the current line. By default, this is unbound. +.PD +.SS Commands for Manipulating the History +.PP +.PD 0 +.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 +history line, then restore the history line to its original state. +.TP +.B previous\-history (C\-p) +Fetch the previous command from the history list, moving back in +the list. +.TP +.B next\-history (C\-n) +Fetch the next command from the history list, moving forward in the +list. +.TP +.B beginning\-of\-history (M\-<) +Move to the first line in the history. +.TP +.B end\-of\-history (M\->) +Move to the end of the input history, i.e., the line currently being +entered. +.TP +.B 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. +.TP +.B 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. +.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. +.TP +.B non\-incremental\-forward\-search\-history (M\-n) +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. +.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. +.TP +.B yank\-nth\-arg (M\-C\-y) +Insert the first argument to the previous command (usually +the second word on the previous line) at point (the current +cursor position). With an argument +.IR n , +insert the \fIn\fPth word from the previous command (the words +in the previous command begin with word 0). A negative argument +inserts the \fIn\fPth word from the end of the previous command. +.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. +.PD +.SS Commands for Changing Text +.PP +.PD 0 +.TP +.B 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 +.BR C\-d , +then return +.SM +.BR EOF . +.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. +.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 (M-TAB) +Insert a tab character. +.TP +.B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...) +Insert the character typed. +.TP +.B transpose\-chars (C\-t) +Drag the character before point forward over the character at point. +Point moves forward as well. If point is at the end of the line, then +transpose the two characters before point. Negative arguments don't work. +.TP +.B 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. +.TP +.B upcase\-word (M\-u) +Uppercase the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.TP +.B downcase\-word (M\-l) +Lowercase the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.TP +.B capitalize\-word (M\-c) +Capitalize the current (or following) word. With a negative argument, +do the previous word, but do not move point. +.PD +.SS Killing and Yanking +.PP +.PD 0 +.TP +.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 Rubout) +Kill backward to the beginning of the line. +.TP +.B unix\-line\-discard (C\-u) +Kill backward from point to the beginning of the line. +.\" There is no real difference between this and backward-kill-line +.TP +.B kill\-whole\-line +Kill all characters on the current line, no matter where the +cursor is. By default, this is unbound. +.TP +.B 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 \fBforward\-word\fP. +.TP +.B backward\-kill\-word (M\-Rubout) +Kill the word behind the cursor. Word boundaries are the same as +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 +.BR backward\-kill\-word . +.TP +.B delete\-horizontal\-space +Delete all spaces and tabs around point. By default, this is unbound. +.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 +.B yank +or +.BR yank\-pop . +.PD +.SS Numeric Arguments +.PP +.PD 0 +.TP +.B 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. +.TP +.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. +.PD +.SS Completing +.PP +.PD 0 +.TP +.B complete (TAB) +Attempt to perform completion on the text before point. +The actual completion performed is application-specific. +.BR Bash , +for instance, attempts completion treating the text as a variable +(if the text begins with \fB$\fP), username (if the text begins with +\fB~\fP), hostname (if the text begins with \fB@\fP), or +command (including aliases and functions) in turn. If none +of these produces a match, filename completion is attempted. +.BR Gdb , +on the other hand, +allows completion of program functions and variables, and +only attempts filename completion under certain circumstances. +.TP +.B possible\-completions (M-?) +List the possible completions of the text before point. +.TP +.B insert\-completions +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. +.PD +.SS Keyboard Macros +.PP +.PD 0 +.TP +.B start\-kbd\-macro (C-x (\^) +Begin saving the characters typed into the current keyboard macro. +.TP +.B end\-kbd\-macro (C-x )\^) +Stop saving the characters typed into the current keyboard macro +and save the definition. +.TP +.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 +.SS Miscellaneous +.PP +.PD 0 +.TP +.B 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. +.TP +.B abort (C\-g) +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. +.TP +.B prefix\-meta (ESC) +Metafy the next character typed. +.SM +.B ESC +.B f +is equivalent to +.BR Meta\-f . +.TP +.B undo (C\-_, C\-x C\-u) +Incremental undo, separately remembered for each line. +.TP +.B revert\-line (M\-r) +Undo all changes made to this line. This is like typing the +.B undo +command enough times to return the line to its initial state. +.TP +.B tilde\-expand (M\-~) +Perform tilde expansion on the current word. +.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 emacs\-editing\-mode (C\-e) +When in +.B vi +editing mode, this causes a switch to +.B emacs +editing mode. +.TP +.B vi\-editing\-mode (M\-C\-j) +When in +.B emacs +editing mode, this causes a switch to +.B vi +editing mode. +.PD +.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-<character>, and +are referred to as +.I metafied +characters. +The printable ASCII characters not mentioned in the list of emacs +standard bindings are bound to the +.I self\-insert +function, which just inserts the given character into the input line. +In vi insertion mode, all characters not specifically mentioned are +bound to +.IR self\-insert . +Characters assigned to signal generation by +.IR stty (1) +or the terminal driver, such as C-Z or C-C, +retain that function. +Upper and lower case +.I metafied +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 +.B bell\-style +variable). +.SS Emacs Mode +.RS +.6i +.nf +.ta 2.5i +.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 +.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 +.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 +.sp +.RE +.SS VI Mode bindings +.RS +.6i +.nf +.ta 2.5i +.sp +.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 +.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 +.RE +.SH "SEE ALSO" +.PD 0 +.TP +\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey +.TP +\fIThe Gnu History Library\fP, Brian Fox and Chet Ramey +.TP +\fIbash\fP(1) +.PD +.SH FILES +.PD 0 +.TP +.FN ~/.inputrc +Individual \fBreadline\fP initialization file +.PD +.SH AUTHORS +.RS +Brian Fox, Free Software Foundation (primary author) +.br +bfox@ai.MIT.Edu +.PP +Chet Ramey, Case Western Reserve University +.br +chet@ins.CWRU.Edu +.SH BUG REPORTS +If you find a bug in +.B 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 +.B readline +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. +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 +newsgroup +.BR gnu.bash.bug . +.PP +Comments and bug reports concerning +this manual page should be directed to +.IR chet@ins.CWRU.Edu . +.SH BUGS +.PP +It's too big and too slow. diff --git a/documentation/readline.ps b/documentation/readline.ps new file mode 100644 index 0000000..5e004b1 --- /dev/null +++ b/documentation/readline.ps @@ -0,0 +1,1052 @@ +%!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 <r)108 124.8 Q(eadline.h>)-.18 E +(#include <history)108 136.8 Q(.h>)-.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<ad>.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<ad72>.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 F1<ad6f>3.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 F2<ad>2.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-<character>, 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 new file mode 100644 index 0000000..653a984 --- /dev/null +++ b/documentation/readline.txt @@ -0,0 +1,1122 @@ + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + +NAME + readline - get a line from a user with editing + +SYNOPSIS + #include <readline.h> + #include <history.h> + + 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- + <character>, 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/documentation/texinfo.tex b/documentation/texinfo.tex new file mode 100644 index 0000000..ce8124e --- /dev/null +++ b/documentation/texinfo.tex @@ -0,0 +1,4003 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 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 +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +%USA. + + +%In other words, you are welcome to use, share and improve this program. +%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} +\message{Loading texinfo package [Version \texinfoversion]:} + +% Print the version number if in a .fmt file. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexdots=\dots +\let\ptexdot=\. +\let\ptexstar=\* +\let\ptexend=\end +\let\ptexbullet=\bullet +\let\ptexb=\b +\let\ptexc=\c +\let\ptexi=\i +\let\ptext=\t +\let\ptexl=\l +\let\ptexL=\L + +\def\tie{\penalty 10000\ } % Save plain tex definition of ~. + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset \bindingoffset=0pt +\newdimen \normaloffset \normaloffset=\hoffset +\newdimen\pagewidth \newdimen\pageheight +\pagewidth=\hsize \pageheight=\vsize + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% 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 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions itself, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{\hoffset=\normaloffset +\ifodd\pageno \advance\hoffset by \bindingoffset +\else \advance\hoffset by -\bindingoffset\fi +{\escapechar=`\\\relax % makes sure backslash is used in output files. +\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}% +{\let\hsize=\pagewidth \makefootline}}}% +\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% 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 + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% 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 (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = \baselineskip +\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 +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. + +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\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. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% 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 + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % 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.) 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. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % 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 + % + % 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 + % 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 + % manual), we don't worry about eating any user text. + \comment +} +% +% 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.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \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 + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. + +\def\include{\parsearg\includezzz} +%Use \input\thisfile to avoid blank after \input, which may be an active +%char (in which case the blank would become the \input argument). +%The grouping keeps the value of \thisfile correct even when @include +%is nested. +\def\includezzz #1{\begingroup +\def\thisfile{#1}\input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\par \vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% 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. +% +\def\ignoremorecommands{% + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \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 +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\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 + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% 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 + % command, so that nested ignore constructs work. Thus, we put the + % 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 + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % 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 + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @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 +% didn't need it. +% +\def\set{\parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi +} +\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @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 + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @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 + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @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} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% 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. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\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. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% 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} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\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. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\font\textrm=cmr12 +\font\texttt=cmtt12 +\else +\font\textrm=cmr10 scaled \mainmagstep +\font\texttt=cmtt10 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 +\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 +\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, +% 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 +\let\indsl=\indit +\let\indtt=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\let\indsc=\indrm +\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 +\let\chapbf=\chaprm +\font\chapsc=cmcsc10 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 +\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 + +%\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 + +%\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 +\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 +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% 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 + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% 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. +\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\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \resetmathfonts} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \resetmathfonts} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \resetmathfonts} +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy + \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 + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% 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}% + \null +} +\let\ttfont = \t +%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null} +\def\samp #1{`\tclose{#1}'\null} +\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% 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 \let_\codeunder \codex} +} +\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, +% then @kbd has no effect. + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else\tclose{\look}\fi +\else\tclose{\look}\fi} + +% 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\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \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 + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\par \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\par \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + {\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 + % line. We do not start a paragraph here because then if the next + % 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 + % + % 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 + \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}% + \fi + \endgroup +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\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\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Neccessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \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{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % 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 <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% 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 +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\t##1{\realbackslash r {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\def\doind #1#2{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% Expand all macros now EXCEPT \folio +\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now +% so it will be output as is; and it will print as backslash in the indx. +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}}}% +\temp }% +}\penalty\count10}} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{% + \tex + \dobreak \chapheadingskip {10000} + \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other + \catcode`\$=\other\catcode`\_=\other + \catcode`\~=\other + % + % The following don't help, since the chars were translated + % when the raw index was written, and their fonts were discarded + % due to \indexnofonts. + %\catcode`\"=\active + %\catcode`\^=\active + %\catcode`\_=\active + %\catcode`\|=\active + %\catcode`\<=\active + %\catcode`\>=\active + % % + \def\indexbackslash{\rawbackslashxx} + \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \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 + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns + \Etex +} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% 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 + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % 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 + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % 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. + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +%% Define two-column mode, which is used in indexes. +%% Adapted from the TeXbook, page 416. +\catcode `\@=11 + +\newbox\partialpage + +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % 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 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize + \doublecolumnpagegoal +} + +\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} + +\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth + \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage + \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} + \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} + \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi + \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi +} +\def\doublecolumnpagegoal{% + \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ +} +\def\pagesofar{\unvbox\partialpage % + \hsize=\doublecolumnhsize % have to restore this since output routine + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} +\def\doublecolumnout{% + \setbox5=\copy255 + {\vbadness=10000 \doublecolumnsplit} + \ifvbox255 + \setbox0=\vtop to\dimen@{\unvbox0} + \setbox2=\vtop to\dimen@{\unvbox2} + \onepageout\pagesofar \unvbox255 \penalty\outputpenalty + \else + \setbox0=\vbox{\unvbox5} + \ifvbox0 + \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip + \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth + {\vbadness=10000 + \loop \global\setbox5=\copy0 + \setbox1=\vsplit5 to\dimen@ + \setbox3=\vsplit5 to\dimen@ + \ifvbox5 \global\advance\dimen@ by1pt \repeat + \setbox0=\vbox to\dimen@{\unvbox1} + \setbox2=\vbox to\dimen@{\unvbox3} + \global\setbox\partialpage=\vbox{\pagesofar} + \doublecolumnpagegoal + } + \fi + \fi +} + +\catcode `\@=\other +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\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}% +\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}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{Appendix \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{Appendix \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% 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). +% +% 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<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appenixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\heading{\parsearg\secheadingi} + +\def\subheading{\parsearg\subsecheadingi} + +\def\subsubheading{\parsearg\subsubsecheadingi} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain} + +\def\chfplain #1#2{% + \pchapsepmacro + {% + \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #2\enspace #1}% + }% + \bigskip + \penalty5000 +} + +\def\unnchfplain #1{% +\pchapsepmacro % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen} + +% Parameter controlling skip before section headings. + +\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} + +\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} + +% @paragraphindent is defined for the Info formatting commands only. +\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. + +\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} +\def\plainsecheading #1{\secheadingi {#1}} +\def\secheadingi #1{{\advance \secheadingskip by \parskip % +\secheadingbreak}% +{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + + +% 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}} +\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + +\def\subsubsecfonts{\subsecfonts} % Maybe this should change: + % Perhaps make sssec fonts scaled + % magstep half +\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}} +\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000} + + +\message{toc printing,} + +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + \pagealignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % 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 + \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}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{Short Contents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% 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 } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in in \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + + +% 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 +% page number. +% +% 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 + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% 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.) +% +\def\tocentry#1#2{\begingroup + \hyphenpenalty = 10000 + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% 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 +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +\let\ptexequiv = \equiv + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +\def\point{$\star$} + +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl +\let\L=\ptexL +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% 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 % +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% 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}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \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 + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% 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 + \let\Elisp = \nonfillfinish + \tt + \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{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller interline space and fonts for small examples. + \baselineskip 10pt + \indexfonts \tt + \rawbackslash % output the \ character from the current font + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking 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} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\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 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #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\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\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 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\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 % +%% }% +%%} + +\def\defopvarparsebody #1#2#3#4#5 {\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 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\functionparens +\code{#1}% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #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}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% #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}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #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}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\code{#2} #3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% 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 +\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% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thischapter} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 Chapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +Section\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +Section\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 % +\else \ifnum \subsubsecno=0 % +Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +Section\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 + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\=\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% 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. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% 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. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% 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{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% 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 + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% 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} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +%\hsize = 6.5in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 18pt plus 1pt +\setleading{15pt} +\advance\topskip by 1.2cm + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% 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}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + +% These values for secheadingskip and subsecheadingskip are +% experiments. RJC 7 Aug 1992 +\global\secheadingskip = 17pt plus 6pt minus 3pt +\global\subsecheadingskip = 14pt plus 6pt minus 3pt + +\global\lispnarrowing = 0.3in +\setleading{12pt} +\advance\topskip by -1cm +\global\parskip 3pt plus 1pt +\global\hsize = 5in +\global\vsize=7.5in +\global\tolerance=700 +\global\hfuzz=1pt +\global\contentsrightmargin=0pt + +\global\pagewidth=\hsize +\global\pageheight=\vsize + +\global\let\smalllisp=\smalllispx +\global\let\smallexample=\smalllispx +\global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% 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 @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +% \lvvmode is equivalent in function to \leavevmode. +% Using \leavevmode runs into trouble when written out to +% an index file due to the expansion of \leavevmode into ``\unhbox +% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our +% magic tricks with @. +\def\lvvmode{\vbox to 0pt{}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\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`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% 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. +% +@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 +% that, assuming it is called before the first `\' could plausibly occur. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} + +%% 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 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/endian.c b/endian.c new file mode 100644 index 0000000..7de8706 --- /dev/null +++ b/endian.c @@ -0,0 +1,148 @@ +/* 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 <sys/types.h> +#include <stdio.h> +#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); +} @@ -0,0 +1,244 @@ +/* error.c -- Functions for handling errors. */ +/* 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 <stdio.h> +#include <sys/types.h> +#include <fcntl.h> + +#if defined (HAVE_VFPRINTF) +#include <varargs.h> +#endif + +#include <errno.h> +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "bashansi.h" +#include "flags.h" +#include "error.h" +#include "command.h" +#include "general.h" + +extern int interactive_shell; +extern char *dollar_vars[]; +extern char *shell_name; +extern char *the_current_maintainer; +#if defined (JOB_CONTROL) +extern pid_t shell_pgrp; +#endif /* JOB_CONTROL */ + +/* Return the name of the shell or the shell script for error reporting. */ +char * +get_name_for_error () +{ + char *name = (char *) NULL; + + if (!interactive_shell) + name = dollar_vars[0]; + if (!name && shell_name && *shell_name) + name = base_pathname (shell_name); + if (!name) + name = "bash"; + + return (name); +} + +/* Report an error having to do with FILENAME. */ +void +file_error (filename) + char *filename; +{ + report_error ("%s: %s", filename, strerror (errno)); +} + +#if !defined (HAVE_VFPRINTF) +void +programming_error (reason, arg1, arg2, arg3, arg4, arg5) + char *reason; +{ +#if defined (JOB_CONTROL) + give_terminal_to (shell_pgrp); +#endif /* JOB_CONTROL */ + + report_error (reason, arg1, arg2); + fprintf (stderr, "Report this to %s\n", the_current_maintainer); + fprintf (stderr, "Stopping myself..."); + fflush (stderr); + abort (); +} + +void +report_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, "\n"); + if (exit_immediately_on_error) + exit (1); +} + +void +fatal_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, "\n"); + + exit (2); +} + +void +internal_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, "\n"); +} + +#else /* We have VARARGS support, so use it. */ + +void +programming_error (va_alist) + va_dcl +{ + va_list args; + char *format; + +#if defined (JOB_CONTROL) + give_terminal_to (shell_pgrp); +#endif /* JOB_CONTROL */ + + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + va_end (args); + + fprintf (stderr, "Tell %s to fix this someday.\n", the_current_maintainer); + fprintf (stderr, "Stopping myself..."); + fflush (stderr); + abort (); +} + +void +report_error (va_alist) + va_dcl +{ + va_list args; + char *format; + + fprintf (stderr, "%s: ", get_name_for_error ()); + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); + if (exit_immediately_on_error) + exit (1); +} + +void +fatal_error (va_alist) + va_dcl +{ + va_list args; + char *format; + + fprintf (stderr, "%s: ", get_name_for_error ()); + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); + exit (2); +} + +void +internal_error (va_alist) + va_dcl +{ + va_list args; + char *format; + + fprintf (stderr, "%s: ", get_name_for_error ()); + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); +} + +itrace (va_alist) + va_dcl +{ + va_list args; + char *format; + + fprintf(stderr, "TRACE: pid %d: ", getpid()); + va_start (args); + format = va_arg (args, char *); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); + + fflush(stderr); +} + +#if 0 +/* A trace function for silent debugging -- doesn't require a control + terminal. */ +trace (va_alist) + va_dcl +{ + va_list args; + char *format; + static FILE *tracefp = (FILE *)NULL; + + if (tracefp == NULL) + tracefp = fopen("/usr/tmp/bash-trace.log", "a+"); + + if (tracefp == NULL) + tracefp = stderr; + else + fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */ + + fprintf(tracefp, "TRACE: pid %d: ", getpid()); + + va_start (args); + format = va_arg (args, char *); + vfprintf (tracefp, format, args); + fprintf (tracefp, "\n"); + + va_end (args); + + fflush(tracefp); +} +#endif +#endif /* HAVE_VFPRINTF */ @@ -0,0 +1,34 @@ +/* error.h -- External declarations of functions appearing in error.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. */ + +/* 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 (); + +/* Report a programmer's error, and abort. Pass REASON, and ARG1 ... ARG5. */ +extern void programming_error (); + +/* General error reporting. Pass FORMAT and ARG1 ... ARG5. */ +extern void report_error (); + +/* Report an unrecoverable error and exit. Pass FORMAT and ARG1 ... ARG5. */ +extern void fatal_error (); diff --git a/examples/alias-conv.sh b/examples/alias-conv.sh new file mode 100755 index 0000000..edbed86 --- /dev/null +++ b/examples/alias-conv.sh @@ -0,0 +1,22 @@ +#! /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/functions/autoload b/examples/functions/autoload new file mode 100644 index 0000000..a6ae421 --- /dev/null +++ b/examples/functions/autoload @@ -0,0 +1,103 @@ +# +# 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 func [func...] +# +# The first cut of this was by Bill Trost, trost@reed.bitnet +# +# Chet Ramey +# chet@ins.CWRU.Edu + +# +# 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 $?; }' +} + +# +# 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() +{ + # + # Save the list of functions; we're going to blow away the arguments + # in a second. If any of the names contain white space, TFB. + # + + local args="$*" + + # + # This should, I think, list the functions marked as autoload and not + # yet defined, but we don't have enough information to do that here. + # + if [ $# -eq 0 ] ; then + echo "usage: autoload function [function...]" + return 1 + fi + + # + # If there is no $FPATH, there is no work to be done + # + + if [ -z "$FPATH" ] ; then + echo autoload: FPATH not set + return 1 + fi + + # + # This treats FPATH exactly like PATH: a null field anywhere in the + # FPATH is treated the same as the current directory. + # + # The path splitting command is taken from Kernighan and Pike + # + + fp=$(echo $FPATH | sed 's/^:/.:/ + s/::/:.:/g + s/:$/:./ + s/:/ /g') + + for FUNC in $args ; do + # + # We're blowing away the arguments to autoload here... + # We have to; there are no arrays. + # + set $fp + + while [ $# -ne 0 ] ; do + if [ -f $1/$FUNC ] ; then + break # found it! + fi + shift + done + + if [ $# -eq 0 ] ; then + echo "$FUNC: autoload function not found" + continue + fi + +# echo auto-loading $FUNC from $1/$FUNC + aload $FUNC $1/$FUNC + done + + return 0 +} diff --git a/examples/functions/basename b/examples/functions/basename new file mode 100644 index 0000000..a541349 --- /dev/null +++ b/examples/functions/basename @@ -0,0 +1,23 @@ +# Date: Fri, 11 Oct 91 11:22:36 edt +# From: friedman@gnu.ai.mit.edu +# To: bfox@gnu.ai.mit.edu + +# A replacement for basename(1). Not all the systems I use have this +# program. Usage: basename [path] {extension} +function basename () +{ + local path="$1" + local suffix="$2" + local tpath="${path%/}" + + # Strip trailing '/' characters from path (unusual that this should + # ever occur, but basename(1) seems to deal with it.) + while [ "${tpath}" != "${path}" ]; do + tpath="${path}" + path="${tpath%/}" + done + + path="${path##*/}" # Strip off pathname + echo ${path%${suffix}} # Also strip off extension, if any. +} + diff --git a/examples/functions/csh-compat b/examples/functions/csh-compat new file mode 100644 index 0000000..8eaf754 --- /dev/null +++ b/examples/functions/csh-compat @@ -0,0 +1,36 @@ +# C-shell compatabilty package. +# setenv VAR VALUE +function setenv () { + export $1="$2" +} + +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".' +} + +# Make this work like csh's. Special case "term" and "path". +#set () { +#} + +chdir () { + builtin cd $* + } diff --git a/examples/functions/dirfuncs b/examples/functions/dirfuncs new file mode 100644 index 0000000..3958bbe --- /dev/null +++ b/examples/functions/dirfuncs @@ -0,0 +1,142 @@ +# +# Directory manipulation functions from the book 'The Korn Shell' +# Modified for use with bash Mon Apr 18 08:37 1994 by +# Ken Konecki (kenk@wfg.com) +# +# Modified by Chet Ramey +# +# This could stand to have calls to `select' added back in +# + +alias integer="declare -i" + +integer _push_max=${CDSTACK-31} _push_top=${CDSTACK-31} + +unalias cd +# alias cd=_cd + +# Display directory stack -- $HOME display as ~ +dirs() +{ + dir="${PWD#$HOME/}" + case $dir in + $HOME) dir=\~ ;; + /*) ;; + *) dir=\~/$dir ;; + esac + + integer i=_push_top + integer n=1 + + echo "$n) $dir" + while let "i < $_push_max" + do + n=n+1 + eval "echo \$n\) \$_push_stack_$i" + i=i+1 + done +} + +# Change directory and put directory on front of stack +cd() +{ + typeset dir= + integer n=0 type=4 i + case $1 in + -|-1|2) # cd - + n=_push_top type=1 + ;; + -[1-9]|-[1-9][0-9]) # cd -n + n=_push_top+${1#-}-1 type=2 + ;; + + 1) # keep present directory + echo "$PWD" + return + ;; + + [2-9]|[1-9][0-9]) # cd n + n=_push_top+${1}-2 type=2 + ;; + + *) + if let "_push_top <= 0"; then + type=3 n=_push_max + fi + ;; + esac + + if let "type < 3"; then + if let "n >= _push_max"; then + echo cd: Directory stack not that deep + return 1 + else + eval dir=\${_push_stack_$n} + fi + fi + + case $dir in + ~*) dir=$HOME${dir#\~} ;; + esac + + cd2 ${dir:-$@} > /dev/null || return 1 + dir=${OLDPWD#$HOME/} + case $dir in + $HOME) dir=\~ ;; + /*) ;; + *) dir=\~/$dir ;; + esac + + case $type in + 1) # swap first two elements + eval _push_stack_$_push_top=\$dir ;; + + 2|3) # put $dir on top and shift down by one until top + i=_push_top + unset _dirlist + while let "i < $_push_max" ; do + eval _dirlist=\"\$_dirlist \$_push_stack_$i\" + i=i+1 + done + + i=_push_top + for dir in "$dir" ${_dirlist} ; do + let "i > n" && break + eval _push_stack_$i=\$dir + i=i+1 + done + ;; + 4) # push name + _push_top=_push_top-1; + eval _push_stack_$_push_top=\$dir + ;; + esac + + echo "$PWD" + +} + +# Menu-driven change directory command +function mcd +{ + dirs + echo -n "Select by number or enter a name: " + read + cd $REPLY +} + + +# Emulate ksh cd substitution +cd2() +{ + case "$#" in + 0) builtin cd "$HOME" ;; + 1) builtin cd "$1" ;; + 2) newDir=$(echo $PWD | sed -e "s:$1:$2:g") + case "$newDir" in + $PWD) echo "bash:: cd: bad substitution" >&2 ; return 1 ;; + *) builtin cd "$newDir" ;; + esac ;; + *) echo "bash: cd: wrong arg count" 1>&2 ; return 1 ;; + esac +} diff --git a/examples/functions/dirname b/examples/functions/dirname new file mode 100644 index 0000000..ccb8c84 --- /dev/null +++ b/examples/functions/dirname @@ -0,0 +1,21 @@ +# Date: Fri, 11 Oct 91 11:22:36 edt +# From: friedman@gnu.ai.mit.edu +# To: bfox@gnu.ai.mit.edu + +# A replacement for dirname(1). This one appears less often on some +# systems I use than basename(1), and I really depend on it for some +# things. Usage: dirname [path] +function dirname () +{ + local dir="$1" + local tdir="${dir%/}" + + # Strip trailing '/' characters from dir (unusual that this should + # ever occur, but dirname(1) seems to deal with it.) + while [ "${tdir}" != "${dir}" ]; do + tdir="${dir}" + dir="${tdir%/}" + done + + echo "${dir%/*}" +} diff --git a/examples/functions/exitstat b/examples/functions/exitstat new file mode 100644 index 0000000..bae3f27 --- /dev/null +++ b/examples/functions/exitstat @@ -0,0 +1,22 @@ +# Contributed by Noah Friedman and Roland McGrath. + +# To be run by the PROMPT_COMMAND variable, so that one can see what +# the exit status of processes are. + +function check_exit_status () +{ + local status="$?" + local signal="" + + 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)" + if [ "$signal" ]; then signal="($signal)"; fi + fi + echo "[Exit ${status} ${signal}]" 1>&2 + fi + return 0 +} + +PROMPT_COMMAND=check_exit_status diff --git a/examples/functions/external b/examples/functions/external new file mode 100644 index 0000000..c2e52cd --- /dev/null +++ b/examples/functions/external @@ -0,0 +1,50 @@ +# Contributed by Noah Friedman. + +# To avoid using a function in bash, you can use the `builtin' or +# `command' builtins, but neither guarantees that you use an external +# program instead of a bash builtin if there's a builtin by that name. So +# this function can be used like `command' except that it guarantees the +# program is external by first disabling any builtin by that name. After +# the command is done executing, the state of the builtin is restored. +function external () +{ + local state="" + local exit_status + + if builtin_p "$1"; then + state="builtin" + enable -n "$1" + fi + + command "$@" + exit_status=$? + + if [ "$state" = "builtin" ]; then + enable "$1" + fi + + return ${exit_status} +} + +# What is does is tell you if a particular keyword is currently enabled as +# a shell builtin. It does NOT tell you if invoking that keyword will +# necessarily run the builtin. For that, do something like +# +# test "$(builtin type -type [keyword])" = "builtin" +# +# Note also, that disabling a builtin with "enable -n" will make builtin_p +# return false, since the builtin is no longer available. +function builtin_p () +{ + local word + + set $(builtin type -all -type "$1") + + for word in "$@" ; do + if [ "${word}" = "builtin" ]; then + return 0 + fi + done + + return 1 +} diff --git a/examples/functions/fact b/examples/functions/fact new file mode 100644 index 0000000..cd7bf46 --- /dev/null +++ b/examples/functions/fact @@ -0,0 +1,13 @@ +# Who said shells can't use recursion? Here is a factorial function. +# You call it with a number as an argument, and it returns the factorial +# of that number. + +fact () +{ + local num=$1; + if [ "$num" = 1 ] ; then + echo 1 + return ; + fi; + echo $[ $num * $(fact $[ $num - 1 ])] +} diff --git a/examples/functions/fstty b/examples/functions/fstty new file mode 100644 index 0000000..a770d84 --- /dev/null +++ b/examples/functions/fstty @@ -0,0 +1,59 @@ +# +# A function that works as a front end for both stty and the `bind' +# builtin, so the tty driver and readline see the same changes +# + +# +# Convert between the stty ^H control character form and the readline \C-H +# form +# +cvt() +{ + echo "$@" | cat -v | sed 's/\^/\\C-/' +} + +# +# stty front-end. Parses the argument list and creates two command strings, +# one for stty, another for bind. +# +fstty() +{ + local cmd="" bargs="" + local e + + while [ $# -gt 0 ] + do + case "$1" in + -a) cmd="$cmd everything" + ;; + erase) shift; + e=$(cvt "$1") + cmd="$cmd erase $1" + bargs="$bargs '\"$e\": backward-delete-char'" + ;; + kill) shift + e=$(cvt "$1") + cmd="$cmd kill $1" + bargs="$bargs '\"$e\": unix-line-discard'" + ;; + werase) shift; + e=$(cvt "$1") + cmd="$cmd erase $1" + bargs="$bargs '\"$e\": backward-kill-word'" + ;; + lnext) shift; + e=$(cvt "$1") + cmd="$cmd erase $1" + bargs="$bargs '\"$e\": quoted-insert'" + ;; + *) cmd="$cmd $1" + ;; + esac + shift + done + + command stty $cmd + if [ -n "$bargs" ]; then + builtin bind $bargs + fi +} diff --git a/examples/functions/func b/examples/functions/func new file mode 100644 index 0000000..710f643 --- /dev/null +++ b/examples/functions/func @@ -0,0 +1,27 @@ +# +# func -- print out definitions for functions named by arguments +# +# usage: func name [name ...] +# +# Chet Ramey +# chet@ins.CWRU.Edu +func() +{ + local status=0 + + if [ $# -eq 0 ] ; then + echo "usage: func name [name...]" 1>&2 + return 1 + fi + + for f + do + if [ "$(builtin type -type $f)" != "function" ] ; then + echo "func: $f: not a function" 1>&2 + status=1 # one failed + continue + fi + builtin type $f | sed 1d + done + return $status +} diff --git a/examples/functions/jj.bash b/examples/functions/jj.bash new file mode 100644 index 0000000..212c9ce --- /dev/null +++ b/examples/functions/jj.bash @@ -0,0 +1,12 @@ +jj () +{ + p=$(jobs $1); + echo $p + + case "$p" in + [*) echo matches '[*' + ;; + *) echo not a match\? + ;; + esac +} diff --git a/examples/functions/kshenv b/examples/functions/kshenv new file mode 100644 index 0000000..fbec76f --- /dev/null +++ b/examples/functions/kshenv @@ -0,0 +1,183 @@ +# +# .kshenv -- functions and aliases to provide the beginnings of a ksh +# environment for bash. +# +# Chet Ramey +# chet@ins.CWRU.Edu +# +# +# These are definitions for the ksh compiled-in `exported aliases'. There +# are others, but we already have substitutes for them: "history", "type", +# and "hash". +# +alias r="fc -e -" +alias functions="typeset -f" +alias integer="typeset -i" +alias nohup="nohup " +alias true=":" +alias false="let 0" +alias hist="fc" + +# +# An almost-ksh compatible `whence' command. This is as hairy as it is +# because of the desire to exactly mimic ksh (whose behavior was determined +# empirically). +# +# This depends somewhat on knowing the format of the output of the bash +# `builtin type' command. +# + +whence() +{ + local vflag + local path + + vflag= + path= + if [ "$#" = "0" ] ; then + echo "whence: argument expected" + return 1 + fi + case "$1" in + -v) vflag=1 + shift 1 + ;; + -*) echo "whence: bad option: $1" + return 1 + ;; + *) ;; + esac + + if [ "$#" = "0" ] ; then + echo "whence: bad argument count" + return 1 + fi + + for cmd + do + if [ "$vflag" ] ; then + echo $(builtin type $cmd | sed 1q) + else + path=$(builtin type -path $cmd) + if [ "$path" ] ; then + echo $path + else + case "$cmd" in + /*) echo "" + ;; + *) case "$(builtin type -type $cmd)" in + "") echo "" + ;; + *) echo "$cmd" + ;; + esac + ;; + esac + fi + fi + done + return 0 +} + +# +# For real ksh homeboy fanatics, redefine the `type' builtin with a ksh +# version. +# +#type() +#{ +# whence -v "$*" +#} + +cd() +{ + case $# in + 0) builtin cd "$HOME" ;; + 1) builtin cd "$@" ;; + 2) old="$1" + new="$2" + dir=$(echo "$PWD" | sed "s:$old:$new:g") + case "$dir" in + "$PWD") echo "bash: cd: bad substitution" >&2 ; return 1 ;; + *) echo "$dir" + builtin cd "$dir" + ;; + esac + ;; + *) echo "cd: wrong arg count" >&2 ; return 1 ;; + esac +} + +# +# ksh print emulation +# +# print [-Rnprsu[n]] [arg ...] +# +# - end of options +# -R BSD-style -- only accept -n, no escapes +# -n do not add trailing newline +# -p no-op (no coprocesses) +# -r no escapes +# -s no-op (print to the history file) +# -u n redirect output to fd n +# + +print() +{ + local eflag=-e + local nflag= + local fd=1 + + OPTIND=1 + while getopts "Rnprsu:" c + do + case $c in + R) eflag= + ;; + r) eflag= + ;; + n) nflag=-n + ;; + u) fd=$OPTARG + ;; + p|s) ;; + esac + done + shift $[ $OPTIND - 1 ] + + builtin echo $eflag $nflag "$@" >&$fd +} + +# substring function +# this function should be equivalent to the substring built-in which was +# eliminated after the 06/29/84 version +substring () +{ + local lpat flag str #local variables + set -f + case $1 in + -l|-L) + flag=$1 + lpat=$2 + shift 2 + ;; + esac + # test for too few or too many arguments + if [ x"$1" = x -o $# -gt 2 ]; then + print -u2 'substring: bad argument count' + return 1 + fi + str=$1 + if [ x"$flag" = x-l ]; then #substring -l lpat + str=${str#$lpat} + elif [ x"$flag" = x-L ]; then + str=${str##$lpat} #substring -L lpat + fi + + if [ x"$2" != x ]; then + echo ${str%$2} + else + echo $str + fi + + return 0 +} diff --git a/examples/functions/manpage b/examples/functions/manpage new file mode 100644 index 0000000..3fdc7ac --- /dev/null +++ b/examples/functions/manpage @@ -0,0 +1,129 @@ +# Written from scratch by Tom Tromey (tromey@cns.caltech.edu) +# +# manpage -- find and print a manual page. +# usage: manpage section name [printing] +# +function manpage () +{ + local i h cmd zot sec + local num="$1" + local page="$2" + local printing="$3" + local mp + + mp="${MANPATH:-/usr/man}" + if [ "$#" -lt 2 ]; then return 1; fi # should print usage + if [ "$num" != "" ]; then + sec="${num%%[a-zA-Z]*}" + else + sec='[168234571lnpo]' + num="$sec" + fi + for i in $(echo "$mp" | tr : ' '); do + if [ ! -d "$i" ]; then continue; fi + file="$i"/man"$sec"/"$page"."$num"* + set $file + file="$1" + if [ -f "$file" ]; then + zot=$(head -1 "$file") + cmd=${MANROFF:-"nroff -man - | col | cat -s"} + h=${zot##"'"'\"'} + if [ "$h" != "$zot" ]; then + while [ "$h" != "" ]; do + case "$h" in + *e) cmd="${MANEQN:-neqn} | $cmd";; + *r) cmd="refer | $cmd";; + *t) cmd="tbl | $cmd";; + *v) cmd="vgrind | $cmd";; + *) ;; # should print error + esac + h=${h%?} + done + fi + if [ "$printing" != "" ]; then + (cd "$i"; eval "$cmd") < "$file" | ${PAGER:-more} + else + (cd "$i"; eval "$cmd") < "$file" > /tmp/manpage-$$ + ${PAGER:-more} /tmp/manpage-$$ + rm -f /tmp/manpage-$$ + fi + break + fi + done +} + +function whatis_internal () +{ + local j + for j in $(echo "$MANPATH" | tr : ' '); do + if [ -f "$j/whatis" ]; then + eval $2 -i -e "$1" $j/whatis + fi + done +} + +function whatis () +{ + local name=$(basename "$1") + whatis_internal "$name" "grep -w" +} + +function apropos () +{ + whatis_internal "$1" "fgrep" +} + +# Note: "-" and "-t" together not supported. This man could be +# made a lot better, but it does everything I want. +function man () +{ + local PAGER printing mpath MANROFF num + mpath="${MANPATH:-/usr/man}" + while true; do + case "$1" in + -) PAGER=cat + printing= ;; + -t) + MANROFF=${TROFF:-"ptroff -man -t"} + PAGER="${TCAT:-lpr}" + printing=yes ;; + -M) + mpath="$2" + shift;; + *) break;; + esac + shift + done + local MANPATH="$mpath" + case "$1" in + -f | -k) + local g a + if [ "$1" = "-f" ]; then + g="grep -w" + a=$(basename "$2") + else + g=fgrep + a="$2" + fi + whatis_internal "$a" "$g" + ;; + [0-9npol] | [0-9][a-z]* | new | public | old | local) + if [ "$1" = "new" ]; then + num=n + elif [ "$1" = "public" ]; then + num=p + elif [ "$1" = "old" ]; then + num=o + elif [ "$1" = "local" ]; then + num=l + else + num="$1" + fi + shift + manpage "$num" "$1" "$printing" + ;; + *) + manpage "$num" "$1" "$printing" + ;; + esac +} diff --git a/examples/functions/notify.bash b/examples/functions/notify.bash new file mode 100644 index 0000000..dafbac5 --- /dev/null +++ b/examples/functions/notify.bash @@ -0,0 +1,58 @@ +trap _notify CHLD +NOTIFY_ALL=false +unset NOTIFY_LIST +unalias false + +false() +{ + return 1 +} + +_notify () +{ + local i j + local newlist= + + if $NOTIFY_ALL + then + return # let bash take care of this itself + elif [ -z "$NOTIFY_LIST" ]; then + return + else + set -- $NOTIFY_LIST + for i in "$@" + do + j=$(jobs -n %$i) + if [ -n "$j" ]; then + echo "$j" + jobs -n %$i >/dev/null + else + newlist="newlist $i" + fi + done + NOTIFY_LIST="$newlist" + fi +} + +notify () +{ + local i j + + if [ $# -eq 0 ]; then + NOTIFY_ALL=: + set -b + return + else + for i in "$@" + do + # turn a valid job spec into a job number + j=$(jobs $i) + case "$j" in + [*) j=${j%%]*} + j=${j#[} + NOTIFY_LIST="$NOTIFY_LIST $j" + ;; + esac + done + fi +} diff --git a/examples/functions/shcat b/examples/functions/shcat new file mode 100644 index 0000000..55a3096 --- /dev/null +++ b/examples/functions/shcat @@ -0,0 +1,7 @@ +shcat() +{ + while read line + do + echo "$line" + done +} diff --git a/examples/functions/substr b/examples/functions/substr new file mode 100644 index 0000000..c557677 --- /dev/null +++ b/examples/functions/substr @@ -0,0 +1,79 @@ +# +# substr -- a function to emulate the ancient ksh builtin +# + +# +# -l == shortest from left +# -L == longest from left +# -r == shortest from right (the default) +# -R == longest from right + +substr() +{ + local flag pat str + local usage="usage: substr -lLrR pat string or substr string pat" + + case "$1" in + -l | -L | -r | -R) + flag="$1" + pat="$2" + shift 2 + ;; + -*) + echo "substr: unknown option: $1" + echo "$usage" + return 1 + ;; + *) + flag="-r" + pat="$2" + ;; + esac + + if [ "$#" -eq 0 -o "$#" -gt 2 ] ; then + echo "substr: bad argument count" + return 2 + fi + + str="$1" + + # + # We don't want -f, but we don't want to turn it back on if + # we didn't have it already + # + case "$-" in + "*f*") + ;; + *) + fng=1 + set -f + ;; + esac + + case "$flag" in + -l) + str="${str#$pat}" # substr -l pat string + ;; + -L) + str="${str##$pat}" # substr -L pat string + ;; + -r) + str="${str%$pat}" # substr -r pat string + ;; + -R) + str="${str%%$pat}" # substr -R pat string + ;; + *) + str="${str%$2}" # substr string pat + ;; + esac + + echo "$str" + + # + # If we had file name generation when we started, re-enable it + # + if [ "$fng" = "1" ] ; then + set +f + fi +} diff --git a/examples/functions/substr2 b/examples/functions/substr2 new file mode 100644 index 0000000..f5e7547 --- /dev/null +++ b/examples/functions/substr2 @@ -0,0 +1,81 @@ +# +# substr -- a function to emulate the ancient ksh builtin +# + +# -l == remove shortest from left +# -L == remove longest from left +# -r == remove shortest from right (the default) +# -R == remove longest from right + +substr() +{ + local flag pat str + local usage="usage: substr -lLrR pat string or substr string pat" + local options="l:L:r:R:" + + OPTIND=1 + while getopts "$options" c + do + case "$c" in + l | L | r | R) + flag="-$c" + pat="$OPTARG" + ;; + '?') + echo "$usage" + return 1 + ;; + esac + done + + if [ "$OPTIND" -gt 1 ] ; then + shift $[ $OPTIND -1 ] + fi + + if [ "$#" -eq 0 -o "$#" -gt 2 ] ; then + echo "substr: bad argument count" + return 2 + fi + + str="$1" + + # + # We don't want -f, but we don't want to turn it back on if + # we didn't have it already + # + case "$-" in + "*f*") + ;; + *) + fng=1 + set -f + ;; + esac + + case "$flag" in + -l) + str="${str#$pat}" # substr -l pat string + ;; + -L) + str="${str##$pat}" # substr -L pat string + ;; + -r) + str="${str%$pat}" # substr -r pat string + ;; + -R) + str="${str%%$pat}" # substr -R pat string + ;; + *) + str="${str%$2}" # substr string pat + ;; + esac + + echo "$str" + + # + # If we had file name generation when we started, re-enable it + # + if [ "$fng" = "1" ] ; then + set +f + fi +} diff --git a/examples/functions/term b/examples/functions/term new file mode 100644 index 0000000..fbe99f1 --- /dev/null +++ b/examples/functions/term @@ -0,0 +1,35 @@ +# +# term -- a shell function to set the terminal type interactively or not. +# + +term() +{ + local t + + if [ $# != 0 ] ; then + eval $(tset -sQ $1) + else # interactive + if [ -z "$TERM" ] ; then + TERM="unknown" + fi + + case "$TERM" in + network|dialup|unknown|lat) + TERM=unknown + ;; + *) + eval $(tset -sQ) + ;; + esac + + while [ "$TERM" = "unknown" ] ; do + echo -n "Terminal type: " + read t + if [ -n "$t" ] ; then + eval $(tset -sQ $t) + fi + done + fi +} + + diff --git a/examples/functions/whatis b/examples/functions/whatis new file mode 100644 index 0000000..56c5a58 --- /dev/null +++ b/examples/functions/whatis @@ -0,0 +1,52 @@ +# +# whatis -- and implementation of the 10th Edition Unix sh builtin `whatis' +# command. +# +# usage: whatis arg [...] +# +# For each argument, whatis prints the associated value as a parameter, +# builtin, function, alias, or executable file as appropriate. In each +# case, the value is printed in a form which would yield the same value +# if typed as input to the shell itself. +# + +whatis() +{ + local wusage='usage: whatis arg [arg...]' + local fail=0 + + if [ $# -eq 0 ] ; then + echo "$wusage" + return 1 + fi + + for arg + do + case $(builtin type -type $arg 2>/dev/null) in + "alias") + builtin alias "$arg" + ;; + "function") + builtin type "$arg" | sed 1d + ;; + "builtin") + echo builtin "$arg" + ;; + "file") + builtin type -path "$arg" + ;; + *) + # OK, we could have a variable, or we could have nada + if [ "$(eval echo \${$arg+set})" = "set" ] ; then + # It is a variable, and it is set + echo -n "$arg=" + eval echo '\"'\$$arg'\"' + else + echo whatis: $arg: not found + fail=1 + fi + ;; + esac + done + return $fail +} diff --git a/examples/functions/whence b/examples/functions/whence new file mode 100644 index 0000000..70b2322 --- /dev/null +++ b/examples/functions/whence @@ -0,0 +1,59 @@ +# +# An almost-ksh compatible `whence' command. This is as hairy as it is +# because of the desire to exactly mimic ksh. +# +# This depends somewhat on knowing the format of the output of the bash +# `builtin type' command. +# +# Chet Ramey +# chet@ins.CWRU.Edu +# +whence() +{ + local vflag= path= + + if [ "$#" = "0" ] ; then + echo "whence: argument expected" + return 1 + fi + case "$1" in + -v) vflag=1 + shift 1 + ;; + -*) echo "whence: bad option: $1" + return 1 + ;; + *) ;; + esac + + if [ "$#" = "0" ] ; then + echo "whence: bad argument count" + return 1 + fi + + for cmd + do + if [ "$vflag" ] ; then + echo $(builtin type $cmd | sed 1q) + else + path=$(builtin type -path $cmd) + if [ "$path" ] ; then + echo $path + else + case "$cmd" in + /*) if [ -x "$cmd" ]; then + echo "$cmd" + fi + ;; + *) case "$(builtin type -type $cmd)" in + "") ;; + *) echo "$cmd" + ;; + esac + ;; + esac + fi + fi + done + return 0 +} diff --git a/examples/scripts/adventure.sh b/examples/scripts/adventure.sh new file mode 100755 index 0000000..a6d2eaa --- /dev/null +++ b/examples/scripts/adventure.sh @@ -0,0 +1,545 @@ +#!/bin/bash +# ash -- "Adventure shell" +# last edit: 86/04/21 D A Gwyn +# SCCS ID: @(#)ash.sh 1.4 + +OPATH=$PATH + +ask() +{ + echo -n "$@" '[y/n] ' + read ans + + case "$ans" in + y*|Y*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +CAT=${PAGER:-more} + +ash_inst() +{ + cat <<- EOF + + Instructions for the Adventure shell + + Welcome to the Adventure shell! In this exploration of the UNIX file + system, I will act as your eyes and hands. As you move around, I will + describe whatever is visible and will carry out your commands. The + general form of a command is + Verb Object Extra_stuff. + Most commands pay no attention to the "Extra_stuff", and many do not + need an "Object". A typical command is + get all + which picks up all files in the current "room" (directory). You can + find out what you are carrying by typing the command + inventory + The command "help" results in a full description of all commands that I + understand. To quit the Adventure shell, type + quit + + There are UNIX monsters lurking in the background. These are also + known as "commands with arguments". + + Good luck! + EOF +} + +ash_help() +{ +echo "I understand the following commands (synonyms in parentheses):" +echo "" + +echo "change OBJECT to NEW_NAME changes the name of the object" +echo "clone OBJECT as NEW_NAME duplicates the object" +echo "drop OBJECTS leaves the objects in the room" +echo "enter (go) PASSAGE takes the labeled passage" +echo "examine OBJECTS describes the objects in detail" +echo "feed OBJECT to MONSTER stuffs the object into a UNIX monster" +echo "get (take) OBJECTS picks up the specified objects" +echo "gripe (bug) report a problem with the Adventure shell" +echo "help prints this summary" +echo "inventory (i) tells what you are carrying" +echo "kill (destroy) OBJECTS destroys the objects" +echo "look (l) describes the room, including hidden objects" +echo "open (read) OBJECT shows the contents of an object" +echo "quit (exit) leaves the Adventure shell" +echo "resurrect OBJECTS attempts to restore dead objects" +echo "steal OBJECT from MONSTER obtains the object from a UNIX monster" +echo "throw OBJECT at daemon feeds the object to the printer daemon" +echo "up takes the overhead passage" +echo "wake MONSTER awakens a UNIX monster" +echo "where (w) tells you where you are" +echo "xyzzy moves you to your home" +} + +MAINT=chet@ins.cwru.edu + +PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin:. +export PATH + +trap 'echo Ouch!' 2 3 +#trap '' 18 # disable Berkeley job control + +ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; } +ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; } +ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; } + +cd +LIM=.limbo # $HOME/$LIM contains "destroyed" objects +mkdir $LIM >&- 2>&- +KNAP=.knapsack # $HOME/$KNAP contains objects being "carried" +if [ ! -d $KNAP ] +then mkdir $KNAP >&- 2>&- + if [ $? = 0 ] + then echo 'You found a discarded empty knapsack.' + else echo 'You have no knapsack to carry things in.' + exit 1 + fi +else echo 'One moment while I peek in your old knapsack...' +fi + +kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\`` + +if ask 'Welcome to the Adventure shell! Do you need instructions?' +then + ash_inst + echo -n 'Type a newline to continue: ' + read +fi + +wiz=false +cha=false +prev=$LIM +while : +do room=`pwd` + if [ $room != $prev ] + then if [ $room = $HOME ] + then echo 'You are in your own home.' + else echo "You have entered $room." + fi + exs= + obs= + hexs= + hobs= + f=false + for i in `ls -a` + do case $i in + .|..) ;; + .*) if [ -f $i ] + then hobs="$hobs $i" + elif [ -d $i ] + then hexs="$hexs $i" + else f=true + fi + ;; + *) if [ -f $i ] + then obs="$obs $i" + elif [ -d $i ] + then exs="$exs $i" + else f=true + fi + ;; + esac + done + if [ "$obs" ] + then echo 'This room contains:' + ash_pr $obs + else echo 'The room looks empty.' + fi + if [ "$exs" ] + then echo 'There are exits labeled:' + ash_pr $exs + echo 'as well as a passage overhead.' + else echo 'There is a passage overhead.' + fi + if sh -c $f + then echo 'There are shadowy figures in the corner.' + fi + prev=$room + fi + + echo -n '-advsh> ' # prompt + read verb obj x + if [ $? != 0 ] + then verb=quit # EOF + fi + + case $verb in + change) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then set -- $x + case "$1" in + to) if [ "$2" ] + then if [ -f $2 ] + then echo "You must destroy $2 first." + set -- + fi + if [ "$2" ] + then if mv $obj $2 >&- 2>&- + then echo "The $obj shimmers and turns into $2." + obs=`ash_rm "$2 $obs" "$obj"` + else echo "There is a cloud of smoke but the $obj is unchanged." + fi + fi + else echo 'To what?' + fi + ;; + *) echo "Change $obj to what?" + ;; + esac + else if ash_lk "$kn" "$obj" + then echo 'You must drop it first.' + else echo "I see no $obj here." + fi + fi + else echo 'Change what?' + fi + ;; + clone) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then if [ ! -r $obj ] + then echo "The $obj does not wish to be cloned." + else set -- $x + case "$1" in + as) if [ "$2" ] + then if [ -f $2 ] + then echo "You must destroy $2 first." + else if cp $obj $2 >&- 2>&- + then echo "Poof! When the smoke clears, you see the new $2." + obs="$obs $2" + else echo 'You hear a dull thud but no clone appears.' + fi + fi + else echo 'As what?' + fi + ;; + *) echo "Clone $obj as what?" + ;; + esac + fi + else if ash_lk "$kn" "$obj" + then echo 'You must drop it first.' + else echo "I see no $obj here." + fi + fi + else echo 'Clone what?' + fi + ;; + drop) if [ "$obj" ] + then for it in $obj $x + do if ash_lk "$kn" "$it" + then if [ -w $it ] + then echo "You must destroy $it first." + else if mv $HOME/$KNAP/$it $it >&- 2>&- + then echo "$it: dropped." + kn=`ash_rm "$kn" "$it"` + obs=`echo $it $obs` + else echo "The $it is caught in your knapsack." + fi + fi + else echo "You're not carrying the $it!" + fi + done + else echo 'Drop what?' + fi + ;; + enter|go) if [ "$obj" ] + then if [ $obj != up ] + then if ash_lk "$exs $hexs" "$obj" + then if [ -x $obj ] + then if cd $obj + then echo 'You squeeze through the passage.' + else echo "You can't go that direction." + fi + else echo 'An invisible force blocks your way.' + fi + else echo 'I see no such passage.' + fi + else if cd .. + then echo 'You struggle upwards.' + else echo "You can't reach that high." + fi + fi + else echo 'Which passage?' + fi + ;; + examine) if [ "$obj" ] + then if [ $obj = all ] + then $obj=`echo $obs $exs` + x= + fi + for it in $obj $x + do if ash_lk "$obs $hobs $exs $hexs" "$it" + then echo "Upon close inspection of the $it, you see:" + ls -ld $it 2>&- + if [ $? != 0 ] + then echo "-- when you look directly at the $it, it vanishes." + fi + else if ash_lk "$kn" "$it" + then echo 'You must drop it first.' + else echo "I see no $it here." + fi + fi + done + else echo 'Examine what?' + fi + ;; + feed) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then set -- $x + case "$1" in + to) if [ "$2" ] + then shift + if PATH=$OPATH $* <$obj 2>&- + then echo "The $1 monster devours your $obj." + if rm -f $obj >&- 2>&- + then obs=`ash_rm "$obs" "$obj"` + else echo 'But he spits it back up.' + fi + else echo "The $1 monster holds his nose in disdain." + fi + else echo 'To what?' + fi + ;; + *) echo "Feed $obj to what?" + ;; + esac + else if ash_lk "$kn" "$obj" + then echo 'You must drop it first.' + else echo "I see no $obj here." + fi + fi + else echo 'Feed what?' + fi + ;; + get|take) if [ "$obj" ] + then if [ $obj = all ] + then obj="$obs" + x= + fi + for it in $obj $x + do if ash_lk "$obs $hobs" "$it" + then if ash_lk "$kn" "$it" + then echo 'You already have one.' + else if mv $it $HOME/$KNAP/$it >&- 2>&- + then echo "$it: taken." + kn="$it $kn" + obs=`ash_rm "$obs" "$it"` + else echo "The $it is too heavy." + fi + fi + else echo "I see no $it here." + fi + done + else echo 'Get what?' + fi + ;; + gripe|bug) echo 'Please describe the problem and your situation at the time it failed.\nEnd the bug report with a line containing just a Ctrl-D.' + cat | mail $MAINT -s 'ash bug' + echo 'Thank you!' + ;; + help) ash_help + ;; + inventory|i) if [ "$kn" ] + then echo 'Your knapsack contains:' + ash_pr $kn + else echo 'You are poverty-stricken.' + fi + ;; + kill|destroy) if [ "$obj" ] + then if [ $obj = all ] + then x= + if ask "Do you really want to attempt to $verb them all?" + then obj=`echo $obs` + else echo 'Chicken!' + obj= + fi + fi + for it in $obj $x + do if ash_lk "$obs $hobs" "$it" + then if mv $it $HOME/$LIM <&- >&- 2>&- + then if [ $verb = kill ] + then echo "The $it cannot defend himself; he dies." + else echo "You have destroyed the $it; it vanishes." + fi + obs=`ash_rm "$obs" "$it"` + else if [ $verb = kill ] + then echo "Your feeble blows are no match for the $it." + else echo "The $it is indestructible." + fi + fi + else if ash_lk "$kn" "$it" + then echo "You must drop the $it first." + found=false + else echo "I see no $it here." + fi + fi + done + else echo 'Kill what?' + fi + ;; + look|l) obs=`echo $obs $hobs` + hobs= + if [ "$obs" ] + then echo 'The room contains:' + ash_pr $obs + else echo 'The room is empty.' + fi + exs=`echo $exs $hexs` + hexs= + if [ "$exs" ] + then echo 'There are exits plainly labeled:' + ash_pr $exs + echo 'and a passage directly overhead.' + else echo 'The only exit is directly overhead.' + fi + ;; + magic) if [ "$obj" = mode ] + then if sh -c $cha + then echo 'You had your chance and you blew it.' + else if ask 'Are you a wizard?' + then echo -n 'Prove it! Say the magic word: ' + read obj + if [ "$obj" = armadillo ] + then echo 'Yes, master!!' + wiz=true + else echo "Homie says: I don't think so" + cha=true + fi + else echo "I didn't think so." + fi + fi + else echo 'Nice try.' + fi + ;; + open|read) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then if [ -r $obj ] + then if [ -s $obj ] + then echo "Opening the $obj reveals:" + $CAT < $obj + if [ $? != 0 ] + then echo '-- oops, you lost the contents!' + fi + else echo "There is nothing inside the $obj." + fi + else echo "You do not have the proper tools to open the $obj." + fi + else if ash_lk "$kn" "$obj" + then echo 'You must drop it first.' + found=false + else echo "I see no $obj here." + fi + fi + else echo 'Open what?' + fi + ;; + quit|exit) if ask 'Do you really want to quit now?' + then if [ "$kn" ] + then echo 'The contents of your knapsack will still be there next time.' + fi + rm -rf $HOME/$LIM + echo 'See you later!' + exit 0 + fi + ;; + resurrect) if [ "$obj" ] + then for it in $obj $x + do if ash_lk "$obs $hobs" "$it" + then echo "The $it is already alive and well." + else if mv $HOME/$LIM/$it $it <&- >&- 2>&- + then echo "The $it staggers to his feet." + obs=`echo $it $obs` + else echo "There are sparks but no $it appears." + fi + fi + done + else echo 'Resurrect what?' + fi + ;; + steal) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then echo 'There is already one here.' + else set -- $x + case "$1" in + from) if [ "$2" ] + then shift + if PATH=$OPATH $* >$obj 2>&- + then echo "The $1 monster drops the $obj." + obs=`echo $obj $obs` + else echo "The $1 monster runs away as you approach." + rm -f $obj >&- 2>&- + fi + else echo 'From what?' + fi + ;; + *) echo "Steal $obj from what?" + ;; + esac + fi + else echo 'Steal what?' + fi + ;; + throw) if [ "$obj" ] + then if ash_lk "$obs $hobs" "$obj" + then set -- $x + case "$1" in + at) case "$2" in + daemon) if sh -c "lpr -r $obj" + then echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket." + obs=`ash_rm "$obs" "$obj"` + else echo "The daemon is nowhere to be found." + fi + ;; + *) echo 'At what?' + ;; + esac + ;; + *) echo "Throw $obj at what?" + ;; + esac + else if ash_lk "$kn" "$obj" + then echo 'It is in your knapsack.' + found=false + else echo "I see no $obj here." + fi + fi + else echo 'Throw what?' + fi + ;; + u|up) if cd .. + then echo 'You pull yourself up a level.' + else echo "You can't reach that high." + fi + ;; + wake) if [ "$obj" ] + then echo "You awaken the $obj monster:" + PATH=$OPATH $obj $x + echo 'The monster slithers back into the darkness.' + else echo 'Wake what?' + fi + ;; + w|where) echo "You are in $room." + ;; + xyzzy) if cd + then echo 'A strange feeling comes over you.' + else echo 'Your spell fizzles out.' + fi + ;; + *) if [ "$verb" ] + then if sh -c $wiz + then PATH=$OPATH $verb $obj $x + else echo "I don't know how to \"$verb\"." + echo 'Type "help" for assistance.' + fi + else echo 'Say something!' + fi + ;; + esac +done diff --git a/examples/scripts/bcsh.sh b/examples/scripts/bcsh.sh new file mode 100644 index 0000000..9d93b30 --- /dev/null +++ b/examples/scripts/bcsh.sh @@ -0,0 +1,1254 @@ +# 1-Feb-86 09:37:35-MST,30567;000000000001 +# Return-Path: <unix-sources-request@BRL.ARPA> +# Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Sat 1 Feb 86 09:36:16-MST +# Received: from usenet by TGR.BRL.ARPA id a002623; 1 Feb 86 9:33 EST +# From: chris <chris@globetek.uucp> +# Newsgroups: net.sources +# Subject: Improved Bcsh (Bourne Shell Cshell-Emulator) +# Message-ID: <219@globetek.UUCP> +# Date: 30 Jan 86 17:34:26 GMT +# To: unix-sources@BRL-TGR.ARPA +# +# This is a new, improved version of my Bourne shell cshell-emulator. +# The code has been cleaned up quite a bit, and a couple of new features +# added (now supports 'noclobber' and 'iclobber' variables). A bug with +# 'eval' that caused "illegal I/O" error messages on vanilla V7 shells has +# also been fixed. + +# I have posted the program in its entirety because a context diff of the +# old and new versions was longer than the new version... + +# --Chris +# Bcsh -- A Simple Cshell-Like Command Pre-Processor For The Bourne Shell +# +# "Copyright (c) Chris Robertson, December 1985" +# +# This software may be used for any purpose provided the original +# copyright notice and this notice are affixed thereto. No warranties of +# any kind whatsoever are provided with this software, and it is hereby +# understood that the author is not liable for any damagages arising +# from the use of this software. +# +# Features Which the Cshell Does Not Have: +# ---------------------------------------- +# +# + command history persists across bcsh sessions +# + global last-command editing via 'g^string1^string2^' syntax +# + edit any command via $EDITOR or $VISUAL editors +# + history file name, .bcshrc file name, alias file name, and number +# of commands saved on termination can be set by environment variables +# + prompt may evaluate commands, such as `pwd`, `date`, etc. +# + the whole text of interactive 'for' and 'while' loops and 'if' +# statements goes into the history list and may be re-run or edited +# + multiple copies of commands and requests to see command history +# are not added to the history list +# + the history mechanism actually stores all commands entered in a +# current session, not just $history of them. This means that you +# can increase $history on the fly and at once have a larger history. +# +# +# Synonyms: +# --------- +# +# logout, exit, bye write out history file and exit +# h, history show current history list +# +# +# Aliases: +# -------- +# +# alias NAME CMND create an alias called NAME to run CMND +# unalias NAME remove the alias NAME +# +# There are no 'current-session only' aliases -- all alias and unalias +# commands are permanent, and stored in the $aliasfile. +# +# If an alias contains positional variables -- $1, $2, $*, etc. -- any +# arguments following the alias name are considered to be values for +# those variables, and the alias is turned into a command of the form +# 'set - arguments;alias'. Otherwise, a simple substitution is performed +# for the alias and the rest of the command preserved. The cshell +# convention of using '\!:n' in an alias to get bits of the current +# command is mercifully abandoned. +# +# Quotes are not necessary around the commands comprising an alias; +# in fact, any enclosing quotes are stripped when the alias is added +# to the file. +# +# A couple of typical aliases might be: +# +# goto cd $1;pwd +# l ls -F +# +# Note that aliasing something to "commands;logout" will not work -- if +# you want something to happen routinely on logout put it in the file +# specified by $logoutfile, default = $HOME/.blogout. +# +# +# Command Substitutions: +# ---------------------- +# +# !! substitute last command from history list +# !!:N substitute Nth element of last command from +# history list -- 0 = command name, 1 = 1st arg +# !!:$ substitute last element of last command from +# history list +# !!:* substitute all arguments to last command +# from history list +# !NUMBER substitute command NUMBER from the history list +# !NUMBER:N as above, but substitute Nth element, where +# 0 = command name, 1 = 1st arg, etc. +# !NUMBER:$ as above, but substitute last element +# !NUMBER:* as above, but substitute all arguments +# !-NUMBER substitute the command NUMBER lines from the +# end of the history list; 1 = last command +# !-NUMBER:N as above, but substitute Nth element, where +# 0 = command name, 1 = 1st arg, etc. +# !-NUMBER:$ as above, but substitute last element +# !-NUMBER:* as above, but substitute all arguments +# !?STRING substitute most-recent command from history list +# containing STRING -- STRING must be enclosed in +# braces if followed by any other characters +# !?STRING:N as above, but substitute Nth element, where +# 0 = command name, 1 = 1st arg, etc. +# !?STRING:$ as above, but substitute last element +# !?STRING:* as above, but substitute all arguments +# +# +# Command Editing: +# ---------------- +# +# CMND~e edit CMND using $EDITOR, where CMND may be found +# using a history substitution +# CMND~v edit CMND using $VISUAL, where CMND may be found +# using a history substitution +# " ^string1^string2^ substitute string2 for string1 in last command" +# command and run it +# " g^string1^string2^ globally substitute string2 for string1 in " +# last command and run it +# !NUMBER:s/string1/string2/ +# substitute string2 for string1 in +# command NUMBER and run it +# !NUMBER:gs/string1/string2/ +# globally substitute string2 for string1 in +# command NUMBER and run it +# !?STRING:s/string1/string2/ +# substitute string2 for string1 in last command +# containing STRING and run it +# !?STRING:gs/string1/string2/ +# globally substitute string2 for string1 in last +# command containing STRING and run it +# +# Any command which ends in the string ":p" is treated as a normal +# command until all substitutions have been completed. The trailing +# ":p" is then stripped, and the command is simply echoed and added to +# the history list instead of being executed. +# +# None of the other colon extensions of the cshell are supported. +# +# +# Shell Environment Variables: +# ---------------------------- +# +# EDITOR editor used by ~e command, default = "ed" +# VISUAL editor used by ~v command, default = "vi" +# MAIL your system mailbox +# PAGER paging program used by history command, default = "more" +# PS1 primary prompt +# PS2 secondary prompt +# history number of commands in history list, default = 22 +# histfile file history list is saved in, default = $HOME/.bhistory +# savehist number of commands remembered from last bcsh session +# aliasfile file of aliased commands, default = $HOME/.baliases +# logoutfile file of commands to be executed before termination +# inc_cmdno yes/no -- keep track of command numbers or not +# noclobber if set, existing files are not overwritten by '>' +# iclobber if both noclobber and iclobber are set, the user is +# prompted for confirmation before existing files are +# overwritten by '>' +# +# Note: if you are setting either noclobber or iclobber mid-session, +# set them to 'yes' +# +# +# Regular Shell Variables: +# ------------------------ +# +# Shell variables may be set via Bourne or cshell syntax, e.g., both +# "set foo=bar" and "foo=bar" set a variable called "foo" with the value +# "bar". However, all variables are automatically set as environment +# variables, so there is no need to export them. Conversely, there +# are NO local variables. Sorry, folks. +# +# A cshell-style "setenv" command is turned into a regular "set" command. +# +# +# The Prompt: +# ---------- +# +# You may, if you wish, have a command executed in your prompt. If +# the variable PS1 contains a dollar sign or a backquote, it is +# evaluated and the result used as the prompt, provided the evaluation +# did not produce a "not found" error message. The two special cases +# of PS1 consisting solely of "$" or "$ " are handled correctly. For +# example, to have the prompt contain the current directory followed +# by a space, enter: +# +# PS1=\'echo "`pwd` "\' +# +# You need the backslashed single quotes to prevent the command being +# evaluated by the variable-setting mechanism and the shell before it +# is assigned to PS1. +# +# To include the command number in your prompt, enter the command: +# +# PS1=\'echo "$cmdno "\' +# +# +# Shell Control-Flow Syntax: +# -------------------------- +# +# 'While', 'for', 'case', and 'if' commands entered in Bourne shell +# syntax are executed as normal. +# +# A valiant attempt is made to convert 'foreach' loops into 'for' loops, +# cshell-syntax 'while' loops into Bourne shell syntax, and 'switch' +# statements into 'case' statements. I cannot guarantee to always get it +# right. If you forget the 'do' in a 'while' or 'for' loop, or finish +# them with 'end' instead of 'done', this will be corrected. +# +# Note that cshell-to-Bourne control flow conversions do not take place +# if control is nested -- e.g., a 'foreach' inside a 'while' will fail. +# +# The simple-case cshell "if (condition) command" is turned into Bourne +# syntax. Other 'if' statements are left alone apart from making the +# 'then' a separate statement, because constructing a valid interactive +# cshell 'if' statement is essentially an exercise in frustration anyway. +# The cshell and Bourne shell have sufficiently different ideas about +# conditions that if is probably best to resign yourself to learning +# the Bourne shell conventions. +# +# Note that since most of the testing built-ins of the cshell are +# not available in the Bourne shell, a complex condition in a 'while' +# loop or an 'if' statement will probably fail. +# +# +# Bugs, Caveats, etc.: +# -------------------- +# +# This is not a super-speedy program. Be patient, especially on startup. +# +# To the best of my knowledge this program should work on ANY Bourne +# shell -- note that if your shell does not understand 'echo -n' you +# will have to re-set the values of '$n' and '$c'. +# +# This program may run out of stack space on a 16-bit machine where +# /bin/sh is not split-space. +# +# Mail checking is done every 10 commands if $MAIL is set in your +# environment. For anything fancier, you will have to hack the code. +# +# Because commands are stuffed in a file before sh is invoked on them, +# error messages from failed commands are ugly. +# +# Failed history substitutions either give nothing at all, or a +# "not found" style of error message. +# +# A command history is kept whether you want it or not. This may be +# perceived as a bug or a feature, depending on which side of bed you +# got out on. +# +# If you want a real backslash in a command, you will have to type two +# of them because the shell swallows the first backslash in the initial +# command pickup. This means that to include a non-history '!' in a +# command you need '\\!' -- a real wart, especially for net mail, +# but unavoidable. +# +# Commands containing an '@' will break all sorts of things. +# +# Very complex history substitutions may fail. +# +# File names containing numbers may break numeric history sustitutions. +# +# Commands containing bizzare sequences of characters may conflict +# with internal kludges. +# +# Aliasing something to "commands;logout" will not work -- if you +# want something to happen routinely on logout, put it in the file +# specified by $logoutfile, default = $HOME/.blogout. +# +# Please send all bug reports to ihnp4!utzoo!globetek!chris. +# Flames will be posted to net.general with 'Reply-to' set to your +# ' path... :-) ' +# +# +# +# ************* VERY IMPORTANT NOTICE ************* +# +# If your shell supports # comments, then REPLACE all the colon 'comments' +# with # comments. If it does not, then REMOVE all the 'comment' lines from the +# working copy of the file, as it will run MUCH faster -- the shell evaluates +# lines starting with a colon but does not actually execute them, so you will +# save the read-and-evaluate time by removing them. + +case "`echo -n foo`" in + -n*) + n= + c="\c" + ;; + foo) + n=-n + c= + ;; + *) + echo "Your 'echo' command is broken." + exit 1 + ;; +esac +history=${history-22} +savehist=${savehist-22} +histfile=${histfile-$HOME/.bhistory} +logoutfile=${logoutfile-$HOME/.blogout} +EDITOR=${EDITOR-ed} +VISUAL=${VISUAL-vi} +PAGER=${PAGER-more} + +aliasfile=${aliasfile-$HOME/.baliases} + +# the alias file may contain 1 blank line, so a test -s will not work + +case "`cat $aliasfile 2> /dev/null`" in + "") + doalias=no + ;; + *) + doalias=yes + ;; +esac + +if test -s "${sourcefile-$HOME/.bcshrc}" + then + . ${sourcefile-$HOME/.bcshrc} +fi + +if test -s "$histfile" + then + cmdno="`set - \`wc -l $histfile\`;echo $1`" + cmdno="`expr \"$cmdno\" + 1`" + lastcmd="`tail -1 $histfile`" + copy=false + ohist=$histfile + while test ! -w "$histfile" + do + echo "Cannot write to history file '$histfile'." + echo $n "Please enter a new history filename: $c" + read histfile + copy=true + done + if $copy + then + cp $ohist $histfile + fi +else + cat /dev/null > $histfile + cmdno=1 + lastcmd= +fi + +# keep track of command number as the default + +inc_cmdno=${inc_cmdo-yes} + +# default prompts -- PS1 and PS2 may be SET but EMPTY, so '${PS1-% }' syntax +# is not used here + +case "$PS1" in + "") + PS1="% " + ;; +esac +case "$PS2" in + "") + PS2="> " + ;; +esac + +export histfile savehist history aliasfile EDITOR VISUAL PAGER cmdno PS1 PS2 + +case "$MAIL" in + "") + ;; + *) + if [ -f $MAIL ]; then + mailsize=`set - \`wc -c $MAIL\`;echo $1` + else + mailsize=0 + fi + ;; +esac + +trap ':' 2 +trap exit 3 +trap "tail -$savehist $histfile>/tmp/hist$$;uniq /tmp/hist$$ > $histfile;\ +rm -f /tmp/*$$;exit 0" 15 + +getcmd=yes +mailcheck= +exclaim= +echoit= +mailprompt= + +while : +do + + run=yes + case "$mailprompt" in + "") + ;; + *) + echo "$mailprompt" + ;; + esac + case "$getcmd" in + yes) + : guess if the prompt should be evaluated or not + case "$PS1" in + \$|\$\ ) + echo $n "$PS1$c" + ;; + *\`*|*\$*) + tmp="`(eval $PS1) 2>&1`" + case "$tmp" in + *not\ found) + echo $n "$PS1$c" + ;; + *) + echo $n "$tmp$c" + ;; + esac + ;; + *) + echo $n "$PS1$c" + ;; + esac + + read cmd || cmd="exit" + ;; + *) ;; + esac + + case "$MAIL" in + "") + ;; + *) + : check for mail every 10 commands + case "$mailcheck" in + 1111111111) + mailcheck= + if [ -f $MAIL ]; then + newsize="`set - \`wc -c $MAIL\`;echo $1`" + else + newsize=0 + fi + if test "$newsize" -gt "$mailsize"; then + mailprompt="You have new mail" + else + mailprompt= + fi + mailsize=$newsize + ;; + *) + mailcheck=1$mailcheck + ;; + esac + ;; + esac + hist=no + + case "$cmd" in + "") + continue + ;; + sh) + sh + run=no + ;; + !!) + cmd=$lastcmd + echoit=yes + getcmd=no + continue + ;; + *:p) + cmd="`expr \"$cmd\" : '\(.*\):p'` +~+p" + getcmd=no + continue + ;; + foreach[\ \ ]*) + while test "$line" != "end"; do + echo $n "$PS2$c" + read line + cmd="${cmd};$line" + done + echo "$cmd" > /tmp/bcsh$$ + ed - /tmp/bcsh$$ << ++++ + s/end/done/ + s/foreach[ ]\(.*\)(/for \1 in / + s/)// + s/;/;do / + w +++++ + ;; + for[\ \ ]*|while[\ \ ]*) + # try to catch the most common cshell-to-Bourne-shell + # mistakes + + echo $n "$PS2$c" + read line + case "$line" in + *do) + line="do :" + ;; + *do*) + ;; + *) + line="do $line" + ;; + esac + + cmd="${cmd};$line" + while test "$line" != "done" -a "$line" != "end" + do + echo $n "$PS2$c" + read line + case "$line" in + end) + line=done + ;; + esac + cmd="${cmd};$line" + done + echo "$cmd" > /tmp/bcsh$$ + ;; + if[\ \ ]*) + while test "$line" != "fi" -a "$line" != "endif" + do + echo $n "$PS2$c" + read line + case "$line" in + *[a-z]*then) + line="`expr \"$line\" : '\(.*\)then'`;then" + ;; + endif) + line=fi + ;; + esac + cmd="${cmd};$line" + done + echo "$cmd" > /tmp/bcsh$$ + case "`grep then /tmp/bcsh$$`" in + "") + # fix 'if foo bar' cases + + ed - /tmp/bcsh$$ << ++++ + s/)/);then/ + s/.*/;fi/ + w +++++ + ;; + esac + ;; + case[\ \ ]*) + while test "$line" != "esac" + do + echo $n "$PS2$c" + read line + cmd="${cmd}@$line" + done + cmd="`echo \"$cmd\" | tr '@' ' '`" + echo "$cmd" > /tmp/bcsh$$ + ;; + switch[\ \ ]*) + while test "$line" != "endsw" + do + echo $n "$PS2$c" + read line + cmd="${cmd}@$line" + done + echo "$cmd" > /tmp/bcsh$$ + ed - /tmp/bcsh$$ << '++++' + 1,$s/@/\ +/g + g/switch.*(/s//case "/ + s/)/" in/ + 1,$s/case[ ]\(.*\):$/;;\ + \1)/ + 2d + 1,$s/endsw/;;\ +esac/ + g/breaksw/s/// + 1,$s/default.*/;;\ + *)/ + w +++++ + cmd="`cat /tmp/bcsh$$`" + ;; + *!*) + hist=yes + ;; + esac + + case "$hist" in + yes) + # deal with genuine exclamation marks, go back and parse again + + case "$cmd" in + *\>![\ \ ]*|*\\!*) + cmd="`echo \"$cmd\" | sed -e 's@\\!@REALEXCLAMATIONMARK@g'`" + exclaim=yes + getcmd=no + continue + ;; + esac + + # break command into elements, parse each one + + tmp= + for i in $cmd + do + # find element with !, peel off stuff up to ! + + case "$i" in + !) + # most likely a typo for !!, so fix it + front= + $i=!! + ;; + !!*) + front= + i="`expr \"$i\" : '.*\(!!.*\)'`" + ;; + *!!*) + front="`expr \"$i\" : '\(.*\)!!.*'`" + i="`expr \"$i\" : '.*\(!!.*\)'`" + ;; + !*) + front= + i="`expr \"$i\" : '.*!\(.*\)'`" + ;; + *) + tmp="$tmp$i " + continue + ;; + esac + case "$i" in + !!*) + # want last command + + rest="`expr \"$i\" : '!!\(.*\)'`" + i=$lastcmd + ;; + -*) + # we want to search back through the history list + + case "$i" in + -) + rest="`expr \"$i\" : '-\(.*\)'`" + i=$lastcmd + ;; + -[0-9]*) + wanted="`expr \"$i\" : '-\([0-9][0-9]*\).*'`" + rest="`expr \"$i\" : '-[0-9][0-9]*\(.*\)'`" + i="`tail -$wanted $histfile | sed -e "1q"`" + ;; + esac + ;; + [0-9]*) + # find which number command is wanted + + wanted="`expr \"$i\" : '\([0-9][0-9]*\).*'`" + rest="`expr \"$i\" : '[0-9][0-9]*\(.*\)'`" + i="`grep -n . $histfile | grep \"^$wanted\"`" + i="`expr \"$i\" : \"${wanted}.\(.*\)\"`" + ;; + \?*) + + # find which 'command-contains' match is wanted + + case "$i" in + \?{*}*) + wanted="`expr \"$i\" : '?{\(.*\)}.*'`" + rest="`expr \"$i\" : '?.*}\(.*\)'`" + ;; + \?*:*) + wanted="`expr \"$i\" : '?\(.*\):.*'`" + rest="`expr \"$i\" : '?.*\(:.*\)'`" + ;; + \?*) + wanted="`expr \"$i\" : '?\(.*\)'`" + rest= + ;; + esac + i="`grep \"$wanted\" $histfile | tail -1`" + ;; + *) + # find which 'start-of-command' match is wanted + + case "$i" in + {*}*) + wanted="`expr \"$i\" : '{\(.*\)}.*'`" + rest="`expr \"$i\" : '.*}\(.*\)'`" + ;; + *:*) + wanted="`expr \"$i\" : '\(.*\):.*'`" + rest="`expr \"$i\" : '.*\(:.*\)'`" + ;; + *) + wanted="$i" + rest= + ;; + esac + i="`grep \"^$wanted\" $histfile | tail -1`" + ;; + esac + + # see if we actually found anything to substitute + + case "$i" in + "") + badsub="Event not found" + break + ;; + *) + badsub=no + ;; + esac + + case "$rest" in + "") + tmp="$front$tmp$i " + continue + ;; + :[0-9]*) + # find which element of $i is wanted + + number="`expr \"$rest\" : ':\([0-9][0-9]*\).*'`" + rest="`expr \"$rest\" : ':[0-9][0-9]*\(.*\)'`" + + # count through $i till we get to the + # right element + + counter=0 + for element in $i + do + case "$counter" in + $number) + break + ;; + *) + counter="`expr \"$counter\" + 1`" + # counter=$[ $counter + 1 ] + ;; + esac + done + case "$counter" in + $number) + badsub=no + ;; + *) + badsub="Bad command element" + break + ;; + esac + tmp="$tmp$front$element$rest " + continue + ;; + :\$*) + # spin through $i till we hit the last element + + rest="`expr \"$rest\" : ':\$\(.*\)'`" + for element in $i + do + : + done + tmp="$tmp$front$element$rest " + continue + ;; + :\**) + # we want all elements except the command itself + + rest="`expr \"$rest\" : ':\*\(.*\)'`" + save=$i + set - $i + shift + case "$*" in + "") + badsub="No arguments to command '$save'" + break + ;; + *) + badsub=no + ;; + esac + tmp="$tmp$front$*$rest " + continue + ;; + :s*|:gs*) + # we are doing a substitution + # put / on end if needed + + case "$rest" in + :s/*/*/*|:gs/*/*/*) + ;; + :s/*/*|:gs/*/*) + rest="${rest}/" + ;; + esac + + # find what substitution is wanted + + first="`expr \"$rest\" : ':*s\/\(.*\)\/.*\/.*'`" + second="`expr \"$i\" : ':*s/.*/\(.*\)/.*'`" + + # see if it is a global substitution + + case "$rest" in + :gs*) + global=g + ;; + :s*) + global= + ;; + esac + rest="`expr \"$rest\" : '.*/.*/.*/\(.*\)'`" + i="`echo \"$i\" | sed -e \"s@$first@$second@$global\"`" + + # see if subsitution worked + + case "$i" in + "") + badsub="Substiution failed" + break + ;; + *) + badsub=no + ;; + esac + tmp="$tmp$front$i$rest " + continue + ;; + *) + tmp="$tmp$front$i$rest " + ;; + esac + done + case "$badsub" in + no) + ;; + *) + echo "$badsub" + badsub=no + continue + ;; + esac + cmd="$tmp" + echoit=yes + getcmd=no + continue + ;; + *) + run=yes + ;; + esac + + case "$cmd" in + *\^*\^*\^*) + # see if the substitution is global + case "$cmd" in + g*) + global=g + ;; + *) + global= + ;; + esac + + # put a '^' on the end if necessary + case "$cmd" in + *\^) + ;; + *) + cmd="${cmd}^" + ;; + esac + + # find what substitution is wanted + + first="`expr \"$cmd\" : '*\^\(.*\)\^.*\^.*'`" + second="`expr \"$cmd\" : '*\^.*\^\(.*\)\^.*'`" + rest="`expr \"$cmd\" : '*\^.*\^.*\^\(.*\)'`" + cmd="`echo \"$lastcmd\" | sed -e \"s@$first@$second@$global\"`$rest" + + # see if the substitution worked + + case "$cmd" in + "") + echo "Substitution failed" + continue + ;; + esac + echoit=yes + getcmd=no + continue + ;; + *~e) + echo "$cmd" | sed -e "s@~e@@" > /tmp/bcsh$$ + $EDITOR /tmp/bcsh$$ + cmd="`cat /tmp/bcsh$$`" + getcmd=no + continue + ;; + *~v) + echo "$cmd" | sed -e "s@~v@@" > /tmp/bcsh$$ + echo "$lastcmd" > /tmp/bcsh$$ + $VISUAL /tmp/bcsh$$ + cmd="`cat /tmp/bcsh$$`" + getcmd=no + continue + ;; + exec[\ \ ]*) + tail -$savehist $histfile>/tmp/hist$$ + uniq /tmp/hist$$ > $histfile + rm -f /tmp/*$$ + echo $cmd > /tmp/cmd$$ + . /tmp/cmd$$ + ;; + login[\ \ ]*|newgrp[\ \ ]*) + tail -$savehist $histfile>/tmp/hist$$ + uniq /tmp/hist$$ > $histfile + rm -f /tmp/*$$ + echo $cmd > /tmp/cmd$$ + . /tmp/cmd$$ + ;; + logout|exit|bye) + if test -s "$logoutfile" + then + # sh $logoutfile + $SHELL $logoutfile + fi + tail -$savehist $histfile > /tmp/hist$$ + uniq /tmp/hist$$ > $histfile + rm -f /tmp/*$$ + exit 0 + ;; + h|history) + grep -n . $histfile | tail -$history | sed -e 's@:@ @' | $PAGER + continue + ;; + h[\ \ ]\|*|h[\ \ ]\>*|h\|*|h\>*) + cmd="`echo \"$cmd\" | sed -e \"s@h@grep -n . $histfile | tail -$history | sed -e 's@:@ @'@\"`" + getcmd=no + continue + ;; + history[\ \ ]*\|*|history[\ \ ]*\>*) + cmd="`echo \"$cmd\" | sed -e \"s@history@grep -n . $histfile | tail -$history | sed -e 's@:@ @'@\"`" + getcmd=no + continue + ;; + source[\ \ ]*) + set - $cmd + shift + echo . $* > /tmp/cmd$$ + . /tmp/cmd$$ + run=no + ;; + wait) + wait + run=no + ;; + .[\ \ ]*) + echo $cmd > /tmp/cmd$$ + . /tmp/cmd$$ + run=no + ;; + cd|cd[\ \ ]*) + # check if it will work first, or else this shell will terminate + # if the cd dies. If you have a built-in test, you might want + # to replace the try-it-and-see below with a couple of tests, + # but it is probably just as fast like this. + + echo $cmd > /tmp/cmd$$ + if ($SHELL /tmp/cmd$$) ; then + . /tmp/cmd$$ + fi + run=no + ;; + awk[\ \ ]*|dd[\ \ ]*|cc[\ \ ]*|make[\ \ ]*) + # these are the only commands I can think of whose syntax + # includes an equals sign. Add others as you find them. + + echo "$cmd" > /tmp/bcsh$$ + ;; + setenv*|*=*) + # handle setting shell variables, turning cshell syntax to Bourne + # syntax -- note all variables must be exported or they will not + # be usable in other commands + + echo "$cmd" > /tmp/cmd$$ + ed - /tmp/cmd$$ << ++++ + g/^setenv[ ]/s/[ ]/@/ + g/^setenv@/s/[ ]/=/ + g/^setenv@/s/// + g/^set/s/// + .t. + \$s/=.*// + s/^/export / + w +++++ + . /tmp/cmd$$ + rm -f /tmp/cmd$$ + run=no + ;; + unset[\ \ ]*|umask[\ \ ]*|export[\ \ ]*|set[\ \ ]*) + # handle commands which twiddle current environment + + $cmd + run=no + ;; + alias|alias[\ \ ]) + if [ -f $aliasfile ]; then + $PAGER $aliasfile + fi + lastcmd=$cmd + run=no + continue + ;; + alias[\ \ ]*) + case "$cmd" in + alias[\ \ ]\|*|alias[\ \ ]\>*) + cmd="`echo \"$cmd\" | sed -e \"s@alias@cat $aliasfile@\"`" + getcmd=no + continue + ;; + alias[\ \ ]*[\ \ ]*) + ;; + *) + echo "Syntax: alias name command" + cmd= + continue + ;; + esac + set - $cmd + shift + cmd="$*" + + # make sure there is always 1 blank line in file so + # unaliasing will always work -- ed normally refuses + # to write an empty file + echo "" >> $aliasfile + cat << ++++ >> $aliasfile +$cmd +++++ + +# ed - $aliasfile << '++++' +# g/alias[ ]/s/// +# g/^['"]\(.*\)['"]$/s//\1/ +# g/^/s//alias / +# w +#++++ + + sort -u -o $aliasfile $aliasfile + doalias=yes + cmd="alias $cmd" + run=no + ;; + unalias[\ \ ]*) + set - $cmd + case "$#" in + 2) + cmd=$2 + ;; + *) + echo "Syntax: unalias alias_name" + continue + ;; + esac + ed - $aliasfile << ++++ + /^$cmd[ ]/d + w +++++ + case "`set - \`wc -l $aliasfile\`;echo $1`" in + 1) + # just removed last alias + doalias=no + ;; + esac + run=no + ;; + *) + case "$doalias" in + yes) + set - $cmd + tmp="`grep \"^$1 \" $aliasfile`" + case "$tmp" in + $1[\ \ ]*) + shift + cmd=$* + set - $tmp + shift + tmp=$* + case "$tmp" in + *\$*) + # uses positional variables + + cmd="set - $cmd ; $tmp" + getcmd=no + continue + ;; + *) + cmd="$tmp $cmd" + getcmd=no + continue + ;; + esac + ;; + *) + echo "$cmd" > /tmp/bcsh$$ + ;; + esac + ;; + no) + echo "$cmd" > /tmp/bcsh$$ + ;; + esac + ;; + esac + + case "$cmd" in + *+~+p) + cmd="`expr \"$cmd\" : '\(.*\)+~+p'`" + echoit=yes + run=no + ;; + esac + + case "$cmd" in + "") + continue + ;; + *) + case "$exclaim" in + yes) + cmd="`echo \"$cmd\" | sed -e 's@REALEXCLAMATIONMARK@!@g'`" + echo "$cmd" > /tmp/bcsh$$ + ;; + esac + case "$echoit" in + yes) + echo $cmd + ;; + esac + case "$run" in + yes) + case "${noclobber+yes}" in + yes) + case "$cmd" in + *\>![\ \ ]*) + ed - /tmp/bcsh$$ << ++++ + g/>!/s//>/ + w +++++ + ;; + *\>\>*) + ;; + *\>*) + outfile="`expr \"$cmd\" : '.*>\(.*\)'`" + case "$outfile" in + \&*) + ;; + *) + set - $outfile + outfile="$1" + if test -s "$outfile" + then + case "${iclobber+yes}" in + yes) + echo $n "Overwrite ${outfile}? $c" + read answer + case "$answer" in + y*) + ;; + *) + echo ':' > /tmp/bcsh$$ + ;; + esac + ;; + *) + echo "${outfile}: file exists" + echo ':' > /tmp/bcsh$$ + ;; + esac + fi + ;; + esac + ;; + esac + ;; + *) + case "$cmd" in + *\>![\ \ ]*) + ed - /tmp/bcsh$$ << ++++ + g/>!/s//>/g + w +++++ + ;; + esac + ;; + esac + (trap 'exit 1' 2 3; $BASH /tmp/bcsh$$) + ;; + esac + case "$cmd" in + $lastcmd) + ;; + *) + case "$exclaim" in + yes) + cmd="`echo \"$cmd\" | sed -e 's@!@\\\\!@g'`" + ;; + esac + + cat << ++++ >> $histfile +$cmd +++++ + lastcmd=$cmd + + case "$inc_cmdno" in + yes) + cmdno="`expr \"$cmdno\" + 1`" + # cmdno=$[$cmdno + 1] + ;; + esac + ;; + esac + ;; + esac + + # The next commented-out line sets the prompt to include the command + # number -- you should only un-comment this if it is the ONLY thing + # you ever want as your prompt, because it will override attempts + # to set PS1 from the command level. If you want the command number + # in your prompt without sacrificing the ability to change the prompt + # later, replace the default setting for PS1 before the beginning of + # the main loop with the following: PS1='echo -n "${cmdno}% "' + # Doing it this way is, however, slower than the simple version below. + + PS1="${cmdno}% " + + getcmd=yes + echoit=no + exclaim=no +done +exit 0 + +# Christine Robertson {linus, ihnp4, decvax}!utzoo!globetek!chris diff --git a/examples/scripts/precedence b/examples/scripts/precedence new file mode 100644 index 0000000..9bbdb97 --- /dev/null +++ b/examples/scripts/precedence @@ -0,0 +1,75 @@ +# @(#)precedence_test 1.0 91/07/24 Maarten Litmaath +# test of relative precedences for `&&' and `||' operators + +echo "\`Say' echos its argument. Its return value is of no interest." +case `echo -n` in + '') Say () { echo -n "$*" ; } ;; + *) Say () { echo "$*\c" ; } ;; +esac + +echo "\`Truth' echos its argument and returns a TRUE result." +Truth () { + Say $1; + return 0; +} + +echo "\`False' echos its argument and returns a FALSE result." +False () { + Say $1; + return 1; +} + +echo "" + +cmd1='$open $test1 && $test2 $close || $test3' +cmd2='$test1 || $open $test2 && $test3 $close' + +grouping_sh= +grouping_C='( )' + +test3='Say 3' + +for i in 1 2 +do + eval proto=\$cmd$i + + for test1 in 'Truth 1' 'False 1' + do + for test2 in 'Truth 2' 'False 2' + do + for precedence in sh C + do + eval set x \$grouping_$precedence + shift + open=${1-' '} + close=${2-' '} + eval cmd=\""$proto"\" + Say "$cmd output=" + output=`eval "$cmd"` + Say "$output" + read correct || { echo 'Input fubar. Abort.' >&2; exit 1; } + test "X$output" = "X$correct" || echo " correct=$correct" + echo '' + done + + echo '' + done + done +done << EOF +12 +12 +123 +123 +13 +13 +13 +13 +13 +1 +13 +1 +123 +123 +12 +12 +EOF diff --git a/examples/scripts/shprompt b/examples/scripts/shprompt new file mode 100755 index 0000000..ec8b997 --- /dev/null +++ b/examples/scripts/shprompt @@ -0,0 +1,137 @@ +# +# shprompt -- give a prompt and get an answer satisfying certain criteria +# +# shprompt [-dDfFsy] prompt +# s = prompt for string +# f = prompt for filename +# F = prompt for full pathname to a file or directory +# d = prompt for a directory name +# D = prompt for a full pathname to a directory +# y = prompt for y or n answer +# +# Chet Ramey +# chet@ins.CWRU.Edu + +type=file + +OPTS=dDfFsy + +succeed() +{ + echo "$1" + exit 0 +} + +while getopts "$OPTS" c +do + case "$c" in + s) type=string + ;; + f) type=file + ;; + F) type=path + ;; + d) type=dir + ;; + D) type=dirpath + ;; + y) type=yesno + ;; + ?) echo "usage: $0 [-$OPTS] prompt" 1>&2 + exit 2 + ;; + esac +done + +if [ "$OPTIND" -gt 1 ] ; then + shift $[$OPTIND - 1] +fi + +while : +do + case "$type" in + string) + echo -n "$1" 1>&2 + read ans || exit 1 + if [ -n "$ans" ] ; then + succeed "$ans" + fi + ;; + file|path) + echo -n "$1" 1>&2 + read ans || exit 1 + # + # use `fn' and eval so that bash will do tilde expansion for + # me + # + eval fn="$ans" + case "$fn" in + /*) if test -e "$fn" ; then + succeed "$fn" + else + echo "$0: '$fn' does not exist" 1>&2 + fi + ;; + *) if [ "$type" = "path" ] ; then + echo "$0: must give full pathname to file" 1>&2 + else + if test -e "$fn" ; then + succeed "$fn" + else + echo "$0: '$fn' does not exist" 1>&2 + fi + fi + ;; + esac + ;; + dir|dirpath) + echo -n "$1" 1>&2 + read ans || exit 1 + # + # use `fn' and eval so that bash will do tilde expansion for + # me + # + eval fn="$ans" + case "$fn" in + /*) if test -d "$fn" ; then + succeed "$fn" + elif test -e "$fn" ; then + echo "$0 '$fn' is not a directory" 1>&2 + else + echo "$0: '$fn' does not exist" 1>&2 + fi + ;; + *) if [ "$type" = "dirpath" ] ; then + echo "$0: must give full pathname to directory" 1>&2 + else + if test -d "$fn" ; then + succeed "$fn" + elif test -e "$fn" ; then + echo "$0 '$fn' is not a directory" 1>&2 + else + echo "$0: '$fn' does not exist" 1>&2 + fi + fi + ;; + esac + ;; + yesno) + echo -n "$1" 1>&2 + read ans || exit 1 + case "$ans" in + y|Y|[yY][eE][sS]) + succeed "yes" + ;; + n|N|[nN][oO]) + succeed "no" + exit 0 + ;; + *) + echo "$0: yes or no required" 1>&2 + ;; + esac + ;; + esac +done + +exit 1 diff --git a/examples/startup-files/Bash_aliases b/examples/startup-files/Bash_aliases new file mode 100644 index 0000000..012ad5c --- /dev/null +++ b/examples/startup-files/Bash_aliases @@ -0,0 +1,63 @@ +# Some useful aliases. +alias texclean='rm -f *.toc *.aux *.log *.cp *.fn *.tp *.vr *.pg *.ky' +alias clean='echo -n "Really clean this directory?"; + read yorn; + if test "$yorn" = "y"; then + rm -f \#* *~ .*~ *.bak .*.bak *.tmp .*.tmp core a.out; + echo "Cleaned."; + else + echo "Not cleaned."; + fi' +alias h='history' +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" + +# +# Csh compatability: +# +alias unsetenv=unset +function setenv () { + export $1="$2" +} + +# Function which adds an alias to the current shell and to +# the ~/.bash_aliases file. +add-alias () +{ + local name=$1 value="$2" + echo alias $name=\'$value\' >>~/.bash_aliases + eval alias $name=\'$value\' + alias $name +} + +# "repeat" command. Like: +# +# repeat 10 echo foo +repeat () +{ + local count="$1" i; + shift; + for i in $(seq 1 "$count"); + do + eval "$@"; + done +} + +# Subfunction needed by `repeat'. +seq () +{ + local lower upper output; + lower=$1 upper=$2; + while [ $lower -le $upper ]; + do + output="$output $lower"; + lower=$[ $lower + 1 ]; + done; + echo $output +} + diff --git a/examples/startup-files/Bash_profile b/examples/startup-files/Bash_profile new file mode 100644 index 0000000..b1b24c0 --- /dev/null +++ b/examples/startup-files/Bash_profile @@ -0,0 +1,20 @@ +# Startup file for bash login shells. +# +default_dir=/usr/local/lib/ + +if [ "$PS1" ]; then + PS1='\u@\h(\#)$ ' + ignoreeof=3 +fi + +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 +fi + diff --git a/examples/startup-files/Bashrc b/examples/startup-files/Bashrc new file mode 100644 index 0000000..935bff8 --- /dev/null +++ b/examples/startup-files/Bashrc @@ -0,0 +1,72 @@ +# Bourne Again SHell init file. +# +# Files you make look like rw-rw-r +umask 002 + +# Don't make useless coredump files. If you want a coredump, +# say "ulimit -c unlimited" and then cause a segmentation fault. +ulimit -c 0 + +# Sometimes, there are lots of places that one can find tex inputs. +export TEXINPUTS=.:$HOME/bin:/usr/lib/tex/inputs:/usr/local/lib/tex/inputs + +# Where's the Gnu stuff at? +GNU=/usr/gnu/bin +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 +fi + +if [ -d $HOME/bin ]; then + MY_PATH=$MY_PATH:$HOME/bin +fi + +if [ -d /usr/hosts ]; then + STANDARD_PATH=$STANDARD_PATH:/usr/hosts +fi + +PATH=.:$MY_PATH:$UTIL_PATH:$STANDARD_PATH + +# If running interactively, then: +if [ "$PS1" ]; then + + # 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 auto_resume if you want to resume on "emacs", as well as on + # "%emacs". + auto_resume= + + # Set notify if you want to be asynchronously notified about background + # job completion. + notify= + + # Make it so that failed `exec' commands don't flush this shell. + no_exit_on_failed_exec= + + if [ ! "$LOGIN_SHELL" ]; then + PS1="\u@\h\$ " + fi + + HISTSIZE=256 + MAILCHECK=60 + + # 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 diff --git a/examples/startup-files/bash-profile b/examples/startup-files/bash-profile new file mode 100644 index 0000000..01c322a --- /dev/null +++ b/examples/startup-files/bash-profile @@ -0,0 +1,54 @@ +HOME=/usr/homes/chet +MAIL=/usr/homes/chet/mbox +MAILCHECK=30 +HISTFILE=/usr/homes/chet/.history + +MACHINE=$(/usr/local/bin/machine) +HOST=$(hostname) + +PATH1=/usr/homes/chet/bin.$MACHINE:/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: +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 + +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 + +# +# Bogus 1003.2 variables. This should really be in /etc/profile +# +LOGNAME=${USER-$(whoami)} +TZ=EST5EDT + +export HOME ENV VISUAL EDITOR MAIL SHELL PATH TERM +export PAGER LESS TERMCAP HISTSZIE HISTFILE +export MAIL MAILCHECK HOST HOSTNAME NNTPSERVER NS LOGNAME TZ + +PS1="${HOST}$ " +PS2='> ' +export PS1 PS2 + +umask 022 + +if [ -f /unix ] ; then + stty intr ^c +fi + +if [ -f ~/.bashrc ] ; then + . ~/.bashrc +fi diff --git a/examples/startup-files/bashrc b/examples/startup-files/bashrc new file mode 100644 index 0000000..5363e58 --- /dev/null +++ b/examples/startup-files/bashrc @@ -0,0 +1,139 @@ +if [ "$PS1" != "" ] ; then + +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 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 c="clear" +alias m="more" +alias j="jobs" + +if [ -z "$HOST" ] ; then + export HOST=`hostname` +fi + +history_control=ignoredups + +psgrep() +{ + ps -aux | grep $1 | grep -v grep +} + +# +# This is a little like `zap' from Kernighan and Pike +# + +pskill() +{ + local pid + + pid=$(ps -ax | grep $1 | grep -v grep | awk '{ print $1 }') + echo -n "killing $1 (process $pid)..." + kill -9 $pid + echo "slaughtered." +} + +term() +{ + TERM=$1 + export TERM + tset +} + +cd() +{ + builtin cd $* + xtitle $HOST: $PWD +} + +bold() +{ + tput smso +} + +unbold() +{ + tput rmso +} + +if [ -f /unix ] ; then +clear() +{ + tput clear +} +fi + +rot13() +{ + if [ $# = 0 ] ; then + tr "[a-m][n-z][A-M][N-Z]" "[n-z][a-m][N-Z][A-M]" + else + tr "[a-m][n-z][A-M][N-Z]" "[n-z][a-m][N-Z][A-M]" < $1 + fi +} + +watch() +{ + if [ $# -ne 1 ] ; then + tail -f nohup.out + else + tail -f $1 + fi +} + +# +# Remote login passing all 8 bits (so meta key will work) +# +rl() +{ + rlogin $* -8 +} + +function setenv() +{ + if [ $# -ne 2 ] ; then + echo "setenv: Too few arguments" + else + export $1="$2" + fi +} + +function chmog() +{ + if [ $# -ne 4 ] ; then + echo "usage: chmog mode owner group file" + return 1 + else + chmod $1 $4 + chown $2 $4 + chgrp $3 $4 + fi +} + +# +# Source kshenv for ksh-compatibility definitions +# + +if [ -f ~/.kshenv ] ; then + . ~/.kshenv +fi + +fi +#end of .bashrc diff --git a/examples/suncmd.termcap b/examples/suncmd.termcap new file mode 100644 index 0000000..c3422fb --- /dev/null +++ b/examples/suncmd.termcap @@ -0,0 +1,30 @@ +#Posted-Date: Fri, 9 Mar 90 18:34:29 EST +#Date: Fri, 9 Mar 90 18:34:29 EST +#From: "Eirik Fuller" <wonton.tn.cornell.edu!eirik@ucsbcsl.UUCP> +#To: bfox@ai.mit.edu (Brian Fox) +#Subject: Patch to bash 1.05 for SunView +# +#I think this works: +# +Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s: +# +#Another alternative is to send the ti string at startup time (and, I +#guess, the te string at exit time); that is how vi works in a cmdtool. +#The best reason to not do this is that this also disables scrolling +#which, as I understand it, is why anyone would use cmdtool in the +#first place. Sending the ti string at startup time would do strange +#things on other systems too; in xterm it would use the alternate +#screen. +# +#The problem with cmdtool, in case that is less than obvious, is that +#almost none of the capabilities advertised in /etc/termcap are enabled +#while scrolling is enabled. It has other problems too, like being +#part of an outdated proprietary windowing system, but there's probably +#no need to dwell on that. In a sense, though, the sun-cmd termcap +#entry doesn't lie about the capabilities; I think the termcap man page +#does warn about some terminals having cursor motion capabilities only +#in the "ti/te window". +# +#A general solution to this problem would require a termcap capability +#which somehow tells which features are available outside of the ti/te +#window. There is no such capability in termcap now, of course. diff --git a/execute_cmd.c b/execute_cmd.c new file mode 100644 index 0000000..55274ea --- /dev/null +++ b/execute_cmd.c @@ -0,0 +1,3698 @@ +/* execute_command.c -- Execute a COMMAND structure. */ + +/* 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 (AIX) && defined (RISC6000) && !defined (__GNUC__) + #pragma alloca +#endif /* AIX && RISC6000 && !__GNUC__ */ + +#include <stdio.h> +#include <ctype.h> +#include "bashtypes.h" +#include <sys/file.h> +#include "filecntl.h" +#include "posixstat.h" +#include <signal.h> + +#if !defined (SIGABRT) +#define SIGABRT SIGIOT +#endif + +#include <sys/param.h> +#include <errno.h> + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "shell.h" +#include "y.tab.h" +#include "flags.h" +#include "hash.h" +#include "jobs.h" +#include "execute_cmd.h" + +#include "sysdefs.h" +#include "builtins/common.h" +#include "builtins/builtext.h" /* list of builtins */ + +#include <glob/fnmatch.h> +#include <tilde/tilde.h> + +#if defined (BUFFERED_INPUT) +# include "input.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 command_string_index, variable_context, line_number; +extern int dot_found_in_search; +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 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 add_undo_close_redirect (), add_exec_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 char *find_user_command_internal (), *find_user_command_in_path (); + +/* The line number that the currently executing function starts on. */ +static int function_line_number = 0; + +/* Set to 1 if fd 0 was the subject of redirection to a subshell. */ +static int stdin_redir = 0; + +/* The name of the command that is currently being executed. + `test' needs this, for example. */ +char *this_command_name; + +struct stat SB; /* used for debugging */ + +static REDIRECTEE rd; + +/* For catching RETURN in a function. */ +int return_catch_flag = 0; +int return_catch_value; +jmp_buf return_catch; + +/* The value returned by the last synchronous command. */ +int last_command_exit_value = 0; + +/* The list of redirections to perform which will undo the redirections + that I made in the shell. */ +REDIRECT *redirection_undo_list = (REDIRECT *)NULL; + +/* The list of redirections to perform which will undo the internal + redirections performed by the `exec' builtin. These are redirections + that must be undone even when exec discards redirection_undo_list. */ +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; + +struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; + +#define FD_BITMAP_DEFAULT_SIZE 32 +/* Functions to allocate and deallocate the structures used to pass + information from the shell to its children about file descriptors + to close. */ +struct fd_bitmap * +new_fd_bitmap (size) + long size; +{ + struct fd_bitmap *ret; + + ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); + + ret->size = size; + + if (size) + { + ret->bitmap = xmalloc (size); + bzero (ret->bitmap, size); + } + else + ret->bitmap = (char *)NULL; + return (ret); +} + +void +dispose_fd_bitmap (fdbp) + struct fd_bitmap *fdbp; +{ + FREE (fdbp->bitmap); + free (fdbp); +} + +void +close_fd_bitmap (fdbp) + struct fd_bitmap *fdbp; +{ + register int i; + + if (fdbp) + { + for (i = 0; i < fdbp->size; i++) + if (fdbp->bitmap[i]) + { + close (i); + fdbp->bitmap[i] = 0; + } + } +} + +/* 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. + + EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible + return values. Executing a command with nothing in it returns + EXECUTION_SUCCESS. */ +execute_command (command) + COMMAND *command; +{ + struct fd_bitmap *bitmap; + int result; + + current_fds_to_close = (struct fd_bitmap *)NULL; + bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); + begin_unwind_frame ("execute-command"); + add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); + + /* Just do the command, but not asynchronously. */ + result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); + + dispose_fd_bitmap (bitmap); + discard_unwind_frame ("execute-command"); + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + return (result); +} + +/* Return 1 if TYPE is a shell control structure type. */ +static int +shell_control_structure (type) + enum command_type type; +{ + switch (type) + { + case cm_for: +#if defined (SELECT_COMMAND) + case cm_select: +#endif + case cm_case: + case cm_while: + case cm_until: + case cm_if: + case cm_group: + return (1); + + default: + return (0); + } +} + +/* A function to use to unwind_protect the redirection undo list + for loops. */ +static void +cleanup_redirects (list) + REDIRECT *list; +{ + do_redirections (list, 1, 0, 0); + dispose_redirects (list); +} + +/* Function to unwind_protect the redirections for functions and builtins. */ +static void +cleanup_func_redirects (list) + REDIRECT *list; +{ + do_redirections (list, 1, 0, 0); +} + +static void +dispose_exec_redirects () +{ + if (exec_redirection_undo_list) + { + dispose_redirects (exec_redirection_undo_list); + exec_redirection_undo_list = (REDIRECT *)NULL; + } +} + +#if defined (JOB_CONTROL) +/* A function to restore the signal mask to its proper value when the shell + is interrupted or errors occur while creating a pipeline. */ +static int +restore_signal_mask (set) + sigset_t set; +{ + return (sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL)); +} +#endif /* JOB_CONTROL */ + +/* A debugging function that can be called from gdb, for instance. */ +void +open_files () +{ + register int i; + int f, fd_table_size; + + fd_table_size = getdtablesize (); + + fprintf (stderr, "pid %d open files:", getpid ()); + for (i = 3; i < fd_table_size; i++) + { + if ((f = fcntl (i, F_GETFD, 0)) != -1) + fprintf (stderr, " %d (%s)", i, f ? "close" : "open"); + } + fprintf (stderr, "\n"); +} + +#define DESCRIBE_PID(pid) if (interactive) describe_pid (pid) + +/* Execute the command passed in COMMAND, perhaps doing it asynchrounously. + COMMAND is exactly what read_command () places into GLOBAL_COMMAND. + ASYNCHROUNOUS, if non-zero, says to do this command in the background. + PIPE_IN and PIPE_OUT are file descriptors saying where input comes + from and where it goes. They can have the value of NO_PIPE, which means + I/O is stdin/stdout. + FDS_TO_CLOSE is a list of file descriptors to close once the child has + been forked. This list often contains the unusable sides of pipes, etc. + + 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, + 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; + + if (!command || breaking || continuing) + return (EXECUTION_SUCCESS); + + run_pending_traps (); + + invert = (command->flags & CMD_INVERT_RETURN) != 0; + + /* 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) || + (shell_control_structure (command->type) && + (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous))) + { + pid_t paren_pid; + + /* Fork a subshell, turn off the subshell bit, turn off job + control and call execute_command () on the command again. */ + paren_pid = make_child (savestring (make_command_string (command)), + asynchronous); + if (paren_pid == 0) + { + 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), + turn off `asynchronous', so that two subshells aren't spawned. + + 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 + builtins in the background, which executed in a subshell + environment. I just don't see the need to fork two subshells. */ + + /* Don't fork again, we are already in a subshell. A `doubly + async' shell is not interactive, however. */ + if (asynchronous) + { +#if defined (JOB_CONTROL) + /* If a construct like ( exec xxx yyy ) & is given while job + control is active, we want to prevent exec from putting the + subshell back into the original process group, carefully + undoing all the work we just did in make_child. */ + original_pgrp = -1; +#endif /* JOB_CONTROL */ + interactive_shell = 0; + asynchronous = 0; + } + + /* Subshells are neither login nor interactive. */ + login_shell = interactive = 0; + + subshell_environment = 1; + +#if defined (JOB_CONTROL) + /* Delete all traces that there were any jobs running. This is + only for subshells. */ + without_job_control (); +#endif /* JOB_CONTROL */ + do_piping (pipe_in, pipe_out); + + /* If this is a user subshell, set a flag if stdin was redirected. + This is used later to decide whether to redirect fd 0 to + /dev/null for async commands in the subshell. This adds more + 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) + { + case r_input_direction: + case r_inputa_direction: + case r_input_output: + case r_reading_until: + case r_deblank_reading_until: + stdin_redir++; + break; + case r_duplicating_input: + case r_duplicating_input_word: + case r_close_this: + if (r->redirector == 0) + stdin_redir++; + break; + } + } + + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + /* Do redirections, then dispose of them before recursive call. */ + if (command->redirects) + { + if (do_redirections (command->redirects, 1, 0, 0) != 0) + exit (EXECUTION_FAILURE); + + dispose_redirects (command->redirects); + command->redirects = (REDIRECT *)NULL; + } + + /* If this is a simple command, tell execute_disk_command that it + might be able to get away without forking and simply exec. + This means things like ( sleep 10 ) will only cause one fork. */ + if (user_subshell && command->type == cm_simple) + { + command->flags |= CMD_NO_FORK; + command->value.Simple->flags |= CMD_NO_FORK; + } + + /* If we're inside a function while executing this subshell, we + need to handle a possible `return'. */ + function_value = 0; + if (return_catch_flag) + function_value = setjmp (return_catch); + + if (function_value) + return_code = return_catch_value; + else + return_code = execute_command_internal + (command, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); + + /* If we were explicitly placed in a subshell with (), we need + to do the `shell cleanup' things, such as running traps[0]. */ + if (user_subshell && signal_is_trapped (0)) + { + last_command_exit_value = return_code; + return_code = run_exit_trap (); + } + + exit (return_code); + } + else + { + close_pipes (pipe_in, pipe_out); + +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + /* 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 + and return its exit status as usual. */ + if (pipe_out != NO_PIPE) + return (EXECUTION_SUCCESS); + + stop_pipeline (asynchronous, (COMMAND *)NULL); + + if (!asynchronous) + { + 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); + } + else + return (last_command_exit_value); + } + else + { + DESCRIBE_PID (paren_pid); + + run_pending_traps (); + + return (EXECUTION_SUCCESS); + } + } + } + + /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input + redirection.) */ + if (do_redirections (command->redirects, 1, 1, 0) != 0) + { + cleanup_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + dispose_exec_redirects (); + return (EXECUTION_FAILURE); + } + + if (redirection_undo_list) + { + my_undo_list = (REDIRECT *)copy_redirects (redirection_undo_list); + dispose_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + } + else + my_undo_list = (REDIRECT *)NULL; + + if (exec_redirection_undo_list) + { + exec_undo_list = (REDIRECT *)copy_redirects (exec_redirection_undo_list); + dispose_redirects (exec_redirection_undo_list); + exec_redirection_undo_list = (REDIRECT *)NULL; + } + else + exec_undo_list = (REDIRECT *)NULL; + + if (my_undo_list || exec_undo_list) + begin_unwind_frame ("loop_redirections"); + + if (my_undo_list) + add_unwind_protect ((Function *)cleanup_redirects, my_undo_list); + + if (exec_undo_list) + add_unwind_protect ((Function *)dispose_redirects, exec_undo_list); + + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + QUIT; + + switch (command->type) + { + case cm_for: + if (ignore_return) + command->value.For->flags |= CMD_IGNORE_RETURN; + exec_result = execute_for_command (command->value.For); + break; + +#if defined (SELECT_COMMAND) + case cm_select: + if (ignore_return) + command->value.Select->flags |= CMD_IGNORE_RETURN; + exec_result = execute_select_command (command->value.Select); + break; +#endif + + case cm_case: + if (ignore_return) + command->value.Case->flags |= CMD_IGNORE_RETURN; + exec_result = execute_case_command (command->value.Case); + break; + + case cm_while: + if (ignore_return) + command->value.While->flags |= CMD_IGNORE_RETURN; + exec_result = execute_while_command (command->value.While); + break; + + case cm_until: + if (ignore_return) + command->value.While->flags |= CMD_IGNORE_RETURN; + exec_result = execute_until_command (command->value.While); + break; + + case cm_if: + if (ignore_return) + command->value.If->flags |= CMD_IGNORE_RETURN; + exec_result = execute_if_command (command->value.If); + break; + + case cm_group: + + /* This code can be executed from either of two paths: an explicit + '{}' command, or via a function call. If we are executed via a + function call, we have already taken care of the function being + executed in the background (down there in execute_simple_command ()), + and this command should *not* be marked as asynchronous. If we + are executing a regular '{}' group command, and asynchronous == 1, + we must want to execute the whole command in the background, so we + need a subshell, and we want the stuff executed in that subshell + (this group command) to be executed in the foreground of that + subshell (i.e. there will not be *another* subshell forked). + + What we do is to force a subshell if asynchronous, and then call + execute_command_internal again with asynchronous still set to 1, + but with the original group command, so the printed command will + look right. + + The code above that handles forking off subshells will note that + both subshell and async are on, and turn off async in the child + after forking the subshell (but leave async set in the parent, so + the normal call to describe_pid is made). This turning off + async is *crucial*; if it is not done, this will fall into an + infinite loop of executions through this spot in subshell after + subshell until the process limit is exhausted. */ + + if (asynchronous) + { + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = + execute_command_internal (command, 1, pipe_in, pipe_out, + fds_to_close); + } + else + { + if (ignore_return && command->value.Group->command) + command->value.Group->command->flags |= CMD_IGNORE_RETURN; + exec_result = + execute_command_internal (command->value.Group->command, + asynchronous, pipe_in, pipe_out, + fds_to_close); + } + 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; + + 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 (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 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 (!ignore_return && exit_immediately_on_error && !invert && + (exec_result != EXECUTION_SUCCESS)) + { + last_command_exit_value = exec_result; + run_pending_traps (); + longjmp (top_level, EXITPROG); + } + + break; + + case cm_connection: + switch (command->value.Connection->connector) + { + /* Do the first command asynchronously. */ + case '&': + { + COMMAND *tc = command->value.Connection->first; + REDIRECT *rp; + + if (!tc) + break; + + 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 */ + { + REDIRECT *tr; + + rd.filename = make_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. */ + REDIRECT *tr, *tl; + + tr = tc->redirects; + do + { + tl = tc->redirects; + tc->redirects = tc->redirects->next; + } + while (tc->redirects && tc->redirects != rp); + + tl->next = (REDIRECT *)NULL; + dispose_redirects (tr); + } + + { + register COMMAND *second; + + second = command->value.Connection->second; + + if (second) + { + if (ignore_return) + second->flags |= CMD_IGNORE_RETURN; + + exec_result = execute_command_internal + (second, asynchronous, pipe_in, pipe_out, fds_to_close); + } + } + } + break; + + case ';': + /* Just call execute command on both of them. */ + 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 '|': + { + int prev, fildes[2], new_bitmap_size, dummyfd; + COMMAND *cmd; + struct fd_bitmap *fd_bitmap; + +#if defined (JOB_CONTROL) + sigset_t set, oset; + BLOCK_CHILD (set, oset); +#endif /* JOB_CONTROL */ + + 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) + { + report_error ("pipe error: %s", strerror (errno)); +#if defined (JOB_CONTROL) + 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); + +#if defined (JOB_CONTROL) + 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; + } + + /* 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 defined (JOB_CONTROL) + UNBLOCK_CHILD (oset); +#endif + } + break; + + 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; + } + + /* 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 (command->value.Connection->first) + command->value.Connection->first->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 (command->value.Connection->second); + } + break; + + default: + programming_error ("Bad connector `%d'!", + command->value.Connection->connector); + longjmp (top_level, DISCARD); + break; + } + break; + + case cm_function_def: + exec_result = intern_function (command->value.Function_def->name, + command->value.Function_def->command); + break; + + default: + programming_error + ("execute_command: Bad command type `%d'!", command->type); + } + + if (my_undo_list) + { + do_redirections (my_undo_list, 1, 0, 0); + dispose_redirects (my_undo_list); + } + + if (exec_undo_list) + dispose_redirects (exec_undo_list); + + if (my_undo_list || exec_undo_list) + discard_unwind_frame ("loop_redirections"); + + /* Invert the return value if we have to */ + if (invert) + { + if (exec_result == EXECUTION_SUCCESS) + exec_result = EXECUTION_FAILURE; + else + exec_result = EXECUTION_SUCCESS; + } + + last_command_exit_value = exec_result; + run_pending_traps (); + return (last_command_exit_value); +} + +#if defined (JOB_CONTROL) +# define REAP() \ + do \ + { \ + if (!interactive_shell) \ + reap_dead_jobs (); \ + } \ + while (0) +#else /* !JOB_CONTROL */ +# define REAP() \ + do \ + { \ + if (!interactive_shell) \ + cleanup_dead_jobs (); \ + } \ + while (0) +#endif /* !JOB_CONTROL */ + + +/* Execute a FOR command. The syntax is: FOR word_desc IN word_list; + DO command; DONE */ +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; + char *identifier; + SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ + int retval = EXECUTION_SUCCESS; + + if (check_identifier (for_command->name, 1) == 0) + return (EXECUTION_FAILURE); + + loop_level++; + identifier = for_command->name->word; + + list = releaser = expand_words_no_vars (for_command->map_list); + + begin_unwind_frame ("for"); + add_unwind_protect (dispose_words, releaser); + + if (lexical_scoping) + { + old_value = copy_variable (find_variable (identifier)); + if (old_value) + add_unwind_protect (dispose_variable, old_value); + } + + if (for_command->flags & CMD_IGNORE_RETURN) + for_command->action->flags |= CMD_IGNORE_RETURN; + + while (list) + { + QUIT; + bind_variable (identifier, list->word->word); + execute_command (for_command->action); + retval = last_command_exit_value; + REAP (); + QUIT; + + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + + list = list->next; + } + + loop_level--; + + 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); + } + } + + dispose_words (releaser); + discard_unwind_frame ("for"); + return (retval); +} + +#if defined (SELECT_COMMAND) +static int LINES, COLS, tabsize; + +#define RP_SPACE ") " +#define RP_SPACE_LEN 2 + +/* XXX - does not handle numbers > 1000000 at all. */ +#define NUMBER_LEN(s) \ +((s < 10) ? 1 \ + : ((s < 100) ? 2 \ + : ((s < 1000) ? 3 \ + : ((s < 10000) ? 4 \ + : ((s < 100000) ? 5 \ + : 6))))) + +static int +print_index_and_element (len, ind, list) + int len, ind; + WORD_LIST *list; +{ + register WORD_LIST *l; + register int i; + + if (list == 0) + return (0); + i = ind; + l = list; + while (l && --i) + l = l->next; + fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); + return (STRLEN (l->word->word)); +} + +static void +indent (from, to) + int from, to; +{ + while (from < to) + { + if ((to / tabsize) > (from / tabsize)) + { + putc ('\t', stderr); + from += tabsize - from % tabsize; + } + else + { + putc (' ', stderr); + from++; + } + } +} + +static void +print_select_list (list, list_len, max_elem_len, indices_len) + WORD_LIST *list; + int list_len, max_elem_len, indices_len; +{ + int ind, row, elem_len, pos, cols, rows; + int first_column_indices_len, other_indices_len; + + if (list == 0) + { + putc ('\n', stderr); + return; + } + + cols = COLS / max_elem_len; + if (cols == 0) + cols = 1; + rows = list_len ? list_len / cols + (list_len % cols != 0) : 1; + cols = list_len ? list_len / rows + (list_len % rows != 0) : 1; + + if (rows == 1) + { + rows = cols; + cols = 1; + } + + first_column_indices_len = NUMBER_LEN (rows); + other_indices_len = indices_len; + + for (row = 0; row < rows; row++) + { + ind = row; + pos = 0; + while (1) + { + indices_len = (pos == 0) ? first_column_indices_len : other_indices_len; + elem_len = print_index_and_element (indices_len, ind + 1, list); + elem_len += indices_len + RP_SPACE_LEN; + ind += rows; + if (ind >= list_len) + break; + indent (pos + elem_len, pos + max_elem_len); + pos += max_elem_len; + } + putc ('\n', stderr); + } +} + +/* Print the elements of LIST, one per line, preceded by an index from 1 to + LIST_LEN. Then display PROMPT and wait for the user to enter a number. + If the number is between 1 and LIST_LEN, return that selection. If EOF + is read, return a null string. If a blank line is entered, the loop is + executed again. */ +static char * +select_query (list, list_len, prompt) + WORD_LIST *list; + int list_len; + char *prompt; +{ + int max_elem_len, indices_len, len, reply; + WORD_LIST *l; + char *repl_string, *t; + + t = get_string_value ("LINES"); + LINES = (t && *t) ? atoi (t) : 24; + t = get_string_value ("COLUMNS"); + COLS = (t && *t) ? atoi (t) : 80; + +#if 0 + t = get_string_value ("TABSIZE"); + tabsize = (t && *t) ? atoi (t) : 8; + if (tabsize <= 0) + tabsize = 8; +#else + tabsize = 8; +#endif + + max_elem_len = 0; + for (l = list; l; l = l->next) + { + len = STRLEN (l->word->word); + if (len > max_elem_len) + max_elem_len = len; + } + indices_len = NUMBER_LEN (list_len); + max_elem_len += indices_len + RP_SPACE_LEN + 2; + + while (1) + { + print_select_list (list, list_len, max_elem_len, indices_len); + printf ("%s", prompt); + fflush (stdout); + QUIT; + + if (read_builtin ((WORD_LIST *)NULL) == EXECUTION_FAILURE) + { + putchar ('\n'); + return ((char *)NULL); + } + repl_string = get_string_value ("REPLY"); + if (*repl_string == 0) + continue; + reply = atoi (repl_string); + if (reply < 1 || reply > list_len) + return ""; + + l = list; + while (l && --reply) + l = l->next; + return (l->word->word); + } +} + +/* Execute a SELECT command. The syntax is: + SELECT word IN list DO command_list DONE + Only `break' or `return' in command_list will terminate + the command. */ +execute_select_command (select_command) + SELECT_COM *select_command; +{ + WORD_LIST *releaser, *list; + 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); + + loop_level++; + identifier = select_command->name->word; + + /* command and arithmetic substitution, parameter and variable expansion, + word splitting, pathname expansion, and quote removal. */ + list = releaser = expand_words_no_vars (select_command->map_list); + list_len = list_length (list); + if (list == 0 || list_len == 0) + { + if (list) + dispose_words (list); + return (EXECUTION_SUCCESS); + } + + 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; + + unwind_protect_int (return_catch_flag); + unwind_protect_jmp_buf (return_catch); + return_catch_flag++; + + while (1) + { + ps3_prompt = get_string_value ("PS3"); + if (!ps3_prompt) + ps3_prompt = "#? "; + + QUIT; + selection = select_query (list, list_len, ps3_prompt); + QUIT; + if (selection == 0) + break; + else + bind_variable (identifier, selection); + + return_val = setjmp (return_catch); + + if (return_val) + { + retval = return_catch_value; + break; + } + else + retval = execute_command (select_command->action); + + REAP (); + QUIT; + + if (breaking) + { + breaking--; + break; + } + } + + 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); +} +#endif /* SELECT_COMMAND */ + +/* Execute a CASE command. The syntax is: CASE word_desc IN pattern_list ESAC. + 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. */ +execute_case_command (case_command) + CASE_COM *case_command; +{ + register WORD_LIST *list; + WORD_LIST *wlist; + PATTERN_LIST *clauses; + char *word; + int retval; + + /* Posix.2 specifies that the WORD is tilde expanded. */ + if (member ('~', case_command->word->word)) + { + word = 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 (""); + retval = EXECUTION_SUCCESS; + + begin_unwind_frame ("case"); + add_unwind_protect (dispose_words, wlist); + add_unwind_protect ((Function *)xfree, word); + + while (clauses) + { + QUIT; + list = clauses->patterns; + while (list) + { + 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); + free (list->word->word); + list->word->word = expansion; + } + + es = expand_word_leave_quoted (list->word, 0); + + if (es && es->word && es->word->word && *(es->word->word)) + pattern = quote_string_for_globbing (es->word->word, 1); + else + pattern = savestring (""); + + /* 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); + free (pattern); + + dispose_words (es); + + if (match) + { + if (clauses->action && + (case_command->flags & CMD_IGNORE_RETURN)) + clauses->action->flags |= CMD_IGNORE_RETURN; + execute_command (clauses->action); + retval = last_command_exit_value; + goto exit_command; + } + + list = list->next; + QUIT; + } + + clauses = clauses->next; + } + + exit_command: + dispose_words (wlist); + free (word); + discard_unwind_frame ("case"); + + return (retval); +} + +#define CMD_WHILE 0 +#define CMD_UNTIL 1 + +/* The WHILE command. Syntax: WHILE test DO action; DONE. + Repeatedly execute action while executing test produces + EXECUTION_SUCCESS. */ +execute_while_command (while_command) + WHILE_COM *while_command; +{ + return (execute_while_or_until (while_command, CMD_WHILE)); +} + +/* UNTIL is just like WHILE except that the test result is negated. */ +execute_until_command (while_command) + WHILE_COM *while_command; +{ + return (execute_while_or_until (while_command, CMD_UNTIL)); +} + +/* The body for both while and until. The only difference between the + two is that the test value is treated differently. TYPE is + 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. */ +execute_while_or_until (while_command, type) + WHILE_COM *while_command; + int type; +{ + int return_value, body_status; + + body_status = EXECUTION_SUCCESS; + loop_level++; + + while_command->test->flags |= CMD_IGNORE_RETURN; + if (while_command->flags & CMD_IGNORE_RETURN) + while_command->action->flags |= CMD_IGNORE_RETURN; + + while (1) + { + return_value = execute_command (while_command->test); + REAP (); + + if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) + break; + if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS) + break; + + QUIT; + body_status = execute_command (while_command->action); + QUIT; + + if (breaking) + { + breaking--; + break; + } + + if (continuing) + { + continuing--; + if (continuing) + break; + } + } + loop_level--; + + return (body_status); +} + +/* IF test THEN command [ELSE command]. + IF also allows ELIF in the place of ELSE IF, but + the parser makes *that* stupidity transparent. */ +execute_if_command (if_command) + IF_COM *if_command; +{ + int return_value; + + if_command->test->flags |= CMD_IGNORE_RETURN; + return_value = execute_command (if_command->test); + + 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; + return (execute_command (if_command->true_case)); + } + else + { + QUIT; + + if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN)) + if_command->false_case->flags |= CMD_IGNORE_RETURN; + + return (execute_command (if_command->false_case)); + } +} + +static void +bind_lastarg (arg) + char *arg; +{ + SHELL_VAR *var; + + if (!arg) + arg = ""; + var = bind_variable ("_", arg); + var->attributes &= ~att_exported; +} + +/* 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. */ +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; + pid_t old_last_command_subst_pid; + + result = EXECUTION_SUCCESS; + + /* If we're in a function, update the pseudo-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)); + strcpy (command_line, the_printed_command); + + first_word_quoted = + simple_command->words ? simple_command->words->word->quoted : 0; + + old_last_command_subst_pid = last_command_subst_pid; + + /* If we are re-running this as the result of executing the `command' + builtin, do not expand the command words a second time. */ + if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0) + { + current_fds_to_close = fds_to_close; + 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) + { + Function *builtin; + SHELL_VAR *func; + + begin_unwind_frame ("simple-command"); + + if (echo_command_at_execute) + { + char *line = string_list (words); + + if (line && *line) + fprintf (stderr, "%s%s\n", indirection_level_string (), line); + + FREE (line); + } + + if (simple_command->flags & CMD_NO_FUNCTIONS) + func = (SHELL_VAR *)NULL; + else + func = find_function (words->word->word); + + 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; + +#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); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin; + + if (builtin || func) + { + if ((pipe_in != NO_PIPE) || (pipe_out != NO_PIPE) || async) + { + if (make_child (savestring (command_line), async) == 0) + { + /* 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); + } + else + { + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + goto return_result; + } + } + else + { + result = execute_builtin_or_function + (words, builtin, func, simple_command->redirects, fds_to_close, + simple_command->flags); + + goto return_result; + } + } + + execute_disk_command (words, simple_command->redirects, command_line, + pipe_in, pipe_out, async, fds_to_close, + (simple_command->flags & CMD_NO_FORK)); + + goto return_result; + } + else 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 (savestring (""), async) == 0) + { + /* Cancel traps, in trap.c. */ + restore_original_signals (); + + do_piping (pipe_in, pipe_out); + + subshell_environment = 1; + + if (do_redirections (simple_command->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 + result = EXECUTION_SUCCESS; + 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; + } + + 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"); + return (result); +} + +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; + + /* 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 + eval builtin is being called, and we're supposed to ignore the exit + value of the command, we turn the -e flag off ourselves, then + restore it when the command completes. */ + if (subshell == 0 && builtin == eval_builtin && (flags & CMD_IGNORE_RETURN)) + { + begin_unwind_frame ("eval_builtin"); + unwind_protect_int (exit_immediately_on_error); + exit_immediately_on_error = 0; + } + + /* The temporary environment for a builtin is supposed to apply to + all commands executed by that builtin. Currently, this is a + problem only with the `source' builtin. */ + if (builtin == source_builtin) + { + if (subshell == 0) + begin_unwind_frame ("builtin_env"); + + if (temporary_env) + { + builtin_env = copy_array (temporary_env); + if (subshell == 0) + add_unwind_protect (dispose_builtin_env, (char *)NULL); + dispose_used_env_vars (); + } +#if 0 + else + builtin_env = (char **)NULL; +#endif + } + + result = ((*builtin) (words->next)); + + if (subshell == 0 && builtin == source_builtin) + { + dispose_builtin_env (); + discard_unwind_frame ("builtin_env"); + } + + if (subshell == 0 && builtin == eval_builtin && (flags & CMD_IGNORE_RETURN)) + { + exit_immediately_on_error += old_e_flag; + discard_unwind_frame ("eval_builtin"); + } + + 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; + WORD_LIST *words; + int flags, subshell, async; + struct fd_bitmap *fds_to_close; +{ + int return_val, result; + COMMAND *tc, *fc; + + 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) + { + push_context (); + add_unwind_protect (pop_context, (char *)NULL); + unwind_protect_int (line_number); + } + 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); + + /* 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); + dispose_used_env_vars (); + } +#if 0 + else + 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); + + line_number = function_line_number = tc->line; + + if (subshell) + { +#if defined (JOB_CONTROL) + stop_pipeline (async, (COMMAND *)NULL); +#endif + if (tc->type == cm_group) + fc = tc->value.Group->command; + else + fc = tc; + + if (fc && (flags & CMD_IGNORE_RETURN)) + fc->flags |= CMD_IGNORE_RETURN; + + variable_context++; + } + else + fc = tc; + + return_catch_flag++; + return_val = setjmp (return_catch); + + if (return_val) + result = return_catch_value; + else + result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); + + if (subshell) + run_unwind_frame ("subshell_function_calling"); + else + run_unwind_frame ("function_calling"); + + return (result); +} + +/* Execute a shell builtin or function in a subshell environment. This + routine does not return; it only calls exit(). If BUILTIN is non-null, + it points to a function to call to execute a shell builtin; otherwise + VAR points at the body of a function to execute. WORDS is the arguments + to the command, REDIRECTS specifies redirections to perform before the + command is executed. */ +static void +execute_subshell_builtin_or_function (words, redirects, builtin, var, + pipe_in, pipe_out, async, fds_to_close, + flags) + WORD_LIST *words; + REDIRECT *redirects; + Function *builtin; + SHELL_VAR *var; + int pipe_in, pipe_out, async; + struct fd_bitmap *fds_to_close; + int flags; +{ + /* A subshell is neither a login shell nor interactive. */ + login_shell = interactive = 0; + + subshell_environment = 1; + + maybe_make_export_env (); + +#if defined (JOB_CONTROL) + /* Eradicate all traces of job control after we fork the subshell, so + all jobs begun by this subshell are in the same process group as + the shell itself. */ + + /* Allow the output of `jobs' to be piped. */ + if (builtin == jobs_builtin && !async && + (pipe_out != NO_PIPE || pipe_in != NO_PIPE)) + kill_current_pipeline (); + else + without_job_control (); + + set_sigchld_handler (); +#endif /* JOB_CONTROL */ + + set_sigint_handler (); + + do_piping (pipe_in, pipe_out); + + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + if (do_redirections (redirects, 1, 0, 0) != 0) + exit (EXECUTION_FAILURE); + + 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); + + if (result == EXITPROG) + exit (last_command_exit_value); + else if (result) + exit (EXECUTION_FAILURE); + else + exit (execute_builtin (builtin, words, flags, 1)); + } + else + { + exit (execute_function (var, words, flags, fds_to_close, async, 1)); + } +} + +/* Execute a builtin or function in the current shell context. If BUILTIN + is non-null, it is the builtin command to execute, otherwise VAR points + to the body of a function. WORDS are the command's arguments, REDIRECTS + are the redirections to perform. FDS_TO_CLOSE is the usual bitmap of + file descriptors to close. + + If BUILTIN is exec_builtin, the redirections specified in REDIRECTS are + not undone before this function returns. */ +static int +execute_builtin_or_function (words, builtin, var, redirects, + fds_to_close, flags) + WORD_LIST *words; + Function *builtin; + SHELL_VAR *var; + REDIRECT *redirects; + struct fd_bitmap *fds_to_close; + int flags; +{ + int result = EXECUTION_FAILURE; + REDIRECT *saved_undo_list; + + if (do_redirections (redirects, 1, 1, 0) != 0) + { + cleanup_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + dispose_exec_redirects (); + return (EXECUTION_FAILURE); + } + + saved_undo_list = redirection_undo_list; + + /* Calling the "exec" builtin changes redirections forever. */ + if (builtin == exec_builtin) + { + dispose_redirects (saved_undo_list); + saved_undo_list = exec_redirection_undo_list; + exec_redirection_undo_list = (REDIRECT *)NULL; + } + else + dispose_exec_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); + } + + redirection_undo_list = (REDIRECT *)NULL; + + if (builtin) + result = execute_builtin (builtin, words, flags, 0); + else + result = execute_function (var, words, flags, fds_to_close, 0, 0); + + if (saved_undo_list) + { + redirection_undo_list = saved_undo_list; + discard_unwind_frame ("saved redirects"); + } + + if (redirection_undo_list) + { + do_redirections (redirection_undo_list, 1, 0, 0); + dispose_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + } + + return (result); +} + +void +setup_async_signals () +{ +#if defined (JOB_CONTROL) + if (job_control == 0) +#endif + { + set_signal_handler (SIGINT, SIG_IGN); + set_signal_ignored (SIGINT); + set_signal_handler (SIGQUIT, SIG_IGN); + set_signal_ignored (SIGQUIT); + } +} + +/* Execute a simple command that is hopefully defined in a disk file + somewhere. + + 1) fork () + 2) connect pipes + 3) look up the command + 4) do redirections + 5) execve () + 6) If the execve failed, see if the file has executable mode set. + If so, and it isn't a directory, then execute its contents as + a shell script. + + Note that the filename hashing stuff has to take place up here, + in the parent. This is probably why the Bourne style shells + don't handle it, since that would require them to go through + this gnarly hair, for no good reason. */ +static void +execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, + async, fds_to_close, nofork) + WORD_LIST *words; + REDIRECT *redirects; + char *command_line; + int pipe_in, pipe_out, async; + 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; + + pathname = words->word->word; +#if defined (RESTRICTED_SHELL) + if (restricted && strchr (pathname, '/')) + { + report_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; + } + } + + 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 + { + command = find_user_command (pathname); + if (command && !hashing_disabled && !temp_path) + remember_filename (pathname, command, dot_found_in_search, 1); + } + + 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, + don't bother to fork, just directly exec the command. */ + if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + pid = 0; + else + pid = make_child (savestring (command_line), async); + + if (pid == 0) + { + int old_interactive; + + /* Cancel traps, in trap.c. */ + restore_original_signals (); + + /* restore_original_signals may have undone the work done + by make_child to ensure that SIGINT and SIGQUIT are ignored + in asynchronous children. */ + if (async) + setup_async_signals (); + + 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; + + /* 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 + bitmap of all such file descriptors. */ + if (fds_to_close) + close_fd_bitmap (fds_to_close); + + if (redirects && (do_redirections (redirects, 1, 0, 0) != 0)) + { +#if defined (PROCESS_SUBSTITUTION) + /* Try to remove named pipes that may have been created as the + result of redirections. */ + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + exit (EXECUTION_FAILURE); + } + + if (async) + interactive = old_interactive; + + if (!command) + { + report_error ("%s: command not found", args[0]); + exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ + } + + exit (shell_execve (command, args, export_env)); + } + else + { + /* Make sure that the pipes are closed in the parent. */ + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + FREE (command); + } +} + +/* 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 + the script; it and ARGS, the arguments given by the user, will + become arguments to the specified interpreter. ENV is the environment + to pass to the interpreter. + + The word immediately following the #! is the interpreter to execute. + A single argument to the interpreter is allowed. */ +static int +execute_shell_script (sample, sample_len, command, args, env) + unsigned char *sample; + int sample_len; + char *command; + char **args, **env; +{ + register int i; + char *execname, *firstarg; + int start, size_increment, larry; + + /* Find the name of the interpreter to exec. */ + for (i = 2; whitespace (sample[i]) && i < sample_len; i++) + ; + + for (start = i; + !whitespace (sample[i]) && sample[i] != '\n' && i < sample_len; + i++) + ; + + execname = xmalloc (1 + (i - start)); + strncpy (execname, (char *) (sample + start), i - start); + execname[i - start] = '\0'; + size_increment = 1; + + /* Now the argument, if any. */ + firstarg = (char *)NULL; + for (start = i; + whitespace (sample[i]) && sample[i] != '\n' && i < sample_len; + i++) + ; + + /* If there is more text on the line, then it is an argument for the + interpreter. */ + if (i < sample_len && sample[i] != '\n' && !whitespace (sample[i])) + { + for (start = i; + !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'; + + size_increment = 2; + } + + larry = array_len (args) + size_increment; + + args = (char **)xrealloc ((char *)args, (1 + larry) * sizeof (char *)); + + for (i = larry - 1; i; i--) + args[i] = args[i - size_increment]; + + args[0] = execname; + if (firstarg) + { + args[1] = firstarg; + args[2] = command; + } + else + args[1] = command; + + args[larry] = (char *)NULL; + + return (shell_execve (execname, args, env)); +} + +/* Call execve (), handling interpreting shell scripts, and handling + exec failures. */ +int +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 + execve (command, args, env); +#endif /* !(isc386 && _POSIX_SOURCE) */ + + /* 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 + file_error (command); + + 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; + + { + int fd = open (command, O_RDONLY); + if (fd != -1) + { + 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); + } + } + } +#if defined (JOB_CONTROL) + /* Forget about the way that job control was working. We are + in a subshell. */ + without_job_control (); +#endif /* JOB_CONTROL */ +#if defined (ALIAS) + /* Forget about any aliases that we knew of. We are in a subshell. */ + delete_all_aliases (); +#endif /* ALIAS */ + +#if defined (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 *)); + + for (i = larray - 1; i; i--) + args[i] = args[i - 1]; + + args[0] = shell_name; + args[1] = command; + args[larray] = (char *)NULL; + + if (args[0][0] == '-') + args[0]++; + + if (should_exec) + { + struct stat finfo; + +#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 */ + + /* 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]); + + return (EXECUTION_FAILURE); + } + else + { + subshell_argc = larray; + subshell_argv = args; + subshell_envp = env; + longjmp (subshell_top_level, 1); + } + } + } +} + +#if defined (PROCESS_SUBSTITUTION) +/* Currently unused */ +void +close_all_files () +{ + register int i, fd_table_size; + + fd_table_size = getdtablesize (); + if (fd_table_size > 256) /* clamp to a reasonable value */ + fd_table_size = 256; + + for (i = 3; i < fd_table_size; i++) + close (i); +} +#endif /* PROCESS_SUBSTITUTION */ + +static void +close_pipes (in, out) + int in, out; +{ + if (in >= 0) + close (in); + if (out >= 0) + close (out); +} + +/* Redirect input and output to be from and to the specified pipes. + NO_PIPE and REDIRECT_BOTH are handled correctly. */ +static void +do_piping (pipe_in, pipe_out) + int 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)); + if (pipe_in > 0) + close (pipe_in); + } + if (pipe_out != NO_PIPE) + { + 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)); + if (pipe_out == 0 || pipe_out > 1) + close (pipe_out); + } + else + dup2 (1, 2); + } +} + +#define AMBIGUOUS_REDIRECT -1 +#define NOCLOBBER_REDIRECT -2 +#define RESTRICTED_REDIRECT -3 /* Only can happen in restricted shells. */ + +/* Perform the redirections on LIST. If FOR_REAL, then actually make + input and output file descriptors, otherwise just do whatever is + neccessary for side effecting. INTERNAL says to remember how to + undo the redirections later, if non-zero. If SET_CLEXEC is non-zero, + file descriptors opened in do_redirection () have their close-on-exec + flag set. */ +static int +do_redirections (list, for_real, internal, set_clexec) + REDIRECT *list; + int for_real, internal, set_clexec; +{ + register int error; + register REDIRECT *temp = list; + + if (internal) + { + if (redirection_undo_list) + { + dispose_redirects (redirection_undo_list); + redirection_undo_list = (REDIRECT *)NULL; + } + if (exec_redirection_undo_list) + dispose_exec_redirects (); + } + + while (temp) + { + 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); + return (error); + } + + temp = temp->next; + } + return (0); +} + +/* Return non-zero if the redirection pointed to by REDIRECT has a + redirectee.filename that can be expanded. */ +static int +expandable_redirection_filename (redirect) + REDIRECT *redirect; +{ + int result; + + switch (redirect->instruction) + { + case r_output_direction: + case r_appending_to: + case r_input_direction: + case r_inputa_direction: + case r_err_and_out: + case r_input_output: + case r_output_force: + case r_duplicating_input_word: + case r_duplicating_output_word: + result = 1; + break; + + default: + result = 0; + } + return (result); +} + +/* Expand the word in WORD returning a string. If WORD expands to + multiple words (or no words), then return NULL. */ +char * +redirection_expand (word) + WORD_DESC *word; +{ + char *result; + WORD_LIST *tlist1, *tlist2; + + tlist1 = make_word_list (copy_word (word), (WORD_LIST *)NULL); + tlist2 = expand_words_no_vars (tlist1); + dispose_words (tlist1); + + 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); + dispose_words (tlist2); + return (result); +} + +/* Do the specific redirection requested. Returns errno in case of error. + If FOR_REAL is zero, then just do whatever is neccessary to produce the + appropriate side effects. REMEMBERING, if non-zero, says to remember + how to undo each redirection. If SET_CLEXEC is non-zero, then + we set all file descriptors > 2 that we open to be close-on-exec. */ +static int +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; + char *redirectee_word; + enum r_instruction ri = redirect->instruction; + REDIRECT *new_redirect; + + if (ri == r_duplicating_input_word || ri == r_duplicating_output_word) + { + /* We have [N]>&WORD or [N]<&WORD. Expand WORD, then translate + the redirection into a new one and continue. */ + redirectee_word = redirection_expand (redirectee); + + if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') + { + rd.dest = 0L; + new_redirect = make_redirection (redirector, r_close_this, rd); + } + else if (all_digits (redirectee_word)) + { + if (ri == r_duplicating_input_word) + { + rd.dest = atol (redirectee_word); + new_redirect = make_redirection (redirector, r_duplicating_input, rd); + } + else + { + rd.dest = atol (redirectee_word); + new_redirect = make_redirection (redirector, r_duplicating_output, rd); + } + } + else if (ri == r_duplicating_output_word && redirector == 1) + { + if (!posixly_correct) + { + rd.filename = make_word (redirectee_word); + new_redirect = make_redirection (1, r_err_and_out, rd); + } + else + new_redirect = copy_redirect (redirect); + } + else + { + free (redirectee_word); + return (AMBIGUOUS_REDIRECT); + } + + free (redirectee_word); + + /* Set up the variables needed by the rest of the function from the + new redirection. */ + if (new_redirect->instruction == r_err_and_out) + { + char *alloca_hack; + + /* Copy the word without allocating any memory that must be + explicitly freed. */ + redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); + xbcopy ((char *)new_redirect->redirectee.filename, + (char *)redirectee, sizeof (WORD_DESC)); + + alloca_hack = (char *) + alloca (1 + strlen (new_redirect->redirectee.filename->word)); + redirectee->word = alloca_hack; + strcpy (redirectee->word, new_redirect->redirectee.filename->word); + } + else + /* It's guaranteed to be an integer, and shouldn't be freed. */ + redirectee = new_redirect->redirectee.filename; + + redir_fd = new_redirect->redirectee.dest; + redirector = new_redirect->redirector; + ri = new_redirect->instruction; + + /* Overwrite the flags element of the old redirect with the new value. */ + redirect->flags = new_redirect->flags; + dispose_redirects (new_redirect); + } + + switch (ri) + { + case r_output_direction: + case r_appending_to: + case r_input_direction: + case r_inputa_direction: + 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) + 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)) + { + free (redirectee_word); + return (RESTRICTED_REDIRECT); + } +#endif /* RESTRICTED_SHELL */ + + /* 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)) + { + struct stat finfo; + int stat_result; + + stat_result = stat (redirectee_word, &finfo); + + if ((stat_result == 0) && (S_ISREG (finfo.st_mode))) + { + free (redirectee_word); + return (NOCLOBBER_REDIRECT); + } + + /* 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) + redirect->flags |= O_EXCL; + + fd = open (redirectee_word, redirect->flags, 0666); + + if ((fd < 0) && (errno == EEXIST)) + { + free (redirectee_word); + return (NOCLOBBER_REDIRECT); + } + } + else + { + fd = open (redirectee_word, redirect->flags, 0666); +#if defined (AFS_CREATE_BUG) + if ((fd < 0) && (errno == EACCES)) + fd = open (redirectee_word, (redirect->flags & ~O_CREAT), 0666); +#endif /* AFS_CREATE_BUG */ + } + free (redirectee_word); + + if (fd < 0) + return (errno); + + if (for_real) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + + if ((fd != redirector) && (dup2 (fd, redirector) < 0)) + return (errno); + +#if defined (BUFFERED_INPUT) + /* Do not change the buffered stream for an implicit redirection + of /dev/null to fd 0 for asynchronous commands without job + control (r_inputa_direction). */ + if (ri == r_input_direction || ri == r_input_output) + duplicate_buffered_stream (fd, redirector); +#endif /* BUFFERED_INPUT */ + + /* + * If we're remembering, then this is the result of a while, for + * or until loop with a loop redirection, or a function/builtin + * executing in the parent shell with a redirection. In the + * function/builtin case, we want to set all file descriptors > 2 + * to be close-on-exec to duplicate the effect of the old + * for i = 3 to NOFILE close(i) loop. In the case of the loops, + * both sh and ksh leave the file descriptors open across execs. + * The Posix standard mentions only the exec builtin. + */ + if (set_clexec && (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + + if (fd != redirector) + { +#if defined (BUFFERED_INPUT) + if (ri == r_input_direction || ri == r_inputa_direction || + ri == r_input_output) + close_buffered_fd (fd); + else +#endif /* !BUFFERED_INPUT */ + close (fd); /* Don't close what we just opened! */ + } + + /* If we are hacking both stdout and stderr, do the stderr + redirection here. */ + if (ri == r_err_and_out) + { + if (for_real) + { + if (remembering) + add_undo_redirect (2); + if (dup2 (1, 2) < 0) + return (errno); + } + } + break; + + case r_reading_until: + case r_deblank_reading_until: + /* REDIRECTEE is a pointer to a WORD_DESC containing the text of + the new input. Place it in a temporary file. */ + if (redirectee) + { + char filename[40]; + pid_t pid = getpid (); + + /* Make the filename for the temp file. */ + sprintf (filename, "/tmp/t%d-sh", pid); + + fd = open (filename, O_TRUNC | O_WRONLY | O_CREAT, 0666); + if (fd < 0) + return (errno); + + errno = 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); + } + } + } + + close (fd); + if (errno) + return (errno); + + /* 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) + close (fd); + return (errno); + } + + if (for_real) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + if (dup2 (fd, redirector) < 0) + { + close (fd); + return (errno); + } + +#if defined (BUFFERED_INPUT) + duplicate_buffered_stream (fd, redirector); +#endif + + if (set_clexec && (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + +#if defined (BUFFERED_INPUT) + close_buffered_fd (fd); +#else + close (fd); +#endif + } + break; + + case r_duplicating_input: + case r_duplicating_output: + if (for_real && (redir_fd != redirector)) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if (fcntl (redirector, F_GETFD, 0) != -1) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + /* This is correct. 2>&1 means dup2 (1, 2); */ + if (dup2 (redir_fd, redirector) < 0) + return (errno); + +#if defined (BUFFERED_INPUT) + if (ri == r_duplicating_input) + duplicate_buffered_stream (redir_fd, redirector); +#endif /* BUFFERED_INPUT */ + + /* First duplicate the close-on-exec state of redirectee. dup2 + leaves the flag unset on the new descriptor, which means it + stays open. Only set the close-on-exec bit for file descriptors + greater than 2 in any case, since 0-2 should always be open + unless closed by something like `exec 2<&-'. */ + /* if ((already_set || set_unconditionally) && (ok_to_set)) + set_it () */ + if (((fcntl (redir_fd, F_GETFD, 0) == 1) || set_clexec) && + (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + break; + + case r_close_this: + if (for_real) + { + if (remembering && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); + close_buffered_fd (redirector); +#else /* !BUFFERED_INPUT */ + close (redirector); +#endif /* !BUFFERED_INPUT */ + } + break; + } + return (0); +} + +#define SHELL_FD_BASE 10 + +/* Remember the file descriptor associated with the slot FD, + on REDIRECTION_UNDO_LIST. Note that the list will be reversed + before it is executed. Any redirections that need to be undone + even if REDIRECTION_UNDO_LIST is discarded by the exec builtin + are also saved on EXEC_REDIRECTION_UNDO_LIST. */ +static int +add_undo_redirect (fd) + int fd; +{ + int new_fd, clexec_flag; + REDIRECT *new_redirect, *closer; + + new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); + + if (new_fd < 0) + { + file_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); + + rd.dest = (long)new_fd; + new_redirect = make_redirection (fd, r_duplicating_output, rd); + new_redirect->next = closer; + + 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); + } + return (0); +} + +/* Set up to close FD when we are finished with the current command + and its redirections. */ +static void +add_undo_close_redirect (fd) + int fd; +{ + REDIRECT *closer; + + rd.dest = 0L; + closer = make_redirection (fd, r_close_this, rd); + closer->next = redirection_undo_list; + redirection_undo_list = closer; +} + +static void +add_exec_redirect (dummy_redirect) + REDIRECT *dummy_redirect; +{ + dummy_redirect->next = exec_redirection_undo_list; + 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) +#define X_BIT(x) ((x) & 1) + +/* Return some flags based on information about this file. + The EXISTS bit is non-zero if the file is found. + The EXECABLE bit is non-zero the file is executble. + Zero is returned if the file is not found. */ +int +file_status (name) + char *name; +{ + struct stat finfo; + static int user_id = -1; + + /* Determine whether this file exists or not. */ + if (stat (name, &finfo) < 0) + return (0); + + /* 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); + +#if defined (AFS) + /* We have to use access(2) to determine access because AFS does not + support Unix file system semantics. This may produce wrong + answers for non-AFS files when ruid != euid. I hate AFS. */ + if (access (name, X_OK) == 0) + return (FS_EXISTS | FS_EXECABLE); + else + return (FS_EXISTS); +#else /* !AFS */ + + /* Find out if the file is actually executable. By definition, the + only other criteria is that the file has an execute bit set that + we can use. */ + if (user_id == -1) + user_id = current_user.euid; + + /* Root only requires execute permission for any of owner, group or + others to be able to exec a file. */ + if (user_id == 0) + { + int bits; + + bits = (u_mode_bits (finfo.st_mode) | + g_mode_bits (finfo.st_mode) | + o_mode_bits (finfo.st_mode)); + + if (X_BIT (bits)) + return (FS_EXISTS | FS_EXECABLE); + } + + /* If we are the owner of the file, the owner execute bit applies. */ + if (user_id == finfo.st_uid && X_BIT (u_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + + /* If we are in the owning group, the group permissions apply. */ + if (group_member (finfo.st_gid) && X_BIT (g_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + + /* If `others' have execute permission to the file, then so do we, + since we are also `others'. */ + if (X_BIT (o_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + else + return (FS_EXISTS); +#endif /* !AFS */ +} + +/* Return non-zero if FILE exists and is executable. + Note that this function is the definition of what an + executable file is; do not change this unless YOU know + what an executable file is. */ +int +executable_file (file) + char *file; +{ + return (file_status (file) & FS_EXECABLE); +} + +/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () + encounters a `.' as the directory pathname while scanning the + list of possible pathnames; i.e., if `.' comes before the directory + containing the file of interest. */ +int dot_found_in_search = 0; + +/* Locate the executable file referenced by NAME, searching along + the contents of the shell PATH variable. Return a new string + which is the full pathname to the file, or NULL if the file + couldn't be found. If a file is found that isn't executable, + and that is the only match, then return that. */ +char * +find_user_command (name) + char *name; +{ + return (find_user_command_internal (name, FS_EXEC_PREFERRED)); +} + +/* Locate the file referenced by NAME, searching along the contents + of the shell PATH variable. Return a new string which is the full + pathname to the file, or NULL if the file couldn't be found. This + returns the first file found. */ +char * +find_path_file (name) + char *name; +{ + return (find_user_command_internal (name, FS_EXISTS)); +} + +static char * +find_user_command_internal (name, flags) + char *name; + int flags; +{ + char *path_list; + SHELL_VAR *var; + + /* 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)) + path_list = value_cell (var); + else + path_list = (char *)NULL; + + if (path_list == 0 || *path_list == '\0') + return (savestring (name)); + + return (find_user_command_in_path (name, path_list, flags)); +} + +/* 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. + Return the next element of PATH_LIST or NULL if there are no more. */ +static char * +get_next_path_element (path_list, path_index_pointer) + char *path_list; + int *path_index_pointer; +{ + char *path; + + path = extract_colon_unit (path_list, path_index_pointer); + + if (!path) + return (path); + + if (!*path) + { + free (path); + path = savestring ("."); + } + + return (path); +} + +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; + static char **match_list = NULL; + static int match_list_size = 0; + static int match_index = 0; + + if (!state) + { + /* Create the list of matches. */ + if (!match_list) + { + match_list = + (char **) xmalloc ((match_list_size = 5) * sizeof(char *)); + + for (i = 0; i < match_list_size; i++) + match_list[i] = 0; + } + + /* Clear out the old match list. */ + for (i = 0; i < match_list_size; i++) + match_list[i] = NULL; + + /* We haven't found any files yet. */ + match_index = 0; + + 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) + break; + + match = find_user_command_in_path (name, path_element, flags); + + free (path_element); + + if (!match) + continue; + + if (match_index + 1 == match_list_size) + match_list = (char **)xrealloc + (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + match_list[match_index++] = match; + match_list[match_index] = (char *)NULL; + } + + /* We haven't returned any strings yet. */ + match_index = 0; + } + + match = match_list[match_index]; + + if (match) + match_index++; + + 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 * +make_full_pathname (path, name, name_len) + char *path, *name; + int name_len; +{ + char *full_path; + int path_len; + + path_len = strlen (path); + full_path = xmalloc (2 + path_len + name_len); + strcpy (full_path, path); + full_path[path_len] = '/'; + strcpy (full_path + path_len + 1, name); + return (full_path); +} + +/* This does the dirty work for find_path_file () and find_user_command (). + 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. + Some values are: + FS_EXEC_ONLY: The file must be an executable to be found. + 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. +*/ +static char * +find_user_command_in_path (name, path_list, flags) + char *name; + 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; + + /* We haven't started looking, so we certainly haven't seen + a `.' as the directory path yet. */ + dot_found_in_search = 0; + + 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); + } + } + + /* Find out the location of the current working directory. */ + stat (".", &finfo); + + path_index = 0; + while (path_list && 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) + 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); + 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) + { + FREE (file_to_lose_on); + + 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) + { + if (!file_to_lose_on) + file_to_lose_on = savestring (full_path); + } + + next_file: + free (full_path); + } + + /* We didn't find exactly what the user was looking for. Return + the contents of FILE_TO_LOSE_ON which is NULL when the search + required an executable, or non-NULL if a file was found and the + 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 new file mode 100644 index 0000000..e096103 --- /dev/null +++ b/execute_cmd.h @@ -0,0 +1,47 @@ +/* execute_cmd.h - functions from execute_cmd.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 (_EXECUTE_CMD_H_) +#define _EXECUTE_CMD_H_ + +#include "stdc.h" + +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 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 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) +extern void close_all_files __P((void)); +#endif + +#endif /* _EXECUTE_CMD_H_ */ @@ -0,0 +1,902 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990, 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. */ + +/* + All arithmetic is done as long integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "-", "+" [(unary operators)] + "!", "~" + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "=" + + (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 + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@ins.CWRU.Edu +*/ + +#include <stdio.h> +#include "bashansi.h" +#include "shell.h" + +#define variable_starter(c) (isletter(c) || (c == '_')) +#define variable_character(c) (isletter(c) || (c == '_') || digit(c)) + +/* 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. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Either Bitwise OR, or what Chet is. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror ("expression recursion level exceeded"); + + if (expr_depth >= expr_stack_size) + { + expr_stack = (EXPR_CONTEXT **) + xrealloc (expr_stack, (expr_stack_size += EXPR_STACK_GROW_SIZE) + * sizeof (EXPR_CONTEXT *)); + } + + context->curtok = curtok; + context->lasttok = lasttok; + context->expression = expression; + context->tp = tp; + context->tokval = tokval; + context->tokstr = tokstr; + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth == 0) + evalerror ("Recursion stack underflow"); + + context = expr_stack[--expr_depth]; + curtok = context->curtok; + lasttok = context->lasttok; + expression = context->expression; + tp = context->tp; + tokval = context->tokval; + tokstr = context->tokstr; + free (context); +} + +/* Evaluate EXPR, and return the arithmetic result. + + 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 + 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. */ +long +evalexp (expr) + char *expr; +{ + long val = 0L; + jmp_buf old_evalbuf; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + /* Save the value of evalbuf to protect it around possible recursive + calls to evalexp (). */ + xbcopy ((char *)evalbuf, (char *)old_evalbuf, sizeof (jmp_buf)); + + if (setjmp (evalbuf)) + { + if (tokstr) /* Clean up local allocation. */ + free (tokstr); + + if (expression) + free (expression); + + while (--expr_depth) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + } + longjmp (top_level, DISCARD); + } + + pushexp (); + curtok = lasttok = 0; + expression = savestring (expr); + tp = expression; + + tokstr = (char *)NULL; + tokval = 0l; + + readtok (); + + val = expassign (); + + if (curtok != 0) + evalerror ("syntax error in expression"); + + if (tokstr) + free (tokstr); + if (expression) + free (expression); + + popexp (); + + /* 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)); + + return (val); +} + +/* Bind/create a shell variable with the name LHS to the RHS. + This creates or modifies a variable such that it is an integer. + + This should really be in variables.c, but it is here so that all of the + expression evaluation stuff is localized. Since we don't want any + recursive evaluation from bind_variable() (possible without this code, + since bind_variable() calls the evaluator for variables with the integer + attribute set), we temporarily turn off the integer attribute for each + variable we set here, then turn it back on after binding as necessary. */ + +void +bind_int_variable (lhs, rhs) + char *lhs, *rhs; +{ + register SHELL_VAR *v; + int isint = 0; + + v = find_variable (lhs); + if (v) + { + isint = integer_p (v); + v->attributes &= ~att_integer; + } + + v = bind_variable (lhs, rhs); + if (isint) + v->attributes |= att_integer; +} + +static long +expassign () +{ + register long value; + char *lhs, *rhs; + + value = explor (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special = curtok == OP_ASSIGN; + int op; + long lvalue; + + if (lasttok != STR) + evalerror ("attempted expassign to non-variable"); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + lhs = savestring (tokstr); + readtok (); + value = expassign (); + + if (special) + { + switch (op) + { + case MUL: + lvalue *= value; + break; + case DIV: + lvalue /= value; + break; + case MOD: + lvalue %= value; + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + default: + evalerror ("bug: bad expassign token %d", assigntok); + break; + } + value = lvalue; + } + + rhs = itos (value); + bind_int_variable (lhs, rhs); + free (rhs); + free (lhs); + free (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + return (value); +} + +/* Logical OR. */ +static long +explor () +{ + register long val1, val2; + + val1 = expland (); + + while (curtok == LOR) + { + readtok (); + val2 = expland (); + val1 = val1 || val2; + } + + return (val1); +} + +/* Logical AND. */ +static long +expland () +{ + register long val1, val2; + + val1 = expbor (); + + while (curtok == LAND) + { + readtok (); + val2 = expbor (); + val1 = val1 && val2; + } + + return (val1); +} + +/* Bitwise OR. */ +static long +expbor () +{ + register long val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + } + + return (val1); +} + +/* Bitwise XOR. */ +static long +expbxor () +{ + register long val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + } + + return (val1); +} + +/* Bitwise AND. */ +static long +expband () +{ + register long val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + } + + return (val1); +} + +static long +exp5 () +{ + register long val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + } + return (val1); +} + +static long +exp4 () +{ + register long val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else if (op == GT) + val1 = val1 > val2; + } + return (val1); +} + +/* Left and right shifts. */ +static long +expshift () +{ + register long val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + } + + return (val1); +} + +static long +exp3 () +{ + register long val1, val2; + + val1 = exp2 (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = exp2 (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + } + return (val1); +} + +static long +exp2 () +{ + register long val1, val2; + + val1 = exp1 (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + + readtok (); + + val2 = exp1 (); + + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + evalerror ("division by 0"); + + if (op == MUL) + val1 *= val2; + else if (op == DIV) + val1 /= val2; + else if (op == MOD) + val1 %= val2; + } + return (val1); +} + +static long +exp1 () +{ + register long val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + } + else + val = exp0 (); + + return (val); +} + +static long +exp0 () +{ + register long val = 0L; + + if (curtok == MINUS) + { + readtok (); + val = - exp0 (); + } + else if (curtok == PLUS) + { + readtok (); + val = exp0 (); + } + else if (curtok == LPAR) + { + readtok (); + val = expassign (); + + if (curtok != RPAR) + evalerror ("missing `)'"); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + readtok (); + } + else + evalerror ("syntax error in expression"); + + return (val); +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp = tp; + register int c, c1; + + /* Skip leading whitespace. */ + c = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + lasttp = tp = cp - 1; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + + if (variable_starter (c)) + { + /* Semi-bogus K*rn shell compatibility feature -- variable + names not preceded with a dollar sign are shell variables. */ + char *value; + + while (variable_character (c)) + c = *cp++; + + c = *--cp; + *cp = '\0'; + + if (tokstr) + free (tokstr); + tokstr = savestring (tp); + value = get_string_value (tokstr); + + if (value && *value) + tokval = evalexp (value); + else + tokval = 0; + + *cp = c; + lasttok = curtok; + curtok = STR; + } + else if (digit(c)) + { + while (digit (c) || isletter (c) || c == '#') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if (c1 == EQ && member(c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else + cp--; /* `unget' the character */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + char *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 : ""); + 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). */ +static long +strlong (num) + char *num; +{ + register char *s = num; + register int c; + int base = 10; + long val = 0L; + + if (s == NULL || *s == '\0') + return 0L; + + if (*s == '0') + { + s++; + + if (s == NULL || *s == '\0') + return 0L; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + } + + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + 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; + + val = 0L; + } + 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; + } + return (val); +} + +#if defined (EXPR_TEST) +char * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +char * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +jmp_buf top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + long v; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i]); + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + int n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ diff --git a/externs.h b/externs.h new file mode 100644 index 0000000..8330838 --- /dev/null +++ b/externs.h @@ -0,0 +1,67 @@ +/* externs.h -- extern function declarations which do not appear in their + own header file. */ + +/* 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. */ + +/* Make sure that this is included *after* config.h! */ + +#if !defined (__EXTERNS_H__) +# define __EXTERNS_H__ + +#include "stdc.h" + +/* Functions from expr.c. */ +extern long evalexp __P((char *)); + +/* 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)); + +/* 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)); + +/* Functions from test.c. */ +extern int group_member (); + +/* 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 not declared anywhere but used. */ +extern char **glob_filename __P((char *)); + +#endif /* __EXTERNS_H__ */ diff --git a/filecntl.h b/filecntl.h new file mode 100644 index 0000000..c0b2081 --- /dev/null +++ b/filecntl.h @@ -0,0 +1,36 @@ +/* filecntl.h - Definitions to set file descriptors to close-on-exec. */ + +/* 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 (_FILECNTL_H_) +#define _FILECNTL_H_ + +#include <fcntl.h> + +/* Definitions to set file descriptors to close-on-exec, the Posix way. */ +#if !defined (FD_CLOEXEC) +#define FD_CLOEXEC 1 +#endif + +#define FD_NCLOEXEC 0 + +#define SET_CLOSE_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_CLOEXEC)) +#define SET_OPEN_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_NCLOEXEC)) + +#endif /* ! _FILECNTL_H_ */ @@ -0,0 +1,270 @@ +/* flags.c -- Everything about flags except the `set' command. That + is in builtins.c */ + +/* 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 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. */ + +/* Flags hacking. */ + +#include "shell.h" +#include "flags.h" + +/* **************************************************************** */ +/* */ +/* The Standard Sh Flags. */ +/* */ +/* **************************************************************** */ + +/* Non-zero means automatically mark variables which are modified or created + as auto export variables. */ +int mark_modified_vars = 0; + +/* Non-zero causes asynchronous job notification. Otherwise, job state + notification only takes place just before a primary prompt is printed. */ +int asynchronous_notification = 0; + +/* Non-zero means exit immediately if a command exits with a non-zero + exit status. */ +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 + for debugging shell scripts that should do something hairy and possibly + desctructive. */ +int read_but_dont_execute = 0; + +/* Non-zero means end of file is after one command. */ +int just_one_command = 0; + +/* Non-zero means don't overwrite existing files while doing redirections. */ +int noclobber = 0; + +/* Non-zero means trying to get the value of $i where $i is undefined + causes an error, instead of a null substitution. */ +int unbound_vars_is_error = 0; + +/* Non-zero means type out input lines after you read them. */ +int echo_input_at_read = 0; + +/* Non-zero means type out the command definition after reading, but + before executing. */ +int echo_command_at_execute = 0; + +/* Non-zero means turn on the job control features. */ +int jobs_m_flag = 0; + +/* Non-zero means this shell is interactive, even if running under a + pipe. */ +int forced_interactive = 0; + +/* By default, follow the symbolic links as if they were real directories + while hacking the `cd' command. This means that `cd ..' moves up in + the string of symbolic links that make up the current directory, instead + of the absolute directory. The shell variable `nolinks' also controls + this flag. */ +int no_symbolic_links = 0; + +/* **************************************************************** */ +/* */ +/* Non-Standard Flags Follow Here. */ +/* */ +/* **************************************************************** */ + + +/* Non-zero means do lexical scoping in the body of a FOR command. */ +int lexical_scoping = 0; + +/* 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; + +#if defined (BANG_HISTORY) +/* Non-zero means that we are doing history expansion. The default. + This means !22 gets the 22nd line of history. */ +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 + disallows: changing directories, command or path names containing `/', + unsetting or resetting the values of $PATH and $SHELL, and any type of + output redirection. */ +int restricted = 0; +#endif /* RESTRICTED_SHELL */ + +/* Non-zero means that this shell is running in `privileged' mode. This + mode is entered on startup if the real and effective uids or gids + differ. */ +int privileged_mode = 0; + +/* **************************************************************** */ +/* */ +/* The Flags ALIST. */ +/* */ +/* **************************************************************** */ + +struct flags_alist shell_flags[] = { + /* Standard sh flags. */ + { 'a', &mark_modified_vars }, +#if defined (JOB_CONTROL) + { 'b', &asynchronous_notification }, +#endif /* JOB_CONTROL */ + { 'e', &exit_immediately_on_error }, + { 'f', &disallow_filename_globbing }, + { 'h', &locate_commands_in_functions }, /* Oh, yeah, good mnemonic. */ + { 'i', &forced_interactive }, + { 'k', &place_keywords_in_env }, +#if defined (JOB_CONTROL) + { 'm', &jobs_m_flag }, +#endif /* JOB_CONTROL */ + { 'n', &read_but_dont_execute }, + { 'p', &privileged_mode }, +#if defined (RESTRICTED_SHELL) + { 'r', &restricted }, +#endif /* RESTRICTED_SHELL */ + { 't', &just_one_command }, + { 'u', &unbound_vars_is_error }, + { 'v', &echo_input_at_read }, + { 'x', &echo_command_at_execute }, + { 'C', &noclobber }, + + /* New flags that control non-standard things. */ + { 'l', &lexical_scoping }, + { 'I', &no_invisible_vars }, + + /* I want `h', but locate_commands_in_functions has it. Great. */ + { 'd', &hashing_disabled }, + + { 'P', &no_symbolic_links }, + +#if defined (BANG_HISTORY) + /* Once again, we don't have the right mnemonic. */ + { 'H', &history_expansion }, +#endif /* BANG_HISTORY */ + + {0, (int *)NULL} +}; + +#define NUM_SHELL_FLAGS (sizeof (shell_flags) / sizeof (struct flags_alist)) + +int * +find_flag (name) + int name; +{ + int i = 0; + while (shell_flags[i].name) + { + if (shell_flags[i].name == name) + return (shell_flags[i].value); + i++; + } + return (FLAG_UNKNOWN); +} + +/* Change the state of a flag, and return it's original value, or return + FLAG_ERROR if there is no flag called NAME. ON_OR_OFF should be one + of FLAG_ON or FLAG_OFF. */ +int +change_flag (flag, on_or_off) + int flag; + int on_or_off; +{ + int *value = find_flag (flag); + int old_value; + +#if defined (RESTRICTED_SHELL) + /* Don't allow "set +r" in a shell which is `restricted'. */ + if (restricted && flag == 'r' && on_or_off == FLAG_OFF) + return (FLAG_ERROR); +#endif /* RESTRICTED_SHELL */ + + if (value == (int *)FLAG_UNKNOWN) + return (FLAG_ERROR); + else + old_value = *value; + + if (on_or_off == FLAG_ON) + *value = 1; + else + { + if (on_or_off == FLAG_OFF) + *value = 0; + else + return (FLAG_ERROR); + } + + /* Special cases for a few flags. */ + switch (flag) + { +#if defined (JOB_CONTROL) + case 'm': + set_job_control (on_or_off == '-'); + break; +#endif /* JOB_CONTROL */ + + 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; + } + break; + } + + return (old_value); +} + +/* Return a string which is the names of all the currently + set shell flags. */ +char * +which_set_flags () +{ + char *temp = (char *)xmalloc (1 + NUM_SHELL_FLAGS); + + int i, string_index = 0; + + for (i = 0; shell_flags[i].name; i++) + if (*(shell_flags[i].value)) + temp[string_index++] = shell_flags[i].name; + + temp[string_index] = '\0'; + return (temp); +} @@ -0,0 +1,65 @@ +/* flags.h -- a list of all the flags that the shell knows about. You add + a flag to this program by adding the name here, and in flags.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 (_FLAGS_H) +#define _FLAGS_H + +#include "stdc.h" + +/* Welcome to the world of Un*x, where everything is slightly backwards. */ +#define FLAG_ON '-' +#define FLAG_OFF '+' + +#define FLAG_ERROR -1 +#define FLAG_UNKNOWN (int *)0 + +/* The thing that we build the array of flags out of. */ +struct flags_alist { + char name; + int *value; +}; + +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, + 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, + asynchronous_notification, interactive_comments, no_symbolic_links; + +#if defined (BANG_HISTORY) +extern int history_expansion; +#endif /* BANG_HISTORY */ + +#if defined (RESTRICTED_SHELL) +extern int restricted; +#endif /* RESTRICTED_SHELL */ + +extern int *find_flag __P((int)); +extern int change_flag __P((int, int)); +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 */ diff --git a/general.c b/general.c new file mode 100644 index 0000000..9ccfce6 --- /dev/null +++ b/general.c @@ -0,0 +1,1273 @@ +/* general.c -- Stuff that is used by all files. */ + +/* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992 + 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" /* includes unistd.h for us */ +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include "bashtypes.h" +#include <sys/param.h> +#if defined (_POSIX_VERSION) +# if defined (amiga) && defined (USGr4) +# define _POSIX_SOURCE +# endif +# include <signal.h> +# if defined (amiga) && defined (USGr4) +# undef _POSIX_SOURCE +# endif +#endif /* _POSIX_VERSION */ +#include "filecntl.h" +#include "bashansi.h" +#include "shell.h" +#include <tilde/tilde.h> + +#if !defined (USG) || defined (HAVE_RESOURCE) +# include <sys/time.h> +#endif + +#include <sys/times.h> +#include "maxpath.h" + +#if !defined (errno) +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!"); + + 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; +{ + free (string); +} + +/* **************************************************************** */ +/* */ +/* Integer to String Conversion */ +/* */ +/* **************************************************************** */ + +/* Number of characters that can appear in a string representation + of an integer. 32 is larger than the string rep of 2^^31 - 1. */ +#define MAX_INT_LEN 32 + +/* Integer to string conversion. This conses the string; the + caller should free it. */ +char * +itos (i) + int i; +{ + char *buf, *p, *ret; + int negative = 0; + unsigned int ui; + + buf = xmalloc (MAX_INT_LEN); + + if (i < 0) + { + negative++; + i = -i; + } + + ui = (unsigned int) i; + + buf[MAX_INT_LEN - 1] = '\0'; + p = &buf[MAX_INT_LEN - 2]; + + do + *p-- = (ui % 10) + '0'; + while (ui /= 10); + + if (negative) + *p-- = '-'; + + ret = savestring (p + 1); + free (buf); + 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) + char *s; +{ + long ret = 0L; + int neg = 0; + + while (s && *s && whitespace (*s)) + s++; + if (*s == '-' || *s == '+') + { + neg = *s == '-'; + s++; + } + for ( ; s && *s && digit (*s); s++) + ret = (ret * 10) + digit_value (*s); + return (neg ? -ret : ret); +} + +#if defined (RLIMTYPE) +RLIMTYPE +string_to_rlimtype (s) + char *s; +{ + RLIMTYPE ret = 0; + int neg = 0; + + while (s && *s && whitespace (*s)) + s++; + if (*s == '-' || *s == '+') + { + neg = *s == '-'; + s++; + } + for ( ; s && *s && digit (*s); s++) + ret = (ret * 10) + digit_value (*s); + return (neg ? -ret : ret); +} + +void +print_rlimtype (n, addnl) + RLIMTYPE n; + int addnl; +{ + char s[sizeof (RLIMTYPE) * 3 + 1]; + int len = sizeof (RLIMTYPE) * 3 + 1; + + if (n == 0) + { + printf ("0%s", addnl ? "\n" : ""); + return; + } + + if (n < 0) + { + putchar ('-'); + n = -n; + } + + s[--len] = '\0'; + for ( ; n != 0; n /= 10) + s[--len] = n % 10 + '0'; + printf ("%s%s", s + len, addnl ? "\n" : ""); +} +#endif /* RLIMTYPE */ + +/* 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. */ +int +legal_identifier (name) + char *name; +{ + register char *s; + + if (!name || !*name || digit (*name)) + return (0); + + for (s = name; s && *s; s++) + { + if (!isletter (*s) && !digit (*s) && (*s != '_')) + return (0); + } + return (1); +} + +/* Make sure that WORD is a valid shell identifier, i.e. + does not contain a dollar sign, nor is quoted in any way. Nor + 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. */ +check_identifier (word, check_word) + WORD_DESC *word; + int check_word; +{ + if (word->dollar_present || word->quoted || all_digits (word->word)) + { + report_error ("`%s' is 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); + return (0); + } + else + return (1); +} + +/* 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. */ + +#if !defined (O_NDELAY) +# if defined (FNDELAY) +# define O_NDELAY FNDELAY +# endif +#endif /* O_NDELAY */ + +/* Make sure no-delay mode is not set on file descriptor FD. */ +void +unset_nodelay_mode (fd) + int fd; +{ + int flags, set = 0; + + if ((flags = fcntl (fd, F_GETFL, 0)) < 0) + return; + +#if defined (O_NONBLOCK) + 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. */ +void +map_over_list (list, function) + GENERIC_LIST *list; + Function *function; +{ + while (list) + { + (*function) (list); + list = list->next; + } +} + +/* 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; + + while (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); +} + +/* 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 ((*comparer) (temp, arg)) + { + if (prev) + prev->next = temp->next; + else + *list = temp->next; + return (temp); + } + prev = temp; + temp = temp->next; + } + 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); + + 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 (array) + char **array; +{ + register int i = 0; + + if (!array) return; + + 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; + + 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. */ +int +qsort_string_compare (s1, s2) + register char **s1, **s2; +{ + int result; + + if ((result = **s1 - **s2) == 0) + result = strcmp (*s1, *s2); + + return (result); +} + +/* 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; + + if (!t_head) + return (tail); + + while (t_head->next) + t_head = t_head->next; + t_head->next = tail; + return (head); +} + +/* 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'; + } +} + +/* 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'; +} + +/* Canonicalize PATH, and return a new path. The new path differs from PATH + in that: + Multple `/'s are collapsed to a single `/'. + Leading `./'s and trailing `/.'s are removed. + Trailing `/'s are removed. + Non-leading `../'s and trailing `..'s are handled by removing + portions of the path. */ +char * +canonicalize_pathname (path) + char *path; +{ + register int i, start; + char stub_char; + char *result; + + /* The result cannot be larger than the input PATH. */ + result = savestring (path); + + stub_char = (*path == '/') ? '/' : '.'; + + /* Walk along RESULT looking for things to compact. */ + i = 0; + while (1) + { + if (!result[i]) + break; + + while (result[i] && result[i] != '/') + i++; + + start = i++; + + /* If we didn't find any slashes, then there is nothing left to do. */ + if (!result[start]) + break; + + /* Handle multiple `/'s in a row. */ + while (result[i] == '/') + i++; + +#if !defined (apollo) + if ((start + 1) != i) +#else + if ((start + 1) != i && (start != 0 || i != 2)) +#endif /* apollo */ + { + strcpy (result + start + 1, result + i); + i = start + 1; + } + +#if 0 + /* Handle backslash-quoted `/'. */ + if (start > 0 && result[start - 1] == '\\') + continue; +#endif + + /* Check for trailing `/'. */ + if (start && !result[i]) + { + zero_last: + result[--i] = '\0'; + break; + } + + /* Check for `../', `./' or trailing `.' by itself. */ + if (result[i] == '.') + { + /* Handle trailing `.' by itself. */ + if (!result[i + 1]) + goto zero_last; + + /* Handle `./'. */ + if (result[i + 1] == '/') + { + strcpy (result + i, result + i + 1); + i = (start < 0) ? 0 : start; + continue; + } + + /* Handle `../' or trailing `..' by itself. */ + if (result[i + 1] == '.' && + (result[i + 2] == '/' || !result[i + 2])) + { + while (--start > -1 && result[start] != '/'); + strcpy (result + start + 1, result + i + 2); + i = (start < 0) ? 0 : start; + continue; + } + } + } + + if (!*result) + { + *result = stub_char; + result[1] = '\0'; + } + return (result); +} + +/* Turn STRING (a pathname) into an absolute pathname, assuming that + DOT_PATH contains the symbolic location of `.'. This always + returns a new string, even if STRING was an absolute pathname to + begin with. */ +char * +make_absolute (string, dot_path) + char *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)); + strcpy (result, dot_path); + result_len = strlen (result); + if (result[result_len - 1] != '/') + { + result[result_len++] = '/'; + result[result_len] = '\0'; + } + } + else + { + result = xmalloc (3 + strlen (string)); + result[0] = '.'; result[1] = '/'; result[2] = '\0'; + result_len = 2; + } + + strcpy (result + result_len, string); + } + + return (result); +} + +/* Return 1 if STRING contains an absolute pathname, else 0. */ +int +absolute_pathname (string) + char *string; +{ + if (!string || !*string) + return (0); + + if (*string == '/') + return (1); + + if (*string++ == '.') + { + if (!*string || *string == '/') + return (1); + + if (*string == '.' && (string[1] == '\0' || string[1] == '/')) + return (1); + } + return (0); +} + +/* Return 1 if STRING is an absolute program name; it is absolute if it + contains any slashes. This is used to decide whether or not to look + up through $PATH. */ +int +absolute_program (string) + char *string; +{ + return ((char *)strchr (string, '/') != (char *)NULL); +} + +/* Return the `basename' of the pathname in STRING (the stuff after the + last '/'). If STRING is not a full pathname, simply return it. */ +char * +base_pathname (string) + char *string; +{ + char *p; + + if (!absolute_pathname (string)) + return (string); + + p = (char *)strrchr (string, '/'); + if (p) + return (++p); + else + return (string); +} + +/* Return the full pathname of FILE. Easy. Filenames that begin + with a '/' are returned as themselves. Other filenames have + the current working directory prepended. A new string is + returned in either case. */ +char * +full_pathname (file) + char *file; +{ + char *disposer; + + if (*file == '~') + file = tilde_expand (file); + else + 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 ()) + { + 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 (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 <sys/utsname.h> +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); +} +#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]; + +/* Return a pretty pathname. If the first part of the pathname is + the same as $HOME, then replace that with `~'. */ +char * +polite_directory_format (name) + char *name; +{ + char *home = get_string_value ("HOME"); + int l = home ? strlen (home) : 0; + + if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) + { + strcpy (tdir + 1, name + l); + tdir[0] = '~'; + return (tdir); + } + else + 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; +{ + /* 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, fp) + int c; + FILE *fp; +{ + if (local_index == 0 || local_bufused == 0 || c == EOF) + return EOF; + return (localbuf[--local_index] = c); +} + +#endif /* NO_READ_RESTART_ON_SIGNAL */ + +#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 */ + +int +killpg (pgrp, sig) + pid_t pgrp; + int sig; +{ + return (kill (-pgrp, sig)); +} +#endif /* USG || AIX || (_POSIX_VERSION && Ultrix) */ + +/* **************************************************************** */ +/* */ +/* Tilde Initialization and Expansion */ +/* */ +/* **************************************************************** */ + +/* If tilde_expand hasn't been able to expand the text, perhaps it + 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) + char *text; +{ + char *result = (char *)NULL; + + if (!text[1]) + { + if (*text == '+') + result = get_string_value ("PWD"); + else if (*text == '-') + result = get_string_value ("OLDPWD"); + } + + if (result) + result = savestring (result); + + return (result); +} + +/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as + well as handling special tilde prefixes; `:~" and `=~' are indications + that we should do tilde expansion. */ +void +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; + + /* Tell the tilde expander about special strings which start a tilde + expansion, and the special strings that end one. Only do this once. + tilde_initialize () is called from within bashline_reinitialize (). */ + if (times_called == 0) + { + tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *)); + tilde_additional_prefixes[0] = "=~"; + tilde_additional_prefixes[1] = ":~"; + tilde_additional_prefixes[2] = (char *)NULL; + + tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *)); + tilde_additional_suffixes[0] = ":"; + tilde_additional_suffixes[1] = "=~"; + tilde_additional_suffixes[2] = (char *)NULL; + } + 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; +{ + 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 /* _POSIX_VERSION */ diff --git a/general.h b/general.h new file mode 100644 index 0000000..5c8f4d1 --- /dev/null +++ b/general.h @@ -0,0 +1,247 @@ +/* general.h -- defines that everybody likes to use. */ + +/* 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 (_GENERAL_H) +#define _GENERAL_H + +#include "stdc.h" + +/* just to make sure */ +#if defined (HAVE_UNISTD_H) +# ifdef CRAY +# define word __word +# endif +# include <unistd.h> +# ifdef CRAY +# undef word +# endif +#endif + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* !__STDC__ */ +#endif /* !NULL */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#define pointer_to_int(x) (int)((long)(x)) + +#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 whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef digit +#define digit(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef isletter +#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) +#endif + +#ifndef digit_value +#define digit_value(c) ((c) - '0') +#endif + +/* 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. */ +typedef struct g_list { + struct g_list *next; +} GENERIC_LIST; + +/* Here is a generic structure for associating character strings + with integers. It is used in the parser for shell tokenization. */ +typedef struct { + char *word; + int token; +} STRING_INT_ALIST; + +/* 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)) + +#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) +# define FASTCOPY(s, d, n) memcpy (d, s, n) +# else +# define FASTCOPY(s, d, n) memmove (d, s, n) +# endif /* !MEMMOVE_MISSING */ +# else +# define FASTCOPY(s, d, n) bcopy (s, d, n) +# endif /* !USG || HAVE_BCOPY */ +#endif /* !__GNUC__ */ + +/* String comparisons that possibly save a function call each. */ +#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) + +/* More convenience definitions that possibly save system or libc calls. */ +#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) +#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 + +/* 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 NOW ((time_t) time ((time_t *) 0)) + +/* Some defines for calling file status functions. */ +#define FS_EXISTS 0x1 +#define FS_EXECABLE 0x2 +#define FS_EXEC_PREFERRED 0x4 +#define FS_EXEC_ONLY 0x8 + +/* 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. */ + +#if defined (VOID_SIGHANDLER) +# define sighandler void +#else +# define sighandler int +#endif /* !VOID_SIGHANDLER */ + +typedef sighandler SigHandler (); + +#if !defined (_POSIX_VERSION) +# define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler) +#else +extern SigHandler *set_signal_handler (); +#endif /* _POSIX_VERSION */ + +/* This function is defined in trap.c. */ +extern SigHandler *set_sigint_handler __P((void)); + +/* 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_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 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)); + +#if defined (USG) && !defined (HAVE_GETHOSTNAME) +extern int gethostname __P((char *, int)); +#endif /* USG && !HAVE_GETHOSTNAME */ + +#endif /* _GENERAL_H */ diff --git a/getcwd.c b/getcwd.c new file mode 100644 index 0000000..6f6eed3 --- /dev/null +++ b/getcwd.c @@ -0,0 +1,344 @@ +/* getcwd.c -- stolen from the GNU C library and modified to work with bash. */ + +/* 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. */ + +#include "bashtypes.h" +#include <errno.h> + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +#if defined (HAVE_DIRENT_H) +# include <dirent.h> +#else +# include <sys/dir.h> +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +#endif /* !HAVE_DIRENT_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include "posixstat.h" +#include "maxpath.h" +#include "config.h" + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* !HAVE_STDLIB_H */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#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 */ + +#if defined (__STDC__) +# define CONST const +# define PTR void * +#else /* !__STDC__ */ +# define CONST +# define PTR char * +#endif /* !__STDC__ */ + +#if !defined (PATH_MAX) +# if defined (MAXPATHLEN) +# define PATH_MAX MAXPATHLEN +# else /* !MAXPATHLEN */ +# define PATH_MAX 1024 +# 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) +# define lstat stat +#endif + +/* Get the pathname of the current working directory, + and put it in SIZE bytes of BUF. Returns NULL if the + directory couldn't be determined or SIZE was too small. + If successful, returns BUF. In GNU, if BUF is NULL, + an array is allocated with `malloc'; the array is SIZE + bytes long, unless SIZE <= 0, in which case it is as + big as necessary. */ +#if defined (__STDC__) +char * +getcwd (char *buf, size_t size) +#else /* !__STDC__ */ +char * +getcwd (buf, size) + char *buf; + size_t size; +#endif /* !__STDC__ */ +{ + static CONST char dots[] + = "../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../.."; + CONST char *dotp, *dotlist; + size_t dotsize; + dev_t rootdev, thisdev; + ino_t rootino, thisino; + char path[PATH_MAX + 1]; + register char *pathp; + char *pathbuf; + size_t pathsize; + struct stat st; + + if (buf != NULL && size == 0) + { + errno = EINVAL; + return ((char *)NULL); + } + + pathsize = sizeof (path); + pathp = &path[pathsize]; + *--pathp = '\0'; + pathbuf = path; + + if (stat (".", &st) < 0) + return ((char *)NULL); + thisdev = st.st_dev; + thisino = st.st_ino; + + if (stat ("/", &st) < 0) + return ((char *)NULL); + rootdev = st.st_dev; + rootino = st.st_ino; + + dotsize = sizeof (dots) - 1; + dotp = &dots[sizeof (dots)]; + dotlist = dots; + while (!(thisdev == rootdev && thisino == rootino)) + { + register DIR *dirstream; + register struct dirent *d; + dev_t dotdev; + ino_t dotino; + char mount_point; + int namlen; + + /* Look at the parent directory. */ + if (dotp == dotlist) + { + /* My, what a deep directory tree you have, Grandma. */ + char *new; + if (dotlist == dots) + { + new = malloc (dotsize * 2 + 1); + if (new == NULL) + goto lose; + memcpy (new, dots, dotsize); + } + else + { + new = realloc ((PTR) dotlist, dotsize * 2 + 1); + if (new == NULL) + goto lose; + } + memcpy (&new[dotsize], new, dotsize); + dotp = &new[dotsize]; + dotsize *= 2; + new[dotsize] = '\0'; + dotlist = new; + } + + dotp -= 3; + + /* Figure out if this directory is a mount point. */ + if (stat (dotp, &st) < 0) + goto lose; + dotdev = st.st_dev; + dotino = st.st_ino; + mount_point = dotdev != thisdev; + + /* Search for the last directory. */ + dirstream = opendir (dotp); + if (dirstream == NULL) + goto lose; + while ((d = readdir (dirstream)) != NULL) + { + if (d->d_name[0] == '.' && + (d->d_name[1] == '\0' || + (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + if (mount_point || d->d_fileno == thisino) + { + char *name; + + namlen = D_NAMLEN(d); + name = (char *) + alloca (dotlist + dotsize - dotp + 1 + namlen + 1); + memcpy (name, dotp, dotlist + dotsize - dotp); + name[dotlist + dotsize - dotp] = '/'; + memcpy (&name[dotlist + dotsize - dotp + 1], + d->d_name, namlen + 1); + if (lstat (name, &st) < 0) + { + int save = errno; + (void) closedir (dirstream); + errno = save; + goto lose; + } + if (st.st_dev == thisdev && st.st_ino == thisino) + break; + } + } + if (d == NULL) + { + int save = errno; + (void) closedir (dirstream); + errno = save; + goto lose; + } + else + { + size_t space; + + while ((space = pathp - pathbuf) <= namlen) + { + char *new; + + if (pathbuf == path) + { + new = malloc (pathsize * 2); + if (!new) + goto lose; + } + else + { + new = realloc ((PTR) pathbuf, (pathsize * 2)); + if (!new) + goto lose; + pathp = new + space; + } + (void) memcpy (new + pathsize + space, pathp, pathsize - space); + pathp = new + pathsize + space; + pathbuf = new; + pathsize *= 2; + } + + pathp -= namlen; + (void) memcpy (pathp, d->d_name, namlen); + *--pathp = '/'; + (void) closedir (dirstream); + } + + thisdev = dotdev; + thisino = dotino; + } + + if (pathp == &path[sizeof(path) - 1]) + *--pathp = '/'; + + if (dotlist != dots) + free ((PTR) dotlist); + + { + size_t len = pathbuf + pathsize - pathp; + if (buf == NULL) + { + if (len < (size_t) size) + len = size; + buf = (char *) malloc (len); + if (buf == NULL) + goto lose2; + } + else if ((size_t) size < len) + { + errno = ERANGE; + goto lose2; + } + (void) memcpy((PTR) buf, (PTR) pathp, len); + } + + if (pathbuf != path) + free (pathbuf); + + return (buf); + + lose: + if ((dotlist != dots) && dotlist) + { + int e = errno; + free ((PTR) dotlist); + errno = e; + } + + lose2: + if ((pathbuf != path) && pathbuf) + { + int e = errno; + free ((PTR) pathbuf); + errno = e; + } + return ((char *)NULL); +} + +#if defined (TEST) +# include <stdio.h> +main (argc, argv) + int argc; + char **argv; +{ + char b[PATH_MAX]; + + if (getcwd(b, sizeof(b))) + { + printf ("%s\n", b); + exit (0); + } + else + { + perror ("cwd: getcwd"); + exit (1); + } +} +#endif /* TEST */ @@ -0,0 +1,297 @@ +/* Hash.c -- Where hashing for bash is done. */ + +/* 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. */ + +/* 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. */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "shell.h" +#include "hash.h" + +HASH_TABLE *hashed_filenames; + +#define FILENAME_HASH_BUCKETS 107 + +/* Zero the buckets in TABLE. */ +static void +initialize_hash_table (table) + HASH_TABLE *table; +{ + register int i; + for (i = 0; i < table->nbuckets; i++) + table->bucket_array[i] = (BUCKET_CONTENTS *)NULL; +} + +/* Make a new hash table with BUCKETS number of buckets. Initialize + each slot in the table to NULL. */ +HASH_TABLE * +make_hash_table (buckets) + int buckets; +{ + HASH_TABLE *new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE)); + + if (buckets == 0) + buckets = DEFAULT_HASH_BUCKETS; + + new_table->bucket_array = + (BUCKET_CONTENTS **)xmalloc (buckets * sizeof (BUCKET_CONTENTS *)); + new_table->nbuckets = buckets; + new_table->nentries = 0; + initialize_hash_table (new_table); + 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. */ + +#define ALL_ONES (~((unsigned long) 0)) +#define BITS(h, n) ((unsigned long)(h) & ~(ALL_ONES << (n))) + +int +hash_string (string, table) + char *string; + HASH_TABLE *table; +{ + register unsigned int i = 0; + + while (*string) + i = (i << 2) + *string++; + + return (BITS (i, 31) % table->nbuckets); +} + +/* Return a pointer to the hashed item, or NULL if the item + can't be found. */ +BUCKET_CONTENTS * +find_hash_item (string, table) + char *string; + HASH_TABLE *table; +{ + BUCKET_CONTENTS *list; + int which_bucket; + + if (!table) + return (BUCKET_CONTENTS *)NULL; + + which_bucket = hash_string (string, table); + + list = table->bucket_array[which_bucket]; + + while (list) + { + if (STREQ (list->key, string)) + { + list->times_found++; + return (list); + } + else list = list->next; + } + return (BUCKET_CONTENTS *)NULL; +} + +/* Remove the item specified by STRING from the hash table TABLE. + The item removed is returned, so you can free its contents. If + the item isn't in this table NULL is returned. */ +BUCKET_CONTENTS * +remove_hash_item (string, table) + char *string; + HASH_TABLE *table; +{ + int the_bucket; + BUCKET_CONTENTS *prev, *temp; + + if (!table) + return (BUCKET_CONTENTS *)NULL; + + the_bucket = hash_string (string, table); + prev = (BUCKET_CONTENTS *)NULL; + temp = table->bucket_array[the_bucket]; + + while (temp) + { + if (STREQ (temp->key, string)) + { + if (prev) + prev->next = temp->next; + else + table->bucket_array[the_bucket] = temp->next; + + table->nentries--; + return (temp); + } + prev = temp; + temp = temp->next; + } + return ((BUCKET_CONTENTS *) NULL); +} + +/* Create an entry for STRING, in TABLE. If the entry already + exists, then return it. */ +BUCKET_CONTENTS * +add_hash_item (string, table) + char *string; + HASH_TABLE *table; +{ + BUCKET_CONTENTS *item; + + if (!table) + table = make_hash_table (0); + + if ((item = find_hash_item (string, table)) == 0) + { + int bucket = hash_string (string, table); + item = table->bucket_array[bucket]; + + while (item && item->next) + item = item->next; + + if (item) + { + item->next = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS)); + item = item->next; + } + else + { + table->bucket_array[bucket] = + (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS)); + item = table->bucket_array[bucket]; + } + + item->data = (char *)NULL; + item->next = (BUCKET_CONTENTS *)NULL; + item->key = string; + table->nentries++; + item->times_found = 0; + } + + return (item); +} + +/* Return the bucket_contents list of bucket BUCKET in TABLE. If + TABLE doesn't have BUCKET buckets, return NULL. */ +#undef get_hash_bucket +BUCKET_CONTENTS * +get_hash_bucket (bucket, table) + int bucket; + HASH_TABLE *table; +{ + if (table && bucket < table->nbuckets) + return (table->bucket_array[bucket]); + else + return (BUCKET_CONTENTS *)NULL; +} + +#ifdef TEST_HASHING + +#undef NULL +#include <stdio.h> + +HASH_TABLE *table; +#define NBUCKETS 107 + +char * +xmalloc (bytes) + int bytes; +{ + char *result = (char *)malloc (bytes); + if (!result) + { + fprintf (stderr, "Out of memory!"); + abort (); + } + return (result); +} + +main () +{ + char string[256]; + int count = 0; + BUCKET_CONTENTS *tt; + + table = make_hash_table (NBUCKETS); + + for (;;) + { + char *temp_string; + if (fgets (string, sizeof (string), stdin) == 0) + break; + if (!*string) + break; + temp_string = savestring (string); + tt = add_hash_item (temp_string, table); + if (tt->times_found) + { + fprintf (stderr, "You have already added item `%s'\n", string); + free (temp_string); + } + else + { + count++; + } + } + + printf ("You have entered %d (%d) items. The distribution is:\n", + table->nentries, count); + + /* Print out a count of how many strings hashed to each bucket, so we can + see how even the distribution is. */ + for (count = 0; count < table->nbuckets; count++) + { + int bcount; + register BUCKET_CONTENTS *list = get_hash_bucket (count, table); + + printf ("slot %3d: ", count); + bcount = 0; + + for (bcount = 0; list; list = list->next) + bcount++; + + printf ("%d\n", bcount); + } + exit (0); +} + +#endif /* TEST_HASHING */ + +/* + * Local variables: + * compile-command: "gcc -g -DTEST_HASHING -o hash hash.c" + * end: + */ @@ -0,0 +1,61 @@ +/* hash.h -- the data structures used in hashing in Bash. */ + +/* 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 (_HASH_H_) +#define _HASH_H_ + +typedef struct bucket_contents { + struct bucket_contents *next; /* Link to next hashed key in this bucket. */ + char *key; /* What we look up. */ + char *data; /* What we really want. */ + int times_found; /* Number of times this item has been found. */ +} BUCKET_CONTENTS; + +typedef struct hash_table { + BUCKET_CONTENTS **bucket_array; /* Where the data is kept. */ + int nbuckets; /* How many buckets does this table have. */ + int nentries; /* How many entries does this table have. */ +} HASH_TABLE; + +extern int hash_string (); +extern HASH_TABLE *make_hash_table (); +extern BUCKET_CONTENTS *find_hash_item (); +extern BUCKET_CONTENTS *remove_hash_item (); +extern BUCKET_CONTENTS *add_hash_item (); +extern BUCKET_CONTENTS *get_hash_bucket (); + +/* Redefine the function as a macro for speed. */ +#define get_hash_bucket(bucket, table) \ + ((table && (bucket < table->nbuckets)) ? \ + table->bucket_array[bucket] : \ + (BUCKET_CONTENTS *)NULL) + +/* Default number of buckets in the hash table. */ +#define DEFAULT_HASH_BUCKETS 107 + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* !__STDC__ */ +#endif /* !NULL */ + +#endif /* _HASH_H */ @@ -0,0 +1,464 @@ +/* input.c -- functions to perform buffered input with synchronization. */ + +/* Copyright (C) 1992 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. */ + +/* similar to stdio, but input-only. */ + +#include "bashtypes.h" +#include <sys/file.h> +#include "filecntl.h" +#include "posixstat.h" +#include <stdio.h> +#include <errno.h> + +#include "bashansi.h" +#include "config.h" +#include "command.h" +#include "general.h" +#include "input.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#define MAX_INPUT_BUFFER_SIZE 8192 + +#if !defined (SEEK_CUR) +# define SEEK_CUR 1 +#endif /* !SEEK_CUR */ + +void free_buffered_stream (); + +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; + +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +#define ALLOCATE_BUFFERS(n) \ + do { if ((n) >= nbuffers) allocate_buffers (n); } while (0) + +/* Make sure `buffers' has at least N elements. */ +static void +allocate_buffers (n) + int n; +{ + register int i, orig_nbuffers; + + orig_nbuffers = nbuffers; + nbuffers = n + 20; + buffers = (BUFFERED_STREAM **)xrealloc + (buffers, nbuffers * sizeof (BUFFERED_STREAM *)); + + /* Zero out the new buffers. */ + for (i = orig_nbuffers; i < nbuffers; i++) + buffers[i] = (BUFFERED_STREAM *)NULL; +} + +/* Construct and return a BUFFERED_STREAM corresponding to file descriptor + FD, using BUFFER. */ +static BUFFERED_STREAM * +make_buffered_stream (fd, buffer, bufsize) + int fd; + char *buffer; + int bufsize; +{ + BUFFERED_STREAM *bp; + + bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); + ALLOCATE_BUFFERS (fd); + buffers[fd] = bp; + bp->b_fd = fd; + bp->b_buffer = buffer; + bp->b_size = bufsize; + bp->b_used = 0; + bp->b_inputp = 0; + bp->b_flag = 0; + if (bufsize == 1) + bp->b_flag |= B_UNBUFF; + return (bp); +} + +/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */ +static BUFFERED_STREAM * +copy_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + BUFFERED_STREAM *nbp; + + if (!bp) + return ((BUFFERED_STREAM *)NULL); + + nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM)); + xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM)); + return (nbp); +} + +/* Check that file descriptor FD is not the one that bash is currently + using to read input from a script. FD is about to be duplicated onto, + which means that the kernel will close it for us. If FD is the bash + input file descriptor, we need to seek backwards in the script (if + possible and necessary -- scripts read from stdin are still unbuffered), + allocate a new file descriptor to use for bash input, and re-initialize + the buffered stream. */ +int +check_bash_input (fd) + int fd; +{ + int nfd; + + if (fd > 0 && ((bash_input.type == st_bstream && bash_input.location.buffered_fd == fd) || + (interactive_shell == 0 && default_buffered_input == fd))) + { + /* Sync the stream so we can re-read from the new file descriptor. We + might be able to avoid this by copying the buffered stream verbatim + to the new file descriptor. */ + if (buffers[fd]) + sync_buffered_stream (fd); + + /* Now take care of duplicating the file descriptor that bash is + using for input, so we can reinitialize it later. */ + nfd = fcntl (fd, F_DUPFD, 10); + 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)); + return -1; + } + + if (buffers[nfd]) + { + /* 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); + free_buffered_stream (buffers[nfd]); + } + + /* Reinitialize bash_input.location. */ + if (bash_input.type == st_bstream) + { + bash_input.location.buffered_fd = nfd; + fd_to_buffered_stream (nfd); + close_buffered_fd (fd); /* XXX */ + } + else + /* If the current input type is not a buffered stream, but the shell + is not interactive and therefore using a buffered stream to read + input (e.g. with an `eval exec 3>output' inside a script), note + that the input fd has been changed. pop_stream() looks at this + value and adjusts the input fd to the new value of + default_buffered_input accordingly. */ + bash_input_fd_changed++; + + if (default_buffered_input == fd) + default_buffered_input = nfd; + } + return 0; +} + +/* This is the buffered stream analogue of dup2(fd1, fd2). The + 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 3</etc/rc.local. */ +duplicate_buffered_stream (fd1, fd2) + int fd1, fd2; +{ + int is_bash_input, m; + + if (fd1 == fd2) + return 0; + + m = max (fd1, fd2); + ALLOCATE_BUFFERS (m); + + /* If FD2 is the file descriptor bash is currently using for shell input, + we need to do some extra work to make sure that the buffered stream + actually exists (it might not if fd1 was not active, and the copy + didn't actually do anything). */ + is_bash_input = (bash_input.type == st_bstream) && + (bash_input.location.buffered_fd == fd2); + + if (buffers[fd2]) + free_buffered_stream (buffers[fd2]); + buffers[fd2] = copy_buffered_stream (buffers[fd1]); + if (buffers[fd2]) + buffers[fd2]->b_fd = fd2; + + if (is_bash_input) + { + if (!buffers[fd2]) + fd_to_buffered_stream (fd2); + } + return (fd2); +} + +/* Return 1 if a seek on FD will succeed. */ +#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0) + +/* Take FD, a file descriptor, and create and return a buffered stream + corresponding to it. If something is wrong and the file descriptor + is invalid, return a NULL stream. */ +BUFFERED_STREAM * +fd_to_buffered_stream (fd) + int fd; +{ + char *buffer; + int size; + struct stat sb; + + if (fstat (fd, &sb) < 0) + { + close (fd); + return ((BUFFERED_STREAM *)NULL); + } + + if (fd_is_seekable (fd) == 0) + size = 1; + else + size = (sb.st_size > MAX_INPUT_BUFFER_SIZE) ? MAX_INPUT_BUFFER_SIZE + : sb.st_size; + + buffer = (char *)xmalloc (size); + + return (make_buffered_stream (fd, buffer, size)); +} + +/* Return a buffered stream corresponding to FILE, a file name. */ +BUFFERED_STREAM * +open_buffered_stream (file) + char *file; +{ + int fd; + + fd = open (file, O_RDONLY); + if (fd == -1) + return ((BUFFERED_STREAM *)NULL); + return (fd_to_buffered_stream (fd)); +} + +/* Deallocate a buffered stream and free up its resources. Make sure we + zero out the slot in BUFFERS that points to BP. */ +void +free_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + int n; + + if (!bp) + return; + + n = bp->b_fd; + if (bp->b_buffer) + free (bp->b_buffer); + free (bp); + buffers[n] = (BUFFERED_STREAM *)NULL; +} + +/* Close the file descriptor associated with BP, a buffered stream, and free + up the stream. Return the status of closing BP's file descriptor. */ +int +close_buffered_stream (bp) + BUFFERED_STREAM *bp; +{ + int fd; + + if (!bp) + return (0); + fd = bp->b_fd; + free_buffered_stream (bp); + return (close (fd)); +} + +/* Deallocate the buffered stream associated with file descriptor FD, and + close FD. Return the status of the close on FD. */ +int +close_buffered_fd (fd) + int fd; +{ + if (fd >= nbuffers || !buffers || !buffers[fd]) + return (close (fd)); + return (close_buffered_stream (buffers[fd])); +} + +/* Read a buffer full of characters from BP, a buffered stream. */ +static int +b_fill_buffer (bp) + BUFFERED_STREAM *bp; +{ + do + { + bp->b_used = read (bp->b_fd, bp->b_buffer, bp->b_size); + } + while (bp->b_used < 0 && errno == EINTR); + if (bp->b_used <= 0) + { + bp->b_buffer[0] = 0; + if (bp->b_used == 0) + bp->b_flag |= B_EOF; + else + bp->b_flag |= B_ERROR; + return (EOF); + } + bp->b_inputp = 0; + return (bp->b_buffer[bp->b_inputp++] & 0xFF); +} + +/* Get a character from buffered stream BP. */ +#define bufstream_getc(bp) \ + (bp->b_inputp == bp->b_used || !bp->b_used) \ + ? b_fill_buffer (bp) \ + : bp->b_buffer[bp->b_inputp++] & 0xFF + +/* Push C back onto buffered stream BP. */ +static int +bufstream_ungetc(c, bp) + int c; + BUFFERED_STREAM *bp; +{ + if (c == EOF || bp->b_inputp == 0) + return (EOF); + + bp->b_buffer[--bp->b_inputp] = c; + return (c); +} + +/* Seek backwards on file BFD to synchronize what we've read so far + with the underlying file pointer. */ +int +sync_buffered_stream (bfd) + int bfd; +{ + BUFFERED_STREAM *bp; + int chars_left; + + bp = buffers[bfd]; + if (!bp) + return (-1); + chars_left = bp->b_used - bp->b_inputp; + if (chars_left) + lseek (bp->b_fd, -chars_left, SEEK_CUR); + bp->b_used = bp->b_inputp = 0; + return (0); +} + +int +buffered_getchar () +{ + return (bufstream_getc (buffers[bash_input.location.buffered_fd])); +} + +int +buffered_ungetchar (c) + int c; +{ + return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd])); +} + +/* Make input come from file descriptor BFD through a buffered stream. */ +void +with_input_from_buffered_stream (bfd, name) + int bfd; + char *name; +{ + INPUT_STREAM location; + + 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); +} + +#if defined (TEST) + +char * +xmalloc(s) +int s; +{ + return ((char *)malloc (s)); +} + +char * +xrealloc(s, size) +char *s; +int size; +{ + if (!s) + return((char *)malloc (size)); + else + return((char *)realloc (s, size)); +} + +void +init_yy_io () +{ +} + +process(bp) +BUFFERED_STREAM *bp; +{ + int c; + + while ((c = bufstream_getc(bp)) != EOF) + putchar(c); +} + +BASH_INPUT bash_input; + +struct stat dsb; /* can be used from gdb */ + +/* imitate /bin/cat */ +main(argc, argv) +int argc; +char **argv; +{ + register int i; + BUFFERED_STREAM *bp; + + if (argc == 1) { + bp = fd_to_buffered_stream (0); + process(bp); + exit(0); + } + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '\0') { + bp = fd_to_buffered_stream (0); + if (!bp) + continue; + process(bp); + free_buffered_stream (bp); + } else { + bp = open_buffered_stream (argv[i]); + if (!bp) + continue; + process(bp); + close_buffered_stream (bp); + } + } + exit(0); +} +#endif @@ -0,0 +1,115 @@ +/* input.h -- Structures and unions used for reading input. */ +/* 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 (_INPUT_H) +#define _INPUT_H + +#include "stdc.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 */ + +/* Some stream `types'. */ +#define st_none 0 +#define st_stream 1 +#define st_string 2 +#define st_stdin 3 + +#if defined (BUFFERED_INPUT) +#define st_bstream 4 + +/* Possible values for b_flag. */ +#define B_EOF 0x1 +#define B_ERROR 0x2 +#define B_UNBUFF 0x4 + +/* A buffered stream. Like a FILE *, but with our own buffering and + synchronization. Look in input.c for the implementation. */ +typedef struct BSTREAM +{ + int b_fd; + char *b_buffer; /* The buffer that holds characters read. */ + int b_size; /* How big the buffer is. */ + int b_used; /* How much of the buffer we're using, */ + int b_flag; /* Flag values. */ + int b_inputp; /* The input pointer, index into b_buffer. */ +} BUFFERED_STREAM; + +extern BUFFERED_STREAM **buffers; + +extern BUFFERED_STREAM *fd_to_buffered_stream (); + +extern int default_buffered_input; + +#endif /* BUFFERED_INPUT */ + +typedef union { + FILE *file; + char *string; +#if defined (BUFFERED_INPUT) + int buffered_fd; +#endif +} INPUT_STREAM; + +typedef struct { + int type; + char *name; + INPUT_STREAM location; + Function *getter; + Function *ungetter; +} BASH_INPUT; + +extern BASH_INPUT bash_input; + +/* Functions from parse.y. */ +extern void initialize_bash_input __P((void)); +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 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 *)); + +#if defined (BUFFERED_INPUT) +/* Functions from input.c. */ +extern int check_bash_input __P((int)); +extern int duplicate_buffered_stream __P((int, int)); +extern BUFFERED_STREAM *fd_to_buffered_stream __P((int)); +extern BUFFERED_STREAM *open_buffered_stream __P((char *)); +extern void free_buffered_stream __P((BUFFERED_STREAM *)); +extern int close_buffered_stream __P((BUFFERED_STREAM *)); +extern int close_buffered_fd __P((int)); +extern int sync_buffered_stream __P((int)); +extern int buffered_getchar __P((void)); +extern int buffered_ungetchar __P((int)); +extern void with_input_from_buffered_stream __P((int, char *)); +#endif /* BUFFERED_INPUT */ + +#endif /* _INPUT_H */ @@ -0,0 +1,2755 @@ +/* The thing that makes children, remembers them, and contains wait loops. */ + +/* This file works with both POSIX and BSD systems. */ + +/* Copyright (C) 1989, 1992 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. */ + +/* 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 <stdio.h> +#include <signal.h> +#include <errno.h> + +#if !defined (USG) || defined (HAVE_RESOURCE) +#include <sys/time.h> +#endif /* USG */ + +#if !defined (_POSIX_VERSION) +# if defined (HAVE_RESOURCE) +# include <sys/resource.h> +# endif +#endif /* _POSIX_VERSION */ + +#include <sys/file.h> +#include "filecntl.h" +#include <sys/ioctl.h> +#include <sys/param.h> + +#if defined (BUFFERED_INPUT) +# include "input.h" +#endif + +/* Terminal handling stuff, to save and restore tty state. */ +#define NEW_TTY_DRIVER + +/* 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? */ +# 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 <sgtty.h> +#endif + +#if defined (TERMIO_TTY_DRIVER) +#include <termio.h> +#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 <termios.h> +#endif /* TERMIOS_TTY_DRIVER */ + +/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ + +#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) +# include <bsdtty.h> +#endif /* hpux && !TERMIOS_TTY_DRIVER */ + +#include "bashansi.h" +#include "shell.h" +#include "jobs.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 */ + +/* Variables used here but defined in other files. */ +extern int interactive, interactive_shell, asynchronous_notification; +extern int subshell_environment; +extern int posixly_correct, no_symbolic_links, shell_level; +extern int interrupt_immediately, last_command_exit_value; +extern int loop_level, breaking; +extern Function *this_shell_builtin; +extern char *shell_name, *this_command_name; +extern sigset_t top_level_mask; + +/* 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; + +/* The shell's process group. */ +pid_t shell_pgrp = NO_PID; + +/* The terminal's process group. */ +pid_t terminal_pgrp = NO_PID; + +/* The process group of the shell's parent. */ +pid_t original_pgrp = NO_PID; + +/* The process group of the pipeline currently being made. */ +pid_t pipeline_pgrp = (pid_t)0; + +#if defined (PGRP_PIPE) +/* Pipes which each shell uses to communicate with the process group leader + until all of the processes in a pipeline have been started. Then the + process leader is allowed to continue. */ +int pgrp_pipe[2] = { -1, -1 }; +#endif + +/* The job which is current; i.e. the one that `%+' stands for. */ +int current_job = NO_JOB; + +/* The previous job; i.e. the one that `%-' stands for. */ +int previous_job = NO_JOB; + +/* Last child made by the shell. */ +pid_t last_made_pid = NO_PID; + +/* Pid of the last asynchronous child. */ +pid_t last_asynchronous_pid = NO_PID; + +/* The pipeline currently being built. */ +PROCESS *the_pipeline = (PROCESS *)NULL; + +/* If this is non-zero, do job control. */ +int job_control = 1; + +/* Call this when you start making children. */ +int already_making_children = 0; + +/* Functions local to this file. */ +static sighandler flush_child (); +static int waitchld(); +static PROCESS *find_pipeline (); +static char *current_working_directory (); +static char *job_working_directory (); +static pid_t last_pid (); +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 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; + +/* 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; + +#if !defined (_POSIX_VERSION) + +/* These are definitions to map POSIX 1003.1 functions onto existing BSD + library functions and system calls. */ +#define setpgid(pid, pgrp) setpgrp (pid, pgrp) +#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) + +pid_t +tcgetpgrp (fd) + int fd; +{ + pid_t pgrp; + + /* ioctl will handle setting errno correctly. */ + if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) + return (-1); + return (pgrp); +} + +/* 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 + job_working_directory, this does not call malloc (), nor do any + of the functions it calls. This is so that it can safely be called + from a signal handler. */ +static char * +current_working_directory () +{ + char *dir; + static char d[MAXPATHLEN]; + + dir = get_string_value ("PWD"); + + if (!dir && the_current_working_directory && no_symbolic_links) + dir = the_current_working_directory; + + if (!dir) + { + dir = getwd (d); + if (dir) + dir = d; + } + + if (!dir) + return ("<unknown>"); + else + return (dir); +} + +/* Return the working directory for the current process. */ +static char * +job_working_directory () +{ + char *dir; + + dir = get_string_value ("PWD"); + if (dir) + return (savestring (dir)); + + dir = get_working_directory ("job-working-directory"); + if (dir) + return (dir); + + return (savestring ("<unknown>")); +} + +void +making_children () +{ + if (already_making_children) + return; + + already_making_children = 1; + start_pipeline (); +} + +void +stop_making_children () +{ + already_making_children = 0; +} + +void +cleanup_the_pipeline () +{ + if (the_pipeline) + { + discard_pipeline (the_pipeline); + the_pipeline = (PROCESS *)NULL; + } +} + +/* Start building a pipeline. */ +void +start_pipeline () +{ + if (the_pipeline) + { + discard_pipeline (the_pipeline); + the_pipeline = (PROCESS *)NULL; + pipeline_pgrp = 0; +#if defined (PGRP_PIPE) + pipe_close (pgrp_pipe); +#endif + } + +#if defined (PGRP_PIPE) + if (job_control) + { + if (pipe (pgrp_pipe) == -1) + internal_error ("start_pipeline: pgrp pipe"); + } +#endif +} + +/* Stop building a pipeline. Install the process list in the job array. + This returns the index of the newly installed job. + DEFERRED is a command structure to be executed upon satisfactory + execution exit of this pipeline. */ +int +stop_pipeline (async, deferred) + int async; + COMMAND *deferred; +{ + register int i, j; + JOB *newjob = (JOB *)NULL; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + +#if defined (PGRP_PIPE) + /* The parent closes the process group synchronization pipe. */ + pipe_close (pgrp_pipe); +#endif + + cleanup_dead_jobs (); + + if (!job_slots) + { + jobs = + (JOB **)xmalloc ((job_slots = JOB_SLOTS) * sizeof (JOB *)); + + /* Now blank out these new entries. */ + for (i = 0; i < job_slots; i++) + jobs[i] = (JOB *)NULL; + } + + /* Scan from the last slot backward, looking for the next free one. */ + if (interactive) + { + for (i = job_slots; i; i--) + if (jobs[i - 1]) + break; + } + else + { + /* If we're not interactive, we don't need to monotonically increase + the job number (in fact, we don't care about the job number at all), + so we can simply scan for the first free slot. This helps to keep + 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]) + break; + } + + /* Do we need more room? */ + if (i == job_slots) + { + job_slots += JOB_SLOTS; + jobs = (JOB **)xrealloc (jobs, ((1 + job_slots) * sizeof (JOB *))); + + for (j = i; j < job_slots; j++) + jobs[j] = (JOB *)NULL; + } + + /* Add the current pipeline to the job list. */ + if (the_pipeline) + { + register PROCESS *p; + + newjob = (JOB *)xmalloc (sizeof (JOB)); + + 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); + p->next = newjob->pipe; + + the_pipeline = (PROCESS *)NULL; + newjob->pgrp = pipeline_pgrp; + pipeline_pgrp = 0; + + newjob->flags = 0; + + /* Flag to see if in another pgrp. */ + if (job_control) + newjob->flags |= J_JOBCONTROL; + + /* Set the state of this pipeline. */ + { + 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; + } + } + + newjob->wd = job_working_directory (); + newjob->deferred = deferred; + + jobs[i] = newjob; + } + + if (async) + { + if (newjob) + newjob->flags &= ~J_FOREGROUND; + reset_current (); + } + else + { + if (newjob) + { + newjob->flags |= J_FOREGROUND; + /* + * !!!!! NOTE !!!!! (chet@ins.cwru.edu) + * + * The currently-accepted job control wisdom says to set the + * terminal's process group n+1 times in an n-step pipeline: + * once in the parent and once in each child. This is where + * the parent gives it away. + * + */ + if (job_control && newjob->pgrp) + give_terminal_to (newjob->pgrp); + } + } + + stop_making_children (); + UNBLOCK_CHILD (oset); + return (current_job); +} + +/* Delete all DEAD jobs that the user had received notification about. */ +static void +cleanup_dead_jobs () +{ + register int i; + sigset_t set, oset; + + if (!job_slots || freeze_jobs_list) + return; + + BLOCK_CHILD (set, oset); + + for (i = 0; i < job_slots; i++) + if (jobs[i] && JOBSTATE (i) == JDEAD && (jobs[i]->flags & J_NOTIFIED)) + delete_job (i); + + UNBLOCK_CHILD (oset); +} + +/* Delete the job at INDEX from the job list. Must be called + with SIGCHLD blocked. */ +void +delete_job (job_index) + int job_index; +{ + register JOB *temp; + + if (freeze_jobs_list) + return; + + temp = jobs[job_index]; + if (job_index == current_job || job_index == previous_job) + reset_current (); + + jobs[job_index] = (JOB *)NULL; + + free (temp->wd); + discard_pipeline (temp->pipe); + + if (temp->deferred) + dispose_command (temp->deferred); + + free (temp); +} + +/* Get rid of the data structure associated with a process chain. */ +static void +discard_pipeline (chain) + register PROCESS *chain; +{ + register PROCESS *this, *next; + + this = chain; + do + { + next = this->next; + if (this->command) + free (this->command); + free (this); + this = next; + } + while (this != chain); +} + +/* Add this process to the chain being built in the_pipeline. + NAME is the command string that will be exec'ed later. + PID is the process id of the child. */ +static void +add_process (name, pid) + char *name; + pid_t pid; +{ + PROCESS *t = (PROCESS *)xmalloc (sizeof (PROCESS)); + + t->next = the_pipeline; + t->pid = pid; + WSTATUS (t->status) = 0; + t->running = 1; + t->command = name; + the_pipeline = t; + + if (!(t->next)) + t->next = t; + else + { + register PROCESS *p = t->next; + + while (p->next != t->next) + p = p->next; + p->next = t; + } +} + +#if 0 +/* Take the last job and make it the first job. Must be called with + SIGCHLD blocked. */ +rotate_the_pipeline () +{ + PROCESS *p; + + if (the_pipeline->next == the_pipeline) + return; + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + the_pipeline = p; +} + +/* Reverse the order of the processes in the_pipeline. Must be called with + SIGCHLD blocked. */ +reverse_the_pipeline () +{ + PROCESS *p, *n; + + if (the_pipeline->next == the_pipeline) + return; + + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + p->next = (PROCESS *)NULL; + + n = REVERSE_LIST (the_pipeline, PROCESS *); + + the_pipeline = n; + for (p = the_pipeline; p->next; p = p->next) + ; + p->next = the_pipeline; +} +#endif + +/* Map FUNC over the list of jobs. If FUNC returns non-zero, + then it is time to stop mapping, and that is the return value + for map_over_jobs. FUNC is called with a JOB, arg1, arg2, + and INDEX. */ +static int +map_over_jobs (func, arg1, arg2) + Function *func; + int arg1, arg2; +{ + register int i; + int result; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + result = 0; + + for (i = 0; i < job_slots; i++) + { + if (jobs[i]) + { + result = (*func)(jobs[i], arg1, arg2, i); + if (result) + break; + } + } + + UNBLOCK_CHILD (oset); + return (result); +} + +/* Cause all the jobs in the current pipeline to exit. */ +void +terminate_current_pipeline () +{ + if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) + { + killpg (pipeline_pgrp, SIGTERM); + killpg (pipeline_pgrp, SIGCONT); + } +} + +/* Cause all stopped jobs to exit. */ +void +terminate_stopped_jobs () +{ + register int i; + + for (i = 0; i < job_slots; i++) + { + if (jobs[i] && (JOBSTATE (i) == JSTOPPED)) + { + killpg (jobs[i]->pgrp, SIGTERM); + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +/* Cause all jobs, running or stopped, to receive a hangup signal. */ +void +hangup_all_jobs () +{ + register int i; + + for (i = 0; i < job_slots; i++) + { + if (jobs[i]) + { + killpg (jobs[i]->pgrp, SIGHUP); + if (JOBSTATE (i) == JSTOPPED) + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +void +kill_current_pipeline () +{ + stop_making_children (); + start_pipeline (); +} + +/* Return the pipeline that PID belongs to. Note that the pipeline + doesn't have to belong to a job. Must be called with SIGCHLD blocked. */ +static PROCESS * +find_pipeline (pid) + pid_t pid; +{ + int job; + + /* See if this process is in the pipeline that we are building. */ + if (the_pipeline) + { + register PROCESS *p = the_pipeline; + + do + { + /* Return it if we found it. */ + if (p->pid == pid) + return (p); + + p = p->next; + } + while (p != the_pipeline); + } + + job = find_job (pid); + + if (job == NO_JOB) + return ((PROCESS *)NULL); + else + return (jobs[job]->pipe); +} + +/* Return the job index that PID belongs to, or NO_JOB if it doesn't + belong to any job. Must be called with SIGCHLD blocked. */ +static int +find_job (pid) + pid_t pid; +{ + register int i; + register PROCESS *p; + + for (i = 0; i < job_slots; i++) + { + if (jobs[i]) + { + p = jobs[i]->pipe; + + do + { + if (p->pid == pid) + return (i); + + p = p->next; + } + while (p != jobs[i]->pipe); + } + } + + return (NO_JOB); +} + +/* Print descriptive information about the job with leader pid PID. */ +void +describe_pid (pid) + pid_t pid; +{ + int job; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + job = find_job (pid); + + if (job != NO_JOB) + printf ("[%d] %d\n", job + 1, pid); + else + programming_error ("describe_pid: No such pid (%d)!\n", pid); + + UNBLOCK_CHILD (oset); +} + +/* This is the way to print out information on a job if you + know the index. FORMAT is: + + JLIST_NORMAL) [1]+ Running emacs + JLIST_LONG ) [1]+ 2378 Running emacs + -1 ) [1]+ 2378 emacs + + JLIST_NORMAL) [1]+ Stopped ls | more + JLIST_LONG ) [1]+ 2369 Stopped ls + 2367 | more + JLIST_PID_ONLY) + Just list the pid of the process group leader (really + the process group). + JLIST_CHANGED_ONLY) + Use format JLIST_NORMAL, but list only jobs about which + the user has not been notified. */ +static void +pretty_print_job (job_index, format, stream) + 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); + + /* 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) ? '-' : ' '); + + first = last = p = jobs[job_index]->pipe; + 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); + + fprintf (stream, " "); + + if (format > -1) + { + PROCESS *show = format ? p : last; + char *temp = "Done"; + + if (JOBSTATE (job_index) == JSTOPPED && !format) + temp = "Stopped"; + + if (JOBSTATE (job_index) == JRUNNING) + temp = "Running"; + else + { + if (WIFSTOPPED (show->status)) + temp = strsignal (WSTOPSIG (show->status)); + else if (WIFSIGNALED (show->status)) + temp = strsignal (WTERMSIG (show->status)); + else if (WIFEXITED (show->status)) + { + int exit_status; + + temp = retcode_name_buffer; + exit_status = WEXITSTATUS (show->status); + + if (!exit_status) + strcpy (temp, "Done"); + else if (posixly_correct) + sprintf (temp, "Done(%d)", exit_status); + else + sprintf (temp, "Exit %d", exit_status); + } + else + temp = "Unknown status"; + } + + if (p != first) + { + if (format) + { + if (show->running == first->running && + WSTATUS (show->status) == WSTATUS (first->status)) + temp = ""; + } + else + temp = (char *)NULL; + } + + 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 ("| ") */ + + fprintf (stream, "%*s", name_padding, ""); + + if ((WIFSTOPPED (show->status) == 0) && (WIFCORED (show->status))) + fprintf (stream, "(core dumped) "); + } + } + + if (p != first && format) + fprintf (stream, "| "); + + if (p->command) + fprintf (stream, "%s", p->command); + + if (p == last) + { + char *wd = current_working_directory (); + + if (JOBSTATE (job_index) == JRUNNING && + !(jobs[job_index]->flags & J_FOREGROUND)) + fprintf (stream, " &"); + + if (strcmp (wd, jobs[job_index]->wd) != 0) + fprintf (stream, + " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); + } + + if (format || (p == last)) + fprintf (stream, "\r\n"); + + if (p == last) + break; + p = p->next; + } + + fflush (stream); + UNBLOCK_CHILD (oset); +} + +int +list_one_job (job, format, ignore, job_index) + JOB *job; + int format, ignore, job_index; +{ + pretty_print_job (job_index, format, stdout); + return (0); +} + +/* 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) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (list_one_job, format, (int)IGNORE_ARG); +} + +/* Fork, handling errors. Returns the pid of the newly made child, or 0. + COMMAND is just for remembering the name of the command; we don't do + anything else with it. ASYNC_P says what to do with the tty. If + non-zero, then don't give it away. */ +pid_t +make_child (command, async_p) + char *command; + int async_p; +{ + sigset_t set, oset; + pid_t pid; + + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGINT); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + making_children (); + +#if defined (BUFFERED_INPUT) + /* If default_buffered_input is active, we are reading a script. If + the command is asynchronous, we have already duplicated /dev/null + as fd 0, but have not changed the buffered stream corresponding to + the old fd 0. We don't want to sync the stream in this case. */ + if (default_buffered_input != -1 && + (!async_p || default_buffered_input > 0)) + sync_buffered_stream (default_buffered_input); +#endif /* BUFFERED_INPUT */ + + /* Create the child, handle severe errors. */ + if ((pid = fork ()) < 0) + { + internal_error ("fork: %s", strerror (errno)); + + /* Kill all of the processes in the current pipeline. */ + terminate_current_pipeline (); + + /* Discard the current pipeline, if any. */ + if (the_pipeline) + kill_current_pipeline (); + + throw_to_top_level (); /* Reset signals, etc. */ + } + + if (pid == 0) + { + /* In the child. Give this child the right process group, set the + signals to the default state for a new process. */ + pid_t 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, + and it's wrong to close the file in that case. */ + if (default_buffered_input > 0) + { + close_buffered_fd (default_buffered_input); + default_buffered_input = bash_input.location.buffered_fd = -1; + } +#endif /* BUFFERED_INPUT */ + + /* Restore top-level signal mask. */ + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); + + if (job_control) + { + /* All processes in this pipeline belong in the same + process group. */ + + if (!pipeline_pgrp) /* Then 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); + } + else + { + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + } + + /* Set the process group before trying to mess with the terminal's + process group. This is mandated by POSIX. */ + /* This is in accordance with the Posix 1003.1 standard, + section B.7.2.4, which says that trying to set the terminal + process group with tcsetpgrp() to an unused pgrp value (like + this would have for the first child) is an error. Section + B.4.3.3, p. 237 also covers this, in the context of job control + shells. */ + if (setpgid (mine, pipeline_pgrp) < 0) + internal_error ("child setpgid (%d to %d) error %d: %s\n", + mine, pipeline_pgrp, errno, strerror (errno)); +#if defined (PGRP_PIPE) + if (pipeline_pgrp == mine) + { +#endif + if (!async_p) + give_terminal_to (pipeline_pgrp); + +#if defined (PGRP_PIPE) + pipe_read (pgrp_pipe); + } +#endif + } + else /* Without job control... */ + { + if (!pipeline_pgrp) + pipeline_pgrp = shell_pgrp; + + /* If these signals are set to SIG_DFL, we encounter the curious + situation of an interactive ^Z to a running process *working* + and stopping the process, but being unable to do anything with + that process to change its state. On the other hand, if they + are set to SIG_IGN, jobs started from scripts do not stop when + the shell running the script gets a SIGTSTP and stops. */ + + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + } + +#if defined (PGRP_PIPE) + /* Release the process group pipe, since our call to setpgid () + is done. The last call to pipe_close is done in stop_pipeline. */ + pipe_close (pgrp_pipe); +#endif /* PGRP_PIPE */ + + if (async_p) + last_asynchronous_pid = getpid (); + } + else + { + /* In the parent. Remember the pid of the child just created + as the proper pgrp if this is the first child. */ + + if (job_control) + { + if (!pipeline_pgrp) + { + pipeline_pgrp = pid; + /* Don't twiddle terminal pgrps in the parent! This is the bug, + not the good thing of twiddling them in the child! */ + /* give_terminal_to (pipeline_pgrp); */ + } + /* This is done on the recommendation of the Rationale section of + the POSIX 1003.1 standard, where it discusses job control and + shells. It is done to avoid possible race conditions. (Ref. + 1003.1 Rationale, section B.4.3.3, page 236). */ + setpgid (pid, pipeline_pgrp); + } + else + { + if (!pipeline_pgrp) + pipeline_pgrp = shell_pgrp; + } + + /* Place all processes into the jobs array regardless of the + state of job_control. */ + add_process (command, pid); + + if (async_p) + last_asynchronous_pid = pid; + + last_made_pid = pid; + + /* Unblock SIGINT and SIGCHLD. */ + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return (pid); +} + +/* 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. */ + +#if defined (NEW_TTY_DRIVER) +static struct sgttyb shell_tty_info; +static struct tchars shell_tchars; +static struct ltchars shell_ltchars; +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) +static struct termio shell_tty_info; +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) +static struct termios shell_tty_info; +#endif /* TERMIOS_TTY_DRIVER */ + +#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) +/* Since the BSD tty driver does not allow us to change the tty modes + while simultaneously waiting for output to drain and preserving + typeahead, we have to drain the output ourselves before calling + ioctl. We cheat by finding the length of the output queue, and + using select to wait for an appropriate length of time. This is + a hack, and should be labeled as such (it's a hastily-adapted + mutation of a `usleep' implementation). It's only reason for + existing is the flaw in the BSD tty driver. */ + +static int ttspeeds[] = +{ + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400 +}; + +static void +draino (fd, ospeed) + int fd, ospeed; +{ + register int delay = ttspeeds[ospeed]; + int n; + + if (!delay) + return; + + while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) + { + if (n > (delay / 100)) + { + struct timeval tv; + + n *= 10; /* 2 bits more for conservativeness. */ + tv.tv_sec = n / delay; + tv.tv_usec = ((n % delay) * 1000000) / delay; + select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); + } + else + break; + } +} +#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ + +/* Return the fd from which we are actually getting input. */ +#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) + +/* Fill the contents of shell_tty_info with the current tty info. */ +get_tty_state () +{ + int tty = input_tty (); + + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) + ioctl (tty, TIOCGETP, &shell_tty_info); + ioctl (tty, TIOCGETC, &shell_tchars); + ioctl (tty, TIOCGLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCGETA, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcgetattr (tty, &shell_tty_info) < 0) + { +#if 0 + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + internal_error ("[%d: %d] tcgetattr: %s", + getpid (), shell_level, strerror (errno)); +#endif + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + } + return 0; +} + +/* Make the current tty use the state in shell_tty_info. */ +set_tty_state () +{ + int tty = input_tty (); + + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) +# if defined (DRAIN_OUTPUT) + draino (tty, shell_tty_info.sg_ospeed); +# endif /* DRAIN_OUTPUT */ + ioctl (tty, TIOCSETN, &shell_tty_info); + ioctl (tty, TIOCSETC, &shell_tchars); + ioctl (tty, TIOCSLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCSETAW, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + { + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + internal_error ("[%d: %d] tcsetattr: %s", + getpid (), shell_level, strerror (errno)); + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + } + return 0; +} + +/* Given an index into the jobs array JOB, return the pid of the last + process in that job's pipeline. This is the one whose exit status + counts. */ +static pid_t +last_pid (job) + int job; +{ + register PROCESS *p; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + p = jobs[job]->pipe; + while (p->next != jobs[job]->pipe) + p = p->next; + + UNBLOCK_CHILD (oset); + return (p->pid); +} + +/* Wait for a particular child of the shell to finish executing. + This low-level function prints an error message if PID is not + a child of this shell. It returns -1 if it fails, or 0 if not. */ +int +wait_for_single_pid (pid) + pid_t pid; +{ + register PROCESS *child; + + { + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + child = find_pipeline (pid); + UNBLOCK_CHILD (oset); + } + + if (!child) + { + report_error ("wait: pid %d is not a child of this shell", pid); + return (127); + } + + return (wait_for (pid)); +} + +/* Wait for all of the backgrounds of this shell to finish. */ +void +wait_for_background_pids () +{ + while (1) + { + register int i, count = 0; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + for (i = 0; i < job_slots; i++) + if (jobs[i] && (JOBSTATE (i) == JRUNNING) && + (jobs[i]->flags & J_FOREGROUND) == 0) + { + count++; + break; + } + + if (!count) + { + UNBLOCK_CHILD (oset); + break; + } + + for (i = 0; i < job_slots; i++) + if (jobs[i] && (JOBSTATE (i) == JRUNNING) && + (jobs[i]->flags & J_FOREGROUND) == 0) + { + pid_t pid = last_pid (i); + UNBLOCK_CHILD (oset); + QUIT; + wait_for_single_pid (pid); + break; + } + } +} + +/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ +#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids +static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; + +static void +restore_sigint_handler () +{ + if (old_sigint_handler != INVALID_SIGNAL_HANDLER) + { + set_signal_handler (SIGINT, old_sigint_handler); + old_sigint_handler = INVALID_SIGNAL_HANDLER; + } +} + +static int wait_sigint_received = 0; + +/* Handle SIGINT while we are waiting for children in a script to exit. + The `wait' builtin should be interruptible, but all others should be + effectively ignored (i.e. not cause the shell to exit). */ +static sighandler +wait_sigint_handler (sig) + int sig; +{ + if (interrupt_immediately || + (this_shell_builtin && this_shell_builtin == wait_builtin)) + { + last_command_exit_value = EXECUTION_FAILURE; + restore_sigint_handler (); + interrupt_state++; + QUIT; + } + + wait_sigint_received = 1; /* XXX - should this be interrupt_state? */ + /* Otherwise effectively ignore the SIGINT and allow the running job to + be killed. */ +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* !VOID_SIGHANDLER */ +} + +static int +process_exit_status (status) + WAIT status; +{ + if (WIFSIGNALED (status)) + return (128 + WTERMSIG (status)); + else if (!WIFSTOPPED (status)) + return (WEXITSTATUS (status)); + else + return (EXECUTION_SUCCESS); +} + +/* Wait for pid (one of our children) to terminate, then + return the termination state. */ +int +wait_for (pid) + pid_t pid; +{ + int job, termination_state; + register PROCESS *child; + sigset_t set, oset; + + /* In the case that this code is interrupted, and we longjmp () out of it, + we are relying on the code in throw_to_top_level () to restore the + top-level signal mask. */ + BLOCK_CHILD (set, oset); + + /* Ignore interrupts while waiting for a job run without job control + to finish. We don't want the shell to exit if an interrupt is + received, only if one of the jobs run is killed via SIGINT. If + job control is not set, the job will be run in the same pgrp as + the shell, and the shell will see any signals the job gets. */ + + /* This is possibly a race condition -- should it go in stop_pipeline? */ + wait_sigint_received = 0; + if (!job_control) + 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) + QUIT; + + child = find_pipeline (pid); + + if (!child) + { + give_terminal_to (shell_pgrp); + UNBLOCK_CHILD (oset); + programming_error ("wait_for: No record of pid %d", pid); + } + + /* 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. */ + + job = find_job (pid); + + if (job != NO_JOB) + { + register int job_state = 0, any_stopped = 0; + register PROCESS *p = jobs[job]->pipe; + + do + { + job_state |= p->running; + if (!p->running) + 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 (child->running || ((job != NO_JOB) && (JOBSTATE (job) == JRUNNING))) + { +#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); +# 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); +# endif +#endif /* !WAITPID_BROKEN */ + goto wait_loop; + } + + /* 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); + } + else + termination_state = process_exit_status (child->status); + + if (job == NO_JOB || (jobs[job]->flags & J_JOBCONTROL)) + give_terminal_to (shell_pgrp); + + /* If the command did not exit cleanly, or the job is just + being stopped, then reset the tty state back to what it + was before this command. Reset the tty state and notify + the user of the job termination only if the shell is + interactive. Clean up any dead jobs in either case. */ + if (job != NO_JOB) + { + if (interactive_shell && !subshell_environment) + { + if (WIFSIGNALED (child->status) || WIFSTOPPED (child->status)) + set_tty_state (); + else + get_tty_state (); + + /* If job control is enabled, the job was started with job + control, the job was the foreground job, and it was killed + by SIGINT, then print a newline to compensate for the kernel + printing the ^C without a trailing newline. */ + if (job_control && (jobs[job]->flags & J_JOBCONTROL) && + (jobs[job]->flags & J_FOREGROUND) && + 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 (loop_level) + interrupt_state++; + else + { + putchar ('\n'); + fflush (stdout); + } + } + } + + notify_and_cleanup (); + } + else + { + /* If this job is dead, and the shell is not interactive, make + sure we turn on the notify bit so we don't get an unwanted + message about the job's termination, and so delete_job really + clears the slot in the jobs table. */ + if (JOBSTATE(job) == JDEAD) + jobs[job]->flags |= J_NOTIFIED; + cleanup_dead_jobs (); + } + } + + UNBLOCK_CHILD (oset); + + /* Restore the original SIGINT signal handler before we return. */ + restore_sigint_handler (); + + return (termination_state); +} + +/* Wait for the last process in the pipeline for JOB. */ +int +wait_for_job (job) + int job; +{ + pid_t pid = last_pid (job); + return (wait_for (pid)); +} + +/* Print info about dead jobs, and then delete them from the list + of known jobs. This does not actually delete jobs when the + shell is not interactive, because the dead jobs are not marked + as notified. */ +void +notify_and_cleanup () +{ + if (freeze_jobs_list) + return; + + if (interactive) + notify_of_job_status (); + + cleanup_dead_jobs (); +} + +/* Make dead jobs disappear from the jobs array without notification. + This is used when the shell is not interactive. */ +void +reap_dead_jobs () +{ + mark_dead_jobs_as_notified (); + cleanup_dead_jobs (); +} + +/* Return the next closest (chronologically) job to JOB which is in + STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if + there is no next recent job. */ +static int +most_recent_job_in_state (job, state) + int job; + JOB_STATE state; +{ + register int i, result; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + result = NO_JOB; + + for (i = job - 1; i >= 0; i--) + { + if (jobs[i]) + { + if (JOBSTATE (i) == state) + { + result = i; + break; + } + } + } + UNBLOCK_CHILD (oset); + return (result); +} + +/* Return the newest *stopped* job older than JOB, or NO_JOB if not + found. */ +static int +last_stopped_job (job) + int job; +{ + return (most_recent_job_in_state (job, JSTOPPED)); +} + +/* Return the newest *running* job older than JOB, or NO_JOB if not + found. */ +static int +last_running_job (job) + int job; +{ + return (most_recent_job_in_state (job, JRUNNING)); +} + +/* Make JOB be the current job, and make previous be useful. Must be + called with SIGCHLD blocked. */ +static void +set_current_job (job) + int job; +{ + int candidate = NO_JOB; + + if (current_job != job) + { + previous_job = current_job; + current_job = job; + } + + /* First choice for previous_job is the old current_job. */ + if (previous_job != current_job && + previous_job != NO_JOB && + jobs[previous_job] && + JOBSTATE (previous_job) == JSTOPPED) + return; + + /* Second choice: Newest stopped job that is older than + the current job. */ + if (JOBSTATE (current_job) == JSTOPPED) + { + candidate = last_stopped_job (current_job); + + if (candidate != NO_JOB) + { + previous_job = candidate; + return; + } + } + + /* If we get here, there is either only one stopped job, in which case it is + the current job and the previous job should be set to the newest running + job, or there are only running jobs and the previous job should be set to + the newest running job older than the current job. We decide on which + alternative to use based on whether or not JOBSTATE(current_job) is + JSTOPPED. */ + + if (JOBSTATE (current_job) == JRUNNING) + candidate = last_running_job (current_job); + else + candidate = last_running_job (job_slots); + + if (candidate != NO_JOB) + { + previous_job = candidate; + return; + } + + /* There is only a single job, and it is both `+' and `-'. */ + previous_job = current_job; +} + +/* Make current_job be something useful, if it isn't already. */ + +/* Here's the deal: The newest non-running job should be `+', and the + next-newest non-running job should be `-'. If there is only a single + stopped job, the 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; + + if (current_job != NO_JOB && + job_slots && jobs[current_job] && + JOBSTATE (current_job) == JSTOPPED) + { + candidate = current_job; + } + else + { + /* First choice: the previous job! */ + if (previous_job != NO_JOB && jobs[previous_job] && + JOBSTATE (previous_job) == JSTOPPED) + candidate = previous_job; + + /* Second choice: the most recently stopped job. */ + if (candidate == NO_JOB) + candidate = last_stopped_job (job_slots); + + if (candidate == NO_JOB) + { + /* Third choice: the newest running job. */ + candidate = last_running_job (job_slots); + } + } + + /* If we found a job to use, then use it. Otherwise, there + are no jobs period. */ + if (candidate != NO_JOB) + set_current_job (candidate); + else + current_job = previous_job = NO_JOB; +} + +/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, + start the job in the background. JOB is a zero-based index into + JOBS. Returns -1 if it is unable to start a job, and the return + status of the job otherwise. */ +int +start_job (job, foreground) + int job, foreground; +{ + register PROCESS *p; + int already_running; + sigset_t set, oset; + char *wd; +#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) + { + report_error ("%s: job has terminated", this_command_name); + UNBLOCK_CHILD (oset); + return (-1); + } + + if (!foreground && already_running) + { + report_error ("%s: bg background job?", this_command_name); + UNBLOCK_CHILD (oset); + return (-1); + } + + wd = current_working_directory (); + + /* You don't know about the state of this job. Do you? */ + jobs[job]->flags &= ~J_NOTIFIED; + + if (foreground) + { + set_current_job (job); + jobs[job]->flags |= J_FOREGROUND; + } + + /* Tell the outside world what we're doing. */ + p = jobs[job]->pipe; + + if (!foreground) + fprintf (stderr, "[%d]%c ", job + 1, + (job == current_job) ? '+': ((job == previous_job) ? '-' : ' ')); + + do + { + fprintf (stderr, "%s%s", + p->command ? p->command : "", + p->next != jobs[job]->pipe? " | " : ""); + p = p->next; + } + while (p != jobs[job]->pipe); + + if (!foreground) + fprintf (stderr, " &"); + + if (strcmp (wd, jobs[job]->wd) != 0) + fprintf (stderr, " (wd: %s)", polite_directory_format (jobs[job]->wd)); + + fprintf (stderr, "\n"); + + /* Run the job. */ + if (!already_running) + { + /* Each member of the pipeline is now running. */ + p = jobs[job]->pipe; + + do + { + if (WIFSTOPPED (p->status)) + p->running = 1; + p = p->next; + } + while (p != jobs[job]->pipe); + + /* This means that the job is running. */ + JOBSTATE (job) = JRUNNING; + } + + /* Save the tty settings before we start the job in the foreground. */ + if (foreground) + { + get_tty_state (); + save_stty = shell_tty_info; + } + + /* Give the terminal to this job. */ + if (foreground) + { + if (jobs[job]->flags & J_JOBCONTROL) + 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) + { + jobs[job]->flags |= J_NOTIFIED; + killpg (jobs[job]->pgrp, SIGCONT); + } + + UNBLOCK_CHILD (oset); + + if (foreground) + { + pid_t pid = last_pid (job); + int s = wait_for (pid); + + shell_tty_info = save_stty; + set_tty_state (); + return (s); + } + else + { + BLOCK_CHILD (set, oset); + reset_current (); + UNBLOCK_CHILD (oset); + return (0); + } +} + +/* Give PID SIGNAL. This determines what job the pid belongs to (if any). + If PID does belong to a job, and the job is stopped, then CONTinue the + job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, + then kill the process group associated with PID. */ +int +kill_pid (pid, sig, group) + pid_t pid; + int sig, group; +{ + register PROCESS *p; + int job, result = EXECUTION_SUCCESS; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + p = find_pipeline (pid); + job = find_job (pid); + + if (group) + { + if (job != NO_JOB) + { + jobs[job]->flags &= ~J_NOTIFIED; + + /* Kill process in backquotes or one started without job control? */ + if (jobs[job]->pgrp == shell_pgrp) + { + p = jobs[job]->pipe; + + do + { + kill (p->pid, sig); + if (p->running == 0 && (sig == SIGTERM || sig == SIGHUP)) + kill (p->pid, SIGCONT); + p = p->next; + } + while (p != jobs[job]->pipe); + } + else + { + result = killpg (jobs[job]->pgrp, sig); + if (p && (JOBSTATE (job) == JSTOPPED) && + (sig == SIGTERM || sig == SIGHUP)) + killpg (jobs[job]->pgrp, SIGCONT); + } + } + else + result = killpg (pid, sig); + } + else + result = kill (pid, sig); + + UNBLOCK_CHILD (oset); + 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. */ +static sighandler +flush_child (sig) + int sig; +{ + REINSTALL_SIGCHLD_HANDLER; + sigchld++; + if (waiting_for_job == 0) + waitchld (sig); + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* VOID_SIGHANDLER */ +} + +static int +waitchld (s) + int s; +{ + WAIT status; + PROCESS *child; + pid_t pid; + int call_set_current = 0, last_stopped_job = NO_JOB; + int children_exited = 0, flag; + + do + { + flag = WUNTRACED; + if (sigchld || s) + flag |= WNOHANG; + pid = WAITPID (-1, &status, flag); + if (sigchld && (flag & WNOHANG)) + sigchld--; + + if (pid > 0) + { + /* 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. */ + if (child) + { + int job = find_job (pid); + + while (child->pid != pid) + child = child->next; + + /* Remember status, and fact that process is not running. */ + child->status = status; + child->running = 0; + + if (job != NO_JOB) + { + 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); + } + } + } + } + } + } + /* 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); + + /* If a job was running and became stopped, then set the current + job. Otherwise, don't change a thing. */ + if (call_set_current) + if (last_stopped_job != NO_JOB) + set_current_job (last_stopped_job); + else + reset_current (); + + /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ + if (job_control && signal_is_trapped (SIGCHLD) && + trap_list[SIGCHLD] != (char *)IGNORE_SIG) + { + char *trap_command; + + /* Turn off the trap list during the call to parse_and_execute () + to avoid potentially infinite recursive calls. Preserve the + values of last_command_exit_value, last_made_pid, and the_pipeline + around the execution of the trap commands. */ + trap_command = savestring (trap_list[SIGCHLD]); + + begin_unwind_frame ("SIGCHLD trap"); + unwind_protect_int (last_command_exit_value); + unwind_protect_int (last_made_pid); + unwind_protect_int (interrupt_immediately); + unwind_protect_int (freeze_jobs_list); + unwind_protect_pointer (the_pipeline); + + /* We have to add the commands this way because they will be run + in reverse order of adding. We don't want maybe_set_sigchld_trap () + to reference freed memory. */ + add_unwind_protect ((Function *)xfree, trap_command); + add_unwind_protect ((Function *)maybe_set_sigchld_trap, trap_command); + + the_pipeline = (PROCESS *)NULL; + restore_default_signal (SIGCHLD); + freeze_jobs_list = 1; + while (children_exited--) + { + interrupt_immediately = 1; + parse_and_execute (savestring (trap_command), "trap", -1); + } + + run_unwind_frame ("SIGCHLD trap"); + } + + /* We have successfully recorded the useful information about this process + that has just changed state. If we notify asynchronously, and the job + that this process belongs to is no longer running, then notify the user + of that fact now. */ + if (asynchronous_notification && interactive) + notify_of_job_status (); + +} + +/* Function to call when you want to notify people of changes + in job status. This prints out all jobs which are pending + notification to stderr, and marks those printed as already + notified, thus making them candidates for cleanup. */ +static void +notify_of_job_status () +{ + register int job, termsig; + char *dir; + sigset_t set, oset; + + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGTTOU); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + dir = (char *)NULL; + + for (job = 0; job < job_slots; job++) + { + if (jobs[job] && (jobs[job]->flags & J_NOTIFIED) == 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) + { + if (JOBSTATE (job) == JDEAD) + jobs[job]->flags |= J_NOTIFIED; + continue; + } + + 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 (termsig && WIFSIGNALED (s) && termsig != SIGINT) + { + fprintf (stderr, "%s", strsignal (termsig)); + + if (WIFCORED (s)) + fprintf (stderr, " (core dumped)"); + + fprintf (stderr, "\n"); + } + } + else + { + if (!dir) + dir = current_working_directory (); + pretty_print_job (job, 0, stderr); + if (dir && strcmp (dir, jobs[job]->wd) != 0) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + } + + jobs[job]->flags |= J_NOTIFIED; + break; + + case JSTOPPED: + fprintf (stderr, "\n"); + if (!dir) + dir = current_working_directory (); + pretty_print_job (job, 0, stderr); + if (dir && (strcmp (dir, jobs[job]->wd) != 0)) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + jobs[job]->flags |= J_NOTIFIED; + break; + + case JRUNNING: + case JMIXED: + break; + + default: + programming_error ("notify_of_job_status"); + } + } + } + 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. */ +initialize_jobs () +{ + shell_pgrp = getpgid (0); + + if (shell_pgrp == -1) + { + internal_error ("initialize_jobs: getpgrp failed: %s", strerror (errno)); + exit (1); + } + + /* We can only have job control if we are interactive? + I guess that makes sense. */ + + if (!interactive) + { + 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; + } + + if (nds && shell_tty != nds && (dup2 (shell_tty, nds) != -1)) + { + if (shell_tty != fileno (stderr)) + close (shell_tty); + shell_tty = nds; + } + } + +#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. */ + 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); + kill (0, SIGTTIN); + set_signal_handler (SIGTTIN, old_ttin); + continue; + } + break; + } + + if (set_new_line_discipline (shell_tty) < 0) + { + internal_error ("initialize_jobs: line discipline: %s", + strerror (errno)); + job_control = 0; + } + else + { + original_pgrp = shell_pgrp; + shell_pgrp = getpid (); + + if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) + { + internal_error ("initialize_jobs: setpgid: %s", strerror (errno)); + shell_pgrp = original_pgrp; + } + + job_control = 1; + if (give_terminal_to (shell_pgrp) < 0) /* XXX */ + /* job_control = 0 */; /* XXX */ + } + if (job_control == 0) + internal_error ("no job control in this shell"); /* XXX */ + } + + if (shell_tty != fileno (stderr)) + SET_CLOSE_ON_EXEC (shell_tty); + + set_signal_handler (SIGCHLD, flush_child); + + change_flag ('m', job_control ? '-' : '+'); + + if (interactive) + get_tty_state (); + return job_control; +} + +/* Set the line discipline to the best this system has to offer. + Return -1 if this is not possible. */ +static int +set_new_line_discipline (tty) + int tty; +{ +#if defined (NEW_TTY_DRIVER) + int ldisc; + + if (ioctl (tty, TIOCGETD, &ldisc) < 0) + return (-1); + + if (ldisc != NTTYDISC) + { + ldisc = NTTYDISC; + + if (ioctl (tty, TIOCSETD, &ldisc) < 0) + return (-1); + } + return (0); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) +# if defined (NTTYDISC) + if (ioctl (tty, TCGETA, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) + return (-1); + } +# endif /* NTTYDISC */ + return (0); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (TERMIOS_LDISC) + if (tcgetattr (tty, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + return (-1); + } +# endif /* TERMIOS_LDISC */ + return (0); +#endif /* TERMIOS_TTY_DRIVER */ + +#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) + return (-1); +#endif +} + +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; + +static sighandler +sigwinch_sighandler (sig) + int 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) + { +#if defined (aixpc) + shell_tty_info.c_winsize = win; /* structure copying */ +#endif + set_lines_and_columns (win.ws_row, win.ws_col); + } +} +#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ + +/* Setup this shell to handle C-C, etc. */ +void +initialize_job_signals () +{ + if (interactive) + { + set_signal_handler (SIGINT, sigint_sighandler); + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); +#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ + } + else if (job_control) + { + old_tstp = set_signal_handler (SIGTSTP, stop_signal_handler); + old_ttou = set_signal_handler (SIGTTOU, stop_signal_handler); + old_ttin = set_signal_handler (SIGTTIN, stop_signal_handler); + } + /* Leave these things alone for non-interactive shells without job + control. */ +} + +/* Here we handle CONT signals. */ +static sighandler +cont_signal_handler (sig) + int sig; +{ + initialize_job_signals (); + set_signal_handler (SIGCONT, old_cont); + kill (getpid (), SIGCONT); + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* VOID_SIGHANDLER */ +} + +/* Here we handle stop signals while we are running not as a login shell. */ +static sighandler +stop_signal_handler (sig) + int sig; +{ + set_signal_handler (SIGTSTP, old_tstp); + set_signal_handler (SIGTTOU, old_ttou); + set_signal_handler (SIGTTIN, old_ttin); + + old_cont = set_signal_handler (SIGCONT, cont_signal_handler); + + give_terminal_to (shell_pgrp); + + kill (getpid (), sig); + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* VOID_SIGHANDLER */ +} + +/* Give the terminal to PGRP. */ +give_terminal_to (pgrp) + pid_t pgrp; +{ + sigset_t set, oset; + int r = 0; + + if (job_control) + { + sigemptyset (&set); + sigaddset (&set, SIGTTOU); + sigaddset (&set, SIGTTIN); + sigaddset (&set, SIGTSTP); + sigaddset (&set, SIGCHLD); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + if (tcsetpgrp (shell_tty, pgrp) < 0) + { + /* Maybe we should print an error message? */ +/* internal_error ("tcsetpgrp(%d) failed: pid %d to pgrp %d: %s", + shell_tty, getpid(), pgrp, strerror (errno)); */ + r = -1; + } + else + terminal_pgrp = pgrp; + + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return r; +} + +/* Clear out any jobs in the job array. This is intended to be used by + children of the shell, who should not have any job structures as baggage + when they start executing (forking subshells for parenthesized execution + and functions with pipes are the two that spring to mind). */ +static void +delete_all_jobs () +{ + register int i; + sigset_t set, oset; + + if (job_slots) + { + BLOCK_CHILD (set, oset); + + if (job_slots) + { + 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; + } + + UNBLOCK_CHILD (oset); + } +} + +/* Mark all dead jobs as notified, so delete_job () cleans them out + of the job table properly. */ +static void +mark_dead_jobs_as_notified () +{ + register int i; + sigset_t set, oset; + + if (job_slots) + { + BLOCK_CHILD (set, oset); + + for (i = 0; i < job_slots; i++) + if (jobs[i] && JOBSTATE (i) == JDEAD) + jobs[i]->flags |= J_NOTIFIED; + + UNBLOCK_CHILD (oset); + } +} + +/* Allow or disallow job control to take place. Returns the old value + of job_control. */ +int +set_job_control (arg) + int arg; +{ + int old; + + old = job_control; + job_control = arg; + return (old); +} + +/* Turn off all traces of job control. This is run by children of the shell + which are going to do shellsy things, like wait (), etc. */ +void +without_job_control () +{ + stop_making_children (); + start_pipeline (); + delete_all_jobs (); + set_job_control (0); +} + +/* If this shell is interactive, terminate all stopped jobs and + restore the original terminal process group. This is done + before the `exec' builtin calls shell_execve. */ +void +end_job_control () +{ + if (interactive_shell) /* XXX - should it be interactive? */ + { + terminate_stopped_jobs (); + + if (original_pgrp >= 0) + give_terminal_to (original_pgrp); + } + + if (original_pgrp >= 0) + setpgid (0, original_pgrp); +} + +/* Restart job control by closing shell tty and reinitializing. This is + called after an exec fails in an interactive shell and we do not exit. */ +void +restart_job_control () +{ + if (shell_tty != -1) + close (shell_tty); + initialize_jobs (); +} + +/* Set the handler to run when the shell receives a SIGCHLD signal. */ +void +set_sigchld_handler () +{ + set_signal_handler (SIGCHLD, flush_child); +} + +#if defined (PGRP_PIPE) +/* Read from the read end of a pipe. This is how the process group leader + blocks until all of the processes in a pipeline have been made. */ +static void +pipe_read (pp) + int *pp; +{ + char ch; + + if (pp[1] >= 0) + { + close (pp[1]); + pp[1] = -1; + } + + if (pp[0] >= 0) + { + while (read (pp[0], &ch, 1) == -1 && errno == EINTR) + continue; + } +} + +/* Close the read and write ends of PP, an array of file descriptors. */ +static void +pipe_close (pp) + int *pp; +{ + if (pp[0] >= 0) + close (pp[0]); + + if (pp[1] >= 0) + close (pp[1]); + + pp[0] = pp[1] = -1; +} + +/* Functional interface closes our local-to-job-control pipes. */ +close_pgrp_pipe () +{ + pipe_close (pgrp_pipe); +} + +#endif /* PGRP_PIPE */ + +#endif /* JOB_CONTROL */ @@ -0,0 +1,345 @@ +/* jobs.h -- structures and stuff used by the jobs.c file. */ + +/* 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 (__JOBS_H__) +# define __JOBS_H__ + +#include "quit.h" +#include "siglist.h" + +#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) +# include <sys/wait.h> +#else /* !HAVE_WAIT_H */ + +# include "bash_endian.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 */ + +/* 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 */ +typedef int WAIT; +# define WSTATUS(t) (t) +#endif /* _POSIX_VERSION */ + +/* Make sure that parameters to wait3 are defined. */ +#if !defined (WNOHANG) +# define WNOHANG 1 +# define WUNTRACED 2 +#endif /* WNOHANG */ + +/* More Posix P1003.1 definitions. In the POSIX versions, the parameter is + passed as an `int', in the non-POSIX version, as `union wait'. */ +#if defined (_POSIX_VERSION) + +# if !defined (WSTOPSIG) +# define WSTOPSIG(s) ((s) >> 8) +# endif /* !WSTOPSIG */ + +# if !defined (WTERMSIG) +# define WTERMSIG(s) ((s) & 0177) +# endif /* !WTERMSIG */ + +# if !defined (WEXITSTATUS) +# define WEXITSTATUS(s) ((s) >> 8) +# endif /* !WEXITSTATUS */ + +# if !defined (WIFSTOPPED) +# define WIFSTOPPED(s) (((s) & 0177) == 0177) +# endif /* !WIFSTOPPED */ + +# if !defined (WIFEXITED) +# define WIFEXITED(s) (((s) & 0377) == 0) +# endif /* !WIFEXITED */ + +# if !defined (WIFSIGNALED) +# define WIFSIGNALED(s) (!WIFSTOPPED(s) && !WIFEXITED(s)) +# endif /* !WIFSIGNALED */ + +# if !defined (WIFCORED) +# define WIFCORED(s) ((s) & 0200) +# endif /* !WIFCORED */ + +#else /* !_POSIX_VERSION */ + +# if !defined (WSTOPSIG) +# define WSTOPSIG(s) ((s).w_stopsig) +# endif /* !WSTOPSIG */ + +# if !defined (WTERMSIG) +# define WTERMSIG(s) ((s).w_termsig) +# endif /* !WTERMSIG */ + +# if !defined (WEXITSTATUS) +# define WEXITSTATUS(s) ((s).w_retcode) +# endif /* !WEXITSTATUS */ + +# if !defined (WIFCORED) +# define WIFCORED(s) ((s).w_coredump) +# endif /* !WIFCORED */ + +#endif /* !_POSIX_VERSION */ + +/* I looked it up. For pretty_print_job (). The real answer is 24. */ +#define LONGEST_SIGNAL_DESC 24 + +/* We keep an array of jobs. Each entry in the array is a linked list + of processes that are piped together. The first process encountered is + the group leader. */ + +/* Each child of the shell is remembered in a STRUCT PROCESS. A chain of + such structures is a pipeline. The chain is circular. */ +typedef struct process { + struct process *next; /* Next process in the pipeline. A circular chain. */ + pid_t pid; /* Process ID. */ + WAIT status; /* The status of this command as returned by wait. */ + int running; /* Non-zero if this process is running. */ + char *command; /* The particular program that is running. */ +} PROCESS; + +/* A description of a pipeline's state. */ +typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE; +#define JOBSTATE(job) (jobs[(job)]->state) + +/* 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. */ + +typedef struct job { + char *wd; /* The working directory at time of invocation. */ + PROCESS *pipe; /* The pipeline of processes that make up this job. */ + pid_t pgrp; /* The process ID of the process group (necessary). */ + JOB_STATE state; /* The state that this job is in. */ + 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. */ +#endif /* JOB_CONTROL */ +} JOB; + +#define NO_JOB -1 /* An impossible job array index. */ +#define DUP_JOB -2 /* A possible return value for get_job_spec (). */ + +/* 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__) +extern pid_t fork (), getpid (), getpgrp (); +#endif /* !SunOS5 && !USGr4_2 && !__BSD_4_4__ */ + +/* Stuff from the jobs.c file. */ +extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp; +extern pid_t last_made_pid, last_asynchronous_pid; +extern int current_job, previous_job; +extern int asynchronous_notification; +extern JOB **jobs; +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 start_pipeline __P((void)); +extern int stop_pipeline __P((int, COMMAND *)); +extern void delete_job __P((int)); + +extern void terminate_current_pipeline __P((void)); +extern void terminate_stopped_jobs __P((void)); +extern void hangup_all_jobs __P((void)); +extern void kill_current_pipeline __P((void)); + +#if defined (__STDC__) && defined (pid_t) +extern void describe_pid __P((int)); +#else +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 pid_t make_child __P((char *, int)); +extern int get_tty_state __P((void)); +extern int set_tty_state __P((void)); + +extern int wait_for_single_pid __P((pid_t)); +extern void wait_for_background_pids __P((void)); +extern int wait_for __P((pid_t)); +extern int wait_for_job __P((int)); + +extern void notify_and_cleanup __P((void)); +extern void reap_dead_jobs __P((void)); +extern int start_job __P((int, int)); +extern int kill_pid __P((pid_t, int, int)); +extern int initialize_jobs __P((void)); +extern void initialize_job_signals __P((void)); +extern int give_terminal_to __P((pid_t)); + +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)); + +#if defined (JOB_CONTROL) +extern int job_control; +#endif + +#endif /* __JOBS_H__ */ diff --git a/lib/doc-support/Makefile b/lib/doc-support/Makefile new file mode 100644 index 0000000..553b61f --- /dev/null +++ b/lib/doc-support/Makefile @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000..45541f5 --- /dev/null +++ b/lib/doc-support/getopt.h @@ -0,0 +1,129 @@ +/* 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 new file mode 100644 index 0000000..9233bab --- /dev/null +++ b/lib/doc-support/texindex.c @@ -0,0 +1,1666 @@ +/* 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 <stdio.h> +#include <ctype.h> +#include <errno.h> +#include "getopt.h" +#include "bashansi.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#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 <sys/types.h> + +#if defined (_AIX) || !defined (_POSIX_VERSION) +# include <sys/file.h> +#endif + +#include <fcntl.h> + +#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/ChangeLog b/lib/glob/ChangeLog new file mode 100644 index 0000000..377f0c1 --- /dev/null +++ b/lib/glob/ChangeLog @@ -0,0 +1,13 @@ +Thu Oct 29 08:58:12 1992 Brian Fox (bfox@cubit) + + * glob.c (glob_filename): Fix tiny memory leak. Rework some + comments. + +Mon Jul 20 10:57:36 1992 Brian Fox (bfox@cubit) + + * glob.c: (glob_filename) Change use of rindex () to strrchr (). + +Thu Jul 9 10:02:47 1992 Brian Fox (bfox@cubit) + + * fnmatch.c: (fnmatch) Only process `[' as the start of a bracket + expression if there is a closing `]' present in the string. diff --git a/lib/glob/Makefile b/lib/glob/Makefile new file mode 100644 index 0000000..5811ba2 --- /dev/null +++ b/lib/glob/Makefile @@ -0,0 +1,95 @@ +## -*- text -*- #################################################### +# # +# Makefile for the GNU Glob 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. +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 = libglob.a + +# The C code source files for this library. +CSOURCES = $(srcdir)glob.c $(srcdir)fnmatch.c + +# The header files for this library. +HSOURCES = $(srcdir)fnmatch.h + +OBJECTS = glob.o fnmatch.o + +# The texinfo files which document this library. +DOCSOURCE = doc/glob.texi +DOCOBJECT = doc/glob.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) 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 -f $(OBJECTS) $(LIBRARY_NAME) + -(cd doc && $(MAKE) $(MFLAGS) $@) + +maintainer-clean realclean mostlyclean distclean: clean + -(cd doc && $(MAKE) $(MFLAGS) $@) + +###################################################################### +# # +# Dependencies for the object files which make up this library. # +# # +###################################################################### + +fnmatch.o: fnmatch.c fnmatch.h diff --git a/lib/glob/doc/Makefile b/lib/glob/doc/Makefile new file mode 100644 index 0000000..1b6084c --- /dev/null +++ b/lib/glob/doc/Makefile @@ -0,0 +1,5 @@ +all: + cp glob.texi glob.info + +maintainer-clean realclean distclean clean: + rm -f glob.?? glob.info diff --git a/lib/glob/doc/glob.texi b/lib/glob/doc/glob.texi new file mode 100644 index 0000000..0262ef1 --- /dev/null +++ b/lib/glob/doc/glob.texi @@ -0,0 +1 @@ +Nothing happens here. diff --git a/lib/glob/fnmatch.c b/lib/glob/fnmatch.c new file mode 100644 index 0000000..6a8b574 --- /dev/null +++ b/lib/glob/fnmatch.c @@ -0,0 +1,189 @@ +/* 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. */ + +#include <errno.h> +#include "fnmatch.h" + +#if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS) +# if !defined (errno) +extern int errno; +# endif /* !errno */ +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, FNM_NOMATCH if not. */ +int +fnmatch (pattern, string, flags) + char *pattern; + char *string; + int flags; +{ + register char *p = pattern, *n = string; + register char c; + + if ((flags & ~__FNM_FLAGS) != 0) + { + errno = EINVAL; + return (-1); + } + + while ((c = *p++) != '\0') + { + switch (c) + { + case '?': + if (*n == '\0') + return (FNM_NOMATCH); + else if ((flags & FNM_PATHNAME) && *n == '/') + return (FNM_NOMATCH); + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return (FNM_NOMATCH); + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + c = *p++; + if (*n != c) + return (FNM_NOMATCH); + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (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); + + if (c == '\0') + return (0); + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + for (--p; *n != '\0'; ++n) + if ((c == '[' || *n == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return (0); + return (FNM_NOMATCH); + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return (FNM_NOMATCH); + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + return (FNM_NOMATCH); + + /* Make sure there is a closing `]'. If there isn't, the `[' + is just a character to be matched. */ + { + register char *np; + + for (np = p; np && *np && *np != ']'; np++); + + if (np && !*np) + { + if (*n != '[') + return (FNM_NOMATCH); + goto next_char; + } + } + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + if (c == '\0') + /* [ (unterminated) loses. */ + return (FNM_NOMATCH); + + c = *p++; + + if ((flags & FNM_PATHNAME) && c == '/') + /* [/] can never match. */ + return (FNM_NOMATCH); + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return (FNM_NOMATCH); + c = *p++; + } + + if (*n >= cstart && *n <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return (FNM_NOMATCH); + + next_char: + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return (FNM_NOMATCH); + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* 1003.2d11 is unclear if this is right. %%% */ + ++p; + } + if (not) + return (FNM_NOMATCH); + } + break; + + default: + if (c != *n) + return (FNM_NOMATCH); + } + + ++n; + } + + if (*n == '\0') + return (0); + + return (FNM_NOMATCH); +} diff --git a/lib/glob/fnmatch.h b/lib/glob/fnmatch.h new file mode 100644 index 0000000..62c8c8f --- /dev/null +++ b/lib/glob/fnmatch.h @@ -0,0 +1,36 @@ +/* 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. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ +#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch(); + +#endif /* fnmatch.h */ diff --git a/lib/glob/glob.c b/lib/glob/glob.c new file mode 100644 index 0000000..6ff2cb4 --- /dev/null +++ b/lib/glob/glob.c @@ -0,0 +1,574 @@ +/* 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. */ + +/* 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 <stdlib.h> +# else +# include "ansi_stdlib.h" +# endif /* HAVE_STDLIB_H */ +# include <config.h> +#endif + +#include <sys/types.h> + +#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 <dirent.h> +# 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 <sys/ndir.h> +# else /* !Xenix (but USG...) */ +# include "ndir.h" +# endif /* !Xenix */ +# else /* !USG */ +# include <sys/dir.h> +# endif /* !USG */ +#endif /* !HAVE_DIRENT_H */ + +#if defined (_POSIX_SOURCE) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# 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 <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (USG) +# if !defined (isc386) +# include <memory.h> +# 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 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. */ +#if defined (OPENDIR_NOT_ROBUST) +# if defined (SHELL) +# include "posixstat.h" +# else /* !SHELL */ +# include <sys/stat.h> +# endif /* !SHELL */ +#endif /* OPENDIR_NOT_ROBUST */ + +#if !defined (HAVE_STDLIB_H) +extern char *malloc (), *realloc (); +extern void free (); +#endif /* !HAVE_STDLIB_H */ + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* __STDC__ */ +#endif /* !NULL */ + +#if defined (SHELL) +extern int interrupt_state; +#endif /* SHELL */ + +/* Global variable which controls whether or not * matches .*. + Non-zero means don't match .*. */ +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) + char *pattern; +{ + register char *p = pattern; + register char c; + int open = 0; + + while ((c = *p++) != '\0') + switch (c) + { + case '?': + case '*': + return (1); + + case '[': /* Only accept an open brace if there is a close */ + open++; /* brace to match it. Bracket expressions must be */ + continue; /* complete, according to Posix.2 */ + case ']': + if (open) + return (1); + continue; + + case '\\': + if (*p++ == '\0') + return (0); + } + + return (0); +} + +/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ +static void +dequote_pathname (pathname) + char *pathname; +{ + register int i, j; + + for (i = j = 0; pathname && pathname[i]; ) + { + if (pathname[i] == '\\') + i++; + + pathname[j++] = pathname[i++]; + + if (!pathname[i - 1]) + break; + } + pathname[j] = '\0'; +} + + +/* Return a vector of names of files in directory DIR + whose names match glob pattern PAT. + The names are not in any particular order. + Wildcards at the beginning of PAT do not match an initial period. + + The vector is terminated by an element that is a null pointer. + + To free the space allocated, first free the vector's elements, + then free the vector. + + Return 0 if cannot get enough memory to hold the pointer + and the names. + + Return -1 if cannot access directory DIR. + Look in errno for more information. */ + +char ** +glob_vector (pat, dir) + char *pat; + char *dir; +{ + struct globval + { + struct globval *next; + char *name; + }; + + DIR *d; + register struct direct *dp; + struct globval *lastlink; + register struct globval *nextlink; + register char *nextname; + unsigned int count; + int lose, skip; + register char **name_vector; + register unsigned int i; +#if defined (OPENDIR_NOT_ROBUST) + struct stat finfo; + + if (stat (dir, &finfo) < 0) + return ((char **) &glob_error_return); + + if (!S_ISDIR (finfo.st_mode)) + return ((char **) &glob_error_return); +#endif /* OPENDIR_NOT_ROBUST */ + + d = opendir (dir); + if (d == NULL) + return ((char **) &glob_error_return); + + lastlink = 0; + count = 0; + lose = 0; + skip = 0; + + /* If PAT is empty, skip the loop, but return one (empty) filename. */ + if (!pat || !*pat) + { + nextlink = (struct globval *)alloca (sizeof (struct globval)); + nextlink->next = lastlink; + nextname = (char *) malloc (1); + if (!nextname) + lose = 1; + else + { + lastlink = nextlink; + nextlink->name = nextname; + nextname[0] = '\0'; + count++; + } + skip = 1; + } + + /* Scan the directory, finding all names that match. + For each name that matches, allocate a struct globval + on the stack and store the name in it. + Chain those structs together; lastlink is the front of the chain. */ + while (!skip) + { + int flags; /* Flags passed to fnmatch (). */ +#if defined (SHELL) + /* Make globbing interruptible in the bash shell. */ + if (interrupt_state) + { + closedir (d); + lose = 1; + goto lost; + } +#endif /* SHELL */ + + dp = readdir (d); + if (dp == NULL) + break; + + /* If this directory entry is not to be used, try again. */ + if (!REAL_DIR_ENTRY (dp)) + continue; + + /* If a dot must be explicity matched, check to see if they do. */ + if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.') + continue; + + flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; + + if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH) + { + nextlink = (struct globval *) alloca (sizeof (struct globval)); + nextlink->next = lastlink; + nextname = (char *) malloc (D_NAMLEN (dp) + 1); + if (nextname == NULL) + { + lose = 1; + break; + } + lastlink = nextlink; + nextlink->name = nextname; + bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); + ++count; + } + } + (void) closedir (d); + + if (!lose) + { + name_vector = (char **) malloc ((count + 1) * sizeof (char *)); + lose |= name_vector == NULL; + } + + /* Have we run out of memory? */ + lost: + if (lose) + { + /* Here free the strings we have got. */ + while (lastlink) + { + free (lastlink->name); + lastlink = lastlink->next; + } +#if defined (SHELL) + if (interrupt_state) + throw_to_top_level (); +#endif /* SHELL */ + return (NULL); + } + + /* Copy the name pointers from the linked list into the vector. */ + for (i = 0; i < count; ++i) + { + name_vector[i] = lastlink->name; + lastlink = lastlink->next; + } + + name_vector[count] = NULL; + return (name_vector); +} + +/* Return a new array which is the concatenation of each string in ARRAY + to DIR. This function expects you to pass in an allocated ARRAY, and + it takes care of free()ing that array. Thus, you might think of this + function as side-effecting ARRAY. */ +static char ** +glob_dir_to_array (dir, array) + char *dir, **array; +{ + register unsigned int i, l; + int add_slash; + char **result; + + l = strlen (dir); + if (l == 0) + return (array); + + add_slash = dir[l - 1] != '/'; + + i = 0; + while (array[i] != NULL) + ++i; + + result = (char **) malloc ((i + 1) * sizeof (char *)); + if (result == NULL) + return (NULL); + + for (i = 0; array[i] != NULL; i++) + { + result[i] = (char *) malloc (l + (add_slash ? 1 : 0) + + strlen (array[i]) + 1); + if (result[i] == NULL) + return (NULL); + sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); + } + result[i] = NULL; + + /* Free the input array. */ + for (i = 0; array[i] != NULL; i++) + free (array[i]); + free ((char *) array); + + return (result); +} + +/* Do globbing on PATHNAME. Return an array of pathnames that match, + marking the end of the array with a null-pointer as an element. + If no pathnames match, then the array is empty (first element is null). + If there isn't enough memory, then return NULL. + If a file system error occurs, return -1; `errno' has the error code. */ +char ** +glob_filename (pathname) + char *pathname; +{ + char **result; + unsigned int result_size; + char *directory_name, *filename; + unsigned int directory_len; + + result = (char **) malloc (sizeof (char *)); + result_size = 1; + if (result == NULL) + return (NULL); + + result[0] = NULL; + + /* Find the filename. */ + filename = strrchr (pathname, '/'); + if (filename == NULL) + { + filename = pathname; + directory_name = ""; + directory_len = 0; + } + else + { + directory_len = (filename - pathname) + 1; + directory_name = (char *) alloca (directory_len + 1); + + bcopy (pathname, directory_name, directory_len); + directory_name[directory_len] = '\0'; + ++filename; + } + + /* If directory_name contains globbing characters, then we + have to expand the previous levels. Just recurse. */ + if (glob_pattern_p (directory_name)) + { + char **directories; + register unsigned int i; + + if (directory_name[directory_len - 1] == '/') + directory_name[directory_len - 1] = '\0'; + + directories = glob_filename (directory_name); + + if (directories == NULL) + goto memory_error; + else if (directories == (char **)&glob_error_return) + { + free ((char *)result); + return ((char **) &glob_error_return); + } + else if (*directories == NULL) + { + free ((char *) directories); + free ((char *) result); + return ((char **) &glob_error_return); + } + + /* We have successfully globbed the preceding directory name. + For each name in DIRECTORIES, call glob_vector on it and + FILENAME. Concatenate the results together. */ + for (i = 0; directories[i] != NULL; ++i) + { + char **temp_results; + + /* Scan directory even on a NULL pathname. That way, `*h/' + returns only directories ending in `h', instead of all + files ending in `h' with a `/' appended. */ + temp_results = glob_vector (filename, directories[i]); + + /* Handle error cases. */ + if (temp_results == NULL) + goto memory_error; + else if (temp_results == (char **)&glob_error_return) + /* This filename is probably not a directory. Ignore it. */ + ; + else + { + char **array; + register unsigned int l; + + array = glob_dir_to_array (directories[i], temp_results); + l = 0; + while (array[l] != NULL) + ++l; + + result = + (char **)realloc (result, (result_size + l) * sizeof (char *)); + + if (result == NULL) + goto memory_error; + + for (l = 0; array[l] != NULL; ++l) + result[result_size++ - 1] = array[l]; + + result[result_size - 1] = NULL; + + /* Note that the elements of ARRAY are not freed. */ + free ((char *) array); + } + } + /* Free the directories. */ + for (i = 0; directories[i]; i++) + free (directories[i]); + + free ((char *) directories); + + return (result); + } + + /* If there is only a directory name, return it. */ + if (*filename == '\0') + { + result = (char **) realloc ((char *) result, 2 * sizeof (char *)); + if (result == NULL) + return (NULL); + result[0] = (char *) malloc (directory_len + 1); + if (result[0] == NULL) + goto memory_error; + bcopy (directory_name, result[0], directory_len + 1); + result[1] = NULL; + return (result); + } + else + { + char **temp_results; + + /* There are no unquoted globbing characters in DIRECTORY_NAME. + Dequote it before we try to open the directory since there may + be quoted globbing characters which should be treated verbatim. */ + if (directory_len > 0) + dequote_pathname (directory_name); + + /* We allocated a small array called RESULT, which we won't be using. + Free that memory now. */ + free (result); + + /* Just return what glob_vector () returns appended to the + directory name. */ + temp_results = + glob_vector (filename, (directory_len == 0 ? "." : directory_name)); + + if (temp_results == NULL || temp_results == (char **)&glob_error_return) + return (temp_results); + + return (glob_dir_to_array (directory_name, temp_results)); + } + + /* We get to memory_error if the program has run out of memory, or + if this is the shell, and we have been interrupted. */ + memory_error: + if (result != NULL) + { + register unsigned int i; + for (i = 0; result[i] != NULL; ++i) + free (result[i]); + free ((char *) result); + } +#if defined (SHELL) + if (interrupt_state) + throw_to_top_level (); +#endif /* SHELL */ + return (NULL); +} + +#if defined (TEST) + +main (argc, argv) + int argc; + char **argv; +{ + unsigned int i; + + for (i = 1; i < argc; ++i) + { + char **value = glob_filename (argv[i]); + if (value == NULL) + puts ("Out of memory."); + else if (value == &glob_error_return) + perror (argv[i]); + else + for (i = 0; value[i] != NULL; i++) + puts (value[i]); + } + + exit (0); +} +#endif /* TEST. */ diff --git a/lib/glob/ndir.h b/lib/glob/ndir.h new file mode 100644 index 0000000..31261eb --- /dev/null +++ b/lib/glob/ndir.h @@ -0,0 +1,50 @@ +/* <dir.h> -- definitions for 4.2BSD-compatible directory access. + last edit: 09-Jul-1983 D A Gwyn. */ + +#if defined (VMS) +# if !defined (FAB$C_BID) +# include <fab.h> +# endif +# if !defined (NAM$C_BID) +# include <nam.h> +# endif +# if !defined (RMS$_SUC) +# include <rmsdef.h> +# endif +# include "dir.h" +#endif /* VMS */ + +/* Size of directory block. */ +#define DIRBLKSIZ 512 + +/* NOTE: MAXNAMLEN must be one less than a multiple of 4 */ + +#if defined (VMS) +# define MAXNAMLEN (DIR$S_NAME + 7) /* 80 plus room for version #. */ +# define MAXFULLSPEC NAM$C_MAXRSS /* Maximum full spec */ +#else +# define MAXNAMLEN 15 /* Maximum filename length. */ +#endif /* VMS */ + +/* Data from readdir (). */ +struct direct { + long d_ino; /* Inode number of entry. */ + unsigned short d_reclen; /* Length of this record. */ + unsigned short d_namlen; /* Length of string in d_name. */ + char d_name[MAXNAMLEN + 1]; /* Name of file. */ +}; + +/* Stream data from opendir (). */ +typedef struct { + int dd_fd; /* File descriptor. */ + int dd_loc; /* Offset in block. */ + int dd_size; /* Amount of valid data. */ + char dd_buf[DIRBLKSIZ]; /* Directory block. */ +} DIR; + +extern DIR *opendir (); +extern struct direct *readdir (); +extern long telldir (); +extern void seekdir (), closedir (); + +#define rewinddir(dirp) seekdir (dirp, 0L) diff --git a/lib/malloc/Makefile b/lib/malloc/Makefile new file mode 100644 index 0000000..4c0ab72 --- /dev/null +++ b/lib/malloc/Makefile @@ -0,0 +1,28 @@ +# 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/alloca.c b/lib/malloc/alloca.c new file mode 100644 index 0000000..567ea1b --- /dev/null +++ b/lib/malloc/alloca.c @@ -0,0 +1,480 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + 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. + J.Otto Tennant <jot@cray.com> contributed the Cray support. + + 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. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* If compiling with GCC 2, this file's not needed. */ +#if !defined (__GNUC__) || __GNUC__ < 2 + +/* If alloca is defined somewhere, this file is not needed. */ +#ifndef alloca + +#ifdef emacs +#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 */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif /* CRAY && CRAY_STACKSEG_END */ + +#if __STDC__ +typedef void *pointer; +#else +typedef char *pointer; +#endif + +#define NULL 0 + +/* Different portions of Emacs need to call different versions of + malloc. The Emacs executable needs alloca to call xmalloc, because + ordinary malloc isn't protected from input signals. On the other + hand, the utilities in lib-src need alloca to call malloc; some of + them are very simple, and don't have an xmalloc routine. + + Non-Emacs programs expect this to call use xmalloc. + + Callers below should use malloc. */ + +#ifndef emacs +#define malloc xmalloc +extern pointer xmalloc (); +#endif + +/* 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 () +{ + static char *addr = NULL; /* Address of first `dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (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; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return 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. */ + +pointer +alloca (size) + unsigned size; +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd 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 = malloc (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)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include <stdio.h> +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + /* This might be _getb67() or GETB67 () or getb67 () */ + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY && CRAY_STACKSEG_END */ + +#endif /* no alloca */ +#endif /* !__GNUC__ || __GNUC__ < 2 */ diff --git a/lib/malloc/getpagesize.h b/lib/malloc/getpagesize.h new file mode 100644 index 0000000..0cb4416 --- /dev/null +++ b/lib/malloc/getpagesize.h @@ -0,0 +1,49 @@ +/* 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 (HAVE_UNISTD_H) +# include <unistd.h> +# if defined (_SC_PAGESIZE) +# define getpagesize() sysconf(_SC_PAGESIZE) +# endif /* _SC_PAGESIZE */ +#endif + +#if !defined (getpagesize) +# include <sys/param.h> +# 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 (getpagesize) +# define getpagesize() 4096 /* Just punt and use reasonable value */ +#endif diff --git a/lib/malloc/i386-alloca.s b/lib/malloc/i386-alloca.s new file mode 100644 index 0000000..01b2cfe --- /dev/null +++ b/lib/malloc/i386-alloca.s @@ -0,0 +1,16 @@ + .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/malloc/malloc.c b/lib/malloc/malloc.c new file mode 100644 index 0000000..78fb640 --- /dev/null +++ b/lib/malloc/malloc.c @@ -0,0 +1,668 @@ +/* dynamic memory allocation for GNU. */ + +/* Copyright (C) 1985, 1987 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. + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + +/* + * @(#)nmalloc.c 1 (Caltech) 2/21/82 + * + * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs + * + * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks + * that don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are (2^n)-4 (or -16) bytes long. + * This is designed for use in a program that uses vast quantities of + * memory, but bombs when it runs out. To make it a little better, it + * warns the user when he starts to get near the end. + * + * June 84, ACT: modified rcheck code to check the range given to malloc, + * rather than the range determined by the 2-power used. + * + * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. + * No longer Emacs-specific; can serve as all-purpose malloc for GNU. + * You should call malloc_init to reinitialize after loading dumped Emacs. + * Call malloc_stats to get info on memory stats if MSTATS turned on. + * realloc knows how to return same block given, just changing its size, + * if the power of 2 is correct. + */ + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information will + * go in the first int of the block, and the returned pointer will point + * to the second. + * +#ifdef MSTATS + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. +#endif + */ + +#if defined (emacs) || defined (HAVE_CONFIG_H) +# include "config.h" +#endif /* emacs */ + +#if !defined (USG) +# if defined (HPUX) || defined (UnixPC) || defined (Xenix) +# define USG +# endif /* HPUX || UnixPC || Xenix */ +#endif /* !USG */ + +/* Determine which kind of system this is. */ +#include <sys/types.h> +#include <signal.h> + +#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. */ +# include "getpagesize.h" +#endif + +#if defined (HAVE_RESOURCE) +# include <sys/time.h> +# include <sys/resource.h> +#endif /* HAVE_RESOURCE */ + +/* Check for the needed symbols. If they aren't present, this + system's <sys/resource.h> isn't very useful to us. */ +#if !defined (RLIMIT_DATA) +# undef HAVE_RESOURCE +#endif + +#define start_of_data() &etext + +#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ +#define ISFREE ((char) 0x54) /* magic byte that implies free block */ + /* this is for error checking only */ +#define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by + memalign, with the rest of the word + being the distance to the true + beginning of the block. */ +extern char etext; + +#if !defined (NO_SBRK_DECL) +extern char *sbrk (); +#endif /* !NO_SBRK_DECL */ + +/* 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 */ + +/* start of data space; can be changed by calling init_malloc */ +static char *data_space_start; + +static void get_lim_data (); + +#ifdef MSTATS +static int nmalloc[30]; +static int nmal, nfre; +#endif /* MSTATS */ + +/* If range checking is not turned on, all we have is a flag indicating + whether memory is allocated, an index in nextf[], and a size field; to + realloc() memory we copy either size bytes or 1<<(index+3) bytes depending + on whether the former can hold the exact size (given the value of + 'index'). If range checking is on, we always need to know how much space + is allocated, so the 'size' field is never used. */ + +struct mhead { + char mh_alloc; /* ISALLOC or ISFREE */ + char mh_index; /* index in nextf[] */ +/* Remainder are valid only when block is allocated */ + unsigned short mh_size; /* size, if < 0x10000 */ +#ifdef rcheck + unsigned mh_nbytes; /* number of bytes allocated */ + int mh_magic4; /* should be == MAGIC4 */ +#endif /* rcheck */ +}; + +/* Access free-list pointer of a block. + It is stored at block + 4. + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ + +#define CHAIN(a) \ + (*(struct mhead **) (sizeof (char *) + (char *) (a))) + +#ifdef rcheck +# include <stdio.h> +# if !defined (botch) +# define botch(x) abort () +# endif /* botch */ + +# if !defined (__STRING) +# if defined (__STDC__) +# define __STRING(x) #x +# else +# define __STRING(x) "x" +# endif +# endif + + /* To implement range checking, we write magic values in at the beginning + and end of each allocated block, and make sure they are undisturbed + whenever a free or a realloc occurs. */ + + /* Written in each of the 4 bytes following the block's real space */ +# define MAGIC1 0x55 + /* Written in the 4 bytes before the block's real space */ +# define MAGIC4 0x55555555 +# define ASSERT(p) if (!(p)) botch(__STRING(p)); else +# define EXTRA 4 /* 4 bytes extra for MAGIC1s */ +#else /* !rcheck */ +# define ASSERT(p) +# define EXTRA 0 +#endif /* rcheck */ + +/* nextf[i] is free list of blocks of size 2**(i + 3) */ + +static struct mhead *nextf[30]; + +/* busy[i] is nonzero while allocation of block size i is in progress. */ + +static char busy[30]; + +/* Number of bytes of writable memory we can expect to be able to get */ +static unsigned int lim_data; + +/* Level number of warnings already issued. + 0 -- no warnings issued. + 1 -- 75% warning already issued. + 2 -- 85% warning already issued. +*/ +static int warnlevel; + +/* Function to call to issue a warning; + 0 means don't issue them. */ +static void (*warnfunction) (); + +/* nonzero once initial bunch of free blocks made */ +static int gotpool; + +char *_malloc_base; + +static void getpool (); + +/* Cause reinitialization based on job parameters; + also declare where the end of pure storage is. */ +void +malloc_init (start, warnfun) + char *start; + void (*warnfun) (); +{ + if (start) + data_space_start = start; + lim_data = 0; + warnlevel = 0; + warnfunction = warnfun; +} + +/* Return the maximum size to which MEM can be realloc'd + without actually requiring copying. */ + +int +malloc_usable_size (mem) + char *mem; +{ + int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + + return blocksize - sizeof (struct mhead) - EXTRA; +} + +static void +morecore (nu) /* ask system for more memory */ + register int nu; /* size index to get more of */ +{ + register char *cp; + register int nblks; + register unsigned int siz; + int oldmask; + +#if defined (BSD4_2) + oldmask = sigsetmask (-1); +#endif /* BSD4_2 */ + + if (!data_space_start) + { + data_space_start = start_of_data (); + } + + if (lim_data == 0) + get_lim_data (); + + /* On initial startup, get two blocks of each size up to 1k bytes */ + if (!gotpool) + { getpool (); getpool (); gotpool = 1; } + + /* Find current end of memory and issue warning if getting near max */ + + cp = sbrk (0); + siz = cp - data_space_start; + malloc_sbrk_used = siz; + malloc_sbrk_unused = lim_data - siz; + + if (warnfunction) + switch (warnlevel) + { + case 0: + if (siz > (lim_data / 4) * 3) + { + warnlevel++; + (*warnfunction) ("Warning: past 75% of memory limit"); + } + break; + case 1: + if (siz > (lim_data / 20) * 17) + { + warnlevel++; + (*warnfunction) ("Warning: past 85% of memory limit"); + } + break; + case 2: + if (siz > (lim_data / 20) * 19) + { + warnlevel++; + (*warnfunction) ("Warning: past 95% of memory limit"); + } + break; + } + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Take at least 2k, and figure out how many blocks of the desired size + we're about to get */ + nblks = 1; + if ((siz = nu) < 8) + nblks = 1 << ((siz = 8) - nu); + + if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) + return; /* no more room! */ + + if ((int) cp & 7) + { /* shouldn't happen, but just in case */ + cp = (char *) (((int) cp + 8) & ~7); + nblks--; + } + + /* save new header and link the nblks blocks together */ + nextf[nu] = (struct mhead *) cp; + siz = 1 << (nu + 3); + while (1) + { + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + if (--nblks <= 0) break; + CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); + cp += siz; + } + CHAIN ((struct mhead *) cp) = 0; + +#if defined (BSD4_2) + sigsetmask (oldmask); +#endif /* BSD4_2 */ +} + +static void +getpool () +{ + register int nu; + register char *cp = sbrk (0); + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Record address of start of space allocated by malloc. */ + if (_malloc_base == 0) + _malloc_base = cp; + + /* Get 2k of storage */ + + cp = sbrk (04000); + if (cp == (char *) -1) + return; + + /* Divide it into an initial 8-word block + plus one block of size 2**nu for nu = 3 ... 10. */ + + CHAIN (cp) = nextf[0]; + nextf[0] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = 0; + cp += 8; + + for (nu = 0; nu < 7; nu++) + { + CHAIN (cp) = nextf[nu]; + nextf[nu] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + cp += 8 << nu; + } +} + +char * +malloc (n) /* get a block */ + unsigned n; +{ + register struct mhead *p; + register unsigned int nbytes; + register int nunits = 0; + + /* Figure out how many bytes are required, rounding up to the nearest + multiple of 4, then figure out which nextf[] area to use */ + nbytes = (n + sizeof *p + EXTRA + 3) & ~3; + { + register unsigned int shiftr = (nbytes - 1) >> 2; + + while (shiftr >>= 1) + nunits++; + } + + /* In case this is reentrant use of malloc from signal handler, + pick a block size that no other malloc level is currently + trying to allocate. That's the easiest harmless way not to + interfere with the other level of execution. */ + while (busy[nunits]) nunits++; + busy[nunits] = 1; + + /* If there are no blocks of the appropriate size, go get some */ + /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ + if (nextf[nunits] == 0) + morecore (nunits); + + /* Get one block off the list, and set the new list head */ + if ((p = nextf[nunits]) == 0) + { + busy[nunits] = 0; + return 0; + } + nextf[nunits] = CHAIN (p); + busy[nunits] = 0; + + /* Check for free block clobbered */ + /* If not for this check, we would gobble a clobbered free chain ptr */ + /* and bomb out on the NEXT allocate of this size block */ + if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) +#ifdef rcheck + botch ("block on free list clobbered"); +#else /* not rcheck */ + abort (); +#endif /* not rcheck */ + + /* Fill in the info, and if range checking, set up the magic numbers */ + p -> mh_alloc = ISALLOC; +#ifdef rcheck + p -> mh_nbytes = n; + p -> mh_magic4 = MAGIC4; + { + register char *m = (char *) (p + 1) + n; + + *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; + } +#else /* not rcheck */ + p -> mh_size = n; +#endif /* not rcheck */ +#ifdef MSTATS + nmalloc[nunits]++; + nmal++; +#endif /* MSTATS */ + return (char *) (p + 1); +} + +void +free (mem) + char *mem; +{ + register struct mhead *p; + { + register char *ap = mem; + + if (ap == 0) + return; + + p = (struct mhead *) ap - 1; + + if (p -> mh_alloc == ISMEMALIGN) + { +#ifdef rcheck + ap -= p->mh_nbytes; +#endif + p = (struct mhead *) ap - 1; + } + +#ifndef rcheck + if (p -> mh_alloc != ISALLOC) + abort (); + +#else /* rcheck */ + if (p -> mh_alloc != ISALLOC) + { + if (p -> mh_alloc == ISFREE) + botch ("free: Called with already freed block argument\n"); + else + botch ("free: Called with bad argument\n"); + } + + ASSERT (p -> mh_magic4 == MAGIC4); + ap += p -> mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); +#endif /* rcheck */ + } + { + register int nunits = p -> mh_index; + + ASSERT (nunits <= 29); + p -> mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MSTATS + nmalloc[nunits]--; + nfre++; +#endif /* MSTATS */ + } +} + +char * +realloc (mem, n) + char *mem; + register unsigned n; +{ + register struct mhead *p; + register unsigned int tocopy; + register unsigned int nbytes; + register int nunits; + + if ((p = (struct mhead *) mem) == 0) + return malloc (n); + p--; + nunits = p -> mh_index; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef rcheck + ASSERT (p -> mh_magic4 == MAGIC4); + { + register char *m = mem + (tocopy = p -> mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); + } +#else /* not rcheck */ + if (p -> mh_index >= 13) + tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; + else + tocopy = p -> mh_size; +#endif /* not rcheck */ + + /* See if desired size rounds to same power of 2 as actual size. */ + nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + + /* If ok, use the same block, just marking its size as changed. */ + if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) + { +#ifdef rcheck + register char *m = mem + tocopy; + *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; + p-> mh_nbytes = n; + m = mem + n; + *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; +#else /* not rcheck */ + p -> mh_size = n; +#endif /* not rcheck */ + return mem; + } + + if (n < tocopy) + tocopy = n; + { + register char *new; + + if ((new = malloc (n)) == 0) + return 0; + bcopy (mem, new, tocopy); + free (mem); + return new; + } +} + +char * +memalign (alignment, size) + unsigned alignment, size; +{ + register char *ptr = malloc (size + alignment); + register char *aligned; + register struct mhead *p; + + if (ptr == 0) + return 0; + /* If entire block has the desired alignment, just accept it. */ + if (((int) ptr & (alignment - 1)) == 0) + return ptr; + /* Otherwise, get address of byte in the block that has that alignment. */ + aligned = (char *) (((int) ptr + alignment - 1) & -alignment); + + /* Store a suitable indication of how to free the block, + so that free can find the true beginning of it. */ + p = (struct mhead *) aligned - 1; + p -> mh_size = aligned - ptr; + p -> mh_alloc = ISMEMALIGN; + return aligned; +} + +#if !defined (HPUX) && !defined (Multimax) && !defined (Multimax32k) +/* This runs into trouble with getpagesize on HPUX, and Multimax machines. + Patching out seems cleaner than the ugly fix needed. */ +char * +valloc (size) +{ + return memalign (getpagesize (), size); +} +#endif /* !HPUX && !Multimax && !Multimax32k */ + +#ifdef MSTATS +/* Return statistics describing allocation of blocks of size 2**n. */ + +struct mstats_value + { + int blocksize; + int nfree; + int nused; + }; + +struct mstats_value +malloc_stats (size) + int size; +{ + struct mstats_value v; + register int i; + register struct mhead *p; + + v.nfree = 0; + + if (size < 0 || size >= 30) + { + v.blocksize = 0; + v.nused = 0; + return v; + } + + v.blocksize = 1 << (size + 3); + v.nused = nmalloc[size]; + + for (p = nextf[size]; p; p = CHAIN (p)) + v.nfree++; + + 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 + * BSD systems this is the total space allocatable to stack and + * data. On USG systems this is the data space only. + */ + +#if !defined (HAVE_RESOURCE) +extern long ulimit (); + +static void +get_lim_data () +{ + lim_data = ulimit (3, 0); + lim_data -= (long) data_space_start; +} + +#else /* HAVE_RESOURCE */ +static void +get_lim_data () +{ + struct rlimit XXrlimit; + + getrlimit (RLIMIT_DATA, &XXrlimit); +#ifdef RLIM_INFINITY + lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ +#else + lim_data = XXrlimit.rlim_cur; /* soft limit */ +#endif +} + +#endif /* HAVE_RESOURCE */ diff --git a/lib/malloc/x386-alloca.s b/lib/malloc/x386-alloca.s new file mode 100644 index 0000000..112d33c --- /dev/null +++ b/lib/malloc/x386-alloca.s @@ -0,0 +1,63 @@ +;; 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 <chip@tct.uucp>, <uunet!ateng!tct!chip> + + 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/malloc/xmalloc.c b/lib/malloc/xmalloc.c new file mode 100644 index 0000000..4f6dc76 --- /dev/null +++ b/lib/malloc/xmalloc.c @@ -0,0 +1,78 @@ +/* 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 (ALREADY_HAVE_XMALLOC) +#else +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +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 (); +} +#endif /* !ALREADY_HAVE_XMALLOC */ diff --git a/lib/malloclib/Makefile b/lib/malloclib/Makefile new file mode 100644 index 0000000..7a449c3 --- /dev/null +++ b/lib/malloclib/Makefile @@ -0,0 +1,53 @@ +# 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 new file mode 100644 index 0000000..918d023 --- /dev/null +++ b/lib/malloclib/alloca.c @@ -0,0 +1,189 @@ +/* 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 new file mode 100644 index 0000000..f870e94 --- /dev/null +++ b/lib/malloclib/calloc.c @@ -0,0 +1,39 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..adc1ff6 --- /dev/null +++ b/lib/malloclib/cfree.c @@ -0,0 +1,43 @@ +/* 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 <malloc.h> +#endif + +#undef cfree + +#ifdef _LIBC + +#include <ansidecl.h> +#include <gnu-stabs.h> + +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 new file mode 100644 index 0000000..db97fcb --- /dev/null +++ b/lib/malloclib/free.c @@ -0,0 +1,212 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..b3aa4ba --- /dev/null +++ b/lib/malloclib/getpagesize.h @@ -0,0 +1,56 @@ +/* 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 <unistd.h> +# if defined (_SC_PAGESIZE) +# define getpagesize() sysconf(_SC_PAGESIZE) +# endif /* _SC_PAGESIZE */ +#endif + +#if !defined (HAVE_GETPAGESIZE) +# include <sys/param.h> +# 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 new file mode 100644 index 0000000..01b2cfe --- /dev/null +++ b/lib/malloclib/i386-alloca.s @@ -0,0 +1,16 @@ + .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 new file mode 100644 index 0000000..1d9bc03 --- /dev/null +++ b/lib/malloclib/malloc.c @@ -0,0 +1,324 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..705a8c0 --- /dev/null +++ b/lib/malloclib/malloc.h @@ -0,0 +1,268 @@ +/* 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 <stdio.h> tries to typedef them on some systems. */ +#include <stdio.h> +#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 <stddef.h> +#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 <string.h> +#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 <limits.h> +#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 new file mode 100644 index 0000000..f7d9d4f --- /dev/null +++ b/lib/malloclib/mcheck.c @@ -0,0 +1,133 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..f5ad17c --- /dev/null +++ b/lib/malloclib/memalign.c @@ -0,0 +1,61 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..c9a9ca5 --- /dev/null +++ b/lib/malloclib/morecore.c @@ -0,0 +1,44 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..511cdad --- /dev/null +++ b/lib/malloclib/mstats.c @@ -0,0 +1,39 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..d7689ce --- /dev/null +++ b/lib/malloclib/mtrace.awk @@ -0,0 +1,36 @@ +# +# 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 new file mode 100644 index 0000000..ea1d3a4 --- /dev/null +++ b/lib/malloclib/mtrace.c @@ -0,0 +1,150 @@ +/* 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 <malloc.h> +#endif + +/* Don't #include <stdio.h> because <malloc.h> did it for us. */ + +#ifndef __GNU_LIBRARY__ +extern char *getenv (); +#else +#include <stdlib.h> +#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 new file mode 100644 index 0000000..2d31766 --- /dev/null +++ b/lib/malloclib/realloc.c @@ -0,0 +1,146 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..eb5d372 --- /dev/null +++ b/lib/malloclib/valloc.c @@ -0,0 +1,48 @@ +/* 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 <malloc.h> +#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 new file mode 100644 index 0000000..112d33c --- /dev/null +++ b/lib/malloclib/x386-alloca.s @@ -0,0 +1,63 @@ +;; 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 <chip@tct.uucp>, <uunet!ateng!tct!chip> + + 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 new file mode 100644 index 0000000..a25cb11 --- /dev/null +++ b/lib/malloclib/xmalloc.c @@ -0,0 +1,69 @@ +/* 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 <stdio.h> + +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/ansi_stdlib.h b/lib/posixheaders/ansi_stdlib.h new file mode 100644 index 0000000..52339da --- /dev/null +++ b/lib/posixheaders/ansi_stdlib.h @@ -0,0 +1,41 @@ +/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */ +/* A minimal stdlib.h containing extern declarations for those functions + that bash uses. */ + +/* 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 (_STDLIB_H_) +#define _STDLIB_H_ 1 + +/* String conversion functions. */ +extern int atoi (); +extern long int atol (); + +/* Memory allocation functions. */ +extern char *malloc (); +extern char *realloc (); +extern void free (); + +/* Other miscellaneous functions. */ +extern void abort (); +extern void exit (); +extern char *getenv (); +extern void qsort (); + +#endif /* _STDLIB_H */ diff --git a/lib/posixheaders/filecntl.h b/lib/posixheaders/filecntl.h new file mode 100644 index 0000000..c0b2081 --- /dev/null +++ b/lib/posixheaders/filecntl.h @@ -0,0 +1,36 @@ +/* filecntl.h - Definitions to set file descriptors to close-on-exec. */ + +/* 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 (_FILECNTL_H_) +#define _FILECNTL_H_ + +#include <fcntl.h> + +/* Definitions to set file descriptors to close-on-exec, the Posix way. */ +#if !defined (FD_CLOEXEC) +#define FD_CLOEXEC 1 +#endif + +#define FD_NCLOEXEC 0 + +#define SET_CLOSE_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_CLOEXEC)) +#define SET_OPEN_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_NCLOEXEC)) + +#endif /* ! _FILECNTL_H_ */ diff --git a/lib/posixheaders/memalloc.h b/lib/posixheaders/memalloc.h new file mode 100644 index 0000000..750d53d --- /dev/null +++ b/lib/posixheaders/memalloc.h @@ -0,0 +1,56 @@ +/* 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 <malloc.h> +# else /* !IBMESA */ +# include <alloca.h> +# endif /* !IBMESA */ +# else +extern char *alloca (); +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/lib/posixheaders/posixstat.h b/lib/posixheaders/posixstat.h new file mode 100644 index 0000000..7d1cece --- /dev/null +++ b/lib/posixheaders/posixstat.h @@ -0,0 +1,149 @@ +/* posixstat.h -- Posix stat(2) definitions for systems that + don't have them. */ + +/* 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 <sys/stat.h>. + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include <sys/stat.h> + +#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) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */ + +/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but + do not provide the S_IS* macros that Posix requires. */ + +#if defined (_S_IFMT) && !defined (S_IFMT) +#define S_IFMT _S_IFMT +#endif +#if defined (_S_IFIFO) && !defined (S_IFIFO) +#define S_IFIFO _S_IFIFO +#endif +#if defined (_S_IFCHR) && !defined (S_IFCHR) +#define S_IFCHR _S_IFCHR +#endif +#if defined (_S_IFDIR) && !defined (S_IFDIR) +#define S_IFDIR _S_IFDIR +#endif +#if defined (_S_IFBLK) && !defined (S_IFBLK) +#define S_IFBLK _S_IFBLK +#endif +#if defined (_S_IFREG) && !defined (S_IFREG) +#define S_IFREG _S_IFREG +#endif +#if defined (_S_IFLNK) && !defined (S_IFLNK) +#define S_IFLNK _S_IFLNK +#endif +#if defined (_S_IFSOCK) && !defined (S_IFSOCK) +#define S_IFSOCK _S_IFSOCK +#endif + +/* Test for each symbol individually and define the ones necessary (some + systems claiming Posix compatibility define some but not all). */ + +#if defined (S_IFBLK) && !defined (S_ISBLK) +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */ +#endif + +#if defined (S_IFCHR) && !defined (S_ISCHR) +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */ +#endif + +#if defined (S_IFDIR) && !defined (S_ISDIR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */ +#endif + +#if defined (S_IFREG) && !defined (S_ISREG) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */ +#endif + +#if defined (S_IFIFO) && !defined (S_ISFIFO) +#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */ +#endif + +#if defined (S_IFLNK) && !defined (S_ISLNK) +#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */ +#endif + +#if defined (S_IFSOCK) && !defined (S_ISSOCK) +#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */ +#endif + +/* + * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes + */ + +#if !defined (S_IRWXU) +# if !defined (S_IREAD) +# define S_IREAD 00400 +# define S_IWRITE 00200 +# define S_IEXEC 00100 +# endif /* S_IREAD */ + +# if !defined (S_IRUSR) +# define S_IRUSR S_IREAD /* read, owner */ +# define S_IWUSR S_IWRITE /* write, owner */ +# define S_IXUSR S_IEXEC /* execute, owner */ + +# define S_IRGRP (S_IREAD >> 3) /* read, group */ +# define S_IWGRP (S_IWRITE >> 3) /* write, group */ +# define S_IXGRP (S_IEXEC >> 3) /* execute, group */ + +# define S_IROTH (S_IREAD >> 6) /* read, other */ +# define S_IWOTH (S_IWRITE >> 6) /* write, other */ +# define S_IXOTH (S_IEXEC >> 6) /* execute, other */ +# endif /* !S_IRUSR */ + +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif /* !S_IRWXU */ + +/* These are non-standard, but are used in builtins.c$symbolic_umask() */ +#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) +#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) + +#endif /* _POSIXSTAT_H */ diff --git a/lib/posixheaders/stdc.h b/lib/posixheaders/stdc.h new file mode 100644 index 0000000..5dcc32b --- /dev/null +++ b/lib/posixheaders/stdc.h @@ -0,0 +1,78 @@ +/* stdc.h -- macros to make source compile on both ANSI C and K&R C + compilers. */ + +/* 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 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 (__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) +# define __P(protos) protos +# endif +# define __STRING(x) #x + +# if !defined (__GNUC__) +# define inline +# endif + +#else /* !__STDC__ */ + +# if !defined (__P) +# define __P(protos) () +# endif +# define __STRING(x) "x" + +#if defined (__GNUC__) /* gcc with -traditional */ +# if !defined (const) +# define const __const +# endif +# if !defined (inline) +# define inline __inline +# endif +# if !defined (signed) +# define signed __signed +# endif +# if !defined (volatile) +# define volatile __volatile +# endif +#else /* !__GNUC__ */ +# if !defined (const) +# define const +# endif +# if !defined (inline) +# define inline +# endif +# if !defined (signed) +# define signed +# endif +# if !defined (volatile) +# define volatile +# endif +#endif /* !__GNUC__ */ + +#endif /* !__STDC__ */ + +#endif /* !__STDC_H__ */ diff --git a/lib/readline/COPYING b/lib/readline/COPYING new file mode 100644 index 0000000..1bb82d1 --- /dev/null +++ b/lib/readline/COPYING @@ -0,0 +1,257 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 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 +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. + + 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. + + 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 +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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +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. + + 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. + + 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 + 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. + + 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. + + 7. 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 +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 +Foundation. + + 8. 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 +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 +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. 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 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +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 +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 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + 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. + + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + +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 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. + +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: + + 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. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/lib/readline/ChangeLog b/lib/readline/ChangeLog new file mode 100644 index 0000000..1cf0c00 --- /dev/null +++ b/lib/readline/ChangeLog @@ -0,0 +1,403 @@ +Tue Mar 23 14:36:51 1993 Brian Fox (bfox@eos.crseo.ucsb.edu) + + * readline.c (rl_copy): Changed name to rl_copy_text. + +Mon Mar 22 19:16:05 1993 Brian Fox (bfox@eos.crseo.ucsb.edu) + + * dispose_cmd.c, several other files. Declare dispose_xxx () as + "void". + + * builtins/hashcom.h: Make declarations of hashed_filenames be + "extern" to keep the SGI compiler happy. + + * readline.c (rl_initialize_everything): Assign values to + out_stream and in_stream immediately, since + output_character_function () can be called before + readline_internal () is called. + +Tue Dec 8 09:30:56 1992 Brian Fox (bfox@cubit) + + * readline.c (rl_init_terminal) Set PC from BC, not from *buffer. + +Mon Nov 30 09:35:47 1992 Brian Fox (bfox@cubit) + + * readline.c (invoking_keyseqs_in_map, rl_parse_and_bind) Allow + backslash to quote characters, such as backslash, double quote, + and space. Backslash quotes all character indiscriminately. + + * funmap.c (vi_keymap) Fix type in "vi-replace" declaration. + +Fri Nov 20 10:55:05 1992 Brian Fox (bfox@cubit) + + * readline.c (init_terminal_io, rl_prep_terminal): FINALLY! + Declare and use termcap variable `ospeed' when setting up terminal + parameters. + +Thu Oct 8 08:53:07 1992 Brian J. Fox (bfox@helios) + + * Makefile, this directory: Include (as links to the canonical + sources), tilde.c, tilde.h, posixstat.h and xmalloc.c. + +Tue Sep 29 13:07:21 1992 Brian J. Fox (bfox@helios) + + * readline.c (init_terminal_io) Don't set arrow keys if the key + sequences that represent them are already set. + + * readline.c (rl_function_of_keyseq) New function returns the first + function (or macro) found while searching a key sequence. + +Mon Sep 28 00:34:04 1992 Brian J. Fox (bfox@helios) + + * readline.c (LibraryVersion) New static char * contains current + version number. Version is at 2.0. + + * readline.c (rl_complete_internal): Incorporated clean changes + from gilmore (gnu@cygnus.com) to support quoted substrings within + completion functions. + + * readline.c (many locations) Added support for the _GO32_, + whatever that is. Patches supplied by Cygnus, typed in by hand, + with cleanups. + +Sun Aug 16 12:46:24 1992 Brian Fox (bfox@cubit) + + * readline.c (init_terminal_io): Find out the values of the keypad + arrows and bind them to appropriate RL functions if present. + +Mon Aug 10 18:13:24 1992 Brian Fox (bfox@cubit) + + * history.c (stifle_history): A negative argument to stifle + becomes zero. + +Tue Jul 28 09:28:41 1992 Brian Fox (bfox@cubit) + + * readline.c (rl_variable_bind): New local structure describes + booleans by name and address; code in rl_variable_bind () looks at + structure to set simple variables. + + * parens.c (rl_insert_close): New variable rl_blink_matching_paren + is non-zero if we want to blink the matching open when a close is + inserted. If FD_SET is defined, rl_blink_matching_paren defaults + to 1, else 0. If FD_SET is not defined, and + rl_blink_matching_paren is non-zero, the close character(s) are/is + simply inserted. + +Wed Jul 22 20:03:59 1992 Brian Fox (bfox@cubit) + + * history.c, readline.c, vi_mode.c: Cause the functions strchr () + and strrchr () to be used instead of index () and rindex () + throughout the source. + +Mon Jul 13 11:34:07 1992 Brian Fox (bfox@cubit) + + * readline.c: (rl_variable_bind) New variable "meta-flag" if "on" + means force the use of the 8th bit as Meta bit. Internal variable + is called meta_flag. + +Thu Jul 9 10:37:56 1992 Brian Fox (bfox@cubit) + + * history.c (get_history_event) Change INDEX to LOCAL_INDEX. If + compiling for the shell, allow shell metacharacters to separate + history tokens as they would for shell tokens. + +Sat Jul 4 19:29:12 1992 Brian Fox (bfox@cubit) + + * vi_keymap.c: According to Posix, TAB self-inserts instead of + doing completion. + + * vi_mode.c: (rl_vi_yank_arg) Enter VI insert mode after yanking + an arg from the previous line. + + * search.c: New file takes over vi style searching and implements + non-incremental searching the history. + + Makefile: Add search.c and search.o. + + funmap.c: Add names for non-incremental-forward-search-history and + non-incremental-reverse-search-history. + + readline.h: Add extern definitions for non-incremental searching. + + vi_mode.c: Remove old search code; add calls to code in search.c. + +Fri Jul 3 10:36:33 1992 Brian Fox (bfox@cubit) + + * readline.c (rl_delete_horizontal_space); New function deletes + all whitespace surrounding point. + + funmap.c: Add "delete-horizontal-space". + emacs_keymap.c: Put rl_delete_horizontal_space () on M-\. + + * readline.c (rl_set_signals, rl_clear_signals); New function + rl_set_sighandler () is either defined in a Posix way (if + HAVE_POSIX_SIGNALS is defined) or in a BSD way. Function is + called from rl_set_signals () and rl_clear_signals (). + +Fri May 8 12:50:15 1992 Brian Fox (bfox@cubit) + + * readline.c: (readline_default_bindings) Do comparisons with + _POSIX_VDISABLE casted to `unsigned char'. Change tty characters + to be unsigned char. + +Thu Apr 30 12:36:35 1992 Brian Fox (bfox@cubit) + + * readline.c: (rl_getc) Handle "read would block" error on + non-blocking IO streams. + + * readline.c: (rl_signal_handler): Unblock only the signal that we + have caught, not all signals. + +Sun Feb 23 03:33:09 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: Many functions. Use only the macros META_CHAR and + UNMETA to deal with meta characters. Prior to this, we used + numeric values and tests. + + * readline.c (rl_complete_internal) Report exactly the number of + possible completions, not the number + 1. + + * vi_mode.c (rl_do_move) Do not change the cursor position when + using `cw' or `cW'. + + * vi_mode.c (rl_vi_complete) Enter insert mode after completing + with `*' or `\'. + +Fri Feb 21 05:58:18 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_dispatch) Increment rl_key_sequence_length for + meta characters that map onto ESC map. + +Mon Feb 10 01:41:35 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * history.c (history_do_write) Build a buffer of all of the lines + to write and write them in one fell swoop (lower overhead than + calling write () for each line). Suggested by Peter Ho. + + * readline.c: Include hbullx20 as well as hpux for determining + USGr3ness. + + * readline.c (rl_unix_word_rubout) As per the "Now REMEMBER" + comment, pass arguments to rl_kill_text () in the correct order to + preserve prepending and appending of killed text. + + * readline.c (rl_search_history) malloc (), realloc (), and free + () SEARCH_STRING so that there are no static limits on searching. + + * vi_mode.c (rl_vi_subst) Don't forget to end the undo group. + +Fri Jan 31 14:51:02 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_signal_handler): Zero the current history entry's + pointer after freeing the undo_list when SIGINT received. + Reformat a couple of functions. + +Sat Jan 25 13:47:35 1992 Brian Fox (bfox at bears) + + * readline.c (parser_if): free () TNAME after use. + +Tue Jan 21 01:01:35 1992 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_redisplay) and (rl_character_len): Display + Control characters as "^c" and Meta characters as "\234", instead + of "C-C" and "M-C". + +Sun Dec 29 10:59:00 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (init_terminal_io) Default to environment variables + LINES and COLUMNS before termcap entry values. If all else fails, + then assume 80x24 terminal. + +Sat Dec 28 16:33:11 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: If this machine is USG and it is hpux, then define + USGr3. + + * history.c: Cosmetic fixes. + +Thu Nov 21 00:10:12 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * vi_mode.c: (rl_do_move) Place cursor at end of line, never at + next to last character. + +Thu Nov 14 05:08:01 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * history.c (get_history_event) Non-anchored searches can have a + return index of greater than zero from get_history_event (). + +Fri Nov 1 07:02:13 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_translate_keyseq) Make C-? translate to RUBOUT + unconditionally. + +Mon Oct 28 11:34:52 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c; Use Posix directory routines and macros. + + * funmap.c; Add entry for call-last-kbd-macro. + + * readline.c (rl_prep_term); Use system EOF character on POSIX + systems also. + +Thu Oct 3 16:19:53 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c; Make a distinction between having a TERMIOS tty + driver, and having POSIX signal handling. You might one without + the other. New defines used HAVE_POSIX_SIGNALS, and + TERMIOS_TTY_DRIVER. + +Tue Jul 30 22:37:26 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: rl_getc () If a call to read () returns without an + error, but with zero characters, the file is empty, so return EOF. + +Thu Jul 11 20:58:38 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: (rl_get_next_history, rl_get_previous_history) + Reallocate the buffer space if the line being moved to is longer + the the current space allocated. Amazing that no one has found + this bug until now. + +Sun Jul 7 02:37:05 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c:(rl_parse_and_bind) Allow leading whitespace. + Make sure TERMIO and TERMIOS systems treat CR and NL + disctinctly. + +Tue Jun 25 04:09:27 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: Rework parsing conditionals to pay attention to the + prior states of the conditional stack. This makes $if statements + work correctly. + +Mon Jun 24 20:45:59 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: support for displaying key binding information + includes the functions rl_list_funmap_names (), + invoking_keyseqs_in_map (), rl_invoking_keyseqs (), + rl_dump_functions (), and rl_function_dumper (). + + funmap.c: support for same includes rl_funmap_names (). + + readline.c, funmap.c: no longer define STATIC_MALLOC. However, + update both version of xrealloc () to handle a null pointer. + +Thu Apr 25 12:03:49 1991 Brian Fox (bfox at gnuwest.fsf.org) + + * vi_mode.c (rl_vi_fword, fWord, etc. All functions use + the macro `isident()'. Fixed movement bug which prevents + continious movement through the text. + +Fri Jul 27 16:47:01 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (parser_if) Allow "$if term=foo" construct. + +Wed May 23 16:10:33 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c (rl_dispatch) Correctly remember the last command + executed. Fixed typo in username_completion_function (). + +Mon Apr 9 19:55:48 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: username_completion_function (); For text passed in + with a leading `~', remember that this could be a filename (after + it is completed). + +Thu Apr 5 13:44:24 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: rl_search_history (): Correctly handle case of an + unfound search string, but a graceful exit (as with ESC). + + * readline.c: rl_restart_output (); The Apollo passes the address + of the file descriptor to TIOCSTART, not the descriptor itself. + +Tue Mar 20 05:38:55 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * readline.c: rl_complete (); second call in a row causes possible + completions to be listed. + + * readline.c: rl_redisplay (), added prompt_this_line variable + which is the first character character following \n in prompt. + +Sun Mar 11 04:32:03 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * Signals are now supposedly handled inside of SYSV compilation. + +Wed Jan 17 19:24:09 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * history.c: history_expand (); fixed overwriting memory error, + added needed argument to call to get_history_event (). + +Thu Jan 11 10:54:04 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * readline.c: added mark_modified_lines to control the + display of an asterisk on modified history lines. Also + added a user variable called mark-modified-lines to the + `set' command. + +Thu Jan 4 10:38:05 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * readline.c: start_insert (). Only use IC if we don't have an im + capability. + +Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel) + + * readline.c: rl_prep_terminal (). Only turn on 8th bit + as meta-bit iff the terminal is not using parity. + +Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel) + + * readline.c: start_insert (). Uses multiple + insertion call in cases where that makes sense. + + rl_insert (). Read type-ahead buffer for additional + keys that are bound to rl_insert, and insert them + all at once. Make insertion of single keys given + with an argument much more efficient. + +Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel) + + * readline.c: Changed handling of EOF. readline () returns + (char *)EOF or consed string. The EOF character is read from the + tty, or if the tty doesn't have one, defaults to C-d. + + * readline.c: Added support for event driven programs. + rl_event_hook is the address of a function you want called + while Readline is waiting for input. + + * readline.c: Cleanup time. Functions without type declarations + do not use return with a value. + + * history.c: history_expand () has new variable which is the + characters to ignore immediately following history_expansion_char. + +Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel) + + * rl_prep_terminal () + BSD version turns off C-s, C-q, C-y, C-v. + + * readline.c -- rl_prep_terminal () + SYSV version hacks readline_echoing_p. + BSD version turns on passing of the 8th bit for the duration + of reading the line. + +Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel) + + * readline.c: new variable rl_tilde_expander. + If non-null, this contains the address of a function to call if + the standard meaning for expanding a tilde fails. The function is + called with the text sans tilde (as in "foo"), and returns a + malloc()'ed string which is the expansion, or a NULL pointer if + there is no expansion. + + * readline.h - new file chardefs.h + Separates things that only readline.c needs from the standard + header file publishing interesting things about readline. + + * readline.c: + readline_default_bindings () now looks at terminal chararacters + and binds those as well. + +Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel) + + * Made readline and history into independent libraries. + diff --git a/lib/readline/Makefile b/lib/readline/Makefile new file mode 100644 index 0000000..b36cab7 --- /dev/null +++ b/lib/readline/Makefile @@ -0,0 +1,134 @@ +## -*- 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/README b/lib/readline/README new file mode 100644 index 0000000..131471c --- /dev/null +++ b/lib/readline/README @@ -0,0 +1,6 @@ +This is the distribution of the Gnu Readline library. See the file +STANDALONE for a description of the #defines that can be passed via +the makefile to build readline on different systems. + +The file rlconf.h contains defines that enable and disable certain +readline features. diff --git a/lib/readline/STANDALONE b/lib/readline/STANDALONE new file mode 100644 index 0000000..c1387f3 --- /dev/null +++ b/lib/readline/STANDALONE @@ -0,0 +1,31 @@ +This is a description of C preprocessor defines that readline accepts. +Most are passed in from the parent `make'; e.g. from the bash source +directory. + +NO_SYS_FILE <sys/file.h> is not present +HAVE_UNISTD_H <unistd.h> exists +HAVE_STDLIB_H <stdlib.h> exists +HAVE_VARARGS_H <varargs.h> exists and is usable +HAVE_STRING_H <string.h> exists +HAVE_ALLOCA_H <alloca.h> exists and is needed for alloca() +HAVE_ALLOCA alloca(3) or a define for it exists +PRAGMA_ALLOCA use of alloca() requires a #pragma, as in AIX 3.x +VOID_SIGHANDLER signal handlers are void functions +HAVE_DIRENT_H <dirent.h> exists and is usable +HAVE_SYS_PTEM_H <sys/ptem.h> exists +HAVE_SYS_PTE_H <sys/pte.h> exists +HAVE_SYS_STREAM_H <sys/stream.h> exists + +System-specific options: + +GWINSZ_IN_SYS_IOCTL need to include <sys/ioctl.h> for TIOCGWINSZ +HAVE_GETPW_DECLS the getpw* functions are declared in <pwd.h> and cannot + be redeclared without compiler errors +HAVE_STRCASECMP the strcasecmp and strncasecmp functions are available + +USG Running a variant of System V +USGr3 Running System V.3 +XENIX_22 Xenix 2.2 +Linux Linux +CRAY running a recent version of Cray UNICOS +SunOS4 Running SunOS 4.x diff --git a/lib/readline/ansi_stdlib.h b/lib/readline/ansi_stdlib.h new file mode 100644 index 0000000..52339da --- /dev/null +++ b/lib/readline/ansi_stdlib.h @@ -0,0 +1,41 @@ +/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */ +/* A minimal stdlib.h containing extern declarations for those functions + that bash uses. */ + +/* 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 (_STDLIB_H_) +#define _STDLIB_H_ 1 + +/* String conversion functions. */ +extern int atoi (); +extern long int atol (); + +/* Memory allocation functions. */ +extern char *malloc (); +extern char *realloc (); +extern void free (); + +/* Other miscellaneous functions. */ +extern void abort (); +extern void exit (); +extern char *getenv (); +extern void qsort (); + +#endif /* _STDLIB_H */ diff --git a/lib/readline/bind.c b/lib/readline/bind.c new file mode 100644 index 0000000..8821599 --- /dev/null +++ b/lib/readline/bind.c @@ -0,0 +1,1487 @@ +/* bind.c -- key binding and startup file support for the readline library. */ + +/* 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 + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#if !defined (NO_SYS_FILE) +# include <sys/file.h> +#endif /* !NO_SYS_FILE */ +#include <signal.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <errno.h> +/* 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" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +extern int _rl_horizontal_scroll_mode; +extern int _rl_mark_modified_lines; +extern int _rl_bell_preference; +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; +#if defined (PAREN_MATCHING) +extern int rl_blink_matching_paren; +#endif /* PAREN_MATCHING */ +#if defined (VISIBLE_STATS) +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_explicit_arg; +extern int rl_editing_mode; +extern unsigned short _rl_parsing_conditionalized_out; +extern Keymap _rl_keymap; + +extern char *possible_control_prefixes[], *possible_meta_prefixes[]; + +extern char **rl_funmap_names (); + +/* Forward declarations */ +void rl_set_keymap_from_edit_mode (); + +static int glean_key_from_name (); + +#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 */ + +/* **************************************************************** */ +/* */ +/* Binding keys */ +/* */ +/* **************************************************************** */ + +/* 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. */ +rl_add_defun (name, function, key) + char *name; + Function *function; + int key; +{ + if (key != -1) + rl_bind_key (key, function); + rl_add_funmap_entry (name, function); + return 0; +} + +/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ +int +rl_bind_key (key, function) + int key; + Function *function; +{ + if (key < 0) + return (key); + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (_rl_keymap[ESC].type == ISKMAP) + { + Keymap escmap; + + escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); + key = UNMETA (key); + escmap[key].type = ISFUNC; + escmap[key].function = function; + return (0); + } + return (key); + } + + _rl_keymap[key].type = ISFUNC; + _rl_keymap[key].function = function; + return (0); +} + +/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid + KEY. */ +int +rl_bind_key_in_map (key, function, map) + int key; + Function *function; + Keymap map; +{ + int result; + Keymap oldmap = _rl_keymap; + + _rl_keymap = map; + result = rl_bind_key (key, function); + _rl_keymap = oldmap; + return (result); +} + +/* Make KEY do nothing in the currently selected keymap. + Returns non-zero in case of error. */ +int +rl_unbind_key (key) + int key; +{ + return (rl_bind_key (key, (Function *)NULL)); +} + +/* Make KEY do nothing in MAP. + Returns non-zero in case of error. */ +int +rl_unbind_key_in_map (key, map) + int key; + Keymap map; +{ + return (rl_bind_key_in_map (key, (Function *)NULL, 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. */ +rl_set_key (keyseq, function, map) + char *keyseq; + Function *function; + Keymap map; +{ + return (rl_generic_bind (ISFUNC, 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. */ +rl_macro_bind (keyseq, macro, map) + char *keyseq, *macro; + Keymap map; +{ + char *macro_keys; + int macro_keys_len; + + macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); + + if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) + { + free (macro_keys); + return -1; + } + rl_generic_bind (ISMACR, keyseq, macro_keys, map); + return 0; +} + +/* Bind the key sequence represented by the string KEYSEQ to + the arbitrary pointer DATA. TYPE says what kind of data is + 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. */ +rl_generic_bind (type, keyseq, data, map) + int type; + char *keyseq, *data; + Keymap map; +{ + char *keys; + int keys_len; + register int i; + + /* If no keys to bind to, exit right away. */ + if (!keyseq || !*keyseq) + { + if (type == ISMACR) + free (data); + return -1; + } + + keys = xmalloc (1 + (2 * strlen (keyseq))); + + /* Translate the ASCII representation of KEYSEQ into an array of + characters. Stuff the characters into KEYS, and the length of + KEYS into KEYS_LEN. */ + if (rl_translate_keyseq (keyseq, keys, &keys_len)) + { + free (keys); + return -1; + } + + /* Bind keys, making new keymaps as necessary. */ + for (i = 0; i < keys_len; i++) + { + int ic = (int) ((unsigned char)keys[i]); + + if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic)) + { + ic = UNMETA (ic); + if (map[ESC].type == ISKMAP) + map = FUNCTION_TO_KEYMAP (map, ESC); + } + + if ((i + 1) < keys_len) + { + if (map[ic].type != ISKMAP) + { + if (map[ic].type == ISMACR) + free ((char *)map[ic].function); + + map[ic].type = ISKMAP; + map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); + } + map = FUNCTION_TO_KEYMAP (map, ic); + } + else + { + if (map[ic].type == ISMACR) + free ((char *)map[ic].function); + + map[ic].function = KEYMAP_TO_FUNCTION (data); + map[ic].type = type; + } + } + free (keys); + return 0; +} + +/* 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. */ +rl_translate_keyseq (seq, array, len) + char *seq, *array; + int *len; +{ + register int i, c, l = 0; + + for (i = 0; c = seq[i]; i++) + { + if (c == '\\') + { + c = seq[++i]; + + if (!c) + break; + + 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])); + if (!seq[i]) + i--; + continue; + } + + switch (c) + { + case 'M': + i++; + array[l++] = ESC; + break; + + case 'C': + i += 2; + /* Special hack for C-?... */ + if (seq[i] == '?') + array[l++] = RUBOUT; + else + array[l++] = CTRL (to_upper (seq[i])); + break; + + case 'e': + array[l++] = ESC; + } + + continue; + } + } + array[l++] = c; + } + + *len = l; + array[l] = '\0'; + return (0); +} + +/* Return a pointer to the function that STRING represents. + If STRING doesn't have a matching function, then a NULL pointer + is returned. */ +Function * +rl_named_function (string) + char *string; +{ + register int i; + + rl_initialize_funmap (); + + for (i = 0; funmap[i]; i++) + if (stricmp (funmap[i]->name, string) == 0) + return (funmap[i]->function); + return ((Function *)NULL); +} + +/* Return the function (or macro) definition which would be invoked via + KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is + used. TYPE, if non-NULL, is a pointer to an int which will receive the + type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap), + or ISMACR (macro). */ +Function * +rl_function_of_keyseq (keyseq, map, type) + char *keyseq; + Keymap map; + int *type; +{ + register int i; + + if (!map) + map = _rl_keymap; + + for (i = 0; keyseq && keyseq[i]; i++) + { + int ic = keyseq[i]; + + if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type != ISKMAP) + { + if (type) + *type = map[ESC].type; + + return (map[ESC].function); + } + else + { + map = FUNCTION_TO_KEYMAP (map, ESC); + ic = UNMETA (ic); + } + } + + if (map[ic].type == ISKMAP) + { + /* If this is the last key in the key sequence, return the + map. */ + if (!keyseq[i + 1]) + { + if (type) + *type = ISKMAP; + + return (map[ic].function); + } + else + map = FUNCTION_TO_KEYMAP (map, ic); + } + else + { + if (type) + *type = map[ic].type; + + return (map[ic].function); + } + } + return ((Function *) NULL); +} + +/* The last key bindings file read. */ +static char *last_readline_init_file = (char *)NULL; + +/* Re-read the current keybindings file. */ +rl_re_read_init_file (count, ignore) + int count, ignore; +{ + int r; + r = rl_read_init_file ((char *)NULL); + rl_set_keymap_from_edit_mode (); + return r; +} + +/* Do key bindings from a file. If FILENAME is NULL it defaults + to the first non-null filename from this list: + 1. the filename used for the previous call + 2. the value of the shell variable `INPUTRC' + 3. ~/.inputrc + If the file existed and could be opened and read, 0 is returned, + otherwise errno is returned. */ +int +rl_read_init_file (filename) + char *filename; +{ + register int i; + char *buffer, *openname, *line, *end; + struct stat finfo; + int file; + + /* Default the filename. */ + if (!filename) + { + filename = last_readline_init_file; + if (!filename) + filename = getenv ("INPUTRC"); + if (!filename) + filename = DEFAULT_INPUTRC; + } + + if (!*filename) + filename = DEFAULT_INPUTRC; + + openname = tilde_expand (filename); + + if ((stat (openname, &finfo) < 0) || + (file = open (openname, O_RDONLY, 0666)) < 0) + { + free (openname); + return (errno); + } + else + free (openname); + + if (filename != last_readline_init_file) + { + if (last_readline_init_file) + free (last_readline_init_file); + + last_readline_init_file = savestring (filename); + } + + /* Read the file into BUFFER. */ + buffer = (char *)xmalloc ((int)finfo.st_size + 1); + i = read (file, buffer, finfo.st_size); + close (file); + + if (i != finfo.st_size) + return (errno); + + /* Loop over the lines in the file. Lines that start with `#' are + comments; all other lines are commands for readline initialization. */ + line = buffer; + end = buffer + finfo.st_size; + while (line < end) + { + /* Find the end of this line. */ + for (i = 0; line + i != end && line[i] != '\n'; i++); + + /* Mark end of line. */ + line[i] = '\0'; + + /* Skip leading whitespace. */ + while (*line && whitespace (*line)) + { + line++; + i--; + } + + /* If the line is not a comment, then parse it. */ + if (*line && *line != '#') + rl_parse_and_bind (line); + + /* Move to the next line. */ + line += i + 1; + } + free (buffer); + return (0); +} + +/* **************************************************************** */ +/* */ +/* Parser Directives */ +/* */ +/* **************************************************************** */ + +/* Conditionals. */ + +/* Calling programs set this to have their argv[0]. */ +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; + +/* Push _rl_parsing_conditionalized_out, and set parser state based + on ARGS. */ +static int +parser_if (args) + char *args; +{ + register int i; + + /* Push parser state. */ + if (if_stack_depth + 1 >= if_stack_size) + { + if (!if_stack) + if_stack = (unsigned char *)xmalloc (if_stack_size = 20); + else + if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); + } + if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out; + + /* If parsing is turned off, then nothing can turn it back on except + for finding the matching endif. In that case, return right now. */ + if (_rl_parsing_conditionalized_out) + return 0; + + /* Isolate first argument. */ + for (i = 0; args[i] && !whitespace (args[i]); i++); + + if (args[i]) + args[i++] = '\0'; + + /* 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) + { + char *tem, *tname; + + /* Terminals like "aaa-60" are equivalent to "aaa". */ + tname = savestring (rl_terminal_name); + tem = strchr (tname, '-'); + if (tem) + *tem = '\0'; + + /* Test the `long' and `short' forms of the terminal name so that + 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; + + free (tname); + } +#if defined (VI_MODE) + else if (strnicmp (args, "mode=", 5) == 0) + { + int mode; + + if (stricmp (args + 5, "emacs") == 0) + mode = emacs_mode; + else if (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; + } +#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) + _rl_parsing_conditionalized_out = 0; + else + _rl_parsing_conditionalized_out = 1; + return 0; +} + +/* Invert the current parser state if there is anything on the stack. */ +static int +parser_else (args) + char *args; +{ + register int i; + + if (!if_stack_depth) + { + /* Error message? */ + return 0; + } + + /* Check the previous (n - 1) levels of the stack to make sure that + we haven't previously turned off parsing. */ + for (i = 0; i < if_stack_depth - 1; i++) + if (if_stack[i] == 1) + return 0; + + /* Invert the state of parsing if at top level. */ + _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out; + return 0; +} + +/* Terminate a conditional, popping the value of + _rl_parsing_conditionalized_out from the stack. */ +static int +parser_endif (args) + char *args; +{ + if (if_stack_depth) + _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; + else + { + /* *** What, no error message? *** */ + } + return 0; +} + +/* Associate textual names with actual functions. */ +static struct { + char *name; + Function *function; +} parser_directives [] = { + { "if", parser_if }, + { "endif", parser_endif }, + { "else", parser_else }, + { (char *)0x0, (Function *)0x0 } +}; + +/* Handle a parser directive. STATEMENT is the line of the directive + without any leading `$'. */ +static int +handle_parser_directive (statement) + char *statement; +{ + register int i; + char *directive, *args; + + /* Isolate the actual directive. */ + + /* Skip whitespace. */ + for (i = 0; whitespace (statement[i]); i++); + + directive = &statement[i]; + + for (; statement[i] && !whitespace (statement[i]); i++); + + if (statement[i]) + statement[i++] = '\0'; + + for (; statement[i] && whitespace (statement[i]); i++); + + args = &statement[i]; + + /* Lookup the command, and act on it. */ + for (i = 0; parser_directives[i].name; i++) + if (stricmp (directive, parser_directives[i].name) == 0) + { + (*parser_directives[i].function) (args); + return (0); + } + + /* *** Should an error message be output? */ + 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. */ +rl_parse_and_bind (string) + char *string; +{ + char *funname, *kname; + register int c, i; + int key, equivalency; + + while (string && whitespace (*string)) + string++; + + if (!string || !*string || *string == '#') + return 0; + + /* If this is a parser directive, act on it. */ + if (*string == '$') + { + handle_parser_directive (&string[1]); + return 0; + } + + /* If we aren't supposed to be parsing right now, then we're done. */ + if (_rl_parsing_conditionalized_out) + return 0; + + i = 0; + /* If this keyname is a complex key expression surrounded by quotes, + advance to after the matching close quote. This code allows the + backslash to quote characters in the key expression. */ + if (*string == '"') + { + int passc = 0; + + for (i = 1; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc++; + continue; + } + + if (c == '"') + break; + } + } + + /* Advance to the colon (:) or whitespace which separates the two objects. */ + for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); + + equivalency = (c == ':' && string[i + 1] == '='); + + /* Mark the end of the command (or keyname). */ + if (string[i]) + string[i++] = '\0'; + + /* If doing assignment, skip the '=' sign as well. */ + if (equivalency) + string[i++] = '\0'; + + /* If this is a command to set a variable, then do that. */ + if (stricmp (string, "set") == 0) + { + char *var = string + i; + char *value; + + /* Make VAR point to start of variable name. */ + while (*var && whitespace (*var)) var++; + + /* Make value point to start of value string. */ + value = var; + while (*value && !whitespace (*value)) value++; + if (*value) + *value++ = '\0'; + while (*value && whitespace (*value)) value++; + + rl_variable_bind (var, value); + return 0; + } + + /* Skip any whitespace between keyname and funname. */ + for (; string[i] && whitespace (string[i]); i++); + funname = &string[i]; + + /* Now isolate funname. + For straight function names just look for whitespace, since + that will signify the end of the string. But this could be a + macro definition. In that case, the string is quoted, so skip + to the matching delimiter. We allow the backslash to quote the + delimiter characters in the macro body. */ + /* This code exists to allow whitespace in macro expansions, which + would otherwise be gobbled up by the next `for' loop.*/ + /* XXX - it may be desirable to allow backslash quoting only if " is + the quoted string delimiter, like the shell. */ + if (*funname == '\'' || *funname == '"') + { + int delimiter = string[i++]; + int passc = 0; + + for (; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc = 1; + continue; + } + + if (c == delimiter) + break; + } + if (c) + i++; + } + + /* Advance to the end of the string. */ + for (; string[i] && !whitespace (string[i]); i++); + + /* No extra whitespace at the end of the string. */ + string[i] = '\0'; + + /* Handle equivalency bindings here. Make the left-hand side be exactly + whatever the right-hand evaluates to, including keymaps. */ + if (equivalency) + { + return 0; + } + + /* If this is a new-style key-binding, then do the binding with + rl_set_key (). Otherwise, let the older code deal with it. */ + if (*string == '"') + { + char *seq = xmalloc (1 + strlen (string)); + register int j, k = 0; + int passc = 0; + + for (j = 1; string[j]; j++) + { + /* Allow backslash to quote characters, but leave them in place. + This allows a string to end with a backslash quoting another + backslash, or with a backslash quoting a double quote. The + backslashes are left in place for rl_translate_keyseq (). */ + if (passc || (string[j] == '\\')) + { + seq[k++] = string[j]; + passc = !passc; + continue; + } + + if (string[j] == '"') + break; + + seq[k++] = string[j]; + } + seq[k] = '\0'; + + /* Binding macro? */ + if (*funname == '\'' || *funname == '"') + { + j = strlen (funname); + + /* Remove the delimiting quotes from each end of FUNNAME. */ + if (j && funname[j - 1] == *funname) + funname[j - 1] = '\0'; + + rl_macro_bind (seq, &funname[1], _rl_keymap); + } + else + rl_set_key (seq, rl_named_function (funname), _rl_keymap); + + free (seq); + return 0; + } + + /* Get the actual character we want to deal with. */ + kname = strrchr (string, '-'); + if (!kname) + kname = string; + else + kname++; + + key = glean_key_from_name (kname); + + /* Add in control and meta bits. */ + if (substring_member_of_array (string, possible_control_prefixes)) + key = CTRL (to_upper (key)); + + if (substring_member_of_array (string, possible_meta_prefixes)) + key = META (key); + + /* Temporary. Handle old-style keyname with macro-binding. */ + if (*funname == '\'' || *funname == '"') + { + char seq[2]; + int fl = strlen (funname); + + seq[0] = key; seq[1] = '\0'; + if (fl && funname[fl - 1] == *funname) + funname[fl - 1] = '\0'; + + rl_macro_bind (seq, &funname[1], _rl_keymap); + } +#if defined (PREFIX_META_HACK) + /* Ugly, but working hack to keep prefix-meta around. */ + else if (stricmp (funname, "prefix-meta") == 0) + { + char seq[2]; + + seq[0] = key; + seq[1] = '\0'; + rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap); + } +#endif /* PREFIX_META_HACK */ + else + rl_bind_key (key, rl_named_function (funname)); + return 0; +} + +/* Simple structure for boolean readline variables (i.e., those that can + have one of two values; either "On" or 1 for truth, or "Off" or 0 for + false. */ + +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 }, + { "output-meta", &_rl_output_meta_chars }, +#if defined (VISIBLE_STATS) + { "visible-stats", &rl_visible_stats }, +#endif /* VISIBLE_STATS */ + { "expand-tilde", &rl_complete_with_tilde_expansion }, + { (char *)NULL, (int *)NULL } +}; + +rl_variable_bind (name, value) + char *name, *value; +{ + register int i; + + /* Check for simple variables first. */ + for (i = 0; boolean_varlist[i].name; i++) + { + if (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; + return 0; + } + } + + /* Not a boolean variable, so check for specials. */ + + /* Editing mode change? */ + if (stricmp (name, "editing-mode") == 0) + { + if (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) + { + _rl_keymap = emacs_standard_keymap; + rl_editing_mode = emacs_mode; + } + } + + /* Comment string change? */ + else if (stricmp (name, "comment-begin") == 0) + { +#if defined (VI_MODE) + if (*value) + { + if (rl_vi_comment_begin) + free (rl_vi_comment_begin); + + rl_vi_comment_begin = savestring (value); + } +#endif /* VI_MODE */ + } + else if (stricmp (name, "completion-query-items") == 0) + { + int nval = 100; + if (*value) + { + nval = atoi (value); + if (nval < 0) + nval = 0; + } + rl_completion_query_items = nval; + } + else if (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) + { + if (!*value) + _rl_bell_preference = AUDIBLE_BELL; + else + { + if (stricmp (value, "none") == 0 || stricmp (value, "off") == 0) + _rl_bell_preference = NO_BELL; + else if (stricmp (value, "audible") == 0 || stricmp (value, "on") == 0) + _rl_bell_preference = AUDIBLE_BELL; + else if (stricmp (value, "visible") == 0) + _rl_bell_preference = VISIBLE_BELL; + } + } + else if (stricmp (name, "prefer-visible-bell") == 0) + { + /* Backwards compatibility. */ + if (*value && (stricmp (value, "on") == 0 || + (*value == '1' && !value[1]))) + _rl_bell_preference = VISIBLE_BELL; + else + _rl_bell_preference = AUDIBLE_BELL; + } + + return 0; +} + +/* Return the character which matches NAME. + For example, `Space' returns ' '. */ + +typedef struct { + char *name; + int value; +} assoc_list; + +static assoc_list name_key_alist[] = { + { "DEL", 0x7f }, + { "ESC", '\033' }, + { "Escape", '\033' }, + { "LFD", '\n' }, + { "Newline", '\n' }, + { "RET", '\r' }, + { "Return", '\r' }, + { "Rubout", 0x7f }, + { "SPC", ' ' }, + { "Space", ' ' }, + { "Tab", 0x09 }, + { (char *)0x0, 0 } +}; + +static int +glean_key_from_name (name) + char *name; +{ + register int i; + + for (i = 0; name_key_alist[i].name; i++) + if (stricmp (name, name_key_alist[i].name) == 0) + return (name_key_alist[i].value); + + return (*(unsigned char *)name); /* XXX was return (*name) */ +} + +/* Auxiliary functions to manage keymaps. */ +static struct { + char *name; + Keymap map; +} keymap_names[] = { + { "emacs", emacs_standard_keymap }, + { "emacs-standard", emacs_standard_keymap }, + { "emacs-meta", emacs_meta_keymap }, + { "emacs-ctlx", emacs_ctlx_keymap }, +#if defined (VI_MODE) + { "vi", vi_movement_keymap }, + { "vi-move", vi_movement_keymap }, + { "vi-command", vi_movement_keymap }, + { "vi-insert", vi_insertion_keymap }, +#endif /* VI_MODE */ + { (char *)0x0, (Keymap)0x0 } +}; + +Keymap +rl_get_keymap_by_name (name) + char *name; +{ + register int i; + + for (i = 0; keymap_names[i].name; i++) + if (strcmp (name, keymap_names[i].name) == 0) + return (keymap_names[i].map); + return ((Keymap) NULL); +} + +void +rl_set_keymap (map) + Keymap map; +{ + if (map) + _rl_keymap = map; +} + +Keymap +rl_get_keymap () +{ + return (_rl_keymap); +} + +void +rl_set_keymap_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + _rl_keymap = emacs_standard_keymap; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + _rl_keymap = vi_insertion_keymap; +#endif /* VI_MODE */ +} + +/* **************************************************************** */ +/* */ +/* Key Binding and Function Information */ +/* */ +/* **************************************************************** */ + +/* Each of the following functions produces information about the + state of keybindings and functions known to Readline. The info + is always printed to rl_outstream, and in such a way that it can + be read back in (i.e., passed to rl_parse_and_bind (). */ + +/* Print the names of functions known to Readline. */ +void +rl_list_funmap_names (count, ignore) + int count, ignore; +{ + register int i; + char **funmap_names; + + funmap_names = rl_funmap_names (); + + if (!funmap_names) + return; + + for (i = 0; funmap_names[i]; i++) + fprintf (rl_outstream, "%s\n", funmap_names[i]); + + free (funmap_names); +} + +/* Return a NULL terminated array of strings which represent the key + sequences that are used to invoke FUNCTION in MAP. */ +char ** +rl_invoking_keyseqs_in_map (function, map) + Function *function; + Keymap map; +{ + register int key; + char **result; + int result_index, result_size; + + result = (char **)NULL; + result_index = result_size = 0; + + for (key = 0; key < 128; key++) + { + switch (map[key].type) + { + case ISMACR: + /* Macros match, if, and only if, the pointers are identical. + Thus, they are treated exactly like functions in here. */ + case ISFUNC: + /* If the function in the keymap is the one we are looking for, + then add the current KEY to the list of invoking keys. */ + if (map[key].function == function) + { + char *keyname = (char *)xmalloc (5); + + 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'; + } + + if (result_index + 2 > result_size) + result = (char **) xrealloc + (result, (result_size += 10) * sizeof (char *)); + + result[result_index++] = keyname; + result[result_index] = (char *)NULL; + } + break; + + case ISKMAP: + { + char **seqs = (char **)NULL; + + /* 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)); + + if (seqs) + { + register int i; + + for (i = 0; seqs[i]; i++) + { + 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; + } + + free (seqs); + } + } + break; + } + } + return (result); +} + +/* Return a NULL terminated array of strings which represent the key + sequences that can be used to invoke FUNCTION using the current keymap. */ +char ** +rl_invoking_keyseqs (function) + Function *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. */ +void +rl_function_dumper (print_readably) + int print_readably; +{ + register int i; + char **names; + char *name; + + names = rl_funmap_names (); + + fprintf (rl_outstream, "\n"); + + for (i = 0; name = names[i]; i++) + { + Function *function; + char **invokers; + + function = rl_named_function (name); + invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap); + + if (print_readably) + { + if (!invokers) + fprintf (rl_outstream, "# %s (not bound)\n", name); + else + { + register int j; + + for (j = 0; invokers[j]; j++) + { + fprintf (rl_outstream, "\"%s\": %s\n", + invokers[j], name); + free (invokers[j]); + } + + free (invokers); + } + } + else + { + if (!invokers) + fprintf (rl_outstream, "%s is not bound to any keys\n", + name); + else + { + register int j; + + fprintf (rl_outstream, "%s can be found on ", name); + + for (j = 0; invokers[j] && j < 5; j++) + { + fprintf (rl_outstream, "\"%s\"%s", invokers[j], + invokers[j + 1] ? ", " : ".\n"); + } + + if (j == 5 && invokers[j]) + fprintf (rl_outstream, "...\n"); + + for (j = 0; invokers[j]; j++) + free (invokers[j]); + + free (invokers); + } + } + } +} + +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */ +void +_rl_bind_if_unbound (keyseq, default_func) + char *keyseq; + Function *default_func; +{ + Function *func; + + if (keyseq) + { + func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL); + if (!func || func == rl_do_lowercase_version) + rl_set_key (keyseq, default_func, _rl_keymap); + } +} + +/* **************************************************************** */ +/* */ +/* 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) + char *string, **array; +{ + while (*array) + { + if (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/chardefs.h b/lib/readline/chardefs.h new file mode 100644 index 0000000..8c92811 --- /dev/null +++ b/lib/readline/chardefs.h @@ -0,0 +1,122 @@ +/* chardefs.h -- Character definitions 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. */ + +#ifndef _CHARDEFS_H +#define _CHARDEFS_H + +#include <ctype.h> + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* HAVE_STRING_H */ + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifdef CTRL +#undef CTRL +#endif + +/* Some character stuff. */ +#define control_character_threshold 0x020 /* Smaller than this is control. */ +#define control_character_mask 0x1f /* 0x20 - 1 */ +#define meta_character_threshold 0x07f /* Larger than this is Meta. */ +#define control_character_bit 0x40 /* 0x000000, must be off. */ +#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 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)) + +/* 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 lowercase_p(c) (islower(c)) +#define uppercase_p(c) (isupper(c)) +#define digit_p(x) (isdigit (x)) + +#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c)) + +/* Old versions +# define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c)) +# define to_lower(c) (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)) +#endif + +#ifndef digit_value +#define digit_value(x) ((x) - '0') +#endif + +#ifndef NEWLINE +#define NEWLINE '\n' +#endif + +#ifndef RETURN +#define RETURN CTRL('M') +#endif + +#ifndef RUBOUT +#define RUBOUT 0x7f +#endif + +#ifndef TAB +#define TAB '\t' +#endif + +#ifdef ABORT_CHAR +#undef ABORT_CHAR +#endif +#define ABORT_CHAR CTRL('G') + +#ifdef PAGE +#undef PAGE +#endif +#define PAGE CTRL('L') + +#ifdef SPACE +#undef SPACE +#endif +#define SPACE ' ' /* XXX - was 0x20 */ + +#ifdef ESC +#undef ESC +#endif + +#define ESC CTRL('[') + +#endif /* _CHARDEFS_H */ diff --git a/lib/readline/complete.c b/lib/readline/complete.c new file mode 100644 index 0000000..f219877 --- /dev/null +++ b/lib/readline/complete.c @@ -0,0 +1,1459 @@ +/* complete.c -- filename completion for readline. */ + +/* 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 "config.h" +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#if !defined (NO_SYS_FILE) +# include <sys/file.h> +#endif /* !NO_SYS_FILE */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <errno.h> +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include <pwd.h> +#if defined (USG) && !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwent (); +#endif /* USG && !HAVE_GETPW_DECLS */ + +/* ISC systems don't define getpwent() if _POSIX_SOURCE is defined. */ +#if defined (isc386) && defined (_POSIX_SOURCE) +# if defined (__STDC__) +extern struct passwd *getpwent (void); +# else +extern struct passwd *getpwent (); +# endif /* !__STDC__ */ +#endif /* isc386 && _POSIX_SOURCE */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* 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 Function *rl_last_func; +extern int rl_editing_mode; +extern int screenwidth; + +/* Forward declarations for functions defined and used in this file. */ +char *filename_completion_function (); +char **completion_matches (); + +static int compare_strings (); +static char *rl_strpbrk (); + +#if defined (STATIC_MALLOC) +static char *xmalloc (), *xrealloc (); +#else +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. */ +Function *rl_directory_completion_hook = (Function *)NULL; + +/* Non-zero means readline completion functions perform tilde expansion. */ +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 defined (VISIBLE_STATS) +# if !defined (X_OK) +# define X_OK 1 +# endif + +static int stat_char (); + +/* Non-zero means add an additional character to each filename displayed + during listing completion iff rl_filename_completion_desired which helps + to indicate the type of file being listed. */ +int rl_visible_stats = 0; +#endif /* VISIBLE_STATS */ + +/* **************************************************************** */ +/* */ +/* Completion matching, from readline's point of view. */ +/* */ +/* **************************************************************** */ + +/* Pointer to the generator function for completion_matches (). + NULL means to use filename_entry_function (), the default filename + completer. */ +Function *rl_completion_entry_function = (Function *)NULL; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +CPPFunction *rl_attempted_completion_function = (CPPFunction *)NULL; + +/* Non-zero means to suppress normal filename completion after the + 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 (); + } +} + +/* Up to this many items will be displayed in response to a + possible-completions call. After that, we ask the user if + she is sure she wants to see them all. */ +int rl_completion_query_items = 100; + +/* The basic list of characters that signal a break between words for the + completer routine. The contents of this variable is what breaks words + in the shell, i.e. " \t\n\"\\'`@$><=" */ +char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; + +/* 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. */ +char *rl_completer_word_break_characters = (char *)NULL; + +/* 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. */ +char *rl_completer_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. */ +char *rl_special_prefixes = (char *)NULL; + +/* If non-zero, then disallow duplicates in the matches. */ +int rl_ignore_completion_duplicates = 1; + +/* 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. */ +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 + ALWAYS non-zero on entry, and can only be changed within a completion + entry finder function. */ +int rl_filename_quoting_desired = 1; + +/* This function, if defined, is called by the completer when real + filename completion is done, after all the matching names have been + generated. It is passed a (char**) known as matches in the code below. + It consists of a NULL-terminated array of pointers to potential + matching strings. The 1st element (matches[0]) is the maximal + substring that is common to all matches. This function can re-arrange + the list of matches as required, but all elements of the array must be + free()'d if they are deleted. The main intent of this function is + 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; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = xmalloc (l + 1); + for (quoted = 0, p = text, r = ret; p && *p; p++) + { + /* 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; + } + *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 + are only interested in the basename, the portion following the + final slash. Otherwise, we return what we were passed. */ +static char * +printable_part (pathname) + char *pathname; +{ + char *temp = (char *)NULL; + + if (rl_filename_completion_desired) + temp = strrchr (pathname, '/'); + + if (!temp) + return (pathname); + else + return (++temp); +} + +/* 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)) \ + { \ + putc ('^', rl_outstream); \ + putc (UNCTRL (c), rl_outstream); \ + } \ + else if (c == RUBOUT) \ + { \ + putc ('^', rl_outstream); \ + putc ('?', rl_outstream); \ + } \ + else \ + putc (c, rl_outstream) + +static int +print_filename (to_print, full_pathname) + char *to_print, *full_pathname; +{ +#if !defined (VISIBLE_STATS) + char *s; + + for (s = to_print; *s; s++) + { + PUTX (*s); + } + return 0; +#else + char *s, c, *new_full_pathname; + int extension_char = 0, slen, tlen; + + for (s = to_print; *s; s++) + { + PUTX (*s); + } + + 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 + name before checking for the stat character. */ + if (to_print != full_pathname) + { + /* Terminate the directory name. */ + c = to_print[-1]; + to_print[-1] = '\0'; + + s = tilde_expand (full_pathname); + if (rl_directory_completion_hook) + (*rl_directory_completion_hook) (&s); + + slen = strlen (s); + tlen = strlen (to_print); + new_full_pathname = xmalloc (slen + tlen + 2); + strcpy (new_full_pathname, s); + new_full_pathname[slen] = '/'; + strcpy (new_full_pathname + slen + 1, to_print); + + extension_char = stat_char (new_full_pathname); + + free (new_full_pathname); + to_print[-1] = c; + } + else + { + s = tilde_expand (full_pathname); + extension_char = stat_char (s); + } + + free (s); + if (extension_char) + putc (extension_char, rl_outstream); + return (extension_char != 0); + } + else + return 0; +#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; +{ + 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; + + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + + /* We now look backwards for the start of a filename/variable word. */ + end = rl_point; + + if (rl_point) + { + 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++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + + if (rl_line_buffer[scan] == '\\') + { + pass_next = 1; + found_quote |= 4; + 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])) + { + /* 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; + } + } + } + + if (rl_point == end && quote_char == '\0') + { + 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]; + + 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; + } + } + + /* 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++; + } + } + + /* 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 the user wants to TRY to complete, but then wants to give + up and use the default completion function, they set the + variable rl_attempted_completion_function. */ + if (rl_attempted_completion_function) + { + matches = (*rl_attempted_completion_function) (text, start, end); + + if (matches || rl_attempted_completion_over) + { + rl_attempted_completion_over = 0; + our_func = (Function *)NULL; + goto after_usual_completion; + } + } + +#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) + { + /* delete single and double quotes */ + replacement = _delete_quotes (text); + free (text); + text = replacement; + replacement = (char *)0; + } +#endif /* SHELL */ + + matches = completion_matches (text, our_func); + + after_usual_completion: + free (text); + + if (!matches) + ding (); + else + { + register int i; + int should_quote; + + /* 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) + { + 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); + + /* Remember the lowest common denominator for it may be unique. */ + lowest_common = savestring (matches[0]); + + 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++; + } + + /* 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; + + if (matches[0] != (char *)&dead_slot) + free (matches[0]); + free (matches); + + matches = temp_array; + + /* Place the lowest common denominator back in [0]. */ + matches[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 (matches[0], matches[1]) == 0) + { + free (matches[1]); + matches[1] = (char *)NULL; + } + } + + switch (what_to_do) + { + 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) + { + (void)(*rl_ignore_some_completions_function)(matches); + if (matches == 0 || matches[0] == 0) + { + if (matches) + free (matches); + ding (); + return; + } + } + + /* 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 == '"'); +#else + should_quote = should_quote && !quote_char; +#endif + + if (should_quote) + { + int do_replace; + + do_replace = NO_MATCH; + + /* 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; +#if defined (SHELL) + should_quote = should_quote || rl_strpbrk (matches[0], "#$`?*[!") != 0; +#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 (replacement) + { + 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); + } + + /* 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; + + if (quote_char) + temp_string[temp_string_index++] = quote_char; + + temp_string[temp_string_index++] = delimiter ? delimiter : ' '; + temp_string[temp_string_index++] = '\0'; + + 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; + + 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; + + 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; + + default: + fprintf (stderr, "\r\nreadline: bad value for what_to_do in rl_complete\n"); + abort (); + } + + 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) + { + if (strcmp (rl_line_buffer, saved_line_buffer) != 0) + completion_changed_buffer = 1; + else + completion_changed_buffer = 0; + + free (saved_line_buffer); + } + return 0; +} + +#if defined (VISIBLE_STATS) +/* Return the character which best describes FILENAME. + `@' for symbolic links + `/' for directories + `*' for executables + `=' for sockets */ +static int +stat_char (filename) + char *filename; +{ + struct stat finfo; + int character, r; + +#if defined (S_ISLNK) + r = lstat (filename, &finfo); +#else + r = stat (filename, &finfo); +#endif + + if (r == -1) + return (0); + + character = 0; + if (S_ISDIR (finfo.st_mode)) + character = '/'; +#if defined (S_ISLNK) + else if (S_ISLNK (finfo.st_mode)) + character = '@'; +#endif /* S_ISLNK */ +#if defined (S_ISSOCK) + else if (S_ISSOCK (finfo.st_mode)) + character = '='; +#endif /* S_ISSOCK */ + else if (S_ISREG (finfo.st_mode)) + { + if (access (filename, X_OK) == 0) + character = '*'; + } + return (character); +} +#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 `~'). */ +char * +username_completion_function (text, state) + int state; + char *text; +{ +#if defined (__GO32__) + return (char *)NULL; +#else /* !__GO32__ */ + static char *username = (char *)NULL; + static struct passwd *entry; + static int namelen, first_char, first_char_loc; + + if (!state) + { + if (username) + free (username); + + first_char = *text; + + if (first_char == '~') + first_char_loc = 1; + else + first_char_loc = 0; + + username = savestring (&text[first_char_loc]); + namelen = strlen (username); + setpwent (); + } + + 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)) + break; + } + + if (!entry) + { + endpwent (); + return ((char *)NULL); + } + else + { + char *value = xmalloc (2 + strlen (entry->pw_name)); + + *value = *text; + + strcpy (value + first_char_loc, entry->pw_name); + + if (first_char == '~') + rl_filename_completion_desired = 1; + + return (value); + } +#endif /* !__GO32__ */ +} + +/* **************************************************************** */ +/* */ +/* Completion */ +/* */ +/* **************************************************************** */ + +/* Non-zero means that case is not significant in completion. */ +int completion_case_fold = 0; + +/* 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. + The remaining entries are the possible completions. + The array is terminated with a NULL pointer. + + ENTRY_FUNCTION is a function of two args, and returns a (char *). + The first argument is TEXT. + The second is a state argument; it should be zero on the first call, and + non-zero on subsequent calls. It returns a NULL pointer to the caller + when there are no more matches. + */ +char ** +completion_matches (text, entry_function) + char *text; + CPFunction *entry_function; +{ + /* Number of slots in match_list. */ + int match_list_size; + + /* The list of matches. */ + char **match_list = + (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *)); + + /* Number of matches actually found. */ + int matches = 0; + + /* Temporary string binder. */ + char *string; + + match_list[1] = (char *)NULL; + + while (string = (*entry_function) (text, matches)) + { + if (matches + 1 == match_list_size) + match_list = (char **)xrealloc + (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + + match_list[++matches] = string; + match_list[matches + 1] = (char *)NULL; + } + + /* 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'; + } + } + else /* There were no matches. */ + { + free (match_list); + match_list = (char **)NULL; + } + return (match_list); +} + +/* Okay, now we write the entry_function for filename completion. In the + general case. Note that completion in the shell is a little different + because of all the pathnames that must be followed when looking up the + completion for a command. */ +char * +filename_completion_function (text, state) + int state; + char *text; +{ + static DIR *directory; + static char *filename = (char *)NULL; + static char *dirname = (char *)NULL; + static char *users_dirname = (char *)NULL; + static int filename_len; + + struct dirent *entry = (struct dirent *)NULL; + + /* If we don't have any state, then do some initialization. */ + if (!state) + { + char *temp; + + if (dirname) free (dirname); + if (filename) free (filename); + if (users_dirname) free (users_dirname); + + filename = savestring (text); + if (!*text) text = "."; + dirname = savestring (text); + + temp = strrchr (dirname, '/'); + + if (temp) + { + strcpy (filename, ++temp); + *temp = '\0'; + } + else + strcpy (dirname, "."); + + /* 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); + } + } + directory = opendir (dirname); + filename_len = strlen (filename); + + rl_filename_completion_desired = 1; + } + + /* At this point we should entertain the possibility of hacking wildcarded + filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name + contains globbing characters, then build an array of directories, and + then map over that list while completing. */ + /* *** UNIMPLEMENTED *** */ + + /* Now that we have some state, we can read the directory. */ + + while (directory && (entry = readdir (directory))) + { + /* Special case for no filename. + All entries except "." and ".." match. */ + if (!filename_len) + { + if ((strcmp (entry->d_name, ".") != 0) && + (strcmp (entry->d_name, "..") != 0)) + break; + } + else + { + /* Otherwise, if these match up to the length of filename, then + it is a match. */ + if ((entry->d_name[0] == filename[0]) && + (((int)D_NAMLEN (entry)) >= filename_len) && + (strncmp (filename, entry->d_name, filename_len) == 0)) + break; + } + } + + if (!entry) + { + if (directory) + { + closedir (directory); + directory = (DIR *)NULL; + } + if (dirname) + { + free (dirname); + dirname = (char *)NULL; + } + if (filename) + { + free (filename); + filename = (char *)NULL; + } + if (users_dirname) + { + free (users_dirname); + users_dirname = (char *)NULL; + } + + return (char *)NULL; + } + 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); + temp = xmalloc (2 + dirlen + D_NAMLEN (entry)); + strcpy (temp, dirname); + /* Canonicalization cuts off any final slash present. We need + to add it back. */ + if (dirname[dirlen - 1] != '/') + { + temp[dirlen] = '/'; + temp[dirlen + 1] = '\0'; + } + } + else + { + temp = xmalloc (1 + strlen (users_dirname) + D_NAMLEN (entry)); + strcpy (temp, users_dirname); + } + + strcat (temp, entry->d_name); + } + else + temp = (savestring (entry->d_name)); + + return (temp); + } +} + +/* A function for simple tilde expansion. */ +int +rl_tilde_expand (ignore, key) + int ignore, key; +{ + register int start, end; + char *homedir; + + end = rl_point; + start = end - 1; + + if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') + { + homedir = tilde_expand ("~"); + goto insert; + } + else if (rl_line_buffer[start] != '~') + { + for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--); + start++; + } + + end = start; + do + { + end++; + } + while (!whitespace (rl_line_buffer[end]) && end < rl_end); + + if (whitespace (rl_line_buffer[end]) || end >= rl_end) + end--; + + /* If the first character of the current word is a tilde, perform + tilde expansion and insert the result. If not a tilde, do + 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); + temp[len] = '\0'; + 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 (); + } + + return (0); +} + +/* Find the first occurrence in STRING1 of any character from STRING2. + Return a pointer to the character in STRING1. */ +static char * +rl_strpbrk (string1, string2) + char *string1, *string2; +{ + register char *scan; + + for (; *string1; string1++) + { + for (scan = string2; *scan; scan++) + { + if (*string1 == *scan) + { + return (string1); + } + } + } + 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 new file mode 100644 index 0000000..daf736c --- /dev/null +++ b/lib/readline/display.c @@ -0,0 +1,1276 @@ +/* display.c -- readline redisplay facility. */ + +/* 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 "config.h" +#endif + +#include <stdio.h> +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +/* Global and pseudo-global variables and functions + 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; + +/* Pseudo-global functions (local to the readline library) exported + by this file. */ +void _rl_move_cursor_relative (), _rl_output_some_chars (); +void _rl_move_vert (); + +static void update_line (), clear_to_eol (), space_to_eol (); +static void delete_chars (), insert_some_chars (); + +extern char *xmalloc (), *xrealloc (); + +/* Heuristic used to decide whether it is faster to move from CUR to NEW + by backing up or outputting a carriage return and moving forward. */ +#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) + +/* **************************************************************** */ +/* */ +/* Display stuff */ +/* */ +/* **************************************************************** */ + +/* This is the stuff that is hard for me. I never seem to write good + display routines in C. Let's see how I do this time. */ + +/* (PWP) Well... Good for a simple line updater, but totally ignores + the problems of input lines longer than the screen width. + + update_line and the code that calls it makes a multiple line, + automatically wrapping line update. Careful attention needs + to be paid to the vertical position variables. */ + +/* Keep two buffers; one which reflects the current contents of the + screen, and the other to draw what we think the new contents should + be. Then compare the buffers, and make whatever changes to the + screen itself that we should. Finally, make the buffer that we + just drew into be the one which reflects the current contents of the + screen, and place the cursor where it belongs. + + Commands that want to can fix the display themselves, and then let + this function know that the display has been fixed by setting the + RL_DISPLAY_FIXED variable. This is good for efficiency. */ + +/* Global variables declared here. */ +/* What YOU turn on when you have handled all redisplay yourself. */ +int rl_display_fixed = 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; + +/* Pseudo-global variables declared here. */ +/* The visible cursor position. If you print some text, adjust this. */ +int _rl_last_c_pos = 0; +int _rl_last_v_pos = 0; + +/* Number of lines currently on screen minus 1. */ +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; + +/* The line display buffers. One is the line currently displayed on + the screen. The other is the line about to be displayed. */ +static char *visible_line = (char *)NULL; +static char *invisible_line = (char *)NULL; + +/* A buffer for `modeline' messages. */ +static char msg_buf[128]; + +/* Non-zero forces the redisplay even if we thought it was unnecessary. */ +static int forced_display = 0; + +/* 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; + +/* 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; + +/* 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. */ + +/* Current implementation: + \001 (^A) start non-visible characters + \002 (^B) end non-visible characters + all characters except \001 and \002 (following a \001) are copied to + the returned string; all characters except those between \001 and + \002 are assumed to be `visible'. */ + +static char * +expand_prompt (pmt, lp) + char *pmt; + int *lp; +{ + char *r, *ret, *p; + int l, rl, ignoring; + + /* Short-circuit if we can. */ + if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0) + { + r = savestring (pmt); + if (lp) + *lp = strlen (r); + return r; + } + + l = pmt ? strlen (pmt) : 0; + r = ret = xmalloc (l + 1); + + for (rl = ignoring = 0, p = pmt; p && *p; p++) + { + /* This code strips the invisible character string markers + RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ + if (*p == RL_PROMPT_START_IGNORE) + { + ignoring++; + continue; + } + else if (ignoring && *p == RL_PROMPT_END_IGNORE) + { + ignoring = 0; + continue; + } + else + { + *r++ = *p; + if (!ignoring) + rl++; + } + } + + *r = '\0'; + if (lp) + *lp = rl; + return ret; +} + +/* + * Expand the prompt string into the various display components, if + * necessary. + * + * local_prompt = expanded last line of string in rl_display_prompt + * (portion after the final newline) + * local_prompt_prefix = portion before last newline of rl_display_prompt, + * expanded via expand_prompt + * visible_length = number of visible characters in local_prompt + * prefix_length = number of visible characters in local_prompt_prefix + * + * This function is called once per call to readline(). It may also be + * called arbitrarily to expand the primary prompt. + * + * The return value is the number of visible characters on the last line + * of the (possibly multi-line) prompt. + */ +int +rl_expand_prompt (prompt) + char *prompt; +{ + char *p, *t; + int c; + + /* Clear out any saved values. */ + if (local_prompt) + free (local_prompt); + if (local_prompt_prefix) + free (local_prompt_prefix); + local_prompt = local_prompt_prefix = (char *)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_prefix = (char *)0; + return (visible_length); + } + else + { + /* The prompt spans multiple lines. */ + t = ++p; + local_prompt = expand_prompt (p, &visible_length); + 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); + *t = c; + return (prefix_length); + } +} + +/* Basic redisplay algorithm. */ +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; + char *prompt_this_line; + + if (!readline_echoing_p) + return; + + if (!rl_display_prompt) + rl_display_prompt = ""; + + if (!invisible_line) + { + 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; + } + rl_on_new_line (); + } + + /* Draw the line into the buffer. */ + c_pos = -1; + + /* 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++] = '*'; + line[out] = '\0'; + } + + /* If someone thought that the redisplay was handled, but the currently + visible line has a different modification state than the one about + to become visible, then correct the caller's misconception. */ + if (visible_line[0] != invisible_line[0]) + rl_display_fixed = 0; + + /* If the prompt to be displayed is the `primary' readline prompt (the + 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) + { + 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; + line[out] = '\0'; + wrap_offset = local_len - visible_length; + } + else + { + int pmtlen; + prompt_this_line = strrchr (rl_display_prompt, '\n'); + if (!prompt_this_line) + prompt_this_line = rl_display_prompt; + else + { + prompt_this_line++; + if (forced_display) + _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt); + } + + pmtlen = strlen (prompt_this_line); + strncpy (line + out, prompt_this_line, pmtlen); + out += pmtlen; + line[out] = '\0'; + wrap_offset = 0; + } + + for (in = 0; in < rl_end; in++) + { + c = (unsigned char)rl_line_buffer[in]; + + if (out + 8 >= line_size) /* XXX - 8 for \t */ + { + line_size *= 2; + visible_line = xrealloc (visible_line, line_size); + invisible_line = xrealloc (invisible_line, line_size); + line = invisible_line; + } + + if (in == rl_point) + c_pos = out; + + if (META_CHAR (c)) + { + if (_rl_output_meta_chars == 0) + { + sprintf (line + out, "\\%o", c); + out += 4; + } + else + line[out++] = c; + } +#if defined (DISPLAY_TABS) + else if (c == '\t') + { + register int newout = (out | (int)7) + 1; + while (out < newout) + line[out++] = ' '; + } +#endif + else if (c < ' ') + { + line[out++] = '^'; + line[out++] = UNCTRL (c); /* XXX was c ^ 0x40 */ + } + else if (c == 127) + { + line[out++] = '^'; + line[out++] = '?'; + } + else + line[out++] = c; + } + line[out] = '\0'; + if (c_pos < 0) + c_pos = out; + + /* C_POS == position in buffer where cursor should be placed. */ + + /* PWP: now is when things get a bit hairy. The visible and invisible + line buffers are really multiple lines, which would wrap every + (screenwidth - 1) characters. Go through each in turn, finding + the changed region and updating it. The line order is top to bottom. */ + + /* If we can move the cursor up and down, then use multiple lines, + otherwise, let long lines display in a single terminal line, and + horizontally scroll it. */ + + if (!_rl_horizontal_scroll_mode && term_up && *term_up) + { + int total_screen_chars = screenchars; + int nleft, cursor_linenum, pos, changed_screen_line; + + if (!rl_display_fixed || forced_display) + { + forced_display = 0; + + /* 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; + + /* 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. */ + +#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_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) +#define INV_LINE(line) &invisible_line[L_OFFSET((line), wrap_offset)] + + /* 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); + + /* 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. */ + if (linenum == 0 && + inv_botlin == 0 && + (wrap_offset > visible_wrap_offset) && + (_rl_last_c_pos < visible_first_line_len)) + { + nleft = screenwidth + wrap_offset - _rl_last_c_pos; + if (nleft) + clear_to_eol (nleft); + } + + /* 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; + } + + /* We may have deleted some lines. If so, clear the left over + blank ones at the bottom out. */ + if (_rl_vis_botlin > inv_botlin) + { + char *tt; + for (; linenum <= _rl_vis_botlin; linenum++) + { + tt = VIS_CHARS (linenum); + _rl_move_vert (linenum); + _rl_move_cursor_relative (0, tt); + clear_to_eol + ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth); + } + } + _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; + if (changed_screen_line) + { + _rl_move_vert (cursor_linenum); + /* If we moved up to the line with the prompt using term_up, + the physical cursor position on the screen stays the same, + but the buffer position needs to be adjusted to account + for invisible characters. */ + if (cursor_linenum == 0 && wrap_offset) + _rl_last_c_pos += wrap_offset; + } + + /* 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. */ + nleft = visible_length + wrap_offset; + if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && + _rl_last_c_pos <= nleft && local_prompt) + { + if (term_cr) + tputs (term_cr, 1, _rl_output_character_function); + _rl_output_some_chars (local_prompt, nleft); + _rl_last_c_pos = nleft; + } + + /* Where on that line? And where does that line start + in the buffer? */ + pos = L_OFFSET(cursor_linenum, wrap_offset); + /* 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 + prompt, and there's no good way to tell it, we compensate for + those characters here and call backspace() directly. */ + if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) + { + backspace (_rl_last_c_pos - nleft); + _rl_last_c_pos = nleft; + } + + if (nleft != _rl_last_c_pos) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + } + } + else /* Do horizontal scrolling. */ + { +#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0) + int lmargin, ndisp, nleft, phys_c_pos, t; + + /* Always at top line. */ + _rl_last_v_pos = 0; + + /* Compute where in the buffer the displayed line should start. This + will be LMARGIN. */ + + /* The number of characters that will be displayed before the cursor. */ + ndisp = c_pos - wrap_offset; + nleft = visible_length + wrap_offset; + /* Where the new cursor position will be on the screen. This can be + longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ + phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); + t = screenwidth / 3; + + /* If the number of characters had already exceeded the screenwidth, + last_lmargin will be > 0. */ + + /* If the number of characters to be displayed is more than the screen + width, compute the starting offset so that the cursor is about + two-thirds of the way across the screen. */ + if (phys_c_pos > screenwidth - 2) + { + lmargin = c_pos - (2 * t); + if (lmargin < 0) + lmargin = 0; + /* If the left margin would be in the middle of a prompt with + invisible characters, don't display the prompt at all. */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else if (ndisp < screenwidth - 2) /* XXX - was -1 */ + lmargin = 0; + else if (phys_c_pos < 1) + { + /* If we are moving back towards the beginning of the line and + the last margin is no longer correct, compute a new one. */ + lmargin = ((c_pos - 1) / t) * t; /* XXX */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else + lmargin = last_lmargin; + + /* If the first character on the screen isn't the first character + in the display line, indicate this with a special character. */ + if (lmargin > 0) + line[lmargin] = '<'; + + /* If SCREENWIDTH characters starting at LMARGIN do not encompass + the whole line, indicate that with a special characters at the + right edge of the screen. If LMARGIN is 0, we need to take the + wrap offset into account. */ + t = lmargin + M_OFFSET (lmargin, wrap_offset) + screenwidth; + if (t < out) + line[t - 1] = '>'; + + if (!rl_display_fixed || forced_display || lmargin != last_lmargin) + { + forced_display = 0; + update_line (&visible_line[last_lmargin], + &invisible_line[lmargin], + 0, + screenwidth + visible_wrap_offset, + screenwidth + (lmargin ? 0 : wrap_offset), + 0); + + /* If the visible new line is shorter than the old, but the number + of invisible characters is greater, and we are at the end of + the new line, we need to clear to eol. */ + t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset); + if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) && + (_rl_last_c_pos == out) && + t < visible_first_line_len) + { + nleft = screenwidth - t; + clear_to_eol (nleft); + } + visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); + if (visible_first_line_len > screenwidth) + visible_first_line_len = screenwidth; + + _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); + last_lmargin = lmargin; + } + } + fflush (rl_outstream); + + /* Swap visible and non-visible lines. */ + { + char *temp = visible_line; + visible_line = invisible_line; + invisible_line = temp; + 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 + to 0. */ + if (_rl_horizontal_scroll_mode && last_lmargin) + visible_wrap_offset = 0; + else + visible_wrap_offset = wrap_offset; + } +} + +/* PWP: update_line() is based on finding the middle difference of each + line on the screen; vis: + + /old first difference + /beginning of line | /old last same /old EOL + v v v v +old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as +new: eddie> Oh, my little buggy says to me, as lurgid as + ^ ^ ^ ^ + \beginning of line | \new last same \new end of line + \new first difference + + All are character pointers for the sake of speed. Special cases for + no differences, as well as for end of line additions must be handeled. + + Could be made even smarter, but this works well enough */ +static void +update_line (old, new, current_line, omax, nmax, inv_botlin) + register char *old, *new; + int current_line, omax, nmax; +{ + register char *ofd, *ols, *oe, *nfd, *nls, *ne; + int temp, lendiff, wsatend, od, nd; + + /* 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 + the exact cursor position and cut-and-paste with certain terminal + 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 + && _rl_last_v_pos == current_line - 1) + { + if (new[0]) + putc (new[0], rl_outstream); + else + putc (' ', rl_outstream); + _rl_last_c_pos = 1; /* XXX */ + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + + /* Find first difference. */ + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && (*ofd == *nfd); + ofd++, nfd++) + ; + + /* Move to the end of the screen line. ND and OD are used to keep track + of the distance between ne and new and oe and old, respectively, to + move a subtraction out of each loop. */ + for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++); + for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++); + + /* If no difference, continue to next line. */ + if (ofd == oe && nfd == ne) + return; + + wsatend = 1; /* flag for trailing whitespace */ + ols = oe - 1; /* find last same */ + nls = ne - 1; + while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) + { + if (*ols != ' ') + wsatend = 0; + ols--; + nls--; + } + + if (wsatend) + { + ols = oe; + nls = ne; + } + else if (*ols != *nls) + { + if (*ols) /* don't step past the NUL */ + ols++; + if (*nls) + nls++; + } + + _rl_move_vert (current_line); + + /* 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. + + 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. */ + + lendiff = local_prompt ? strlen (local_prompt) : 0; + if (current_line == 0 && !_rl_horizontal_scroll_mode && + lendiff > visible_length && + _rl_last_c_pos > 0 && (ofd - old) >= lendiff && term_cr) + { + 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); + + /* if (len (new) > len (old)) */ + lendiff = (nls - nfd) - (ols - ofd); + + /* Insert (diff (len (old), len (new)) ch. */ + temp = ne - nfd; + if (lendiff > 0) + { + /* Non-zero if we're increasing the number of lines. */ + int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; + /* Sometimes it is cheaper to print the characters rather than + 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 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)) + { + insert_some_chars (nfd, lendiff); + _rl_last_c_pos += lendiff; + } + else + { + /* At the end of a line the characters do not have to + be "inserted". They can just be placed on the screen. */ + _rl_output_some_chars (nfd, lendiff); + _rl_last_c_pos += lendiff; + } + /* Copy (new) chars to screen from first diff to last match. */ + temp = nls - nfd; + if ((temp - lendiff) > 0) + { + _rl_output_some_chars (nfd + lendiff, temp - lendiff); + _rl_last_c_pos += temp - lendiff; + } + } + else + { + /* cannot insert chars, write to EOL */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += temp; + } + } + else /* Delete characters from line. */ + { + /* If possible and inexpensive to use terminal deletion, then do so. */ + if (term_dc && (2 * temp) >= -lendiff) + { + /* If all we're doing is erasing the invisible characters in the + prompt string, don't bother. It screws up the assumptions + about what's on the screen. */ + if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 && + -lendiff == visible_wrap_offset) + lendiff = 0; + + if (lendiff) + delete_chars (-lendiff); /* delete (diff) characters */ + + /* Copy (new) chars to screen from first diff to last match */ + temp = nls - nfd; + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += temp; + } + } + /* Otherwise, print over the existing material. */ + else + { + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += temp; + } + lendiff = (oe - old) - (ne - new); + if (term_xn && current_line < inv_botlin) + space_to_eol (lendiff); + else + clear_to_eol (lendiff); + } + } +} + +/* Tell the update routines that we have moved onto a new (empty) line. */ +rl_on_new_line () +{ + if (visible_line) + visible_line[0] = '\0'; + + _rl_last_c_pos = _rl_last_v_pos = 0; + _rl_vis_botlin = last_lmargin = 0; + return 0; +} + +/* Actually update the display, period. */ +rl_forced_update_display () +{ + if (visible_line) + { + register char *temp = visible_line; + + while (*temp) *temp++ = '\0'; + } + rl_on_new_line (); + forced_display++; + rl_redisplay (); + return 0; +} + +/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices. + DATA is the contents of the screen line of interest; i.e., where + the movement is being done. */ +void +_rl_move_cursor_relative (new, data) + int new; + char *data; +{ + register int i; + + /* If we don't have to do anything, then return. */ + if (_rl_last_c_pos == new) return; + + /* It may be faster to output a CR, and then move forwards instead + 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 defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (term_cr, 1, _rl_output_character_function); +#endif /* !__MSDOS__ */ + _rl_last_c_pos = 0; + } + + if (_rl_last_c_pos < new) + { + /* Move the cursor forward. We do it by printing the command + to move the cursor forward if there is one, else print that + portion of the output buffer again. Which is cheaper? */ + + /* The above comment is left here for posterity. It is faster + to print one character (non-control) than to print a control + sequence telling the terminal to move forward one character. + That kind of control is for people who don't know what the + data is underneath the cursor. */ +#if defined (HACK_TERMCAP_MOTION) + extern char *term_forward_char; + + if (term_forward_char) + for (i = _rl_last_c_pos; i < new; i++) + tputs (term_forward_char, 1, _rl_output_character_function); + else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); +#else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); +#endif /* HACK_TERMCAP_MOTION */ + } + else if (_rl_last_c_pos != new) + backspace (_rl_last_c_pos - new); + _rl_last_c_pos = new; +} + +/* PWP: move the cursor up or down. */ +void +_rl_move_vert (to) + int to; +{ + register int delta, i; + + if (_rl_last_v_pos == to || to > screenheight) + return; + +#if defined (__GO32__) + { + int row, col; + + ScreenGetCursor (&row, &col); + ScreenSetCursor ((row + to - _rl_last_v_pos), col); + } +#else /* !__GO32__ */ + + if ((delta = to - _rl_last_v_pos) > 0) + { + for (i = 0; i < delta; i++) + putc ('\n', rl_outstream); + tputs (term_cr, 1, _rl_output_character_function); + _rl_last_c_pos = 0; + } + else + { /* delta < 0 */ + if (term_up && *term_up) + for (i = 0; i < -delta; i++) + tputs (term_up, 1, _rl_output_character_function); + } +#endif /* !__GO32__ */ + _rl_last_v_pos = to; /* Now TO is here */ +} + +/* Physically print C on rl_outstream. This is for functions which know + how to optimize the display. Return the number of characters output. */ +rl_show_char (c) + int c; +{ + int n = 1; + if (META_CHAR (c) && (_rl_output_meta_chars == 0)) + { + fprintf (rl_outstream, "M-"); + n += 2; + c = UNMETA (c); + } + +#if defined (DISPLAY_TABS) + if (c < 32 && c != '\t') +#else + if (c < 32) +#endif /* !DISPLAY_TABS */ + { + fprintf (rl_outstream, "C-"); + n += 2; + c += 64; + } + + putc (c, rl_outstream); + fflush (rl_outstream); + return n; +} + +int +rl_character_len (c, pos) + register int c, pos; +{ + unsigned char uc; + + uc = (unsigned char)c; + + if (META_CHAR (uc)) + return ((_rl_output_meta_chars == 0) ? 4 : 1); + + if (uc == '\t') + { +#if defined (DISPLAY_TABS) + return (((pos | 7) + 1) - pos); +#else + return (2); +#endif /* !DISPLAY_TABS */ + } + + 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) +rl_message (va_alist) + va_dcl +{ + char *format; + va_list args; + + va_start (args); + format = va_arg (args, char *); + vsprintf (msg_buf, format, args); + va_end (args); + + rl_display_prompt = msg_buf; + rl_redisplay (); + return 0; +} +#else /* !HAVE_VARARGS_H */ +rl_message (format, arg1, arg2) + char *format; +{ + sprintf (msg_buf, format, arg1, arg2); + rl_display_prompt = msg_buf; + rl_redisplay (); + return 0; +} +#endif /* !HAVE_VARARGS_H */ + +/* How to clear things from the "echo-area". */ +rl_clear_message () +{ + rl_display_prompt = rl_prompt; + rl_redisplay (); + return 0; +} + +rl_reset_line_state () +{ + rl_on_new_line (); + + rl_display_prompt = rl_prompt ? rl_prompt : ""; + forced_display = 1; + return 0; +} + +/* Quick redisplay hack when erasing characters at the end of the line. */ +void +_rl_erase_at_end_of_line (l) + int l; +{ + register int i; + + backspace (l); + for (i = 0; i < l; i++) + putc (' ', rl_outstream); + backspace (l); + for (i = 0; i < l; i++) + visible_line[--_rl_last_c_pos] = '\0'; + rl_display_fixed++; +} + +/* Clear to the end of the line. COUNT is the minimum + number of character spaces to clear, */ +static void +clear_to_eol (count) + int count; +{ +#if !defined (__GO32__) + if (term_clreol) + { + tputs (term_clreol, 1, _rl_output_character_function); + } + else +#endif /* !__GO32__ */ + space_to_eol (count); +} + +/* Clear to the end of the line using spaces. COUNT is the minimum + number of character spaces to clear, */ +static void +space_to_eol (count) + int count; +{ + register int i; + + for (i = 0; i < count; i++) + putc (' ', rl_outstream); + + _rl_last_c_pos += count; +} + +/* Insert COUNT characters from STRING to the output stream. */ +static void +insert_some_chars (string, count) + char *string; + int count; +{ +#if defined (__GO32__) + int row, col, width; + char *row_start; + + ScreenGetCursor (&row, &col); + width = ScreenCols (); + row_start = ScreenPrimary + (row * width); + + memcpy (row_start + col + count, row_start + col, width - col - count); + + /* Place the text on the screen. */ + _rl_output_some_chars (string, count); +#else /* !_GO32 */ + + /* If IC is defined, then we do not have to "enter" insert mode. */ + if (term_IC) + { + char *tgoto (), *buffer; + buffer = tgoto (term_IC, 0, count); + tputs (buffer, 1, _rl_output_character_function); + _rl_output_some_chars (string, count); + } + else + { + register int i; + + /* If we have to turn on insert-mode, then do so. */ + if (term_im && *term_im) + tputs (term_im, 1, _rl_output_character_function); + + /* If there is a special command for inserting characters, then + use that first to open up the space. */ + if (term_ic && *term_ic) + { + for (i = count; i--; ) + tputs (term_ic, 1, _rl_output_character_function); + } + + /* Print the text. */ + _rl_output_some_chars (string, count); + + /* If there is a string to turn off insert mode, we had best use + it now. */ + if (term_ei && *term_ei) + tputs (term_ei, 1, _rl_output_character_function); + } +#endif /* !__GO32__ */ +} + +/* Delete COUNT characters from the display line. */ +static void +delete_chars (count) + int count; +{ +#if defined (__GO32__) + int row, col, width; + char *row_start; + + ScreenGetCursor (&row, &col); + width = ScreenCols (); + row_start = ScreenPrimary + (row * width); + + memcpy (row_start + col, row_start + col + count, width - col - count); + memset (row_start + width - count, 0, count * 2); +#else /* !_GO32 */ + + if (count > screenwidth) /* XXX */ + return; + + if (term_DC && *term_DC) + { + char *tgoto (), *buffer; + buffer = tgoto (term_DC, count, count); + tputs (buffer, count, _rl_output_character_function); + } + else + { + if (term_dc && *term_dc) + while (count--) + tputs (term_dc, 1, _rl_output_character_function); + } +#endif /* !__GO32__ */ +} + +void +_rl_update_final () +{ + int full_lines; + + full_lines = 0; + if (_rl_vis_botlin && visible_line[screenwidth * _rl_vis_botlin] == 0) + { + _rl_vis_botlin--; + full_lines = 1; + } + _rl_move_vert (_rl_vis_botlin); + if (full_lines && term_xn) + { + /* Remove final line-wrap flag in xterm. */ + char *last_line; + last_line = &visible_line[screenwidth * _rl_vis_botlin]; + _rl_move_cursor_relative (screenwidth - 1, last_line); + clear_to_eol (0); + putc (last_line[screenwidth - 1], rl_outstream); + } + _rl_vis_botlin = 0; + crlf (); + fflush (rl_outstream); + rl_display_fixed++; +} + +/* Move to the start of the current line. */ +static void +cr () +{ + if (term_cr) + { + tputs (term_cr, 1, _rl_output_character_function); + _rl_last_c_pos = 0; + } +} + +/* Redisplay the current line after a SIGWINCH is received. */ +void +_rl_redisplay_after_sigwinch () +{ + char *t, *oldp; + + /* Clear the current line and put the cursor at column 0. Make sure + the right thing happens if we have wrapped to a new screen line. */ + if (term_cr) + { + tputs (term_cr, 1, _rl_output_character_function); + _rl_last_c_pos = 0; + if (term_clreol) + tputs (term_clreol, 1, _rl_output_character_function); + else + { + space_to_eol (screenwidth); + tputs (term_cr, 1, _rl_output_character_function); + } + if (_rl_last_v_pos > 0) + _rl_move_vert (0); + } + else + crlf (); + + /* Redraw only the last line of a multi-line prompt. */ + t = strrchr (rl_display_prompt, '\n'); + if (t) + { + oldp = rl_display_prompt; + rl_display_prompt = ++t; + rl_forced_update_display (); + rl_display_prompt = oldp; + } + else + rl_forced_update_display (); +} diff --git a/lib/readline/doc/Makefile b/lib/readline/doc/Makefile new file mode 100644 index 0000000..72b8ce7 --- /dev/null +++ b/lib/readline/doc/Makefile @@ -0,0 +1,55 @@ +# This makefile for History library documentation is in -*- text -*- mode. +# Emacs likes it that way. + +DOC_SUPPORT = ../../doc-support/ +TEXINDEX = $(DOC_SUPPORT)/texindex + +TEX = tex + +RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo +HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo + +DVIOBJ = readline.dvi history.dvi +INFOOBJ = readline.info history.info +PSOBJ = readline.ps history.ps + +all: info dvi + +readline.dvi: $(RLSRC) + $(TEX) rlman.texinfo + $(TEXINDEX) rlman.?? + $(TEX) rlman.texinfo + mv rlman.dvi readline.dvi + +readline.info: $(RLSRC) + makeinfo rlman.texinfo + +history.dvi: ${HISTSRC} + $(TEX) hist.texinfo + $(TEXINDEX) hist.?? + $(TEX) hist.texinfo + mv hist.dvi history.dvi + +history.info: ${HISTSRC} + makeinfo hist.texinfo + +readline.ps: readline.dvi + dvips -D 300 -o $@ readline.dvi + +history.ps: history.dvi + dvips -D 300 -o $@ history.dvi + +info: $(INFOOBJ) +dvi: $(DVIOBJ) +ps: $(PSOBJ) + + +$(TEXINDEX): + (cd $(DOC_SUPPORT); $(MAKE) $(MFLAGS) CFLAGS='$(CFLAGS)' texindex) + +distclean mostlyclean clean: + rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ + *.fns *.kys *.tps *.vrs *.o core + +maintainer-clean realclean: clean + rm -f *.dvi *.info *.info-* *.ps diff --git a/lib/readline/doc/hist.texinfo b/lib/readline/doc/hist.texinfo new file mode 100644 index 0000000..cc80efa --- /dev/null +++ b/lib/readline/doc/hist.texinfo @@ -0,0 +1,113 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header (This is for running Texinfo on a region.) +@setfilename history.info +@settitle GNU History Library +@c %**end of header (This is for running Texinfo on a region.) + +@setchapternewpage odd + +@ignore +last change: Wed Jul 20 09:57:17 EDT 1994 +@end ignore + +@set EDITION 2.0 +@set VERSION 2.0 +@set UPDATED 20 July 1994 +@set UPDATE-MONTH July 1994 + +@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. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@titlepage +@sp 10 +@title GNU History Library +@subtitle Edition @value{EDITION}, for @code{History Library} Version @value{VERSION}. +@subtitle @value{UPDATE-MONTH} +@author Brian Fox, Free Software Foundation +@author Chet Ramey, Case Western Reserve University + +@page +This document describes the GNU History library, a programming tool that +provides a consistent user interface for recalling lines of previously +typed input. + +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +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. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +@end titlepage + +@ifinfo +@node Top +@top 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. +@end menu +@end ifinfo + +@syncodeindex fn vr + +@include hsuser.texinfo +@include hstech.texinfo + +@node Concept Index +@appendix Concept Index +@printindex cp + +@node Function and Variable Index +@appendix Function and Variable Index +@printindex vr + +@contents +@bye diff --git a/lib/readline/doc/history.dvi b/lib/readline/doc/history.dvi Binary files differnew file mode 100644 index 0000000..60d7376 --- /dev/null +++ b/lib/readline/doc/history.dvi diff --git a/lib/readline/doc/history.info b/lib/readline/doc/history.info new file mode 100644 index 0000000..6df0bd9 --- /dev/null +++ b/lib/readline/doc/history.info @@ -0,0 +1,744 @@ +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 new file mode 100644 index 0000000..839598f --- /dev/null +++ b/lib/readline/doc/history.ps @@ -0,0 +1,2037 @@ +%!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 D<FC0000FC00001C00001C00001C +00001C00001C00001CF8001DFE001F07001E03001C03801C01C01C01C01C01C01C01C01C01C01C +01C01C03801E03001F0E001DFC000CF8001217809614>I<03F80FFC1C1C380870006000E000E0 +00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 +000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 +700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF +FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF +FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 +1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 +1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> +I<FC0000FC00001C00001C00001C00001C00001C00001C78001DFE001F86001E07001C07001C07 +001C07001C07001C07001C07001C07001C07001C07001C0700FF8FE0FF8FE01317809614>I<03 +0007800780030000000000000000007F807F800380038003800380038003800380038003800380 +03800380FFFCFFFC0E187D9714>I<FC0000FC00001C00001C00001C00001C00001C00001DFF80 +1DFF801C3C001C78001CF0001DE0001FC0001FC0001FE0001EF0001C70001C38001C38001C1C00 +FE3F80FE3F8011177F9614>107 D<FF80FF800380038003800380038003800380038003800380 +038003800380038003800380038003800380FFFEFFFE0F177E9614>I<FB8E00FFDF003CF3803C +F38038E38038E38038E38038E38038E38038E38038E38038E38038E38038E380FEFBE0FE79E013 +10808F14>I<FC7800FDFE001F86001E07001C07001C07001C07001C07001C07001C07001C0700 +1C07001C07001C0700FF8FE0FF8FE01310808F14>I<07C01FF03C78701C701CE00EE00EE00EE0 +0EE00EE00E701C783C3C781FF007C00F107E8F14>I<FCF800FDFE001F07001E03001C03801C01 +C01C01C01C01C01C01C01C01C01C01C01C03801E03001F0E001DFC001CF8001C00001C00001C00 +001C00001C00001C0000FF8000FF80001218808F14>I<FE1F00FE7F800EE3800F81000F00000F +00000E00000E00000E00000E00000E00000E00000E00000E0000FFF000FFF00011107F8F14> +114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F +14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E +070C03FC00F00F157F9414>I<FC3F00FC3F001C07001C07001C07001C07001C07001C07001C07 +001C07001C07001C07001C07001C1F000FFFE003E7E01310808F14>I<FE3F80FE3F801C1C001C +1C001C1C001C1C000E38000E38000E380006300007700007700007700003E00003E00003E00011 +107F8F14>I<FF7F80FF7F80380E00380E00380E00380E0039CE0039CE0019CC001B6C001B6C00 +1A6C001A6C001E7C000E78000E780011107F8F14>I<7E3F007E3F001E38000E780007700007E0 +0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>I<FE +3F80FE3F801C1C001C1C001C1C000E1C000E38000E380007380007300007300003700003700001 +E00001E00001E00001C00001C00001C0000380007380007700007E00003C000011187F8F14>I< +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>I<FFE7FF0E00700E00700E00700E +00700E00700E00700E00700E00700E00700E00700E00700FFFF00E00700E00700E00700E00700E +00700E00700E00700E00700E00700E00700E00700E0070FFE7FF181A7E991D>72 +D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 +80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 +707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 +E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 +000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 +E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 +600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 +703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 +E010187F8F13>103 D<FC00001C00001C00001C00001C00001C00001C00001C00001C00001C00 +001CF8001D0C001E0E001E0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E +001C0E001C0E00FF9FC0121A7F9915>I<18003C003C001800000000000000000000000000FC00 +1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I<FCF8 +001D0C001E0E001E0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E +001C0E00FF9FC012107F8F15>110 D<07E01C38300C700E6006E007E007E007E007E007E00760 +06700E381C1C3807E010107F8F13>I<FCF8001F0E001E07001C03801C03801C01C01C01C01C01 +C01C01C01C01C01C01C01C03801C03001E07001F0C001CF0001C00001C00001C00001C00001C00 +001C0000FF800012177F8F15>I<FCE01D701E701E201C001C001C001C001C001C001C001C001C +001C001C00FFC00C107F8F0F>114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 +30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C +001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I<FF1F803C06001C0400 +1C04001E0C000E08000E080007100007100007900003A00003A00001C00001C00001C000008000 +11107F8F14>118 D<FF3F803C1C001C18000E100007200007600003C00001C00001E00003E000 +027000043800083800181C00381E00FC3FC012107F8F14>120 D<FF1F803C06001C04001C0400 +1E0C000E08000E080007100007100007900003A00003A00001C00001C00001C000008000008000 +010000010000E10000E20000E4000078000011177F8F14>I E /Ff 2 42 +df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 +00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 +1E000E0007000780038001C000E000700C2E7EA112>40 D<E000700038001C001E000E00070007 +80078003C003C003C001E001E001E001E000E000F000F000F000F000F000F000F000F000F000F0 +00F000F000E001E001E001E001E003C003C003C00780078007000E001E001C0038007000E0000C +2E7DA112>I E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F +C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 +7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F +C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 +001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD +F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F +F87F8007E03F8019167E951C>97 D<FF800000FF8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F8000001F8000001F8000001F87F0001FBFFC001FF03E +001FC01F001F800F801F800FC01F8007C01F8007E01F8007E01F8007E01F8007E01F8007E01F80 +07E01F8007E01F8007C01F8007C01F800FC01F800F801FC01F001E707E001C3FFC00180FE0001B +237EA220>I<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 +FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> +I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 +3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C +003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 +7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 +C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 +003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F +01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 +0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF +807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF +E0001A217F951D>103 D<FF800000FF8000001F8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F8000001F8000001F83F0001F8FFC001F987E001FA03E +001FC03F001FC03F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F80 +3F001F803F001F803F001F803F001F803F001F803F001F803F00FFF1FFE0FFF1FFE01B237DA220 +>I<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 +0F>I<FF800000FF8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F80FF801F80FF801F803C001F8030001F80E0001F81C0 +001F8300001F8600001F9E00001FBE00001FFF00001FDF80001F8FC0001F07C0001F07E0001F03 +F0001F01F8001F00F8001F00FC001F007E00FFE1FFC0FFE1FFC01A237EA21E>107 +D<FF80FF801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C237EA20F>I< +FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F +801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>I<FF03F000FF0FFC001F187E001F203E001F +403F001F403F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F00 +1F803F001F803F001F803F001F803F001F803F001F803F00FFF1FFE0FFF1FFE01B167D9520>I< +00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F +FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>I<FF87F000FF +BFFC001FF07E001FC01F001F800F801F800FC01F800FC01F8007E01F8007E01F8007E01F8007E0 +1F8007E01F8007E01F8007E01F8007C01F800FC01F800FC01F801F801FC01F001FF07E001FBFFC +001F8FE0001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000FFF0 +0000FFF000001B207E9520>I<FF0F80FF1FE01F33F01F63F01F43F01F43F01FC1E01F80001F80 +001F80001F80001F80001F80001F80001F80001F80001F80001F80001F80001F8000FFF800FFF8 +0014167E9518>114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE +003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 +7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF +FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F +C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>I<FF81FF00FF81FF001F +803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F00 +1F803F001F803F001F803F001F803F001F803F001F807F001F80FF000FC1BF0007FF3FE001FC3F +E01B167D9520>I<FFF01FE0FFF01FE00FC007000FC006000FE00E0007E00C0007F01C0003F018 +0003F8180001F8300001F8300000FC600000FC6000007EC000007EC000007FC000003F8000003F +8000001F0000001F0000000E0000000E00001B167F951E>I<FFF3FF87FCFFF3FF87FC1F807C00 +E00FC07C00C00FC07E00C00FE03E01C007E03F018007E07F018003F07F030003F0CF830001F8CF +860001F8CFC60001FD87C60000FD87CC0000FF03EC00007F03F800007F03F800007E01F800003E +01F000003C00F000001C00E000001800600026167F9529>I<FFF0FFC0FFF0FFC00FC01C0007E0 +380007F0700003F0E00001F8C00000FD8000007F0000007F0000003F0000001F8000003FC00000 +37E0000067F00000C3F00001C1F8000380FC000700FE000E007E00FFC1FFE0FFC1FFE01B167F95 +1E>I<FFF01FE0FFF01FE00FC007000FC006000FE00E0007E00C0007F01C0003F0180003F81800 +01F8300001F8300000FC600000FC6000007EC000007EC000007FC000003F8000003F8000001F00 +00001F0000000E0000000E0000000C0000000C00000018000078180000FC380000FC300000FC60 +000069E000007F8000001F0000001B207F951E>I<7FFFE07FFFE0780FC0701FC0601F80E03F00 +C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 +7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 +F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 +00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 +EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 +FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 +D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 +000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 +0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D<FF8FF8FF8FF8FF8FF81C01C01C01C01C01C0 +1C01C01C01C01C01C01C01C01C01C01C01C01C01C01FFFC01FFFC01FFFC01C01C01C01C01C01C0 +1C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C0FF8FF8FF8FF8FF8FF8151E7E9D1A> +72 D<FFFF80FFFF80FFFF8001C00001C00001C00001C00001C00001C00001C00001C00001C000 +01C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C000 +01C00001C000FFFF80FFFF80FFFF80111E7C9D1A>I<FE0FF8FF0FF8FF0FF81D81C01D81C01D81 +C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01C61C01C61C01C71C01C71C01C31C01C31C01C39 +C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0DC01C0DC0FF87C0FF87C0FF83C0151E7E9D1A +>78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 +7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I<FFF000FFFC00FFFF001C0F801C07801C03 +C01C01C01C01C01C01C01C01C01C03C01C07801C0F801FFF001FFC001FFE001C0F001C07001C03 +801C03801C03801C03801C03801C03841C038E1C038E1C038EFF81FCFF81FCFF8070171E7E9D1A +>82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 +3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 +F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 +0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 +0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A +>I<FF01FEFF83FEFF01FE1E00F00E00E00E00E00701C00701C003838003838003C78001C70001 +C70000EE0000EE00007C00007C0000380000380000380000380000380000380000380000380000 +380000380001FF0001FF0001FF00171E7F9D1A>89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A +>95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 +700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 +D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 +007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 +D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F +C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 +C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I<FE0000FE0000FE00000E00000E00000E00000E +00000E00000E00000E3E000EFF800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E +00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E0FFE3FEFFE3FEFFE3FE171E7F9D1A> +104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 +7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I<FE3E00FEFF80FFFFC00FC1C00F80 +E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 +E0FFE3FEFFE3FEFFE3FE17157F941A>110 D<01F00007FC001FFF003E0F803C07807803C07001 +C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC +0001F00013157D941A>I<FF83F0FF8FF8FFBFFC03FC3C03F01803E00003C00003C00003800003 +8000038000038000038000038000038000038000038000038000FFFF00FFFF80FFFF0016157E94 +1A>114 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<FFFFFFE00000FFFFFFFC000003F800FF000003F8001FC00003F80007E00003F800 +03F00003F80001F80003F80001FC0003F80000FC0003F80000FE0003F80000FE0003F800007F00 +03F800007F0003F800007F0003F800007F8003F800007F8003F800007F8003F800007F8003F800 +007F8003F800007F8003F800007F8003F800007F8003F800007F8003F800007F8003F800007F00 +03F800007F0003F800007F0003F80000FE0003F80000FE0003F80001FC0003F80001F80003F800 +03F00003F80007E00003F8001FC00003F800FF8000FFFFFFFE0000FFFFFFE0000029257EA42F> +68 D<FFFFFFFF00FFFFFFFF0003F8007F0003F8000F8003F800078003F800038003F800038003 +F800018003F800018003F800018003F80000C003F80600C003F80600C003F806000003F8060000 +03F80E000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F80600 +0003F806006003F806006003F800006003F80000C003F80000C003F80000C003F80000C003F800 +01C003F80003C003F80003C003F8000F8003F8003F80FFFFFFFF80FFFFFFFF8023257EA428>I< +FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 +0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E +000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 +06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 +F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I<FFFFE0 +FFFFE0FFFFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003FFFFFFF80003FFFFFFF80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F800FFFFE0FFFFE0FFFFE0FFFFE02B257EA430>72 +D<FFFFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8 +0003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8 +0003F80003F80003F80003F80003F80003F80003F80003F80003F800FFFFE0FFFFE013257EA417 +>I<FFFFF000FFFFF00003F8000003F8000003F8000003F8000003F8000003F8000003F8000003 +F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000 +03F8000003F8000003F8000003F8000003F8000603F8000603F8000603F8000C03F8000C03F800 +0C03F8001C03F8001C03F8003C03F8007C03F800F803F803F8FFFFFFF8FFFFFFF81F257EA425> +76 D<FFF8000000FFF8FFFC000001FFF803FC000001FE00037E0000037E00037E0000037E0003 +7E0000037E00033F0000067E00033F0000067E00031F80000C7E00031F80000C7E00030FC00018 +7E00030FC000187E000307E000307E000307E000307E000307E000307E000303F000607E000303 +F000607E000301F800C07E000301F800C07E000300FC01807E000300FC01807E0003007E03007E +0003007E03007E0003007E03007E0003003F06007E0003003F06007E0003001F8C007E0003001F +8C007E0003000FD8007E0003000FD8007E00030007F0007E00030007F0007E00030007F0007E00 +030003E0007E00078003E0007E00FFFC01C01FFFF8FFFC01C01FFFF835257EA43A>I<00FF0080 +07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 +80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F +FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 +0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 +D<FFFF83FFFE01FFF0FFFF83FFFE01FFF007F0001FC0000F0007F0001FC000060003F8000FE000 +0C0003F8000FE0000C0003FC000FF0001C0001FC0007F000180001FC0007F000180000FE000FF8 +00300000FE000FF800300000FE000FFC003000007F0019FC006000007F0019FC006000007F8039 +FE00E000003F8030FE00C000003F8030FE00C000001FC0607F018000001FC0607F018000001FE0 +607F818000000FE0C03F830000000FE0C03F830000000FF1C03FC700000007F1801FC600000007 +F1801FC600000003FB000FEC00000003FB000FEC00000003FF000FFC00000001FE0007F8000000 +01FE0007F800000001FE0007F800000000FC0003F000000000FC0003F000000000780001E00000 +0000780001E000000000780001E000000000300000C000003C257FA43F>87 +D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 +FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC +017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 D<FFC00000FFC000000FC00000 +0FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000 +000FC000000FC3F8000FCFFE000FF81F800FE00FC00FC007E00FC007E00FC003F00FC003F00FC0 +03F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F00FC003F00F +C007E00FC007C00FE00FC00F383F000E1FFE000C07F0001D267EA522>I<007FE003FFF807C07C +1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 +7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 +00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F +8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 +1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E +001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF +C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 +007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 +7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF +FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 +E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< +01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC +007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 +00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 +0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>I<FFC00000FF +C000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000 +0FC000000FC000000FC000000FC1F8000FC7FE000FCC3F000FD01F000FF01F800FE01F800FE01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC0 +1F800FC01F800FC01F800FC01F800FC01F800FC01F80FFFCFFF8FFFCFFF81D267DA522>I<0F00 +1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 +7EA611>I<FFC0FFC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0 +0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FF +FCFFFC0E267EA511>108 D<FF81FC01FC00FF87FF07FF000F8C1F8C1F800F980F980F800FB00F +F00FC00FA00FE00FC00FA00FE00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0 +0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFFCFFFCFFFCFFFCFFFCFFFC +2E187D9733>I<FF81F800FF87FE000F8C3F000F901F000FB01F800FA01F800FA01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F80FFFCFFF8FFFCFFF81D187D9722>I<007F800003FFF0 +0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 +1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F +C0FC0003FFF000007F80001A187E971F>I<FFC3F800FFCFFE000FF83F800FE00FC00FC00FE00F +C007E00FC007F00FC003F00FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F8 +0FC003F80FC007F00FC007F00FC007E00FC00FC00FE01FC00FF83F000FDFFE000FC7F0000FC000 +000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000FFFC0000FFFC +00001D237E9722>I<FF87C0FF8FF00F98F80FB1F80FA1F80FA1F80FE0F00FC0000FC0000FC000 +0FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC000FFFE00 +FFFE0015187E9719>114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 +7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 +EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 +0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 +0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E +0013237FA218>I<FFC1FF80FFC1FF800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC0 +1F800FC03F800FC03F8007C07F8007E0DF8003FF9FF800FE1FF81D187D9722>I<FFF80FF8FFF8 +0FF80FC003C00FE0018007E0030007E0030003F0060003F0060003F80E0001F80C0001FC1C0000 +FC180000FE1800007E3000007E3000003F6000003F6000001FC000001FC000001FC000000F8000 +000F800000070000000700001D187F9720>I<FFF83FF0FFF83FF00FC00F0007E00C0003F01C00 +03F8380001FC700000FCE000007EC000003F8000003F8000001F8000000FC000001FE000001FF0 +000033F8000071F80000E0FC0001C07E0003807F0003003F000F001F80FFC07FF8FFC07FF81D18 +7F9720>120 D<FFF80FF8FFF80FF80FC003C00FE0018007E0030007E0030003F0060003F00600 +03F80E0001F80C0001FC1C0000FC180000FE1800007E3000007E3000003F6000003F6000001FC0 +00001FC000001FC000000F8000000F800000070000000700000006000000060000000C0000300C +0000781C0000FC180000FC380000FC70000078E000007FC000001F0000001D237F9720>I<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 D<FFC0FFC00A027D8A0F>45 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>I<FF83F81E00E01C00C01C00800E00800E01000E02000E02000F040007 +040007080007080007100003900003A00003E00003C00003800001800001000015147C9318>I< +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 D<FFFFFFFFE00000FFFFFFFFFE0000FFFFFFFFFF800000FF0000FFC00000FF00003FF0 +0000FF00001FF80000FF00000FF80000FF000007FC0000FF000007FC0000FF000007FE0000FF00 +0003FE0000FF000003FE0000FF000003FE0000FF000003FE0000FF000007FE0000FF000007FE00 +00FF000007FC0000FF000007FC0000FF00000FF80000FF00001FF00000FF00003FE00000FF0000 +FF800000FF000FFF000000FFFFFFFE000000FFFFFFFFC00000FF00001FF00000FF000007F80000 +FF000003FE0000FF000003FE0000FF000001FF0000FF000001FF8000FF000000FF8000FF000000 +FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF +000000FFC000FF000000FF8000FF000001FF8000FF000001FF0000FF000003FF0000FF000007FE +0000FF00000FFC0000FF00007FF800FFFFFFFFFFE000FFFFFFFFFF8000FFFFFFFFFC000032317E +B039>I<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 +003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 +000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F +E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 +0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 +803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 +0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 +001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 +3A>I<FFFFFFFFFFE0FFFFFFFFFFE0FFFFFFFFFFE000FF80007FE000FF80000FF000FF800003F0 +00FF800001F000FF800001F000FF800000F000FF800000F000FF8000007000FF8000007000FF80 +00007000FF8000003800FF8000003800FF8007003800FF8007003800FF8007000000FF80070000 +00FF8007000000FF800F000000FF801F000000FF803F000000FFFFFF000000FFFFFF000000FFFF +FF000000FF803F000000FF801F000000FF800F000000FF8007000000FF8007000000FF80070000 +00FF8007000000FF8007000000FF8000000000FF8000000000FF8000000000FF8000000000FF80 +00000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80000000 +00FF80000000FFFFFFE00000FFFFFFE00000FFFFFFE000002D317EB033>70 +D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 +0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 +0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 +0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF +C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 +000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF +0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 +00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< +FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F +C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 +7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 +007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF +FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF +8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 +FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 +00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF +FFC03A317EB03F>I<FFFFFF80FFFFFF80FFFFFF8000FF800000FF800000FF800000FF800000FF +800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000 +FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF8000 +00FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF80 +0000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF8000FFFF +FF80FFFFFF80FFFFFF8019317EB01E>I<FFFF800001FFFFC0FFFFC00001FFFFC0FFFFE00001FF +FFC000FFF0000003E00000FFF8000001C00000EFFC000001C00000E7FC000001C00000E7FE0000 +01C00000E3FF000001C00000E1FF800001C00000E0FFC00001C00000E07FE00001C00000E03FE0 +0001C00000E03FF00001C00000E01FF80001C00000E00FFC0001C00000E007FE0001C00000E003 +FE0001C00000E001FF0001C00000E001FF8001C00000E000FFC001C00000E0007FE001C00000E0 +003FF001C00000E0001FF001C00000E0001FF801C00000E0000FFC01C00000E00007FE01C00000 +E00003FF01C00000E00001FF81C00000E00000FF81C00000E00000FFC1C00000E000007FE1C000 +00E000003FF1C00000E000001FF9C00000E000000FFDC00000E0000007FDC00000E0000007FFC0 +0000E0000003FFC00000E0000001FFC00000E0000000FFC00000E00000007FC00000E00000003F +C00000E00000003FC00000E00000001FC00000E00000000FC00001F000000007C000FFFFE00000 +03C000FFFFE0000001C000FFFFE0000001C0003A317EB03F>78 D<FFFFFFFFE000FFFFFFFFFE00 +FFFFFFFFFF8000FF8000FFE000FF80003FF000FF80000FF800FF800007FC00FF800007FC00FF80 +0003FE00FF800003FE00FF800003FF00FF800003FF00FF800003FF00FF800003FF00FF800003FF +00FF800003FF00FF800003FF00FF800003FE00FF800003FE00FF800007FC00FF800007F800FF80 +000FF800FF80003FE000FF8000FFC000FFFFFFFF0000FFFFFFF80000FF8000000000FF80000000 +00FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80 +00000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80000000 +00FF8000000000FF8000000000FF8000000000FF8000000000FF80000000FFFFFF800000FFFFFF +800000FFFFFF80000030317EB037>80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F +C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 +0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 +0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 +0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F +F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 +00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 +00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 +000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF +000031307DAF38>84 D<FFFFFF8003FFFF80FFFFFF8003FFFF80FFFFFF8003FFFF8000FF800000 +07C00000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF8000 +0003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF80 +000003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF +80000003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000 +FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF800000038000 +00FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF8000000380 +0000FF80000003800000FF80000003800000FF800000038000007F800000038000007F80000007 +0000007FC00000070000003FC000000E0000003FC000000E0000001FE000001C0000000FF00000 +3800000007F800007000000003FC0001E000000000FF801FC0000000003FFFFF80000000000FFF +FE000000000000FFE000000039317EB03E>I<FFFFFC0000FFFFFFFFFC0000FFFFFFFFFC0000FF +FF03FF00000003C001FF000000038001FF800000078000FF800000070000FFC000000700007FC0 +00000E00007FC000000E00007FE000001E00003FE000001C00003FF000003C00001FF000003800 +001FF800003800000FF800007000000FFC000070000007FC0000E0000007FC0000E0000007FE00 +01E0000003FE0001C0000003FF0003C0000001FF000380000001FF800380000000FF8007000000 +00FFC00700000000FFC00F000000007FC00E000000007FE01E000000003FE01C000000003FF03C +000000001FF038000000001FF838000000000FF870000000000FF870000000000FFCF000000000 +07FCE00000000007FFE00000000003FFC00000000003FFC00000000001FF800000000001FF8000 +00000000FF000000000000FF000000000000FF0000000000007E0000000000007E000000000000 +3C0000000000003C00000038317EB03D>I<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>I<FFFF801FFCFFFF801FFCFF +FF801FFC0FF80003C007F800038007FC00078003FC00070003FE000F0001FE000E0001FF000E00 +00FF001C0000FF001C00007F803800007F803800007FC07800003FC07000003FE0F000001FE0E0 +00001FF1E000000FF1C000000FF9C0000007FB80000007FB80000003FF00000003FF00000003FF +00000001FE00000001FE00000000FC00000000FC00000000780000000078000026207E9F2B>I< +FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE +00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 +FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 +7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F +FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 +000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 +7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F +E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 +00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 +003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF +FF28207F9F2B>I<FFFF801FFCFFFF801FFCFFFF801FFC0FF80003C007F800038007FC00078003 +FC00070003FE000F0001FE000E0001FF000E0000FF001C0000FF001C00007F803800007F803800 +007FC07800003FC07000003FE0F000001FE0E000001FF1E000000FF1C000000FF9C0000007FB80 +000007FB80000003FF00000003FF00000003FF00000001FE00000001FE00000000FC00000000FC +000000007800000000780000000070000000007000000000F000000000E000000001E000007C01 +C00000FE03C00000FE03800000FE07800000FE0F000000FC1E000000787C0000003FF00000000F +C0000000262E7E9F2B>I 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 D<FFFFFFF800FFFFFFFF00FFFFFFFFC003F8001FE003F8000FF003F80007F803F8 +0003F803F80003FC03F80003FC03F80001FC03F80001FC03F80001FC03F80003FC03F80003F803 +F80003F803F80007F003F8000FF003F8001FC003F800FF8003FFFFFE0003FFFFFFC003F8000FF0 +03F80003F803F80001FC03F80001FE03F80000FE03F80000FE03F80000FF03F80000FF03F80000 +FF03F80000FF03F80000FF03F80000FF03F80000FE03F80001FE03F80003FC03F80007FC03F800 +1FF8FFFFFFFFE0FFFFFFFFC0FFFFFFFE0028297DA830>I<00007FE0030007FFFC07001FFFFF0F +007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 +0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 +0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 +0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 +F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 +>I<FFFFFFFFE0FFFFFFFFE0FFFFFFFFE003FC001FE003FC0007F003FC0001F003FC0001F003FC +0000F003FC00007003FC00007003FC00007003FC01C07803FC01C03803FC01C03803FC01C03803 +FC03C00003FC03C00003FC0FC00003FFFFC00003FFFFC00003FFFFC00003FC0FC00003FC03C000 +03FC03C00003FC01C00E03FC01C00E03FC01C00E03FC01C01C03FC00001C03FC00001C03FC0000 +1C03FC00003C03FC00003803FC00007803FC0000F803FC0001F803FC0003F803FC001FF8FFFFFF +FFF0FFFFFFFFF0FFFFFFFFF027297EA82C>69 D<FFFFFFFFC0FFFFFFFFC0FFFFFFFFC003FC003F +C003FC000FE003FC0003E003FC0001E003FC0001E003FC0000E003FC0000E003FC0000E003FC00 +00F003FC01C07003FC01C07003FC01C07003FC01C00003FC03C00003FC03C00003FC0FC00003FF +FFC00003FFFFC00003FFFFC00003FC0FC00003FC03C00003FC03C00003FC01C00003FC01C00003 +FC01C00003FC01C00003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000 +03FC00000003FC00000003FC000000FFFFFC0000FFFFFC0000FFFFFC000024297EA82A>I<0000 +7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F +0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 +000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 +00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 +00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF +0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 +FFFE0F0000007FF003002D297CA835>I<FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF03FC0000 +3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000 +3FC003FC00003FC003FFFFFFFFC003FFFFFFFFC003FFFFFFFFC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000 +3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC0FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF30297EA835>I<FFFFFC +FFFFFCFFFFFC01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00 +01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00 +01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00FFFFFCFFFFFC +FFFFFC16297FA819>I<FFFE0000003FFF80FFFE0000003FFF80FFFF0000007FFF8003FF000000 +7FE00003FF0000007FE00003BF800000EFE00003BF800000EFE000039FC00001CFE000039FC000 +01CFE000038FE000038FE000038FE000038FE000038FE000038FE0000387F000070FE0000387F0 +00070FE0000383F8000E0FE0000383F8000E0FE0000381FC001C0FE0000381FC001C0FE0000381 +FC001C0FE0000380FE00380FE0000380FE00380FE00003807F00700FE00003807F00700FE00003 +803F80E00FE00003803F80E00FE00003803F80E00FE00003801FC1C00FE00003801FC1C00FE000 +03800FE3800FE00003800FE3800FE000038007F7000FE000038007F7000FE000038007F7000FE0 +00038003FE000FE000038003FE000FE000038001FC000FE000038001FC000FE000038000F8000F +E000FFFE00F803FFFF80FFFE00F803FFFF80FFFE007003FFFF8039297DA840>77 +D<FFFC00007FFFFFFE00007FFFFFFF00007FFF03FF800001C003FFC00001C003BFE00001C0039F +E00001C0039FF00001C0038FF80001C00387FC0001C00383FE0001C00381FF0001C00380FF8001 +C003807F8001C003807FC001C003803FE001C003801FF001C003800FF801C0038007FC01C00380 +03FC01C0038003FE01C0038001FF01C0038000FF81C00380007FC1C00380003FE1C00380001FF1 +C00380000FF1C00380000FF9C003800007FDC003800003FFC003800001FFC003800000FFC00380 +00007FC0038000007FC0038000003FC0038000001FC0038000000FC00380000007C0FFFE000003 +C0FFFE000001C0FFFE000001C030297EA835>I<FFFFFFF800FFFFFFFF00FFFFFFFFC003FC003F +E003FC0007F003FC0003F803FC0003FC03FC0001FC03FC0001FE03FC0001FE03FC0001FE03FC00 +01FE03FC0001FE03FC0001FE03FC0001FE03FC0001FC03FC0003FC03FC0003F803FC0007F003FC +003FE003FFFFFF8003FFFFFE0003FC00000003FC00000003FC00000003FC00000003FC00000003 +FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000 +03FC00000003FC00000003FC000000FFFFF00000FFFFF00000FFFFF0000027297EA82E>80 +D<FFFFFFE00000FFFFFFFE0000FFFFFFFF800003FC003FE00003FC000FF00003FC0007F80003FC +0003FC0003FC0001FC0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FE +0003FC0001FE0003FC0001FC0003FC0003F80003FC0007F80003FC000FE00003FC003FC00003FF +FFFE000003FFFFFE000003FC00FF800003FC003FC00003FC001FE00003FC000FF00003FC0007F8 +0003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC +0007F80003FC0007F80003FC0007F80E03FC0007F80E03FC0003F80E03FC0001FC1CFFFFF000FE +1CFFFFF0007FF8FFFFF0000FE02F297EA832>82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 +3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF +C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 +00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 +E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I<FFFFF0 +00FFFEFFFFF000FFFEFFFFF000FFFE03FC0000038003FC0000038003FC0000038003FC00000380 +03FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00 +00038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00000380 +03FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00 +00038003FC0000038003FC0000038003FC0000038003FC0000038001FC0000070001FE00000700 +00FE00000E00007F00000E00003F00003C00001FC0007800000FF003F0000007FFFFE0000000FF +FF800000001FFC00002F297EA834>85 D<FFFFF0007FFFFFFFF0007FFFFFFFF0007FFF03FE0000 +01C001FE0000038001FE0000038000FF0000070000FF0000070000FF80000F00007F80000E0000 +7FC0000E00003FC0001C00003FE0001C00001FE0003800001FE0003800001FF0007800000FF000 +7000000FF800F0000007F800E0000007FC00E0000003FC01C0000003FC01C0000003FE03C00000 +01FE0380000001FF0780000000FF0700000000FF87000000007F8E000000007F8E000000007FDE +000000003FDC000000003FFC000000001FF8000000001FF8000000000FF0000000000FF0000000 +000FF00000000007E00000000007E00000000003C00000000003C0000030297FA833>I<FFFFE0 +FFFFE01FFFC0FFFFE0FFFFE01FFFC0FFFFE0FFFFE01FFFC003FC0003FC0000700003FC0003FC00 +00700003FE0003FE0000F00001FE0001FE0000E00001FE0001FE0000E00001FF0001FF0001E000 +00FF0001FF0001C00000FF0001FF0001C000007F8003FF80038000007F8003FF80038000007FC0 +07FFC0078000003FC0073FC0070000003FC0073FC0070000003FE00F3FE00F0000001FE00E1FE0 +0E0000001FE00E1FE00E0000000FF01C0FF01C0000000FF01C0FF01C0000000FF01C0FF81C0000 +0007F83807F83800000007F83807F83800000007FC7807FC7800000003FC7003FC7000000003FC +7003FC7000000003FEF003FEF000000001FEE001FEE000000001FEE001FEE000000000FFC000FF +C000000000FFC000FFC000000000FFC000FFC0000000007F80007F80000000007F80007F800000 +00007F80007F80000000003F00003F00000000003F00003F00000000003F00003F00000000001E +00001E00000000001E00001E00000042297FA845>I<03FF80000FFFF0001F01FC003F80FE003F +807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 +0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF +803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D<FFE00000FFE00000FFE000000FE000000FE0 +00000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000F +E000000FE1FE000FE7FF800FFE07E00FF803F00FF001F80FE000FC0FE000FC0FE0007E0FE0007E +0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007E0FE000 +7E0FE0007E0FE000FC0FE000FC0FF001F80FF803F00F9C0FE00F0FFF800E01FC00202A7EA925> +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>I<FFE00000FFE00000FFE000000FE000000FE000000FE000000FE000000FE000000FE000 +000FE000000FE000000FE000000FE000000FE000000FE000000FE07E000FE1FF800FE30FC00FE4 +0FE00FE807E00FF807F00FF007F00FF007F00FE007F00FE007F00FE007F00FE007F00FE007F00F +E007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F0 +0FE007F0FFFE3FFFFFFE3FFFFFFE3FFF202A7DA925>I<07000F801FC03FE03FE03FE01FC00F80 +07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F +E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I<FF +E0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0 +0FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FF +FEFFFEFFFE0F2A7EA912>108 D<FFC07F001FC000FFC1FFC07FF000FFC307E0C1F8000FC407F1 +01FC000FC803F200FC000FD803FE00FE000FD003FC00FE000FD003FC00FE000FE003F800FE000F +E003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800 +FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE0 +03F800FE000FE003F800FE000FE003F800FE000FE003F800FE00FFFE3FFF8FFFE0FFFE3FFF8FFF +E0FFFE3FFF8FFFE0331B7D9A38>I<FFC07E00FFC1FF80FFC30FC00FC40FE00FC807E00FD807F0 +0FD007F00FD007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007 +F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F0FFFE3FFFFFFE +3FFFFFFE3FFF201B7D9A25>I<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 +07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE +0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 +003FE0001D1B7E9A22>I<FFE1FE00FFE7FF80FFFE0FE00FF803F00FF001F80FE001FC0FE000FC +0FE000FE0FE000FE0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE000 +7F0FE0007E0FE000FE0FE000FE0FE000FC0FE001FC0FF001F80FF803F00FFC0FE00FEFFF800FE1 +FC000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE00000FF +FE0000FFFE0000FFFE000020277E9A25>I<FFC3E0FFC7F8FFCC7C0FD8FE0FD0FE0FD0FE0FF0FE +0FE07C0FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE000 +0FE0000FE0000FE0000FE000FFFF00FFFF00FFFF00171B7E9A1B>114 D<03FE300FFFF03E03F0 +7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 +0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> +I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF +E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 +7FA51A>I<FFE07FF0FFE07FF0FFE07FF00FE007F00FE007F00FE007F00FE007F00FE007F00FE0 +07F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00F +E007F00FE007F00FE007F00FE00FF00FE00FF007E017F003F067FF01FFC7FF007F87FF201B7D9A +25>I<FFFE07FFFFFE07FFFFFE07FF07F000E007F000E007F801E003F801C003F801C001FC0380 +01FC038001FE078000FE070000FF0F00007F0E00007F0E00003F9C00003F9C00003FFC00001FF8 +00001FF800000FF000000FF000000FF0000007E0000007E0000003C0000003C000201B7F9A23> +I<FFFC7FFC1FFCFFFC7FFC1FFCFFFC7FFC1FFC0FE00FE001C007F007E0038007F007E0038007F8 +07F0078003F807F0070003F807F8070001FC0FF80E0001FC0FF80E0001FE1FFC1E0000FE1CFC1C +0000FE1CFE1C0000FF387E3C00007F387E3800007F787F3800003FF03F7000003FF03F7000003F +E01FF000001FE01FE000001FE01FE000000FC00FC000000FC00FC000000FC00FC0000007800780 +000007800780002E1B7F9A31>I<FFFC1FFEFFFC1FFEFFFC1FFE07F0078003F8070001FC0F0001 +FE1E0000FE3C00007F7800003FF800003FF000001FE000000FE0000007F0000007F800000FF800 +001FFC00003DFE000038FF0000787F0000F03F8001E03FC003C01FE003800FE0FFF03FFFFFF03F +FFFFF03FFF201B7F9A23>I<FFFE07FFFFFE07FFFFFE07FF07F000E007F000E007F801E003F801 +C003F801C001FC038001FC038001FE078000FE070000FF0F00007F0E00007F0E00003F9C00003F +9C00003FFC00001FF800001FF800000FF000000FF0000007F0000007E0000007E0000003C00000 +03C000000380000003800000078000380700007C070000FE0E0000FE0E0000FE1C0000FE380000 +7C7000003FE000000F80000020277F9A23>I 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 D<FFFFF0FFFFF0FFFFF01C00701C00701C00701C00701C0000 +1C00001C0E001C0E001C0E001FFE001FFE001FFE001C0E001C0E001C0E001C00001C00001C0038 +1C00381C00381C00381C0038FFFFF8FFFFF8FFFFF8151C7F9B18>I<FFFFE0FFFFE0FFFFE01C00 +E01C00E01C00E01C00E01C00001C00001C1C001C1C001C1C001FFC001FFC001FFC001C1C001C1C +001C1C001C00001C00001C00001C00001C00001C00001C0000FFC000FFC000FFC000131C7E9B18 +>I<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F +FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F +07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 +0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 +0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E +00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B +18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 +C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D +C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 +E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 +E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>I<FFFE00FFFF80FFFF +C01C03C01C01E01C00E01C00701C00701C00701C00701C00701C00E01C01E01C03C01FFFC01FFF +801FFE001C00001C00001C00001C00001C00001C00001C00001C0000FF8000FF8000FF8000141C +7F9B18>I<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C +0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C +039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 +80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 +E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF +FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 +700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 +1C7F9B18>I<FF83FEFF83FEFF83FE1C00701C00701C00701C00701C00701C00701C00701C0070 +1C00701C00701C00701C00701C00701C00701C00701C00701C00701C00701C00700E00E00F01E0 +0783C003FF8001FF00007C00171C809B18>I<FF07F8FF07F8FF07F81C01C01E03C00E03800F07 +80070700070700038E00038E0001DC0001DC0001DC0000F80000F8000070000070000070000070 +0000700000700000700000700000700001FC0003FE0001FC00151C7F9B18>89 +D<FFF8FFF8FFF8E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000 +E000E000E000E000E000E000E000E000E000E000E000E000E000E000FFF8FFF8FFF80D24779F18 +>91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 +0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 +007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> +I<FFF8FFF8FFF80038003800380038003800380038003800380038003800380038003800380038 +00380038003800380038003800380038003800380038003800380038FFF8FFF8FFF80D247F9F18 +>I<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 D<FFC0FFC00A027F8A0F>I<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 D<FFFFE0000F80380007801E0007801F0007800F0007800F8007800F8007800F80 +07800F8007800F8007800F0007801F0007801E0007803C0007FFF00007803C0007801E0007800F +0007800F8007800780078007C0078007C0078007C0078007C0078007C00780078007800F800780 +0F0007801F000F803C00FFFFF0001A1F7E9E20>I<000FC040007030C001C009C0038005C00700 +03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 +000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 +3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D +9F21>I<FFFFE0000F803C0007801E000780070007800380078003C0078001E0078001E0078001 +F0078000F0078000F0078000F8078000F8078000F8078000F8078000F8078000F8078000F80780 +00F8078000F8078000F0078000F0078000F0078001E0078001E0078003C0078003800780070007 +800E000F803C00FFFFE0001D1F7E9E23>I<FFFFFF000F800F0007800300078003000780010007 +800180078000800780008007800080078080800780800007808000078080000781800007FF8000 +078180000780800007808000078080000780800007800020078000200780002007800040078000 +4007800040078000C0078000C0078001800F800F80FFFFFF801B1F7E9E1F>I<FFFFFF000F800F +000780030007800300078001000780018007800080078000800780008007800080078080000780 +800007808000078080000781800007FF8000078180000780800007808000078080000780800007 +800000078000000780000007800000078000000780000007800000078000000FC00000FFFE0000 +191F7E9E1E>I<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 +3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 +00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 +01E0070001E0038002E000E0046000781820000FE0001E217D9F24>I<FFF8FFF80F800F800780 +0F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007 +800F0007800F0007FFFF0007800F0007800F0007800F0007800F0007800F0007800F0007800F00 +07800F0007800F0007800F0007800F0007800F0007800F0007800F000F800F80FFF8FFF81D1F7E +9E22>I<FFFC0FC007800780078007800780078007800780078007800780078007800780078007 +80078007800780078007800780078007800780078007800FC0FFFC0E1F7F9E10>I<0FFFC0007C +00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C +00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 +0040780040700030E0000F800012207E9E17>I<FFFE000FC00007800007800007800007800007 +800007800007800007800007800007800007800007800007800007800007800007800007800007 +800007800207800207800207800207800607800407800407800C07801C0F807CFFFFFC171F7E9E +1C>76 D<FF80001FF80F80001F800780001F0005C0002F0005C0002F0005C0002F0004E0004F00 +04E0004F000470008F000470008F000470008F000438010F000438010F000438010F00041C020F +00041C020F00041C020F00040E040F00040E040F00040E040F000407080F000407080F00040708 +0F000403900F000403900F000401E00F000401E00F000401E00F000E00C00F001F00C01F80FFE0 +C1FFF8251F7E9E2A>I<FF803FF807C007C007C0038005E0010005E0010004F001000478010004 +780100043C0100043C0100041E0100040F0100040F010004078100040781000403C1000401E100 +0401E1000400F1000400F1000400790004003D0004003D0004001F0004001F0004000F00040007 +00040007000E0003001F000300FFE001001D1F7E9E22>I<001F800000F0F00001C0380007801E +000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 +01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C +0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 +1C217D9F23>I<FFFFE0000F80780007801C0007801E0007800F0007800F8007800F8007800F80 +07800F8007800F8007800F8007800F0007801E0007801C000780780007FFE00007800000078000 +000780000007800000078000000780000007800000078000000780000007800000078000000780 +0000078000000FC00000FFFC0000191F7E9E1F>I<001F800000F0F00001C0380007801E000F00 +0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 +0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 +3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 +10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>I<FFFF80 +000F80F0000780780007803C0007801E0007801E0007801F0007801F0007801F0007801F000780 +1E0007801E0007803C00078078000780F00007FF80000781C0000780E0000780F0000780700007 +807800078078000780780007807C0007807C0007807C0007807C0407807E0407803E040FC01E08 +FFFC0F10000003E01E207E9E21>I<07E0800C1980100780300380600180600180E00180E00080 +E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 +0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D +9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 +10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F +0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 +0F0000001F800007FFFE001C1F7E9E21>I<FFFC3FF80FC007C007800380078001000780010007 +800100078001000780010007800100078001000780010007800100078001000780010007800100 +078001000780010007800100078001000780010007800100078001000780010007800100038002 +000380020001C0020001C0040000E008000070180000382000000FC0001D207E9E22>I<FFF003 +FE1F8000F80F0000600F800060078000400780004003C0008003C0008003C0008001E0010001E0 +010001F0010000F0020000F0020000F806000078040000780400003C0800003C0800003C080000 +1E1000001E1000001F3000000F2000000F20000007C0000007C0000007C0000003800000038000 +00038000000100001F207F9E22>I<FFF07FF81FF01F800FC007C00F00078003800F0007800100 +0F0007C00100078007C00200078007C00200078007C0020003C009E0040003C009E0040003C009 +E0040003E010F00C0001E010F0080001E010F0080001F02078080000F02078100000F020781000 +00F0403C10000078403C20000078403C20000078C03E2000003C801E4000003C801E4000003C80 +1E4000001F000F8000001F000F8000001F000F8000001E00078000000E00070000000E00070000 +000C000300000004000200002C207F9E2F>I<FEFEC0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0 +C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0FEFE072D7CA10D>91 +D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>I<FEFE06 +060606060606060606060606060606060606060606060606060606060606060606060606060606 +06FEFE072D7FA10D>I<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>I<FF83F81E01E01C00C00E00800E00800E00800701000701000382000382000382 +0001C40001C40001EC0000E80000E80000700000700000700000200015147F9318>I<FF9FE1FC +3C0780701C0300601C0380200E0380400E0380400E03C0400707C0800704C0800704E080038861 +000388710003C8730001D0320001D03A0000F03C0000E01C0000E01C0000601800004008001E14 +7F9321>I<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 +7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>I<FF83F81E01E0 +1C00C00E00800E00800E008007010007010003820003820003820001C40001C40001EC0000E800 +00E800007000007000007000002000002000004000004000004000F08000F08000F10000620000 +3C0000151D7F9318>I<3FFF380E200E201C40384078407000E001E001C00380078007010E011E +011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF +FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F +C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 +FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 +00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 +C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F +F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 +0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 +0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F +F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 +0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF +C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 +FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 +0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F +C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 +D<FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FFFFFFFFFFFC000007FFFFFFFFFFFC000007FFFFFFFFFFFC000007FFFFFFFFFFFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000FFFFFFF803FFFFFFE0FFFF +FFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0433B7CBA4C>I<FFFFFFFE000000 +FFFFFFFE000000FFFFFFFE000000FFFFFFFE000000007FF000000000007FF000000000007FF000 +000000007FF000000000007FF000000000007FF000000000007FF000000000007FF00000000000 +7FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF00000 +0000007FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007F +F000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF0000000 +00007FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF0 +00000000007FF000000780007FF000000780007FF000000780007FF000000780007FF000000780 +007FF000000F80007FF000000F00007FF000000F00007FF000000F00007FF000001F00007FF000 +001F00007FF000001F00007FF000003F00007FF000003F00007FF000007F00007FF00000FF0000 +7FF00001FF00007FF00003FF00007FF0000FFE00007FF0007FFE00FFFFFFFFFFFE00FFFFFFFFFF +FE00FFFFFFFFFFFE00FFFFFFFFFFFE00313B7CBA3A>76 D<FFFFF0000007FFFFE0FFFFF8000007 +FFFFE0FFFFFC000007FFFFE0FFFFFE000007FFFFE0007FFE00000007E000007FFF00000003C000 +007FFF80000003C000007BFFC0000003C000007BFFE0000003C0000079FFE0000003C0000078FF +F0000003C00000787FF8000003C00000783FFC000003C00000783FFE000003C00000781FFE0000 +03C00000780FFF000003C000007807FF800003C000007803FFC00003C000007803FFE00003C000 +007801FFE00003C000007800FFF00003C0000078007FF80003C0000078003FFC0003C000007800 +3FFE0003C0000078001FFF0003C0000078000FFF0003C00000780007FF8003C00000780003FFC0 +03C00000780003FFE003C00000780001FFF003C00000780000FFF003C000007800007FF803C000 +007800003FFC03C000007800003FFE03C000007800001FFF03C000007800000FFF03C000007800 +0007FF83C0000078000003FFC3C0000078000003FFE3C0000078000001FFF3C0000078000000FF +F3C00000780000007FFBC00000780000003FFFC00000780000003FFFC00000780000001FFFC000 +00780000000FFFC000007800000007FFC000007800000003FFC000007800000003FFC000007800 +000001FFC000007800000000FFC0000078000000007FC0000078000000003FC000007800000000 +3FC00000FC000000001FC000FFFFFC0000000FC000FFFFFC00000007C000FFFFFC00000003C000 +FFFFFC00000003C000433B7CBA4C>78 D<FFFFFFF8001FFFFF80FFFFFFF8001FFFFF80FFFFFFF8 +001FFFFF80FFFFFFF8001FFFFF80007FF00000001F8000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000003FF00000001E0000003FF00000001E +0000003FF80000001E0000001FF80000003C0000001FF80000003C0000000FFC00000078000000 +07FC000000F800000007FE000001F000000003FF000003F000000001FF800007E000000000FFE0 +001FC0000000003FFC01FF80000000001FFFFFFE000000000007FFFFF8000000000000FFFFE000 +00000000000FFE00000000413C7CBA4A>85 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>I<FFFFF001FFFCFFFFF001FFFCFFFFF001FFFCFFFFF001FFFC03FE00001F8003FF00001F +0001FF00001E0001FF80003E0000FF80003C0000FF80003C00007FC0007800007FC0007800007F +E000F800003FE000F000003FF001F000001FF001E000001FF803E000000FF803C000000FFC03C0 +000007FC0780000007FC0780000007FE0F80000003FE0F00000003FF1F00000001FF1E00000001 +FFBE00000000FFBC00000000FFFC000000007FF8000000007FF8000000007FF8000000003FF000 +0000003FF0000000001FE0000000001FE0000000000FC0000000000FC000000000078000000000 +0780000000000F80000000000F00000000001F00000000001E00000008003E0000007F003C0000 +007F007C000000FF8078000000FF80F8000000FF80F0000000FF81E00000007F07C00000007C1F +800000003FFF000000001FFE0000000007F0000000002E377EA533>121 +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 new file mode 100644 index 0000000..5f0f600 --- /dev/null +++ b/lib/readline/doc/hstech.texinfo @@ -0,0 +1,489 @@ +@ignore +This file documents the user interface to the GNU History library. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Authored by Brian Fox and Chet Ramey. + +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 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). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and 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. +@end ignore + +@node Programming with GNU History +@chapter 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, @pxref{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. +@end menu + +@node Introduction to History +@section 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 @dfn{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 @code{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. + +@node History Storage +@section History Storage + +The history list is an array of history entries. A history entry is +declared as follows: + +@example +typedef struct _hist_entry @{ + char *line; + char *data; +@} HIST_ENTRY; +@end example + +The history list itself might therefore be declared as + +@example +HIST_ENTRY **the_history_list; +@end example + +The state of the History library is encapsulated into a single structure: + +@example +/* 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; +@end example + +If the flags member includes @code{HS_STIFLED}, the history has been +stifled. + +@node History Functions +@section 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. +@end menu + +@node Initializing History and State Management +@subsection 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. + +@deftypefun void using_history () +Begin a session in which the history functions might be used. This +initializes the interactive variables. +@end deftypefun + +@deftypefun {HISTORY_STATE *} history_get_history_state () +Return a structure describing the current state of the input history. +@end deftypefun + +@deftypefun void history_set_history_state (HISTORY_STATE *state) +Set the state of the history list according to @var{state}. +@end deftypefun + +@node History List Management +@subsection History List Management + +These functions manage individual entries on the history list, or set +parameters managing the list itself. + +@deftypefun void add_history (char *string) +Place @var{string} at the end of the history list. The associated data +field (if any) is set to @code{NULL}. +@end deftypefun + +@deftypefun {HIST_ENTRY *} remove_history (int which) +Remove history entry at offset @var{which} from the history. The +removed element is returned so you can free the line, data, +and containing structure. +@end deftypefun + +@deftypefun {HIST_ENTRY *} replace_history_entry (int which, char *line, char *data) +Make the history entry at offset @var{which} have @var{line} and @var{data}. +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 stifle_history (int max) +Stifle the history list, remembering only the last @var{max} entries. +@end deftypefun + +@deftypefun 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. +@end deftypefun + +@deftypefun int history_is_stifled () +Returns non-zero if the history is stifled, zero if it is not. +@end deftypefun + +@node Information About the History List +@subsection Information About the History List + +These functions return information about the entire history list or +individual list entries. + +@deftypefun {HIST_ENTRY **} history_list () +Return a @code{NULL} terminated array of @code{HIST_ENTRY} which is the +current input history. Element 0 of this list is the beginning of time. +If there is no history, return @code{NULL}. +@end deftypefun + +@deftypefun int where_history () +Returns the offset of the current history element. +@end deftypefun + +@deftypefun {HIST_ENTRY *} current_history () +Return the history entry at the current position, as determined by +@code{where_history ()}. If there is no entry there, return a @code{NULL} +pointer. +@end deftypefun + +@deftypefun {HIST_ENTRY *} history_get (int offset) +Return the history entry at position @var{offset}, starting from +@code{history_base}. If there is no entry there, or if @var{offset} +is greater than the history length, return a @code{NULL} pointer. +@end deftypefun + +@deftypefun 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. +@end deftypefun + +@node Moving Around the History List +@subsection Moving Around the History List + +These functions allow the current index into the history list to be +set or changed. + +@deftypefun int history_set_pos (int pos) +Set the position in the history list to @var{pos}, an absolute index +into the list. +@end deftypefun + +@deftypefun {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 @code{NULL} pointer. +@end deftypefun + +@deftypefun {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 @code{NULL} pointer. +@end deftypefun + +@node Searching the History List +@subsection Searching the History List +@cindex History Searching + +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 @dfn{anchored}, +meaning that the string must match at the beginning of the history entry. +@cindex anchored search + +@deftypefun int history_search (char *string, int direction) +Search the history for @var{string}, starting at the current history +offset. If @var{direction} < 0, then the search is through previous entries, +else through subsequent. If @var{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 +@var{string} was found. Otherwise, nothing is changed, and a -1 is +returned. +@end deftypefun + +@deftypefun int history_search_prefix (char *string, int direction) +Search the history for @var{string}, starting at the current history +offset. The search is anchored: matching lines must begin with +@var{string}. If @var{direction} < 0, then the search is through previous +entries, else through subsequent. If @var{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. +@end deftypefun + +@deftypefun int history_search_pos (char *string, int direction, int pos) +Search for @var{string} in the history list, starting at @var{pos}, an +absolute index into the list. If @var{direction} is negative, the search +proceeds backward from @var{pos}, otherwise forward. Returns the absolute +index of the history element where @var{string} was found, or -1 otherwise. +@end deftypefun + +@node Managing the History File +@subsection 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. + +@deftypefun int read_history (char *filename) +Add the contents of @var{filename} to the history list, a line at a +time. If @var{filename} is @code{NULL}, then read from +@file{~/.history}. Returns 0 if successful, or errno if not. +@end deftypefun + +@deftypefun int read_history_range (char *filename, int from, int to) +Read a range of lines from @var{filename}, adding them to the history list. +Start reading at line @var{from} and end at @var{to}. If +@var{from} is zero, start at the beginning. If @var{to} is less than +@var{from}, then read until the end of the file. If @var{filename} is +@code{NULL}, then read from @file{~/.history}. Returns 0 if successful, +or @code{errno} if not. +@end deftypefun + +@deftypefun int write_history (char *filename) +Write the current history to @var{filename}, overwriting @var{filename} +if necessary. If @var{filename} is +@code{NULL}, then write the history list to @file{~/.history}. Values +returned are as in @code{read_history ()}. +@end deftypefun + +@deftypefun int append_history (int nelements, char *filename) +Append the last @var{nelements} of the history list to @var{filename}. +@end deftypefun + +@deftypefun int history_truncate_file (char *filename, int nlines) +Truncate the history file @var{filename}, leaving only the last +@var{nlines} lines. +@end deftypefun + +@node History Expansion +@subsection History Expansion + +These functions implement @code{csh}-like history expansion. + +@deftypefun int history_expand (char *string, char **output) +Expand @var{string}, placing the result into @var{output}, a pointer +to a string (@pxref{History Interaction}). Returns: +@table @code +@item 0 +If no expansions took place (or, if the only change in +the text was the de-slashifying of the history expansion +character); +@item 1 +if expansions did take place; +@item -1 +if there was an error in expansion; +@item 2 +if the returned line should only be displayed, but not executed, +as with the @code{:p} modifier (@pxref{Modifiers}). +@end table + +If an error ocurred in expansion, then @var{output} contains a descriptive +error message. +@end deftypefun + +@deftypefun {char *} history_arg_extract (int first, int last, char *string) +Extract a string segment consisting of the @var{first} through @var{last} +arguments present in @var{string}. Arguments are broken up as in Bash. +@end deftypefun + +@deftypefun {char *} get_history_event (char *string, int *cindex, int qchar) +Returns the text of the history event beginning at @var{string} + +@var{*cindex}. @var{*cindex} is modified to point to after the event +specifier. At function entry, @var{cindex} points to the index into +@var{string} where the history event specification begins. @var{qchar} +is a character that is allowed to end the event specification in addition +to the ``normal'' terminating characters. +@end deftypefun + +@deftypefun {char **} history_tokenize (char *string) +Return an array of tokens parsed out of @var{string}, much as the +shell might. The tokens are split on white space and on the +characters @code{()<>;&|$}, and shell quoting conventions are +obeyed. +@end deftypefun + +@node History Variables +@section History Variables + +This section describes the externally visible variables exported by +the GNU History Library. + +@deftypevar int history_base +The logical offset of the first entry in the history list. +@end deftypevar + +@deftypevar int history_length +The number of entries currently stored in the history list. +@end deftypevar + +@deftypevar int max_input_history +The maximum number of history entries. This must be changed using +@code{stifle_history ()}. +@end deftypevar + +@deftypevar char history_expansion_char +The character that starts a history event. The default is @samp{!}. +@end deftypevar + +@deftypevar char history_subst_char +The character that invokes word substitution if found at the start of +a line. The default is @samp{^}. +@end deftypevar + +@deftypevar 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. +@end deftypevar + +@deftypevar {char *} history_no_expand_chars +The list of characters which inhibit history expansion if found immediately +following @var{history_expansion_char}. The default is whitespace and +@samp{=}. +@end deftypevar + +@node History Programming Example +@section History Programming Example + +The following program demonstrates simple use of the GNU History Library. + +@smallexample +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"); + @} + @} + @} +@} +@end smallexample diff --git a/lib/readline/doc/hsuser.texinfo b/lib/readline/doc/hsuser.texinfo new file mode 100644 index 0000000..51327a3 --- /dev/null +++ b/lib/readline/doc/hsuser.texinfo @@ -0,0 +1,198 @@ +@ignore +This file documents the user interface to the GNU History library. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Authored by Brian Fox and Chet Ramey. + +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 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). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and 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. +@end ignore + +@node Using History Interactively +@chapter Using History Interactively + +@ifset BashFeatures +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. +@end ifset +@ifclear BashFeatures +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, +@pxref{Programming with GNU History}. +@end ifclear + +@menu +* History Interaction:: What it feels like using History as a user. +@end menu + +@node History Interaction +@section History Interaction +@cindex expansion + +The History library provides a history expansion feature that is similar +to the history expansion provided by @code{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 +@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 +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. +@end menu + +@node Event Designators +@subsection Event Designators +@cindex event designators + +An event designator is a reference to a command line entry in the +history list. +@cindex history events + +@table @asis + +@item @code{!} +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} +Refer to command line @var{n}. + +@item @code{!-n} +Refer to the command @var{n} lines back. + +@item @code{!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{!#} +The entire command line typed so far. + +@item @code{^string1^string2^} +Quick Substitution. Repeat the last command, replacing @var{string1} +with @var{string2}. Equivalent to +@code{!!:s/string1/string2/}. + +@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). + +@table @code + +@item 0 (zero) +The @code{0}th word. For many applications, this is the command word. + +@item n +The @var{n}th word. + +@item ^ +The first argument; that is, word 1. + +@item $ +The last argument. + +@item % +The word matched by the most recent @code{?string?} search. + +@item x-y +A range of words; @code{-@var{y}} abbreviates @code{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; +the empty string is returned in that case. + +@item x* +Abbreviates @code{x-$} + +@item x- +Abbreviates @code{x-$} like @code{x*}, but omits the last word. + +@end table + +@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{:}. + +@table @code + +@item h +Remove a trailing pathname component, leaving only the head. + +@item r +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. + +@ifset BashFeatures +@item q +Quote the substituted words, escaping further substitutions. + +@item x +Quote the substituted words as with @code{q}, +but break into words at spaces, tabs, and newlines. +@end ifset + +@item s/old/new/ +Substitute @var{new} for the first occurrence of @var{old} in the +event line. Any delimiter may be used in place of @key{/}. +The delimiter may be quoted in @var{old} and @var{new} +with a single backslash. If @key{&} 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 +character on the input line. + +@item & +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{&}. + +@end table diff --git a/lib/readline/doc/readline.dvi b/lib/readline/doc/readline.dvi Binary files differnew file mode 100644 index 0000000..aea321a --- /dev/null +++ b/lib/readline/doc/readline.dvi diff --git a/lib/readline/doc/readline.info b/lib/readline/doc/readline.info new file mode 100644 index 0000000..6df0bd9 --- /dev/null +++ b/lib/readline/doc/readline.info @@ -0,0 +1,744 @@ +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 new file mode 100644 index 0000000..839598f --- /dev/null +++ b/lib/readline/doc/readline.ps @@ -0,0 +1,2037 @@ +%!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 D<FC0000FC00001C00001C00001C +00001C00001C00001CF8001DFE001F07001E03001C03801C01C01C01C01C01C01C01C01C01C01C +01C01C03801E03001F0E001DFC000CF8001217809614>I<03F80FFC1C1C380870006000E000E0 +00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 +000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 +700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF +FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF +FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 +1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 +1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> +I<FC0000FC00001C00001C00001C00001C00001C00001C78001DFE001F86001E07001C07001C07 +001C07001C07001C07001C07001C07001C07001C07001C0700FF8FE0FF8FE01317809614>I<03 +0007800780030000000000000000007F807F800380038003800380038003800380038003800380 +03800380FFFCFFFC0E187D9714>I<FC0000FC00001C00001C00001C00001C00001C00001DFF80 +1DFF801C3C001C78001CF0001DE0001FC0001FC0001FE0001EF0001C70001C38001C38001C1C00 +FE3F80FE3F8011177F9614>107 D<FF80FF800380038003800380038003800380038003800380 +038003800380038003800380038003800380FFFEFFFE0F177E9614>I<FB8E00FFDF003CF3803C +F38038E38038E38038E38038E38038E38038E38038E38038E38038E38038E380FEFBE0FE79E013 +10808F14>I<FC7800FDFE001F86001E07001C07001C07001C07001C07001C07001C07001C0700 +1C07001C07001C0700FF8FE0FF8FE01310808F14>I<07C01FF03C78701C701CE00EE00EE00EE0 +0EE00EE00E701C783C3C781FF007C00F107E8F14>I<FCF800FDFE001F07001E03001C03801C01 +C01C01C01C01C01C01C01C01C01C01C01C03801E03001F0E001DFC001CF8001C00001C00001C00 +001C00001C00001C0000FF8000FF80001218808F14>I<FE1F00FE7F800EE3800F81000F00000F +00000E00000E00000E00000E00000E00000E00000E00000E0000FFF000FFF00011107F8F14> +114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F +14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E +070C03FC00F00F157F9414>I<FC3F00FC3F001C07001C07001C07001C07001C07001C07001C07 +001C07001C07001C07001C07001C1F000FFFE003E7E01310808F14>I<FE3F80FE3F801C1C001C +1C001C1C001C1C000E38000E38000E380006300007700007700007700003E00003E00003E00011 +107F8F14>I<FF7F80FF7F80380E00380E00380E00380E0039CE0039CE0019CC001B6C001B6C00 +1A6C001A6C001E7C000E78000E780011107F8F14>I<7E3F007E3F001E38000E780007700007E0 +0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>I<FE +3F80FE3F801C1C001C1C001C1C000E1C000E38000E380007380007300007300003700003700001 +E00001E00001E00001C00001C00001C0000380007380007700007E00003C000011187F8F14>I< +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>I<FFE7FF0E00700E00700E00700E +00700E00700E00700E00700E00700E00700E00700E00700FFFF00E00700E00700E00700E00700E +00700E00700E00700E00700E00700E00700E00700E0070FFE7FF181A7E991D>72 +D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 +80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 +707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 +E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 +000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 +E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 +600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 +703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 +E010187F8F13>103 D<FC00001C00001C00001C00001C00001C00001C00001C00001C00001C00 +001CF8001D0C001E0E001E0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E +001C0E001C0E00FF9FC0121A7F9915>I<18003C003C001800000000000000000000000000FC00 +1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I<FCF8 +001D0C001E0E001E0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C0E +001C0E00FF9FC012107F8F15>110 D<07E01C38300C700E6006E007E007E007E007E007E00760 +06700E381C1C3807E010107F8F13>I<FCF8001F0E001E07001C03801C03801C01C01C01C01C01 +C01C01C01C01C01C01C01C03801C03001E07001F0C001CF0001C00001C00001C00001C00001C00 +001C0000FF800012177F8F15>I<FCE01D701E701E201C001C001C001C001C001C001C001C001C +001C001C00FFC00C107F8F0F>114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 +30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C +001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I<FF1F803C06001C0400 +1C04001E0C000E08000E080007100007100007900003A00003A00001C00001C00001C000008000 +11107F8F14>118 D<FF3F803C1C001C18000E100007200007600003C00001C00001E00003E000 +027000043800083800181C00381E00FC3FC012107F8F14>120 D<FF1F803C06001C04001C0400 +1E0C000E08000E080007100007100007900003A00003A00001C00001C00001C000008000008000 +010000010000E10000E20000E4000078000011177F8F14>I E /Ff 2 42 +df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 +00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 +1E000E0007000780038001C000E000700C2E7EA112>40 D<E000700038001C001E000E00070007 +80078003C003C003C001E001E001E001E000E000F000F000F000F000F000F000F000F000F000F0 +00F000F000E001E001E001E001E003C003C003C00780078007000E001E001C0038007000E0000C +2E7DA112>I E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F +C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 +7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F +C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 +001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD +F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F +F87F8007E03F8019167E951C>97 D<FF800000FF8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F8000001F8000001F8000001F87F0001FBFFC001FF03E +001FC01F001F800F801F800FC01F8007C01F8007E01F8007E01F8007E01F8007E01F8007E01F80 +07E01F8007E01F8007C01F8007C01F800FC01F800F801FC01F001E707E001C3FFC00180FE0001B +237EA220>I<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 +FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> +I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 +3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C +003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 +7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 +C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 +003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F +01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 +0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF +807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF +E0001A217F951D>103 D<FF800000FF8000001F8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F8000001F8000001F83F0001F8FFC001F987E001FA03E +001FC03F001FC03F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F80 +3F001F803F001F803F001F803F001F803F001F803F001F803F00FFF1FFE0FFF1FFE01B237DA220 +>I<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 +0F>I<FF800000FF8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000 +1F8000001F8000001F8000001F8000001F80FF801F80FF801F803C001F8030001F80E0001F81C0 +001F8300001F8600001F9E00001FBE00001FFF00001FDF80001F8FC0001F07C0001F07E0001F03 +F0001F01F8001F00F8001F00FC001F007E00FFE1FFC0FFE1FFC01A237EA21E>107 +D<FF80FF801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C237EA20F>I< +FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F +801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>I<FF03F000FF0FFC001F187E001F203E001F +403F001F403F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F00 +1F803F001F803F001F803F001F803F001F803F001F803F00FFF1FFE0FFF1FFE01B167D9520>I< +00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F +FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>I<FF87F000FF +BFFC001FF07E001FC01F001F800F801F800FC01F800FC01F8007E01F8007E01F8007E01F8007E0 +1F8007E01F8007E01F8007E01F8007C01F800FC01F800FC01F801F801FC01F001FF07E001FBFFC +001F8FE0001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000FFF0 +0000FFF000001B207E9520>I<FF0F80FF1FE01F33F01F63F01F43F01F43F01FC1E01F80001F80 +001F80001F80001F80001F80001F80001F80001F80001F80001F80001F80001F8000FFF800FFF8 +0014167E9518>114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE +003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 +7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF +FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F +C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>I<FF81FF00FF81FF001F +803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F001F803F00 +1F803F001F803F001F803F001F803F001F803F001F807F001F80FF000FC1BF0007FF3FE001FC3F +E01B167D9520>I<FFF01FE0FFF01FE00FC007000FC006000FE00E0007E00C0007F01C0003F018 +0003F8180001F8300001F8300000FC600000FC6000007EC000007EC000007FC000003F8000003F +8000001F0000001F0000000E0000000E00001B167F951E>I<FFF3FF87FCFFF3FF87FC1F807C00 +E00FC07C00C00FC07E00C00FE03E01C007E03F018007E07F018003F07F030003F0CF830001F8CF +860001F8CFC60001FD87C60000FD87CC0000FF03EC00007F03F800007F03F800007E01F800003E +01F000003C00F000001C00E000001800600026167F9529>I<FFF0FFC0FFF0FFC00FC01C0007E0 +380007F0700003F0E00001F8C00000FD8000007F0000007F0000003F0000001F8000003FC00000 +37E0000067F00000C3F00001C1F8000380FC000700FE000E007E00FFC1FFE0FFC1FFE01B167F95 +1E>I<FFF01FE0FFF01FE00FC007000FC006000FE00E0007E00C0007F01C0003F0180003F81800 +01F8300001F8300000FC600000FC6000007EC000007EC000007FC000003F8000003F8000001F00 +00001F0000000E0000000E0000000C0000000C00000018000078180000FC380000FC300000FC60 +000069E000007F8000001F0000001B207F951E>I<7FFFE07FFFE0780FC0701FC0601F80E03F00 +C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 +7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 +F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 +00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 +EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 +FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 +D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 +000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 +0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D<FF8FF8FF8FF8FF8FF81C01C01C01C01C01C0 +1C01C01C01C01C01C01C01C01C01C01C01C01C01C01FFFC01FFFC01FFFC01C01C01C01C01C01C0 +1C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C0FF8FF8FF8FF8FF8FF8151E7E9D1A> +72 D<FFFF80FFFF80FFFF8001C00001C00001C00001C00001C00001C00001C00001C00001C000 +01C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C000 +01C00001C000FFFF80FFFF80FFFF80111E7C9D1A>I<FE0FF8FF0FF8FF0FF81D81C01D81C01D81 +C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01C61C01C61C01C71C01C71C01C31C01C31C01C39 +C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0DC01C0DC0FF87C0FF87C0FF83C0151E7E9D1A +>78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 +7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I<FFF000FFFC00FFFF001C0F801C07801C03 +C01C01C01C01C01C01C01C01C01C03C01C07801C0F801FFF001FFC001FFE001C0F001C07001C03 +801C03801C03801C03801C03801C03841C038E1C038E1C038EFF81FCFF81FCFF8070171E7E9D1A +>82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 +3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 +F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 +0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 +0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A +>I<FF01FEFF83FEFF01FE1E00F00E00E00E00E00701C00701C003838003838003C78001C70001 +C70000EE0000EE00007C00007C0000380000380000380000380000380000380000380000380000 +380000380001FF0001FF0001FF00171E7F9D1A>89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A +>95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 +700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 +D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 +007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 +D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F +C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 +C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I<FE0000FE0000FE00000E00000E00000E00000E +00000E00000E00000E3E000EFF800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E +00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E0FFE3FEFFE3FEFFE3FE171E7F9D1A> +104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 +7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I<FE3E00FEFF80FFFFC00FC1C00F80 +E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 +E0FFE3FEFFE3FEFFE3FE17157F941A>110 D<01F00007FC001FFF003E0F803C07807803C07001 +C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC +0001F00013157D941A>I<FF83F0FF8FF8FFBFFC03FC3C03F01803E00003C00003C00003800003 +8000038000038000038000038000038000038000038000038000FFFF00FFFF80FFFF0016157E94 +1A>114 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<FFFFFFE00000FFFFFFFC000003F800FF000003F8001FC00003F80007E00003F800 +03F00003F80001F80003F80001FC0003F80000FC0003F80000FE0003F80000FE0003F800007F00 +03F800007F0003F800007F0003F800007F8003F800007F8003F800007F8003F800007F8003F800 +007F8003F800007F8003F800007F8003F800007F8003F800007F8003F800007F8003F800007F00 +03F800007F0003F800007F0003F80000FE0003F80000FE0003F80001FC0003F80001F80003F800 +03F00003F80007E00003F8001FC00003F800FF8000FFFFFFFE0000FFFFFFE0000029257EA42F> +68 D<FFFFFFFF00FFFFFFFF0003F8007F0003F8000F8003F800078003F800038003F800038003 +F800018003F800018003F800018003F80000C003F80600C003F80600C003F806000003F8060000 +03F80E000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F80600 +0003F806006003F806006003F800006003F80000C003F80000C003F80000C003F80000C003F800 +01C003F80003C003F80003C003F8000F8003F8003F80FFFFFFFF80FFFFFFFF8023257EA428>I< +FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 +0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E +000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 +06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 +F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I<FFFFE0 +FFFFE0FFFFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003FFFFFFF80003FFFFFFF80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F800 +03F80003F80003F80003F800FFFFE0FFFFE0FFFFE0FFFFE02B257EA430>72 +D<FFFFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8 +0003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F8 +0003F80003F80003F80003F80003F80003F80003F80003F80003F800FFFFE0FFFFE013257EA417 +>I<FFFFF000FFFFF00003F8000003F8000003F8000003F8000003F8000003F8000003F8000003 +F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000 +03F8000003F8000003F8000003F8000003F8000603F8000603F8000603F8000C03F8000C03F800 +0C03F8001C03F8001C03F8003C03F8007C03F800F803F803F8FFFFFFF8FFFFFFF81F257EA425> +76 D<FFF8000000FFF8FFFC000001FFF803FC000001FE00037E0000037E00037E0000037E0003 +7E0000037E00033F0000067E00033F0000067E00031F80000C7E00031F80000C7E00030FC00018 +7E00030FC000187E000307E000307E000307E000307E000307E000307E000303F000607E000303 +F000607E000301F800C07E000301F800C07E000300FC01807E000300FC01807E0003007E03007E +0003007E03007E0003007E03007E0003003F06007E0003003F06007E0003001F8C007E0003001F +8C007E0003000FD8007E0003000FD8007E00030007F0007E00030007F0007E00030007F0007E00 +030003E0007E00078003E0007E00FFFC01C01FFFF8FFFC01C01FFFF835257EA43A>I<00FF0080 +07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 +80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F +FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 +0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 +D<FFFF83FFFE01FFF0FFFF83FFFE01FFF007F0001FC0000F0007F0001FC000060003F8000FE000 +0C0003F8000FE0000C0003FC000FF0001C0001FC0007F000180001FC0007F000180000FE000FF8 +00300000FE000FF800300000FE000FFC003000007F0019FC006000007F0019FC006000007F8039 +FE00E000003F8030FE00C000003F8030FE00C000001FC0607F018000001FC0607F018000001FE0 +607F818000000FE0C03F830000000FE0C03F830000000FF1C03FC700000007F1801FC600000007 +F1801FC600000003FB000FEC00000003FB000FEC00000003FF000FFC00000001FE0007F8000000 +01FE0007F800000001FE0007F800000000FC0003F000000000FC0003F000000000780001E00000 +0000780001E000000000780001E000000000300000C000003C257FA43F>87 +D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 +FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC +017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 D<FFC00000FFC000000FC00000 +0FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000 +000FC000000FC3F8000FCFFE000FF81F800FE00FC00FC007E00FC007E00FC003F00FC003F00FC0 +03F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F00FC003F00F +C007E00FC007C00FE00FC00F383F000E1FFE000C07F0001D267EA522>I<007FE003FFF807C07C +1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 +7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 +00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F +8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 +1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E +001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF +C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 +007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 +7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF +FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 +E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< +01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC +007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 +00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 +0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>I<FFC00000FF +C000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000 +0FC000000FC000000FC000000FC1F8000FC7FE000FCC3F000FD01F000FF01F800FE01F800FE01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC0 +1F800FC01F800FC01F800FC01F800FC01F800FC01F80FFFCFFF8FFFCFFF81D267DA522>I<0F00 +1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 +7EA611>I<FFC0FFC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0 +0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FF +FCFFFC0E267EA511>108 D<FF81FC01FC00FF87FF07FF000F8C1F8C1F800F980F980F800FB00F +F00FC00FA00FE00FC00FA00FE00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0 +0FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFFCFFFCFFFCFFFCFFFCFFFC +2E187D9733>I<FF81F800FF87FE000F8C3F000F901F000FB01F800FA01F800FA01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F80FFFCFFF8FFFCFFF81D187D9722>I<007F800003FFF0 +0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 +1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F +C0FC0003FFF000007F80001A187E971F>I<FFC3F800FFCFFE000FF83F800FE00FC00FC00FE00F +C007E00FC007F00FC003F00FC003F80FC003F80FC003F80FC003F80FC003F80FC003F80FC003F8 +0FC003F80FC007F00FC007F00FC007E00FC00FC00FE01FC00FF83F000FDFFE000FC7F0000FC000 +000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000FFFC0000FFFC +00001D237E9722>I<FF87C0FF8FF00F98F80FB1F80FA1F80FA1F80FE0F00FC0000FC0000FC000 +0FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC000FFFE00 +FFFE0015187E9719>114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 +7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 +EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 +0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 +0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E +0013237FA218>I<FFC1FF80FFC1FF800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC0 +1F800FC03F800FC03F8007C07F8007E0DF8003FF9FF800FE1FF81D187D9722>I<FFF80FF8FFF8 +0FF80FC003C00FE0018007E0030007E0030003F0060003F0060003F80E0001F80C0001FC1C0000 +FC180000FE1800007E3000007E3000003F6000003F6000001FC000001FC000001FC000000F8000 +000F800000070000000700001D187F9720>I<FFF83FF0FFF83FF00FC00F0007E00C0003F01C00 +03F8380001FC700000FCE000007EC000003F8000003F8000001F8000000FC000001FE000001FF0 +000033F8000071F80000E0FC0001C07E0003807F0003003F000F001F80FFC07FF8FFC07FF81D18 +7F9720>120 D<FFF80FF8FFF80FF80FC003C00FE0018007E0030007E0030003F0060003F00600 +03F80E0001F80C0001FC1C0000FC180000FE1800007E3000007E3000003F6000003F6000001FC0 +00001FC000001FC000000F8000000F800000070000000700000006000000060000000C0000300C +0000781C0000FC180000FC380000FC70000078E000007FC000001F0000001D237F9720>I<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 D<FFC0FFC00A027D8A0F>45 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>I<FF83F81E00E01C00C01C00800E00800E01000E02000E02000F040007 +040007080007080007100003900003A00003E00003C00003800001800001000015147C9318>I< +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 D<FFFFFFFFE00000FFFFFFFFFE0000FFFFFFFFFF800000FF0000FFC00000FF00003FF0 +0000FF00001FF80000FF00000FF80000FF000007FC0000FF000007FC0000FF000007FE0000FF00 +0003FE0000FF000003FE0000FF000003FE0000FF000003FE0000FF000007FE0000FF000007FE00 +00FF000007FC0000FF000007FC0000FF00000FF80000FF00001FF00000FF00003FE00000FF0000 +FF800000FF000FFF000000FFFFFFFE000000FFFFFFFFC00000FF00001FF00000FF000007F80000 +FF000003FE0000FF000003FE0000FF000001FF0000FF000001FF8000FF000000FF8000FF000000 +FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF000000FFC000FF +000000FFC000FF000000FF8000FF000001FF8000FF000001FF0000FF000003FF0000FF000007FE +0000FF00000FFC0000FF00007FF800FFFFFFFFFFE000FFFFFFFFFF8000FFFFFFFFFC000032317E +B039>I<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 +003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 +000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F +E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 +0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 +803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 +0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 +001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 +3A>I<FFFFFFFFFFE0FFFFFFFFFFE0FFFFFFFFFFE000FF80007FE000FF80000FF000FF800003F0 +00FF800001F000FF800001F000FF800000F000FF800000F000FF8000007000FF8000007000FF80 +00007000FF8000003800FF8000003800FF8007003800FF8007003800FF8007000000FF80070000 +00FF8007000000FF800F000000FF801F000000FF803F000000FFFFFF000000FFFFFF000000FFFF +FF000000FF803F000000FF801F000000FF800F000000FF8007000000FF8007000000FF80070000 +00FF8007000000FF8007000000FF8000000000FF8000000000FF8000000000FF8000000000FF80 +00000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80000000 +00FF80000000FFFFFFE00000FFFFFFE00000FFFFFFE000002D317EB033>70 +D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 +0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 +0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 +0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF +C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 +000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF +0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 +00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< +FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F +C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 +7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 +007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF +FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF +8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 +FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 +00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF +FFC03A317EB03F>I<FFFFFF80FFFFFF80FFFFFF8000FF800000FF800000FF800000FF800000FF +800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000 +FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF8000 +00FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF80 +0000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF800000FF8000FFFF +FF80FFFFFF80FFFFFF8019317EB01E>I<FFFF800001FFFFC0FFFFC00001FFFFC0FFFFE00001FF +FFC000FFF0000003E00000FFF8000001C00000EFFC000001C00000E7FC000001C00000E7FE0000 +01C00000E3FF000001C00000E1FF800001C00000E0FFC00001C00000E07FE00001C00000E03FE0 +0001C00000E03FF00001C00000E01FF80001C00000E00FFC0001C00000E007FE0001C00000E003 +FE0001C00000E001FF0001C00000E001FF8001C00000E000FFC001C00000E0007FE001C00000E0 +003FF001C00000E0001FF001C00000E0001FF801C00000E0000FFC01C00000E00007FE01C00000 +E00003FF01C00000E00001FF81C00000E00000FF81C00000E00000FFC1C00000E000007FE1C000 +00E000003FF1C00000E000001FF9C00000E000000FFDC00000E0000007FDC00000E0000007FFC0 +0000E0000003FFC00000E0000001FFC00000E0000000FFC00000E00000007FC00000E00000003F +C00000E00000003FC00000E00000001FC00000E00000000FC00001F000000007C000FFFFE00000 +03C000FFFFE0000001C000FFFFE0000001C0003A317EB03F>78 D<FFFFFFFFE000FFFFFFFFFE00 +FFFFFFFFFF8000FF8000FFE000FF80003FF000FF80000FF800FF800007FC00FF800007FC00FF80 +0003FE00FF800003FE00FF800003FF00FF800003FF00FF800003FF00FF800003FF00FF800003FF +00FF800003FF00FF800003FF00FF800003FE00FF800003FE00FF800007FC00FF800007F800FF80 +000FF800FF80003FE000FF8000FFC000FFFFFFFF0000FFFFFFF80000FF8000000000FF80000000 +00FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80 +00000000FF8000000000FF8000000000FF8000000000FF8000000000FF8000000000FF80000000 +00FF8000000000FF8000000000FF8000000000FF8000000000FF80000000FFFFFF800000FFFFFF +800000FFFFFF80000030317EB037>80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F +C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 +0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 +0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 +0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F +F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 +00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 +00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 +000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF +000031307DAF38>84 D<FFFFFF8003FFFF80FFFFFF8003FFFF80FFFFFF8003FFFF8000FF800000 +07C00000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF8000 +0003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF80 +000003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF +80000003800000FF80000003800000FF80000003800000FF80000003800000FF80000003800000 +FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF800000038000 +00FF80000003800000FF80000003800000FF80000003800000FF80000003800000FF8000000380 +0000FF80000003800000FF80000003800000FF800000038000007F800000038000007F80000007 +0000007FC00000070000003FC000000E0000003FC000000E0000001FE000001C0000000FF00000 +3800000007F800007000000003FC0001E000000000FF801FC0000000003FFFFF80000000000FFF +FE000000000000FFE000000039317EB03E>I<FFFFFC0000FFFFFFFFFC0000FFFFFFFFFC0000FF +FF03FF00000003C001FF000000038001FF800000078000FF800000070000FFC000000700007FC0 +00000E00007FC000000E00007FE000001E00003FE000001C00003FF000003C00001FF000003800 +001FF800003800000FF800007000000FFC000070000007FC0000E0000007FC0000E0000007FE00 +01E0000003FE0001C0000003FF0003C0000001FF000380000001FF800380000000FF8007000000 +00FFC00700000000FFC00F000000007FC00E000000007FE01E000000003FE01C000000003FF03C +000000001FF038000000001FF838000000000FF870000000000FF870000000000FFCF000000000 +07FCE00000000007FFE00000000003FFC00000000003FFC00000000001FF800000000001FF8000 +00000000FF000000000000FF000000000000FF0000000000007E0000000000007E000000000000 +3C0000000000003C00000038317EB03D>I<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>I<FFFF801FFCFFFF801FFCFF +FF801FFC0FF80003C007F800038007FC00078003FC00070003FE000F0001FE000E0001FF000E00 +00FF001C0000FF001C00007F803800007F803800007FC07800003FC07000003FE0F000001FE0E0 +00001FF1E000000FF1C000000FF9C0000007FB80000007FB80000003FF00000003FF00000003FF +00000001FE00000001FE00000000FC00000000FC00000000780000000078000026207E9F2B>I< +FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE +00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 +FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 +7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F +FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 +000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 +7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F +E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 +00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 +003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF +FF28207F9F2B>I<FFFF801FFCFFFF801FFCFFFF801FFC0FF80003C007F800038007FC00078003 +FC00070003FE000F0001FE000E0001FF000E0000FF001C0000FF001C00007F803800007F803800 +007FC07800003FC07000003FE0F000001FE0E000001FF1E000000FF1C000000FF9C0000007FB80 +000007FB80000003FF00000003FF00000003FF00000001FE00000001FE00000000FC00000000FC +000000007800000000780000000070000000007000000000F000000000E000000001E000007C01 +C00000FE03C00000FE03800000FE07800000FE0F000000FC1E000000787C0000003FF00000000F +C0000000262E7E9F2B>I 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 D<FFFFFFF800FFFFFFFF00FFFFFFFFC003F8001FE003F8000FF003F80007F803F8 +0003F803F80003FC03F80003FC03F80001FC03F80001FC03F80001FC03F80003FC03F80003F803 +F80003F803F80007F003F8000FF003F8001FC003F800FF8003FFFFFE0003FFFFFFC003F8000FF0 +03F80003F803F80001FC03F80001FE03F80000FE03F80000FE03F80000FF03F80000FF03F80000 +FF03F80000FF03F80000FF03F80000FF03F80000FE03F80001FE03F80003FC03F80007FC03F800 +1FF8FFFFFFFFE0FFFFFFFFC0FFFFFFFE0028297DA830>I<00007FE0030007FFFC07001FFFFF0F +007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 +0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 +0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 +0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 +F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 +>I<FFFFFFFFE0FFFFFFFFE0FFFFFFFFE003FC001FE003FC0007F003FC0001F003FC0001F003FC +0000F003FC00007003FC00007003FC00007003FC01C07803FC01C03803FC01C03803FC01C03803 +FC03C00003FC03C00003FC0FC00003FFFFC00003FFFFC00003FFFFC00003FC0FC00003FC03C000 +03FC03C00003FC01C00E03FC01C00E03FC01C00E03FC01C01C03FC00001C03FC00001C03FC0000 +1C03FC00003C03FC00003803FC00007803FC0000F803FC0001F803FC0003F803FC001FF8FFFFFF +FFF0FFFFFFFFF0FFFFFFFFF027297EA82C>69 D<FFFFFFFFC0FFFFFFFFC0FFFFFFFFC003FC003F +C003FC000FE003FC0003E003FC0001E003FC0001E003FC0000E003FC0000E003FC0000E003FC00 +00F003FC01C07003FC01C07003FC01C07003FC01C00003FC03C00003FC03C00003FC0FC00003FF +FFC00003FFFFC00003FFFFC00003FC0FC00003FC03C00003FC03C00003FC01C00003FC01C00003 +FC01C00003FC01C00003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000 +03FC00000003FC00000003FC000000FFFFFC0000FFFFFC0000FFFFFC000024297EA82A>I<0000 +7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F +0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 +000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 +00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 +00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF +0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 +FFFE0F0000007FF003002D297CA835>I<FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF03FC0000 +3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000 +3FC003FC00003FC003FFFFFFFFC003FFFFFFFFC003FFFFFFFFC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC0000 +3FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003FC00003FC003 +FC00003FC003FC00003FC0FFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFF30297EA835>I<FFFFFC +FFFFFCFFFFFC01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00 +01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00 +01FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE0001FE00FFFFFCFFFFFC +FFFFFC16297FA819>I<FFFE0000003FFF80FFFE0000003FFF80FFFF0000007FFF8003FF000000 +7FE00003FF0000007FE00003BF800000EFE00003BF800000EFE000039FC00001CFE000039FC000 +01CFE000038FE000038FE000038FE000038FE000038FE000038FE0000387F000070FE0000387F0 +00070FE0000383F8000E0FE0000383F8000E0FE0000381FC001C0FE0000381FC001C0FE0000381 +FC001C0FE0000380FE00380FE0000380FE00380FE00003807F00700FE00003807F00700FE00003 +803F80E00FE00003803F80E00FE00003803F80E00FE00003801FC1C00FE00003801FC1C00FE000 +03800FE3800FE00003800FE3800FE000038007F7000FE000038007F7000FE000038007F7000FE0 +00038003FE000FE000038003FE000FE000038001FC000FE000038001FC000FE000038000F8000F +E000FFFE00F803FFFF80FFFE00F803FFFF80FFFE007003FFFF8039297DA840>77 +D<FFFC00007FFFFFFE00007FFFFFFF00007FFF03FF800001C003FFC00001C003BFE00001C0039F +E00001C0039FF00001C0038FF80001C00387FC0001C00383FE0001C00381FF0001C00380FF8001 +C003807F8001C003807FC001C003803FE001C003801FF001C003800FF801C0038007FC01C00380 +03FC01C0038003FE01C0038001FF01C0038000FF81C00380007FC1C00380003FE1C00380001FF1 +C00380000FF1C00380000FF9C003800007FDC003800003FFC003800001FFC003800000FFC00380 +00007FC0038000007FC0038000003FC0038000001FC0038000000FC00380000007C0FFFE000003 +C0FFFE000001C0FFFE000001C030297EA835>I<FFFFFFF800FFFFFFFF00FFFFFFFFC003FC003F +E003FC0007F003FC0003F803FC0003FC03FC0001FC03FC0001FE03FC0001FE03FC0001FE03FC00 +01FE03FC0001FE03FC0001FE03FC0001FE03FC0001FC03FC0003FC03FC0003F803FC0007F003FC +003FE003FFFFFF8003FFFFFE0003FC00000003FC00000003FC00000003FC00000003FC00000003 +FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC000000 +03FC00000003FC00000003FC000000FFFFF00000FFFFF00000FFFFF0000027297EA82E>80 +D<FFFFFFE00000FFFFFFFE0000FFFFFFFF800003FC003FE00003FC000FF00003FC0007F80003FC +0003FC0003FC0001FC0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FE0003FC0001FE +0003FC0001FE0003FC0001FC0003FC0003F80003FC0007F80003FC000FE00003FC003FC00003FF +FFFE000003FFFFFE000003FC00FF800003FC003FC00003FC001FE00003FC000FF00003FC0007F8 +0003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC0007F80003FC +0007F80003FC0007F80003FC0007F80E03FC0007F80E03FC0003F80E03FC0001FC1CFFFFF000FE +1CFFFFF0007FF8FFFFF0000FE02F297EA832>82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 +3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF +C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 +00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 +E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I<FFFFF0 +00FFFEFFFFF000FFFEFFFFF000FFFE03FC0000038003FC0000038003FC0000038003FC00000380 +03FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00 +00038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00000380 +03FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC0000038003FC00 +00038003FC0000038003FC0000038003FC0000038003FC0000038001FC0000070001FE00000700 +00FE00000E00007F00000E00003F00003C00001FC0007800000FF003F0000007FFFFE0000000FF +FF800000001FFC00002F297EA834>85 D<FFFFF0007FFFFFFFF0007FFFFFFFF0007FFF03FE0000 +01C001FE0000038001FE0000038000FF0000070000FF0000070000FF80000F00007F80000E0000 +7FC0000E00003FC0001C00003FE0001C00001FE0003800001FE0003800001FF0007800000FF000 +7000000FF800F0000007F800E0000007FC00E0000003FC01C0000003FC01C0000003FE03C00000 +01FE0380000001FF0780000000FF0700000000FF87000000007F8E000000007F8E000000007FDE +000000003FDC000000003FFC000000001FF8000000001FF8000000000FF0000000000FF0000000 +000FF00000000007E00000000007E00000000003C00000000003C0000030297FA833>I<FFFFE0 +FFFFE01FFFC0FFFFE0FFFFE01FFFC0FFFFE0FFFFE01FFFC003FC0003FC0000700003FC0003FC00 +00700003FE0003FE0000F00001FE0001FE0000E00001FE0001FE0000E00001FF0001FF0001E000 +00FF0001FF0001C00000FF0001FF0001C000007F8003FF80038000007F8003FF80038000007FC0 +07FFC0078000003FC0073FC0070000003FC0073FC0070000003FE00F3FE00F0000001FE00E1FE0 +0E0000001FE00E1FE00E0000000FF01C0FF01C0000000FF01C0FF01C0000000FF01C0FF81C0000 +0007F83807F83800000007F83807F83800000007FC7807FC7800000003FC7003FC7000000003FC +7003FC7000000003FEF003FEF000000001FEE001FEE000000001FEE001FEE000000000FFC000FF +C000000000FFC000FFC000000000FFC000FFC0000000007F80007F80000000007F80007F800000 +00007F80007F80000000003F00003F00000000003F00003F00000000003F00003F00000000001E +00001E00000000001E00001E00000042297FA845>I<03FF80000FFFF0001F01FC003F80FE003F +807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 +0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF +803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D<FFE00000FFE00000FFE000000FE000000FE0 +00000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000F +E000000FE1FE000FE7FF800FFE07E00FF803F00FF001F80FE000FC0FE000FC0FE0007E0FE0007E +0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007E0FE000 +7E0FE0007E0FE000FC0FE000FC0FF001F80FF803F00F9C0FE00F0FFF800E01FC00202A7EA925> +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>I<FFE00000FFE00000FFE000000FE000000FE000000FE000000FE000000FE000000FE000 +000FE000000FE000000FE000000FE000000FE000000FE000000FE07E000FE1FF800FE30FC00FE4 +0FE00FE807E00FF807F00FF007F00FF007F00FE007F00FE007F00FE007F00FE007F00FE007F00F +E007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F0 +0FE007F0FFFE3FFFFFFE3FFFFFFE3FFF202A7DA925>I<07000F801FC03FE03FE03FE01FC00F80 +07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F +E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I<FF +E0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0 +0FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FF +FEFFFEFFFE0F2A7EA912>108 D<FFC07F001FC000FFC1FFC07FF000FFC307E0C1F8000FC407F1 +01FC000FC803F200FC000FD803FE00FE000FD003FC00FE000FD003FC00FE000FE003F800FE000F +E003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800 +FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE003F800FE000FE0 +03F800FE000FE003F800FE000FE003F800FE000FE003F800FE00FFFE3FFF8FFFE0FFFE3FFF8FFF +E0FFFE3FFF8FFFE0331B7D9A38>I<FFC07E00FFC1FF80FFC30FC00FC40FE00FC807E00FD807F0 +0FD007F00FD007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007 +F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F0FFFE3FFFFFFE +3FFFFFFE3FFF201B7D9A25>I<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 +07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE +0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 +003FE0001D1B7E9A22>I<FFE1FE00FFE7FF80FFFE0FE00FF803F00FF001F80FE001FC0FE000FC +0FE000FE0FE000FE0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE000 +7F0FE0007E0FE000FE0FE000FE0FE000FC0FE001FC0FF001F80FF803F00FFC0FE00FEFFF800FE1 +FC000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE000000FE00000FF +FE0000FFFE0000FFFE000020277E9A25>I<FFC3E0FFC7F8FFCC7C0FD8FE0FD0FE0FD0FE0FF0FE +0FE07C0FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE000 +0FE0000FE0000FE0000FE000FFFF00FFFF00FFFF00171B7E9A1B>114 D<03FE300FFFF03E03F0 +7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 +0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> +I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF +E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 +7FA51A>I<FFE07FF0FFE07FF0FFE07FF00FE007F00FE007F00FE007F00FE007F00FE007F00FE0 +07F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00FE007F00F +E007F00FE007F00FE007F00FE00FF00FE00FF007E017F003F067FF01FFC7FF007F87FF201B7D9A +25>I<FFFE07FFFFFE07FFFFFE07FF07F000E007F000E007F801E003F801C003F801C001FC0380 +01FC038001FE078000FE070000FF0F00007F0E00007F0E00003F9C00003F9C00003FFC00001FF8 +00001FF800000FF000000FF000000FF0000007E0000007E0000003C0000003C000201B7F9A23> +I<FFFC7FFC1FFCFFFC7FFC1FFCFFFC7FFC1FFC0FE00FE001C007F007E0038007F007E0038007F8 +07F0078003F807F0070003F807F8070001FC0FF80E0001FC0FF80E0001FE1FFC1E0000FE1CFC1C +0000FE1CFE1C0000FF387E3C00007F387E3800007F787F3800003FF03F7000003FF03F7000003F +E01FF000001FE01FE000001FE01FE000000FC00FC000000FC00FC000000FC00FC0000007800780 +000007800780002E1B7F9A31>I<FFFC1FFEFFFC1FFEFFFC1FFE07F0078003F8070001FC0F0001 +FE1E0000FE3C00007F7800003FF800003FF000001FE000000FE0000007F0000007F800000FF800 +001FFC00003DFE000038FF0000787F0000F03F8001E03FC003C01FE003800FE0FFF03FFFFFF03F +FFFFF03FFF201B7F9A23>I<FFFE07FFFFFE07FFFFFE07FF07F000E007F000E007F801E003F801 +C003F801C001FC038001FC038001FE078000FE070000FF0F00007F0E00007F0E00003F9C00003F +9C00003FFC00001FF800001FF800000FF000000FF0000007F0000007E0000007E0000003C00000 +03C000000380000003800000078000380700007C070000FE0E0000FE0E0000FE1C0000FE380000 +7C7000003FE000000F80000020277F9A23>I 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 D<FFFFF0FFFFF0FFFFF01C00701C00701C00701C00701C0000 +1C00001C0E001C0E001C0E001FFE001FFE001FFE001C0E001C0E001C0E001C00001C00001C0038 +1C00381C00381C00381C0038FFFFF8FFFFF8FFFFF8151C7F9B18>I<FFFFE0FFFFE0FFFFE01C00 +E01C00E01C00E01C00E01C00001C00001C1C001C1C001C1C001FFC001FFC001FFC001C1C001C1C +001C1C001C00001C00001C00001C00001C00001C00001C0000FFC000FFC000FFC000131C7E9B18 +>I<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F +FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F +07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 +0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 +0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E +00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B +18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 +C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D +C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 +E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 +E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>I<FFFE00FFFF80FFFF +C01C03C01C01E01C00E01C00701C00701C00701C00701C00701C00E01C01E01C03C01FFFC01FFF +801FFE001C00001C00001C00001C00001C00001C00001C00001C0000FF8000FF8000FF8000141C +7F9B18>I<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C +0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C +039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 +80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 +E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF +FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 +700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 +1C7F9B18>I<FF83FEFF83FEFF83FE1C00701C00701C00701C00701C00701C00701C00701C0070 +1C00701C00701C00701C00701C00701C00701C00701C00701C00701C00701C00700E00E00F01E0 +0783C003FF8001FF00007C00171C809B18>I<FF07F8FF07F8FF07F81C01C01E03C00E03800F07 +80070700070700038E00038E0001DC0001DC0001DC0000F80000F8000070000070000070000070 +0000700000700000700000700000700001FC0003FE0001FC00151C7F9B18>89 +D<FFF8FFF8FFF8E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000 +E000E000E000E000E000E000E000E000E000E000E000E000E000E000FFF8FFF8FFF80D24779F18 +>91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 +0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 +007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> +I<FFF8FFF8FFF80038003800380038003800380038003800380038003800380038003800380038 +00380038003800380038003800380038003800380038003800380038FFF8FFF8FFF80D247F9F18 +>I<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 D<FFC0FFC00A027F8A0F>I<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 D<FFFFE0000F80380007801E0007801F0007800F0007800F8007800F8007800F80 +07800F8007800F8007800F0007801F0007801E0007803C0007FFF00007803C0007801E0007800F +0007800F8007800780078007C0078007C0078007C0078007C0078007C00780078007800F800780 +0F0007801F000F803C00FFFFF0001A1F7E9E20>I<000FC040007030C001C009C0038005C00700 +03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 +000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 +3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D +9F21>I<FFFFE0000F803C0007801E000780070007800380078003C0078001E0078001E0078001 +F0078000F0078000F0078000F8078000F8078000F8078000F8078000F8078000F8078000F80780 +00F8078000F8078000F0078000F0078000F0078001E0078001E0078003C0078003800780070007 +800E000F803C00FFFFE0001D1F7E9E23>I<FFFFFF000F800F0007800300078003000780010007 +800180078000800780008007800080078080800780800007808000078080000781800007FF8000 +078180000780800007808000078080000780800007800020078000200780002007800040078000 +4007800040078000C0078000C0078001800F800F80FFFFFF801B1F7E9E1F>I<FFFFFF000F800F +000780030007800300078001000780018007800080078000800780008007800080078080000780 +800007808000078080000781800007FF8000078180000780800007808000078080000780800007 +800000078000000780000007800000078000000780000007800000078000000FC00000FFFE0000 +191F7E9E1E>I<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 +3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 +00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 +01E0070001E0038002E000E0046000781820000FE0001E217D9F24>I<FFF8FFF80F800F800780 +0F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007800F0007 +800F0007800F0007FFFF0007800F0007800F0007800F0007800F0007800F0007800F0007800F00 +07800F0007800F0007800F0007800F0007800F0007800F0007800F000F800F80FFF8FFF81D1F7E +9E22>I<FFFC0FC007800780078007800780078007800780078007800780078007800780078007 +80078007800780078007800780078007800780078007800FC0FFFC0E1F7F9E10>I<0FFFC0007C +00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C +00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 +0040780040700030E0000F800012207E9E17>I<FFFE000FC00007800007800007800007800007 +800007800007800007800007800007800007800007800007800007800007800007800007800007 +800007800207800207800207800207800607800407800407800C07801C0F807CFFFFFC171F7E9E +1C>76 D<FF80001FF80F80001F800780001F0005C0002F0005C0002F0005C0002F0004E0004F00 +04E0004F000470008F000470008F000470008F000438010F000438010F000438010F00041C020F +00041C020F00041C020F00040E040F00040E040F00040E040F000407080F000407080F00040708 +0F000403900F000403900F000401E00F000401E00F000401E00F000E00C00F001F00C01F80FFE0 +C1FFF8251F7E9E2A>I<FF803FF807C007C007C0038005E0010005E0010004F001000478010004 +780100043C0100043C0100041E0100040F0100040F010004078100040781000403C1000401E100 +0401E1000400F1000400F1000400790004003D0004003D0004001F0004001F0004000F00040007 +00040007000E0003001F000300FFE001001D1F7E9E22>I<001F800000F0F00001C0380007801E +000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 +01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C +0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 +1C217D9F23>I<FFFFE0000F80780007801C0007801E0007800F0007800F8007800F8007800F80 +07800F8007800F8007800F8007800F0007801E0007801C000780780007FFE00007800000078000 +000780000007800000078000000780000007800000078000000780000007800000078000000780 +0000078000000FC00000FFFC0000191F7E9E1F>I<001F800000F0F00001C0380007801E000F00 +0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 +0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 +3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 +10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>I<FFFF80 +000F80F0000780780007803C0007801E0007801E0007801F0007801F0007801F0007801F000780 +1E0007801E0007803C00078078000780F00007FF80000781C0000780E0000780F0000780700007 +807800078078000780780007807C0007807C0007807C0007807C0407807E0407803E040FC01E08 +FFFC0F10000003E01E207E9E21>I<07E0800C1980100780300380600180600180E00180E00080 +E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 +0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D +9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 +10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F +0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 +0F0000001F800007FFFE001C1F7E9E21>I<FFFC3FF80FC007C007800380078001000780010007 +800100078001000780010007800100078001000780010007800100078001000780010007800100 +078001000780010007800100078001000780010007800100078001000780010007800100038002 +000380020001C0020001C0040000E008000070180000382000000FC0001D207E9E22>I<FFF003 +FE1F8000F80F0000600F800060078000400780004003C0008003C0008003C0008001E0010001E0 +010001F0010000F0020000F0020000F806000078040000780400003C0800003C0800003C080000 +1E1000001E1000001F3000000F2000000F20000007C0000007C0000007C0000003800000038000 +00038000000100001F207F9E22>I<FFF07FF81FF01F800FC007C00F00078003800F0007800100 +0F0007C00100078007C00200078007C00200078007C0020003C009E0040003C009E0040003C009 +E0040003E010F00C0001E010F0080001E010F0080001F02078080000F02078100000F020781000 +00F0403C10000078403C20000078403C20000078C03E2000003C801E4000003C801E4000003C80 +1E4000001F000F8000001F000F8000001F000F8000001E00078000000E00070000000E00070000 +000C000300000004000200002C207F9E2F>I<FEFEC0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0 +C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0FEFE072D7CA10D>91 +D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>I<FEFE06 +060606060606060606060606060606060606060606060606060606060606060606060606060606 +06FEFE072D7FA10D>I<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>I<FF83F81E01E01C00C00E00800E00800E00800701000701000382000382000382 +0001C40001C40001EC0000E80000E80000700000700000700000200015147F9318>I<FF9FE1FC +3C0780701C0300601C0380200E0380400E0380400E03C0400707C0800704C0800704E080038861 +000388710003C8730001D0320001D03A0000F03C0000E01C0000E01C0000601800004008001E14 +7F9321>I<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 +7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>I<FF83F81E01E0 +1C00C00E00800E00800E008007010007010003820003820003820001C40001C40001EC0000E800 +00E800007000007000007000002000002000004000004000004000F08000F08000F10000620000 +3C0000151D7F9318>I<3FFF380E200E201C40384078407000E001E001C00380078007010E011E +011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF +FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F +C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 +FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 +00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 +C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F +F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 +0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 +0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F +F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 +0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF +C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 +FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 +0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F +C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 +D<FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FFFFFFFFFFFC000007FFFFFFFFFFFC000007FFFFFFFFFFFC000007FFFFFFFFFFFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007F +F0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF00000 +01FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000007FF0000001FFC0 +00007FF0000001FFC000007FF0000001FFC000007FF0000001FFC000FFFFFFF803FFFFFFE0FFFF +FFF803FFFFFFE0FFFFFFF803FFFFFFE0FFFFFFF803FFFFFFE0433B7CBA4C>I<FFFFFFFE000000 +FFFFFFFE000000FFFFFFFE000000FFFFFFFE000000007FF000000000007FF000000000007FF000 +000000007FF000000000007FF000000000007FF000000000007FF000000000007FF00000000000 +7FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF00000 +0000007FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007F +F000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF0000000 +00007FF000000000007FF000000000007FF000000000007FF000000000007FF000000000007FF0 +00000000007FF000000780007FF000000780007FF000000780007FF000000780007FF000000780 +007FF000000F80007FF000000F00007FF000000F00007FF000000F00007FF000001F00007FF000 +001F00007FF000001F00007FF000003F00007FF000003F00007FF000007F00007FF00000FF0000 +7FF00001FF00007FF00003FF00007FF0000FFE00007FF0007FFE00FFFFFFFFFFFE00FFFFFFFFFF +FE00FFFFFFFFFFFE00FFFFFFFFFFFE00313B7CBA3A>76 D<FFFFF0000007FFFFE0FFFFF8000007 +FFFFE0FFFFFC000007FFFFE0FFFFFE000007FFFFE0007FFE00000007E000007FFF00000003C000 +007FFF80000003C000007BFFC0000003C000007BFFE0000003C0000079FFE0000003C0000078FF +F0000003C00000787FF8000003C00000783FFC000003C00000783FFE000003C00000781FFE0000 +03C00000780FFF000003C000007807FF800003C000007803FFC00003C000007803FFE00003C000 +007801FFE00003C000007800FFF00003C0000078007FF80003C0000078003FFC0003C000007800 +3FFE0003C0000078001FFF0003C0000078000FFF0003C00000780007FF8003C00000780003FFC0 +03C00000780003FFE003C00000780001FFF003C00000780000FFF003C000007800007FF803C000 +007800003FFC03C000007800003FFE03C000007800001FFF03C000007800000FFF03C000007800 +0007FF83C0000078000003FFC3C0000078000003FFE3C0000078000001FFF3C0000078000000FF +F3C00000780000007FFBC00000780000003FFFC00000780000003FFFC00000780000001FFFC000 +00780000000FFFC000007800000007FFC000007800000003FFC000007800000003FFC000007800 +000001FFC000007800000000FFC0000078000000007FC0000078000000003FC000007800000000 +3FC00000FC000000001FC000FFFFFC0000000FC000FFFFFC00000007C000FFFFFC00000003C000 +FFFFFC00000003C000433B7CBA4C>78 D<FFFFFFF8001FFFFF80FFFFFFF8001FFFFF80FFFFFFF8 +001FFFFF80FFFFFFF8001FFFFF80007FF00000001F8000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F +0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F000000 +7FF00000000F0000007FF00000000F0000007FF00000000F0000007FF00000000F0000007FF000 +00000F0000007FF00000000F0000007FF00000000F0000003FF00000001E0000003FF00000001E +0000003FF80000001E0000001FF80000003C0000001FF80000003C0000000FFC00000078000000 +07FC000000F800000007FE000001F000000003FF000003F000000001FF800007E000000000FFE0 +001FC0000000003FFC01FF80000000001FFFFFFE000000000007FFFFF8000000000000FFFFE000 +00000000000FFE00000000413C7CBA4A>85 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>I<FFFFF001FFFCFFFFF001FFFCFFFFF001FFFCFFFFF001FFFC03FE00001F8003FF00001F +0001FF00001E0001FF80003E0000FF80003C0000FF80003C00007FC0007800007FC0007800007F +E000F800003FE000F000003FF001F000001FF001E000001FF803E000000FF803C000000FFC03C0 +000007FC0780000007FC0780000007FE0F80000003FE0F00000003FF1F00000001FF1E00000001 +FFBE00000000FFBC00000000FFFC000000007FF8000000007FF8000000007FF8000000003FF000 +0000003FF0000000001FE0000000001FE0000000000FC0000000000FC000000000078000000000 +0780000000000F80000000000F00000000001F00000000001E00000008003E0000007F003C0000 +007F007C000000FF8078000000FF80F8000000FF80F0000000FF81E00000007F07C00000007C1F +800000003FFF000000001FFE0000000007F0000000002E377EA533>121 +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 new file mode 100644 index 0000000..ec14066 --- /dev/null +++ b/lib/readline/doc/rlman.texinfo @@ -0,0 +1,111 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename readline.info +@settitle GNU Readline Library +@comment %**end of header (This is for running Texinfo on a region.) +@synindex vr fn +@setchapternewpage odd + +@ignore +last change: Thu Jul 21 16:02:40 EDT 1994 +@end ignore + +@set EDITION 2.0 +@set VERSION 2.0 +@set UPDATED 21 July 1994 +@set UPDATE-MONTH July 1994 + +@ifinfo +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +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. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@titlepage +@sp 10 +@title GNU Readline Library +@subtitle Edition @value{EDITION}, for @code{Readline Library} Version @value{VERSION}. +@subtitle @value{UPDATE-MONTH} +@author Brian Fox, Free Software Foundation +@author Chet Ramey, Case Western Reserve University + +@page +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +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. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +@end titlepage + +@ifinfo +@node Top +@top GNU Readline Library + +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +@menu +* Command Line Editing:: GNU Readline User's Manual. +* Programming with GNU Readline:: GNU Readline Programmer's Manual. +* Concept Index:: Index of concepts described in this manual. +* Function and Variable Index:: Index of externally visible functions + and variables. +@end menu +@end ifinfo + +@include rluser.texinfo +@include rltech.texinfo + +@node Concept Index +@unnumbered Concept Index +@printindex cp + +@node Function and Variable Index +@unnumbered Function and Variable Index +@printindex fn + +@contents +@bye diff --git a/lib/readline/doc/rltech.texinfo b/lib/readline/doc/rltech.texinfo new file mode 100644 index 0000000..636c923 --- /dev/null +++ b/lib/readline/doc/rltech.texinfo @@ -0,0 +1,1406 @@ +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rltech.info +@comment %**end of header (This is for running Texinfo on a region.) +@setchapternewpage odd + +@ifinfo +This document describes the GNU Readline Library, a utility for aiding +in the consitency of user interface across discrete programs that need +to provide a command line interface. + +Copyright (C) 1988, 1994 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@node Programming with GNU Readline +@chapter Programming with GNU Readline + +This chapter describes the interface between the GNU Readline Library and +other programs. If you are a programmer, and you wish to include the +features found in GNU Readline +such as completion, line editing, and interactive history manipulation +in your own programs, this section is for you. + +@menu +* Basic Behavior:: Using the default behavior of Readline. +* Custom Functions:: Adding your own functions to Readline. +* Readline Variables:: Variables accessible to custom + functions. +* Readline Convenience Functions:: Functions which Readline supplies to + aid in writing your own +* Custom Completers:: Supplanting or supplementing Readline's + completion functions. +@end menu + +@node Basic Behavior +@section Basic Behavior + +Many programs provide a command line interface, such as @code{mail}, +@code{ftp}, and @code{sh}. For such programs, the default behaviour of +Readline is sufficient. This section describes how to use Readline in +the simplest way possible, perhaps to replace calls in your code to +@code{gets()} or @code{fgets ()}. + +@findex readline +@cindex readline, function +The function @code{readline ()} prints a prompt and then reads and returns +a single line of text from the user. The line @code{readline} +returns is allocated with @code{malloc ()}; you should @code{free ()} +the line when you are done with it. The declaration for @code{readline} +in ANSI C is + +@example +@code{char *readline (char *@var{prompt});} +@end example + +@noindent +So, one might say +@example +@code{char *line = readline ("Enter a line: ");} +@end example +@noindent +in order to read a line of text from the user. +The line returned has the final newline removed, so only the +text remains. + +If @code{readline} encounters an @code{EOF} while reading the line, and the +line is empty at that point, then @code{(char *)NULL} is returned. +Otherwise, the line is ended just as if a newline had been typed. + +If you want the user to be able to get at the line later, (with +@key{C-p} for example), you must call @code{add_history ()} to save the +line away in a @dfn{history} list of such lines. + +@example +@code{add_history (line)}; +@end example + +@noindent +For full details on the GNU History Library, see the associated manual. + +It is preferable to avoid saving empty lines on the history list, since +users rarely have a burning need to reuse a blank line. Here is +a function which usefully replaces the standard @code{gets ()} library +function, and has the advantage of no static buffer to overflow: + +@example +/* A static variable for holding the line. */ +static char *line_read = (char *)NULL; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +rl_gets () +@{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read) + @{ + free (line_read); + line_read = (char *)NULL; + @} + + /* Get a line from the user. */ + line_read = readline (""); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +@} +@end example + +This function gives the user the default behaviour of @key{TAB} +completion: completion on file names. If you do not want Readline to +complete on filenames, you can change the binding of the @key{TAB} key +with @code{rl_bind_key ()}. + +@example +@code{int rl_bind_key (int @var{key}, int (*@var{function})());} +@end example + +@code{rl_bind_key ()} takes two arguments: @var{key} is the character that +you want to bind, and @var{function} is the address of the function to +call when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert ()} +makes @key{TAB} insert itself. +@code{rl_bind_key ()} returns non-zero if @var{key} is not a valid +ASCII character code (between 0 and 255). + +Thus, to disable the default @key{TAB} behavior, the following suffices: +@example +@code{rl_bind_key ('\t', rl_insert);} +@end example + +This code should be executed once at the start of your program; you +might write a function called @code{initialize_readline ()} which +performs this and other desired initializations, such as installing +custom completers (@pxref{Custom Completers}). + +@node Custom Functions +@section Custom Functions + +Readline provides many functions for manipulating the text of +the line, but it isn't possible to anticipate the needs of all +programs. This section describes the various functions and variables +defined within the Readline library which allow a user program to add +customized functionality to Readline. + +@menu +* The Function Type:: C declarations to make code readable. +* Function Writing:: Variables and calling conventions. +@end menu + +@node The Function Type +@subsection The Function Type + +For readabilty, we declare a new type of object, called +@dfn{Function}. A @code{Function} is a C function which +returns an @code{int}. The type declaration for @code{Function} is: + +@noindent +@code{typedef int Function ();} + +The reason for declaring this new type is to make it easier to write +code describing pointers to C functions. Let us say we had a variable +called @var{func} which was a pointer to a function. Instead of the +classic C declaration + +@code{int (*)()func;} + +@noindent +we may write + +@code{Function *func;} + +@noindent +Similarly, there are + +@example +typedef void VFunction (); +typedef char *CPFunction (); @r{and} +typedef char **CPPFunction (); +@end example + +@noindent +for functions returning no value, @code{pointer to char}, and +@code{pointer to pointer to char}, respectively. + +@node Function Writing +@subsection Writing a New Function + +In order to write new functions for Readline, you need to know the +calling conventions for keyboard-invoked functions, and the names of the +variables that describe the current state of the line read so far. + +The calling sequence for a command @code{foo} looks like + +@example +@code{foo (int count, int key)} +@end example + +@noindent +where @var{count} is the numeric argument (or 1 if defaulted) and +@var{key} is the key that invoked this function. + +It is completely up to the function as to what should be done with the +numeric argument. Some functions use it as a repeat count, some +as a flag, and others to choose alternate behavior (refreshing the current +line as opposed to refreshing the screen, for example). Some choose to +ignore it. In general, if a +function uses the numeric argument as a repeat count, it should be able +to do something useful with both negative and positive arguments. +At the very least, it should be aware that it can be passed a +negative argument. + +@node Readline Variables +@section Readline Variables + +These variables are available to function writers. + +@deftypevar {char *} rl_line_buffer +This is the line gathered so far. You are welcome to modify the +contents of the line, but see @ref{Allowing Undoing}. +@end deftypevar + +@deftypevar int rl_point +The offset of the current cursor position in @code{rl_line_buffer} +(the @emph{point}). +@end deftypevar + +@deftypevar int rl_end +The number of characters present in @code{rl_line_buffer}. When +@code{rl_point} is at the end of the line, @code{rl_point} and +@code{rl_end} are equal. +@end deftypevar + +@deftypevar int rl_mark +The mark (saved position) in the current line. If set, the mark +and point define a @emph{region}. +@end deftypevar + +@deftypevar int rl_done +Setting this to a non-zero value causes Readline to return the current +line immediately. +@end deftypevar + +@deftypevar int rl_pending_input +Setting this to a value makes it the next keystroke read. This is a +way to stuff a single character into the input stream. +@end deftypevar + +@deftypevar {char *} rl_prompt +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_terminal_name +The terminal type, used for initialization. +@end deftypevar + +@deftypevar {char *} rl_readline_name +This variable is set to a unique name by each application using Readline. +The value allows conditional parsing of the inputrc file +(@pxref{Conditional Init Constructs}). +@end deftypevar + +@deftypevar {FILE *} rl_instream +The stdio stream from which Readline reads input. +@end deftypevar + +@deftypevar {FILE *} rl_outstream +The stdio stream to which Readline performs output. +@end deftypevar + +@deftypevar {Function *} rl_startup_hook +If non-zero, this is the address of a function to call just +before @code{readline} prints the first prompt. +@end deftypevar + +@deftypevar {Function *} rl_event_hook +If non-zero, this is the address of a function to call periodically +when readline is waiting for terminal input. +@end deftypevar + +@node Readline Convenience Functions +@section Readline Convenience Functions + +@menu +* Function Naming:: How to give a function you write a name. +* Keymaps:: Making keymaps. +* Binding Keys:: Changing Keymaps. +* Associating Function Names and Bindings:: Translate function names to + key sequences. +* Allowing Undoing:: How to make your functions undoable. +* Redisplay:: Functions to control line display. +* Modifying Text:: Functions to modify @code{rl_line_buffer}. +* Utility Functions:: Generally useful functions and hooks. +@end menu + +@node Function Naming +@subsection Naming a Function + +The user can dynamically change the bindings of keys while using +Readline. This is done by representing the function with a descriptive +name. The user is able to type the descriptive name when referring to +the function. Thus, in an init file, one might find + +@example +Meta-Rubout: backward-kill-word +@end example + +This binds the keystroke @key{Meta-Rubout} to the function +@emph{descriptively} named @code{backward-kill-word}. You, as the +programmer, should bind the functions you write to descriptive names as +well. Readline provides a function for doing that: + +@deftypefun int rl_add_defun (char *name, Function *function, int key) +Add @var{name} to the list of named functions. Make @var{function} be +the function that gets called. If @var{key} is not -1, then bind it to +@var{function} using @code{rl_bind_key ()}. +@end deftypefun + +Using this function alone is sufficient for most applications. It is +the recommended way to add a few functions to the default functions that +Readline has built in. If you need to do something other +than adding a function to Readline, you may need to use the +underlying functions described below. + +@node Keymaps +@subsection Selecting a Keymap + +Key bindings take place on a @dfn{keymap}. The keymap is the +association between the keys that the user types and the functions that +get run. You can make your own keymaps, copy existing keymaps, and tell +Readline which keymap to use. + +@deftypefun Keymap rl_make_bare_keymap () +Returns a new, empty keymap. The space for the keymap is allocated with +@code{malloc ()}; you should @code{free ()} it when you are done. +@end deftypefun + +@deftypefun Keymap rl_copy_keymap (Keymap map) +Return a new keymap which is a copy of @var{map}. +@end deftypefun + +@deftypefun Keymap rl_make_keymap () +Return a new keymap with the printing characters bound to rl_insert, +the lowercase Meta characters bound to run their equivalents, and +the Meta digits bound to produce numeric arguments. +@end deftypefun + +@deftypefun void rl_discard_keymap (Keymap keymap) +Free the storage associated with @var{keymap}. +@end deftypefun + +Readline has several internal keymaps. These functions allow you to +change which keymap is active. + +@deftypefun Keymap rl_get_keymap () +Returns the currently active keymap. +@end deftypefun + +@deftypefun void rl_set_keymap (Keymap keymap) +Makes @var{keymap} the currently active keymap. +@end deftypefun + +@deftypefun Keymap rl_get_keymap_by_name (char *name) +Return the keymap matching @var{name}. @var{name} is one which would +be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}). +@end deftypefun + +@node Binding Keys +@subsection Binding Keys + +You associate keys with functions through the keymap. Readline has +several internal keymaps: @code{emacs_standard_keymap}, +@code{emacs_meta_keymap}, @code{emacs_ctlx_keymap}, +@code{vi_movement_keymap}, and @code{vi_insertion_keymap}. +@code{emacs_standard_keymap} is the default, and the examples in +this manual assume that. + +These functions manage key bindings. + +@deftypefun int rl_bind_key (int key, Function *function) +Binds @var{key} to @var{function} in the currently active keymap. +Returns non-zero in the case of an invalid @var{key}. +@end deftypefun + +@deftypefun int rl_bind_key_in_map (int key, Function *function, Keymap map) +Bind @var{key} to @var{function} in @var{map}. Returns non-zero in the case +of an invalid @var{key}. +@end deftypefun + +@deftypefun int rl_unbind_key (int key) +Bind @var{key} to the null function in the currently active keymap. +Returns non-zero in case of error. +@end deftypefun + +@deftypefun int rl_unbind_key_in_map (int key, Keymap map) +Bind @var{key} to the null function in @var{map}. +Returns non-zero in case of error. +@end deftypefun + +@deftypefun int rl_generic_bind (int type, char *keyseq, char *data, Keymap map) +Bind the key sequence represented by the string @var{keyseq} to the arbitrary +pointer @var{data}. @var{type} says what kind of data is pointed to by +@var{data}; this can be a function (@code{ISFUNC}), a macro +(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as +necessary. The initial keymap in which to do bindings is @var{map}. +@end deftypefun + +@deftypefun int rl_parse_and_bind (char *line) +Parse @var{line} as if it had been read from the @code{inputrc} file and +perform any key bindings and variable assignments found +(@pxref{Readline Init File}). +@end deftypefun + +@deftypefun int rl_read_init_file (char *filename) +Read keybindings and variable assignments from @var{filename} +(@pxref{Readline Init File}). +@end deftypefun + +@node Associating Function Names and Bindings +@subsection Associating Function Names and Bindings + +These functions allow you to find out what keys invoke named functions +and the functions invoked by a particular key sequence. + +@deftypefun {Function *} rl_named_function (char *name) +Return the function with name @var{name}. +@end deftypefun + +@deftypefun {Function *} rl_function_of_keyseq (char *keyseq, Keymap map, int *type) +Return the function invoked by @var{keyseq} in keymap @var{map}. +If @var{map} is NULL, the current keymap is used. If @var{type} is +not NULL, the type of the object is returned in it (one of @code{ISFUNC}, +@code{ISKMAP}, or @code{ISMACR}). +@end deftypefun + +@deftypefun {char **} rl_invoking_keyseqs (Function *function) +Return an array of strings representing the key sequences used to +invoke @var{function} in the current keymap. +@end deftypefun + +@deftypefun {char **} rl_invoking_keyseqs_in_map (Function *function, Keymap map) +Return an array of strings representing the key sequences used to +invoke @var{function} in the keymap @var{map}. +@end deftypefun + +@deftypefun void rl_function_dumper (int readable) +Print the readline function names and the key sequences currently +bound to them to @code{rl_outstream}. If @var{readable} is non-zero, +the list is formatted in such a way that it can be made part of an +@code{inputrc} file and re-read. +@end deftypefun + +@deftypefun void rl_list_funmap_names () +Print the names of all bindable Readline functions to @code{rl_outstream}. +@end deftypefun + +@node Allowing Undoing +@subsection Allowing Undoing + +Supporting the undo command is a painless thing, and makes your +functions much more useful. It is certainly easy to try +something if you know you can undo it. I could use an undo function for +the stock market. + +If your function simply inserts text once, or deletes text once, and +uses @code{rl_insert_text ()} or @code{rl_delete_text ()} to do it, then +undoing is already done for you automatically. + +If you do multiple insertions or multiple deletions, or any combination +of these operations, you should group them together into one operation. +This is done with @code{rl_begin_undo_group ()} and +@code{rl_end_undo_group ()}. + +The types of events that can be undone are: + +@example +enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @}; +@end example + +Notice that @code{UNDO_DELETE} means to insert some text, and +@code{UNDO_INSERT} means to delete some text. That is, the undo code +tells undo what to undo, not how to undo it. @code{UNDO_BEGIN} and +@code{UNDO_END} are tags added by @code{rl_begin_undo_group ()} and +@code{rl_end_undo_group ()}. + +@deftypefun int rl_begin_undo_group () +Begins saving undo information in a group construct. The undo +information usually comes from calls to @code{rl_insert_text ()} and +@code{rl_delete_text ()}, but could be the result of calls to +@code{rl_add_undo ()}. +@end deftypefun + +@deftypefun int rl_end_undo_group () +Closes the current undo group started with @code{rl_begin_undo_group +()}. There should be one call to @code{rl_end_undo_group ()} +for each call to @code{rl_begin_undo_group ()}. +@end deftypefun + +@deftypefun void rl_add_undo (enum undo_code what, int start, int end, char *text) +Remember how to undo an event (according to @var{what}). The affected +text runs from @var{start} to @var{end}, and encompasses @var{text}. +@end deftypefun + +@deftypefun void free_undo_list () +Free the existing undo list. +@end deftypefun + +@deftypefun int rl_do_undo () +Undo the first thing on the undo list. Returns @code{0} if there was +nothing to undo, non-zero if something was undone. +@end deftypefun + +Finally, if you neither insert nor delete text, but directly modify the +existing text (e.g., change its case), call @code{rl_modifying ()} +once, just before you modify the text. You must supply the indices of +the text range that you are going to modify. + +@deftypefun int rl_modifying (int start, int end) +Tell Readline to save the text between @var{start} and @var{end} as a +single undo unit. It is assumed that you will subsequently modify +that text. +@end deftypefun + +@node Redisplay +@subsection Redisplay + +@deftypefun int rl_redisplay () +Change what's displayed on the screen to reflect the current contents +of @code{rl_line_buffer}. +@end deftypefun + +@deftypefun int rl_forced_update_display () +Force the line to be updated and redisplayed, whether or not +Readline thinks the screen display is correct. +@end deftypefun + +@deftypefun int rl_on_new_line () +Tell the update routines that we have moved onto a new (empty) line, +usually after ouputting a newline. +@end deftypefun + +@deftypefun int rl_reset_line_state () +Reset the display state to a clean state and redisplay the current line +starting on a new line. +@end deftypefun + +@deftypefun int rl_message (va_alist) +The arguments are a string as would be supplied to @code{printf}. The +resulting string is displayed in the @dfn{echo area}. The echo area +is also used to display numeric arguments and search strings. +@end deftypefun + +@deftypefun int rl_clear_message () +Clear the message in the echo area. +@end deftypefun + +@node Modifying Text +@subsection Modifying Text + +@deftypefun int rl_insert_text (char *text) +Insert @var{text} into the line at the current cursor position. +@end deftypefun + +@deftypefun int rl_delete_text (int start, int end) +Delete the text between @var{start} and @var{end} in the current line. +@end deftypefun + +@deftypefun {char *} rl_copy_text (int start, int end) +Return a copy of the text between @var{start} and @var{end} in +the current line. +@end deftypefun + +@deftypefun int rl_kill_text (int start, int end) +Copy the text between @var{start} and @var{end} in the current line +to the kill ring, appending or prepending to the last kill if the +last command was a kill command. The text is deleted. +If @var{start} is less than @var{end}, +the text is appended, otherwise prepended. If the last command was +not a kill, a new kill ring slot is used. +@end deftypefun + +@node Utility Functions +@subsection Utility Functions + +@deftypefun int rl_read_key () +Return the next character available. This handles input inserted into +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_stuff_char (int c) +Insert @var{c} into the Readline input stream. It will be "read" +before Readline attempts to read characters from the terminal with +@code{rl_read_key ()}. +@end deftypefun + +@deftypefun int rl_initialize () +Initialize or re-initialize Readline's internal state. +@end deftypefun + +@deftypefun int rl_reset_terminal (char *terminal_name) +Reinitialize Readline's idea of the terminal settings using +@var{terminal_name} as the terminal type (e.g., @code{vt100}). +@end deftypefun + +@deftypefun int alphabetic (int c) +Return 1 if @var{c} is an alphabetic character. +@end deftypefun + +@deftypefun int numeric (int c) +Return 1 if @var{c} is a numeric character. +@end deftypefun + +@deftypefun int ding () +Ring the terminal bell, obeying the setting of @code{bell-style}. +@end deftypefun + +The following are implemented as macros, defined in @code{chartypes.h}. + +@deftypefun int uppercase_p (int c) +Return 1 if @var{c} is an uppercase alphabetic character. +@end deftypefun + +@deftypefun int lowercase_p (int c) +Return 1 if @var{c} is a lowercase alphabetic character. +@end deftypefun + +@deftypefun int digit_p (int c) +Return 1 if @var{c} is a numeric character. +@end deftypefun + +@deftypefun int to_upper (int c) +If @var{c} is a lowercase alphabetic character, return the corresponding +uppercase character. +@end deftypefun + +@deftypefun int to_lower (int c) +If @var{c} is an uppercase alphabetic character, return the corresponding +lowercase character. +@end deftypefun + +@deftypefun int digit_value (int c) +If @var{c} is a number, return the value it represents. +@end deftypefun + +@subsection An Example + +Here is a function which changes lowercase characters to their uppercase +equivalents, and uppercase characters to lowercase. If +this function was bound to @samp{M-c}, then typing @samp{M-c} would +change the case of the character under point. Typing @samp{M-1 0 M-c} +would change the case of the following 10 characters, leaving the cursor on +the last character changed. + +@example +/* Invert the case of the COUNT following characters. */ +int +invert_case_line (count, key) + int count, key; +@{ + register int start, end, i; + + start = rl_point; + + if (rl_point >= rl_end) + return (0); + + if (count < 0) + @{ + direction = -1; + count = -count; + @} + else + direction = 1; + + /* Find the end of the range to modify. */ + end = start + (count * direction); + + /* Force it to be within range. */ + if (end > rl_end) + end = rl_end; + else if (end < 0) + end = 0; + + if (start == end) + return (0); + + if (start > end) + @{ + int temp = start; + start = end; + end = temp; + @} + + /* Tell readline that we are modifying the line, so it will save + the undo information. */ + rl_modifying (start, end); + + for (i = start; i != end; i++) + @{ + if (uppercase_p (rl_line_buffer[i])) + rl_line_buffer[i] = to_lower (rl_line_buffer[i]); + else if (lowercase_p (rl_line_buffer[i])) + rl_line_buffer[i] = to_upper (rl_line_buffer[i]); + @} + /* Move point to on top of the last character changed. */ + rl_point = (direction == 1) ? end - 1 : start; + return (0); +@} +@end example + +@node Custom Completers +@section Custom Completers + +Typically, a program that reads commands from the user has a way of +disambiguating commands and data. If your program is one of these, then +it can provide completion for commands, data, or both. +The following sections describe how your program and Readline +cooperate to provide this service. + +@menu +* How Completing Works:: The logic used to do completion. +* Completion Functions:: Functions provided by Readline. +* Completion Variables:: Variables which control completion. +* A Short Completion Example:: An example of writing completer subroutines. +@end menu + +@node How Completing Works +@subsection How Completing Works + +In order to complete some text, the full list of possible completions +must be available. That is, it is not possible to accurately +expand a partial word without knowing all of the possible words +which make sense in that context. The Readline library provides +the user interface to completion, and two of the most common +completion functions: filename and username. For completing other types +of text, you must write your own completion function. This section +describes exactly what such functions must do, and provides an example. + +There are three major functions used to perform completion: + +@enumerate +@item +The user-interface function @code{rl_complete ()}. This function is +called with the same arguments as other Readline +functions intended for interactive use: @var{count} and +@var{invoking_key}. It isolates the word to be completed and calls +@code{completion_matches ()} to generate a list of possible completions. +It then either lists the possible completions, inserts the possible +completions, or actually performs the +completion, depending on which behavior is desired. + +@item +The internal function @code{completion_matches ()} uses your +@dfn{generator} function to generate the list of possible matches, and +then returns the array of these matches. You should place the address +of your generator function in @code{rl_completion_entry_function}. + +@item +The generator function is called repeatedly from +@code{completion_matches ()}, returning a string each time. The +arguments to the generator function are @var{text} and @var{state}. +@var{text} is the partial word to be completed. @var{state} is zero the +first time the function is called, allowing the generator to perform +any necessary initialization, and a positive non-zero integer for +each subsequent call. When the generator function returns +@code{(char *)NULL} this signals @code{completion_matches ()} that there are +no more possibilities left. Usually the generator function computes the +list of possible completions when @var{state} is zero, and returns them +one at a time on subsequent calls. Each string the generator function +returns as a match must be allocated with @code{malloc()}; Readline +frees the strings when it has finished with them. + +@end enumerate + +@deftypefun int rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{completion_matches ()}). The default is to do filename completion. +@end deftypefun + +@deftypevar {Function *} rl_completion_entry_function +This is a pointer to the generator function for @code{completion_matches +()}. If the value of @code{rl_completion_entry_function} is +@code{(Function *)NULL} then the default filename generator function, +@code{filename_entry_function ()}, is used. +@end deftypevar + +@node Completion Functions +@subsection Completion Functions + +Here is the complete list of callable completion functions present in +Readline. + +@deftypefun int rl_complete_internal (int what_to_do) +Complete the word at or before point. @var{what_to_do} says what to do +with the completion. A value of @samp{?} means list the possible +completions. @samp{TAB} means do standard completion. @samp{*} means +insert all of the possible completions. @samp{!} means to display +all of the possible completions, if there is more than one, as well as +performing partial completion. +@end deftypefun + +@deftypefun int rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{completion_matches ()} and @code{rl_completion_entry_function}). +The default is to do filename +completion. This calls @code{rl_complete_internal ()} with an +argument depending on @var{invoking_key}. +@end deftypefun + +@deftypefun int rl_possible_completions (int count, int invoking_key)) +List the possible completions. See description of @code{rl_complete +()}. This calls @code{rl_complete_internal ()} with an argument of +@samp{?}. +@end deftypefun + +@deftypefun int rl_insert_completions (int count, int invoking_key)) +Insert the list of possible completions into the line, deleting the +partially-completed word. See description of @code{rl_complete ()}. +This calls @code{rl_complete_internal ()} with an argument of @samp{*}. +@end deftypefun + +@deftypefun {char **} completion_matches (char *text, CPFunction *entry_func) +Returns an array of @code{(char *)} which is a list of completions for +@var{text}. If there are no completions, returns @code{(char **)NULL}. +The first entry in the returned array is the substitution for @var{text}. +The remaining entries are the possible completions. The array is +terminated with a @code{NULL} pointer. + +@var{entry_func} is a function of two args, and returns a +@code{(char *)}. The first argument is @var{text}. The second is a +state argument; it is zero on the first call, and non-zero on subsequent +calls. @var{entry_func} returns a @code{NULL} pointer to the caller +when there are no more matches. +@end deftypefun + +@deftypefun {char *} filename_completion_function (char *text, int state) +A generator function for filename completion in the general case. Note +that completion in Bash is a little different because of all +the pathnames that must be followed when looking up completions for a +command. The Bash source is a useful reference for writing custom +completion functions. +@end deftypefun + +@deftypefun {char *} username_completion_function (char *text, int state) +A completion generator for usernames. @var{text} contains a partial +username preceded by a random character (usually @samp{~}). As with all +completion generators, @var{state} is zero on the first call and non-zero +for subsequent calls. +@end deftypefun + +@node Completion Variables +@subsection Completion Variables + +@deftypevar {Function *} rl_completion_entry_function +A pointer to the generator function for @code{completion_matches ()}. +@code{NULL} means to use @code{filename_entry_function ()}, the default +filename completer. +@end deftypevar + +@deftypevar {CPPFunction *} rl_attempted_completion_function +A pointer to an alternative function to create matches. +The function is called with @var{text}, @var{start}, and @var{end}. +@var{start} and @var{end} are indices in @code{rl_line_buffer} saying +what the boundaries of @var{text} are. If this function exists and +returns @code{NULL}, or if this variable is set to @code{NULL}, then +@code{rl_complete ()} will call the value of +@code{rl_completion_entry_function} to generate matches, otherwise the +array of strings returned will be used. +@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 +she wants to see them all. The default value is 100. +@end deftypevar + +@deftypevar {char *} rl_basic_word_break_characters +The basic list of characters that signal a break between words for the +completer routine. The default value of this variable is the characters +which break words for completion in Bash, i.e., +@code{" \t\n\"\\'`@@$><=;|&@{("}. +@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 +@code{rl_basic_word_break_characters}. +@end deftypevar + +@deftypevar {char *} rl_completer_quote_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 +@code{rl_completer_word_break_characters} are treated as any other character, +unless they also appear within this list. +@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. +Programs can use this to help determine what kind of completing to do. +For instance, Bash sets this variable to "$@@" so that it can complete +shell variables and hostnames. +@end deftypevar + +@deftypevar int rl_ignore_completion_duplicates +If non-zero, then disallow duplicates in the matches. Default is 1. +@end deftypevar + +@deftypevar int rl_filename_completion_desired +Non-zero means that the results of the matches are to be treated as +filenames. This is @emph{always} zero on entry, and can only be changed +within a completion entry generator function. If it is set to a non-zero +value, directory names have a slash appended and Readline attempts to +quote completed filenames if they contain any embedded word break +characters. +@end deftypevar + +@deftypevar int rl_filename_quoting_desired +Non-zero means that the results of the matches are to be quoted using +double quotes (or an application-specific quoting mechanism) if the +completed filename contains any characters in +@code{rl_completer_word_break_chars}. This is @emph{always} non-zero +on entry, and can only be changed within a completion entry generator +function. +@end deftypevar + +@deftypevar {Function *} rl_ignore_some_completions_function +This function, if defined, is called by the completer when real filename +completion is done, after all the matching names have been generated. +It is passed a @code{NULL} terminated array of matches. +The first element (@code{matches[0]}) is the +maximal substring common to all matches. This function can +re-arrange the list of matches as required, but each element deleted +from the array must be freed. +@end deftypevar + +@deftypevar {Function *} rl_directory_completion_hook +This function, if defined, is allowed to modify the directory portion +of filenames Readline completes. It is called with the address of a +string (the current directory name) as an argument. It could be used +to expand symbolic links or shell variables in pathnames. +@end deftypevar + +@node A Short Completion Example +@subsection A Short Completion Example + +Here is a small application demonstrating the use of the GNU Readline +library. It is called @code{fileman}, and the source code resides in +@file{examples/fileman.c}. This sample application provides +completion of command names, line editing features, and access to the +history list. + +@page +@smallexample +/* fileman.c -- A tiny application which demonstrates how to use the + GNU Readline library. This application interactively allows users + to manipulate files and their modes. */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/errno.h> + +#include <readline/readline.h> +#include <readline/history.h> + +extern char *getwd (); +extern char *xmalloc (); + +/* The names of functions that actually do the manipulation. */ +int com_list (), com_view (), com_rename (), com_stat (), com_pwd (); +int com_delete (), com_help (), com_cd (), com_quit (); + +/* A structure which contains information on the commands this program + can understand. */ + +typedef struct @{ + char *name; /* User printable name of the function. */ + Function *func; /* Function to call to do the job. */ + char *doc; /* Documentation for this function. */ +@} COMMAND; + +COMMAND commands[] = @{ + @{ "cd", com_cd, "Change to directory DIR" @}, + @{ "delete", com_delete, "Delete FILE" @}, + @{ "help", com_help, "Display this text" @}, + @{ "?", com_help, "Synonym for `help'" @}, + @{ "list", com_list, "List files in DIR" @}, + @{ "ls", com_list, "Synonym for `list'" @}, + @{ "pwd", com_pwd, "Print the current working directory" @}, + @{ "quit", com_quit, "Quit using Fileman" @}, + @{ "rename", com_rename, "Rename FILE to NEWNAME" @}, + @{ "stat", com_stat, "Print out statistics on FILE" @}, + @{ "view", com_view, "View the contents of FILE" @}, + @{ (char *)NULL, (Function *)NULL, (char *)NULL @} +@}; + +/* Forward declarations. */ +char *stripwhite (); +COMMAND *find_command (); + +/* The name of this program, as taken from argv[0]. */ +char *progname; + +/* When non-zero, this global means the user is done using this program. */ +int done; + +char * +dupstr (s) + int s; +@{ + char *r; + + r = xmalloc (strlen (s) + 1); + strcpy (r, s); + return (r); +@} + +main (argc, argv) + int argc; + char **argv; +@{ + char *line, *s; + + progname = argv[0]; + + initialize_readline (); /* Bind our completer. */ + + /* Loop reading and executing lines until the user quits. */ + for ( ; done == 0; ) + @{ + line = readline ("FileMan: "); + + if (!line) + break; + + /* Remove leading and trailing whitespace from the line. + Then, if there is anything left, add it to the history list + and execute it. */ + s = stripwhite (line); + + if (*s) + @{ + add_history (s); + execute_line (s); + @} + + free (line); + @} + exit (0); +@} + +/* Execute a command line. */ +int +execute_line (line) + char *line; +@{ + register int i; + COMMAND *command; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && whitespace (line[i])) + i++; + word = line + i; + + while (line[i] && !whitespace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + command = find_command (word); + + if (!command) + @{ + fprintf (stderr, "%s: No such command for FileMan.\n", word); + return (-1); + @} + + /* Get argument to command, if any. */ + while (whitespace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + return ((*(command->func)) (word)); +@} + +/* Look up NAME as the name of a command, and return a pointer to that + command. Return a NULL pointer if NAME isn't a command name. */ +COMMAND * +find_command (name) + char *name; +@{ + register int i; + + for (i = 0; commands[i].name; i++) + if (strcmp (name, commands[i].name) == 0) + return (&commands[i]); + + return ((COMMAND *)NULL); +@} + +/* Strip whitespace from the start and end of STRING. Return a pointer + into STRING. */ +char * +stripwhite (string) + char *string; +@{ + register char *s, *t; + + for (s = string; whitespace (*s); s++) + ; + + if (*s == 0) + return (s); + + t = s + strlen (s) - 1; + while (t > s && whitespace (*t)) + t--; + *++t = '\0'; + + return s; +@} + +/* **************************************************************** */ +/* */ +/* Interface to Readline Completion */ +/* */ +/* **************************************************************** */ + +char *command_generator (); +char **fileman_completion (); + +/* Tell the GNU Readline library how to complete. We want to try to complete + on command names if this is the first word in the line, or on filenames + if not. */ +initialize_readline () +@{ + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "FileMan"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (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. */ +char ** +fileman_completion (text, start, end) + char *text; + int start, end; +@{ + char **matches; + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + to complete. Otherwise it is the name of a file in the current + directory. */ + if (start == 0) + matches = completion_matches (text, command_generator); + + return (matches); +@} + +/* Generator function for command completion. STATE lets us know whether + to start from scratch; without any state (i.e. STATE == 0), then we + start at the top of the list. */ +char * +command_generator (text, state) + char *text; + int state; +@{ + static int list_index, len; + char *name; + + /* If this is a new word to complete, initialize now. This includes + saving the length of TEXT for efficiency, and initializing the index + variable to 0. */ + if (!state) + @{ + list_index = 0; + len = strlen (text); + @} + + /* Return the next name which partially matches from the command list. */ + while (name = commands[list_index].name) + @{ + list_index++; + + if (strncmp (name, text, len) == 0) + return (dupstr(name)); + @} + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +@} + +/* **************************************************************** */ +/* */ +/* FileMan Commands */ +/* */ +/* **************************************************************** */ + +/* String to pass to system (). This is for the LIST, VIEW and RENAME + commands. */ +static char syscom[1024]; + +/* List the file(s) named in arg. */ +com_list (arg) + char *arg; +@{ + if (!arg) + arg = ""; + + sprintf (syscom, "ls -FClg %s", arg); + return (system (syscom)); +@} + +com_view (arg) + char *arg; +@{ + if (!valid_argument ("view", arg)) + return 1; + + sprintf (syscom, "more %s", arg); + return (system (syscom)); +@} + +com_rename (arg) + char *arg; +@{ + too_dangerous ("rename"); + return (1); +@} + +com_stat (arg) + char *arg; +@{ + struct stat finfo; + + if (!valid_argument ("stat", arg)) + return (1); + + if (stat (arg, &finfo) == -1) + @{ + perror (arg); + return (1); + @} + + printf ("Statistics for `%s':\n", arg); + + printf ("%s has %d link%s, and is %d byte%s in length.\n", arg, + finfo.st_nlink, + (finfo.st_nlink == 1) ? "" : "s", + finfo.st_size, + (finfo.st_size == 1) ? "" : "s"); + printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime)); + printf (" Last access at: %s", ctime (&finfo.st_atime)); + printf (" Last modified at: %s", ctime (&finfo.st_mtime)); + return (0); +@} + +com_delete (arg) + char *arg; +@{ + too_dangerous ("delete"); + return (1); +@} + +/* Print out help for ARG, or for all of the commands if ARG is + not present. */ +com_help (arg) + char *arg; +@{ + register int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) + @{ + if (!*arg || (strcmp (arg, commands[i].name) == 0)) + @{ + printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); + printed++; + @} + @} + + if (!printed) + @{ + printf ("No commands match `%s'. Possibilties are:\n", arg); + + for (i = 0; commands[i].name; i++) + @{ + /* Print in six columns. */ + if (printed == 6) + @{ + printed = 0; + printf ("\n"); + @} + + printf ("%s\t", commands[i].name); + printed++; + @} + + if (printed) + printf ("\n"); + @} + return (0); +@} + +/* Change to the directory ARG. */ +com_cd (arg) + char *arg; +@{ + if (chdir (arg) == -1) + @{ + perror (arg); + return 1; + @} + + com_pwd (""); + return (0); +@} + +/* Print out the current working directory. */ +com_pwd (ignore) + char *ignore; +@{ + char dir[1024], *s; + + s = getwd (dir); + if (s == 0) + @{ + printf ("Error getting pwd: %s\n", dir); + return 1; + @} + + printf ("Current directory is %s\n", dir); + return 0; +@} + +/* The user wishes to quit using this program. Just set DONE non-zero. */ +com_quit (arg) + char *arg; +@{ + done = 1; + return (0); +@} + +/* Function which tells you that you can't do this. */ +too_dangerous (caller) + char *caller; +@{ + fprintf (stderr, + "%s: Too dangerous for me to distribute. Write it yourself.\n", + caller); +@} + +/* Return non-zero if ARG is a valid argument for CALLER, else print + an error message and return zero. */ +int +valid_argument (caller, arg) + char *caller, *arg; +@{ + if (!arg || !*arg) + @{ + fprintf (stderr, "%s: Argument required.\n", caller); + return (0); + @} + + return (1); +@} +@end smallexample diff --git a/lib/readline/doc/rluser.texinfo b/lib/readline/doc/rluser.texinfo new file mode 100644 index 0000000..3567549 --- /dev/null +++ b/lib/readline/doc/rluser.texinfo @@ -0,0 +1,875 @@ +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rluser.info +@comment %**end of header (This is for running Texinfo on a region.) +@setchapternewpage odd + +@ignore +This file documents the end user interface to the GNU command line +editing features. It is to be an appendix to manuals for programs which +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. + +Authored by Brian Fox and Chet Ramey. + +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). + +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 also that the +GNU Copyright statement is available to the distributee, and 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. +@end ignore + +@comment If you are including this manual as an appendix, then set the +@comment variable readline-appendix. + +@node Command Line Editing +@chapter 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. +@end menu + +@node Introduction and Notation +@section Introduction to Line Editing + +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. + +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 +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. + +The text @key{M-C-k} is read as `Meta-Control-k' and describes the +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). + +@node Readline Interaction +@section Readline Interaction +@cindex interaction, readline + +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 @key{RETURN}. You do not have to be at the +end of the line to press @key{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. +@end menu + +@node Readline Bare Essentials +@subsection 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 @key{C-b} to move the cursor to the left, and then +correct your mistake. Afterwards, you can move the cursor to the right +with @key{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. + +@table @asis +@item @key{C-b} +Move back one character. +@item @key{C-f} +Move forward one character. +@item @key{DEL} +Delete the character to the left of the cursor. +@item @key{C-d} +Delete the character underneath the cursor. +@item @w{Printing characters} +Insert the character into the line at the cursor. +@item @key{C-_} +Undo the last thing that you did. You can undo all the way back to an +empty line. +@end table + +@node Readline Movement Commands +@subsection 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 @key{C-b}, @key{C-f}, +@key{C-d}, and @key{DEL}. Here are some commands for moving more rapidly +about the line. + +@table @key +@item C-a +Move to the start of the line. +@item C-e +Move to the end of the line. +@item M-f +Move forward a word. +@item M-b +Move backward a word. +@item C-l +Clear the screen, reprinting the current line at the top. +@end table + +Notice how @key{C-f} moves forward a character, while @key{M-f} moves +forward a word. It is a loose convention that control keystrokes +operate on characters while meta keystrokes operate on words. + +@node Readline Killing Commands +@subsection Readline Killing Commands + +@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) +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 @dfn{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. +@cindex Kill ring + +Here is the list of commands for killing text. + +@table @key +@item C-k +Kill the text from the current cursor position to the end of the line. + +@item M-d +Kill from the cursor to the end of the current word, or if between +words, to the end of the next word. + +@item M-DEL +Kill from the cursor the start of the previous word, or if between +words, to the start of the previous word. + +@item C-w +Kill from the cursor to the previous whitespace. This is different than +@key{M-DEL} because the word boundaries differ. + +@end table + +And, here is how to @dfn{yank} the text back into the line. Yanking +means to copy the most-recently-killed text from the kill buffer. + +@table @key +@item C-y +Yank the most recently killed text back into the buffer at the cursor. + +@item M-y +Rotate the kill-ring, and yank the new top. You can only do this if +the prior command is @key{C-y} or @key{M-y}. +@end table + +@node Readline Arguments +@subsection Readline Arguments + +You can pass numeric arguments to Readline commands. Sometimes the +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}. + +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}. + + +@node Readline Init File +@section 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 @dfn{init} 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 +@ifclear BashFeatures +file is taken from the value of the environment variable @code{INPUTRC}. If +@end ifclear +that variable is unset, the default is @file{~/.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 @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. +* Conditional Init Constructs:: Conditional key bindings in the inputrc file. +@end menu + +@node Readline Init Syntax +@subsection Readline Init 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 +constructs (@pxref{Conditional Init Constructs}). Other lines +denote variable settings and key bindings. + +@table @asis +@item Variable Settings +You can change the state of a few variables in Readline by +using the @code{set} command within the init file. Here is how you +would specify that you wish to use @code{vi} line editing commands: + +@example +set editing-mode vi +@end example + +Right now, there are only a few variables which can be set; +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 +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 +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 +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 +@code{100}. + +@item keymap +@vindex keymap +Sets Readline's idea of the current keymap for key binding commands. +Acceptable @code{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}. The default value is @code{emacs}. +The value of the @code{editing-mode} variable also affects the +default keymap. + +@item show-all-if-ambiguous +@vindex show-all-if-ambiguous +This alters the default behavior of the completion functions. If +set to @code{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}. + +@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}. + +@end table + +@item 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. + +@table @asis +@item @w{@var{keyname}: @var{function-name} or @var{macro}} +@var{keyname} is the name of a key spelled out in English. For example: +@example +Control-u: universal-argument +Meta-Rubout: backward-kill-word +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). + +@item @w{"@var{keyseq}": @var{function-name} or @var{macro}} +@var{keyseq} differs from @var{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. + +@example +"\C-u": universal-argument +"\C-x\C-r": re-read-init-file +"\e[11~": "Function Key 1" +@end example + +In the above example, @samp{C-u} is bound to the function +@code{universal-argument} (just as it was in the first example), +@samp{C-x C-r} is bound to the function @code{re-read-init-file}, and +@samp{ESC [ 1 1 ~} is bound to insert the text @samp{Function Key 1}. +The following escape sequences are available when specifying key +sequences: + +@table @code +@item @kbd{\C-} +control prefix +@item @kbd{\M-} +meta prefix +@item @kbd{\e} +an escape character +@item @kbd{\\} +backslash +@item @kbd{\"} +@key{"} +@item @kbd{\'} +@key{'} +@end table + +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: +@example +"\C-x\\": "\\" +@end example + +@end table +@end table + +@node Conditional Init Constructs +@subsection 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. + +@ftable @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 +Readline. The text of the test extends to the end of the line; +no characters are required to isolate it. + +@table @code +@item mode +The @code{mode=} form of the @code{$if} directive is used to test +whether Readline is in @code{emacs} or @code{vi} mode. +This may be used in conjunction +with the @samp{set keymap} command, for instance, to set bindings in +the @code{emacs-standard} and @code{emacs-ctlx} keymaps only if +Readline is starting out in @code{emacs} mode. + +@item term +The @code{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 +@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}, +for instance. + +@item application +The @var{application} construct is used to include +application-specific settings. Each program using the Readline +library sets the @var{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: +@example +$if bash +# Quote the current or previous word +"\C-xq": "\eb\"\ef\"" +$endif +@end example +@end table + +@item $endif +This command, as you saw in the previous example, terminates an +@code{$if} command. + +@item $else +Commands in this branch of the @code{$if} directive are executed if +the test fails. +@end ftable + +@node Bindable Readline Commands +@section 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. +@end menu + +@node Commands For Moving +@subsection Commands For Moving +@ftable @code +@item beginning-of-line (C-a) +Move to the start of the current line. + +@item end-of-line (C-e) +Move to the end of the line. + +@item forward-char (C-f) +Move forward a character. + +@item backward-char (C-b) +Move back a character. + +@item forward-word (M-f) +Move forward to the end of the next word. Words are composed of +letters and digits. + +@item backward-word (M-b) +Move back to the start of this, or the previous, word. Words are +composed of letters and digits. + +@item clear-screen (C-l) +Clear the screen and redraw the current line, +leaving the current line at the top of the screen. + +@item redraw-current-line () +Refresh the current line. By default, this is unbound. + +@end ftable + +@node Commands For History +@subsection Commands For Manipulating The History + +@ftable @code +@item accept-line (Newline, Return) +@ifset BashFeatures +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 @code{HISTCONTROL} variable. If this line was a history +line, then restore the history line to its original state. +@end ifset +@ifclear BashFeatures +Accept the line regardless of where the cursor is. If this line is +non-empty, add it to the history list. If this line was a history +line, then restore the history line to its original state. +@end ifclear + +@item previous-history (C-p) +Move `up' through the history list. + +@item next-history (C-n) +Move `down' through the history list. + +@item beginning-of-history (M-<) +Move to the first line in the history. + +@item end-of-history (M->) +Move to the end of the input history, i.e., the line you are entering. + +@item 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. + +@item 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. + +@item 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. + +@item 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. + +@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. + +@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 +is a non-incremental search. By default, this command is unbound. + +@item yank-nth-arg (M-C-y) +Insert the first argument to the previous command (usually +the second word on the previous line). With an argument @var{n}, +insert the @var{n}th word from the previous command (the words +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 +argument, behave exactly like @code{yank-nth-arg}. + +@end ftable + +@node Commands For Text +@subsection Commands For Changing Text + +@ftable @code +@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. + +@item backward-delete-char (Rubout) +Delete the character behind the cursor. A numeric arg says to kill +the characters instead of deleting them. + +@item 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 @key{C-q}, for example. + +@item tab-insert (M-TAB) +Insert a tab character. + +@item self-insert (a, b, A, 1, !, ...) +Insert yourself. + +@item 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. + +@item 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. + +@item upcase-word (M-u) +Uppercase the current (or following) word. With a negative argument, +do the previous word, but do not move the cursor. + +@item downcase-word (M-l) +Lowercase the current (or following) word. With a negative argument, +do the previous word, but do not move the cursor. + +@item capitalize-word (M-c) +Capitalize the current (or following) word. With a negative argument, +do the previous word, but do not move the cursor. + +@end ftable + +@node Commands For Killing +@subsection Killing And Yanking + +@ftable @code + +@item kill-line (C-k) +Kill the text from the current cursor position to the end of the line. + +@item backward-kill-line (C-x Rubout) +Kill backward to the beginning of the line. + +@item 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. + +@item kill-whole-line () +Kill all characters on the current line, no matter where the +cursor is. By default, this is unbound. + +@item 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 @code{forward-word}. + +@item backward-kill-word (M-DEL) +Kill the word behind the cursor. Word boundaries are the same +as @code{backward-word}. + +@item 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. + +@item delete-horizontal-space () +Delete all spaces and tabs around point. By default, this is unbound. + +@item yank (C-y) +Yank the top of the kill ring into the buffer at the current +cursor position. + +@item 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. +@end ftable + +@node Numeric Arguments +@subsection Specifying Numeric Arguments +@ftable @code + +@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. + +@item 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. +@end ftable + +@node Commands For Completion +@subsection Letting Readline Type For You + +@ftable @code +@item 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. +@ifset BashFeatures +See the Bash manual page for a complete list of available completion +functions. +@end ifset + +@item possible-completions (M-?) +List the possible completions of the text before the cursor. + +@item insert-completions () +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. + +@end ftable + +@node Keyboard Macros +@subsection Keyboard Macros +@ftable @code + +@item start-kbd-macro (C-x () +Begin saving the characters typed into the current keyboard macro. + +@item end-kbd-macro (C-x )) +Stop saving the characters typed into the current keyboard macro +and save the definition. + +@item 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. + +@end ftable + +@node Miscellaneous Commands +@subsection Some Miscellaneous Commands +@ftable @code + +@item 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. + +@item abort (C-g) +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 prefix-meta (ESC) +Make the next character that you type be metafied. This is for people +without a meta key. Typing @samp{ESC f} is equivalent to typing +@samp{M-f}. + +@item undo (C-_, C-x C-u) +Incremental undo, separately remembered for each line. + +@item revert-line (M-r) +Undo all changes made to this line. This is like typing the @code{undo} +command enough times to get back to the beginning. + +@item tilde-expand (M-~) +Perform tilde expansion on the current word. + +@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. + +@ifset BashFeatures +@item display-shell-version (C-x C-v) +Display version information about the current instance of Bash. + +@item 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. + +@item history-expand-line (M-^) +Perform history expansion on the current line. + +@item insert-last-argument (M-., M-_) +A synonym for @code{yank-last-arg}. + +@item 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. + +@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 +been executed. + +@end ifset + +@end ftable + +@node Readline vi Mode +@section Readline vi Mode + +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. + +@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} +commands (@pxref{The Set Builtin}). +@end ifset +@ifclear BashFeatures +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. + +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 +so forth. diff --git a/lib/readline/doc/texindex.c b/lib/readline/doc/texindex.c new file mode 100644 index 0000000..9233bab --- /dev/null +++ b/lib/readline/doc/texindex.c @@ -0,0 +1,1666 @@ +/* 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 <stdio.h> +#include <ctype.h> +#include <errno.h> +#include "getopt.h" +#include "bashansi.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#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 <sys/types.h> + +#if defined (_AIX) || !defined (_POSIX_VERSION) +# include <sys/file.h> +#endif + +#include <fcntl.h> + +#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 new file mode 100644 index 0000000..849d85f --- /dev/null +++ b/lib/readline/emacs_keymap.c @@ -0,0 +1,885 @@ +/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */ + +/* 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. */ + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* !BUFSIZ */ + +#include "readline.h" + +/* An array of function pointers, one for each possible key. + If the type byte is ISKMAP, then the pointer is the address of + a keymap. */ + +KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { + + /* Control keys. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, rl_beg_of_line }, /* Control-a */ + { ISFUNC, rl_backward }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, rl_delete }, /* Control-d */ + { ISFUNC, rl_end_of_line }, /* Control-e */ + { ISFUNC, rl_forward }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_rubout }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ +#if defined (PAREN_MATCHING) + { ISFUNC, rl_insert_close }, /* ) */ +#else + { ISFUNC, rl_insert }, /* ) */ +#endif /* !PAREN_MATCHING */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ +#if defined (PAREN_MATCHING) + { ISFUNC, rl_insert_close }, /* ] */ +#else + { ISFUNC, rl_insert }, /* ] */ +#endif /* !PAREN_MATCHING */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ +#if defined (PAREN_MATCHING) + { ISFUNC, rl_insert_close }, /* } */ +#else + { ISFUNC, rl_insert }, /* } */ +#endif /* !PAREN_MATCHING */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Pure 8-bit characters (128 - 159). + These might be used in some + character sets. */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + + /* ISO Latin-1 characters (160 - 255) */ + { ISFUNC, rl_insert }, /* No-break space */ + { ISFUNC, rl_insert }, /* Inverted exclamation mark */ + { ISFUNC, rl_insert }, /* Cent sign */ + { ISFUNC, rl_insert }, /* Pound sign */ + { ISFUNC, rl_insert }, /* Currency sign */ + { ISFUNC, rl_insert }, /* Yen sign */ + { ISFUNC, rl_insert }, /* Broken bar */ + { ISFUNC, rl_insert }, /* Section sign */ + { ISFUNC, rl_insert }, /* Diaeresis */ + { ISFUNC, rl_insert }, /* Copyright sign */ + { ISFUNC, rl_insert }, /* Feminine ordinal indicator */ + { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Not sign */ + { ISFUNC, rl_insert }, /* Soft hyphen */ + { ISFUNC, rl_insert }, /* Registered sign */ + { ISFUNC, rl_insert }, /* Macron */ + { ISFUNC, rl_insert }, /* Degree sign */ + { ISFUNC, rl_insert }, /* Plus-minus sign */ + { ISFUNC, rl_insert }, /* Superscript two */ + { ISFUNC, rl_insert }, /* Superscript three */ + { ISFUNC, rl_insert }, /* Acute accent */ + { ISFUNC, rl_insert }, /* Micro sign */ + { ISFUNC, rl_insert }, /* Pilcrow sign */ + { ISFUNC, rl_insert }, /* Middle dot */ + { ISFUNC, rl_insert }, /* Cedilla */ + { ISFUNC, rl_insert }, /* Superscript one */ + { ISFUNC, rl_insert }, /* Masculine ordinal indicator */ + { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */ + { ISFUNC, rl_insert }, /* Vulgar fraction one half */ + { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */ + { ISFUNC, rl_insert }, /* Inverted questionk mark */ + { ISFUNC, rl_insert }, /* Latin capital letter a with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter a with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin capital letter ae */ + { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin capital letter e with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter e with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter i with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter i with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter o with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Multiplication sign */ + { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin capital letter u with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter u with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */ + { ISFUNC, rl_insert }, /* Latin small letter a with grave */ + { ISFUNC, rl_insert }, /* Latin small letter a with acute */ + { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin small letter ae */ + { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin small letter e with grave */ + { ISFUNC, rl_insert }, /* Latin small letter e with acute */ + { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter i with grave */ + { ISFUNC, rl_insert }, /* Latin small letter i with acute */ + { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with grave */ + { ISFUNC, rl_insert }, /* Latin small letter o with acute */ + { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Division sign */ + { ISFUNC, rl_insert }, /* Latin small letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin small letter u with grave */ + { ISFUNC, rl_insert }, /* Latin small letter u with acute */ + { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter y with acute */ + { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */ + { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */ +#endif /* KEYMAP_SIZE > 128 */ +}; + +KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { + + /* Meta keys. Just like above, but the high bit is set. */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */ + { ISFUNC, rl_abort }, /* Meta-Control-g */ + { ISFUNC, rl_backward_kill_word }, /* Meta-Control-h */ + { ISFUNC, rl_tab_insert }, /* Meta-Control-i */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */ + { ISFUNC, rl_revert_line }, /* Meta-Control-r */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */ + { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */ + + { ISFUNC, rl_complete }, /* Meta-Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */ + { ISFUNC, (Function *)0x0 }, /* Meta-! */ + { ISFUNC, (Function *)0x0 }, /* Meta-" */ + { ISFUNC, (Function *)0x0 }, /* 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, (Function *)0x0 }, /* Meta-+ */ + { ISFUNC, (Function *)0x0 }, /* Meta-, */ + { ISFUNC, rl_digit_argument }, /* Meta-- */ + { ISFUNC, rl_yank_last_arg}, /* Meta-. */ + { ISFUNC, (Function *)0x0 }, /* Meta-/ */ + + /* Regular digits. */ + { ISFUNC, rl_digit_argument }, /* Meta-0 */ + { ISFUNC, rl_digit_argument }, /* Meta-1 */ + { ISFUNC, rl_digit_argument }, /* Meta-2 */ + { ISFUNC, rl_digit_argument }, /* Meta-3 */ + { ISFUNC, rl_digit_argument }, /* Meta-4 */ + { ISFUNC, rl_digit_argument }, /* Meta-5 */ + { ISFUNC, rl_digit_argument }, /* Meta-6 */ + { ISFUNC, rl_digit_argument }, /* Meta-7 */ + { ISFUNC, rl_digit_argument }, /* Meta-8 */ + { ISFUNC, rl_digit_argument }, /* Meta-9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-: */ + { ISFUNC, (Function *)0x0 }, /* Meta-; */ + { ISFUNC, rl_beginning_of_history }, /* Meta-< */ + { ISFUNC, (Function *)0x0 }, /* Meta-= */ + { ISFUNC, rl_end_of_history }, /* Meta-> */ + { ISFUNC, rl_possible_completions }, /* Meta-? */ + { ISFUNC, (Function *)0x0 }, /* Meta-@ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-A */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-B */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-C */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-D */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-E */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-F */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-G */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-H */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-I */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-J */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-K */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-L */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-M */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-N */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-O */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-P */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-R */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-S */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-T */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-U */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-V */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-W */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-X */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-[ */ /* was rl_arrow_keys */ + { ISFUNC, rl_delete_horizontal_space }, /* Meta-\ */ + { ISFUNC, (Function *)0x0 }, /* Meta-] */ + { ISFUNC, (Function *)0x0 }, /* Meta-^ */ + { ISFUNC, rl_yank_last_arg }, /* Meta-_ */ + { ISFUNC, (Function *)0x0 }, /* Meta-` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* Meta-a */ + { ISFUNC, rl_backward_word }, /* Meta-b */ + { ISFUNC, rl_capitalize_word }, /* Meta-c */ + { ISFUNC, rl_kill_word }, /* Meta-d */ + { ISFUNC, (Function *)0x0 }, /* Meta-e */ + { ISFUNC, rl_forward_word }, /* Meta-f */ + { ISFUNC, (Function *)0x0 }, /* Meta-g */ + { ISFUNC, (Function *)0x0 }, /* Meta-h */ + { ISFUNC, (Function *)0x0 }, /* Meta-i */ + { ISFUNC, (Function *)0x0 }, /* Meta-j */ + { ISFUNC, (Function *)0x0 }, /* Meta-k */ + { ISFUNC, rl_downcase_word }, /* Meta-l */ + { ISFUNC, (Function *)0x0 }, /* Meta-m */ + { ISFUNC, rl_noninc_forward_search }, /* Meta-n */ + { ISFUNC, (Function *)0x0 }, /* Meta-o */ /* was rl_arrow_keys */ + { ISFUNC, rl_noninc_reverse_search }, /* Meta-p */ + { ISFUNC, (Function *)0x0 }, /* Meta-q */ + { ISFUNC, rl_revert_line }, /* Meta-r */ + { ISFUNC, (Function *)0x0 }, /* Meta-s */ + { ISFUNC, rl_transpose_words }, /* Meta-t */ + { ISFUNC, rl_upcase_word }, /* Meta-u */ + { ISFUNC, (Function *)0x0 }, /* Meta-v */ + { ISFUNC, (Function *)0x0 }, /* Meta-w */ + { ISFUNC, (Function *)0x0 }, /* Meta-x */ + { ISFUNC, rl_yank_pop }, /* Meta-y */ + { ISFUNC, (Function *)0x0 }, /* Meta-z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-{ */ + { ISFUNC, (Function *)0x0 }, /* Meta-| */ + { ISFUNC, (Function *)0x0 }, /* Meta-} */ + { ISFUNC, rl_tilde_expand }, /* Meta-~ */ + { ISFUNC, rl_backward_kill_word }, /* Meta-rubout */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; + +KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = { + + /* Control keys. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, (Function *)0x0 }, /* Control-d */ + { ISFUNC, (Function *)0x0 }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, (Function *)0x0 }, /* Control-h */ + { ISFUNC, (Function *)0x0 }, /* Control-i */ + { ISFUNC, (Function *)0x0 }, /* Control-j */ + { ISFUNC, (Function *)0x0 }, /* Control-k */ + { ISFUNC, (Function *)0x0 }, /* Control-l */ + { ISFUNC, (Function *)0x0 }, /* Control-m */ + { ISFUNC, (Function *)0x0 }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, (Function *)0x0 }, /* Control-p */ + { ISFUNC, (Function *)0x0 }, /* Control-q */ + { ISFUNC, rl_re_read_init_file }, /* Control-r */ + { ISFUNC, (Function *)0x0 }, /* Control-s */ + { ISFUNC, (Function *)0x0 }, /* Control-t */ + { ISFUNC, rl_undo_command }, /* Control-u */ + { ISFUNC, (Function *)0x0 }, /* Control-v */ + { ISFUNC, (Function *)0x0 }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, (Function *)0x0 }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + { ISFUNC, (Function *)0x0 }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, (Function *)0x0 }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, (Function *)0x0 }, /* # */ + { ISFUNC, (Function *)0x0 }, /* $ */ + { ISFUNC, (Function *)0x0 }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, rl_start_kbd_macro }, /* ( */ + { ISFUNC, rl_end_kbd_macro }, /* ) */ + { ISFUNC, (Function *)0x0 }, /* * */ + { ISFUNC, (Function *)0x0 }, /* + */ + { ISFUNC, (Function *)0x0 }, /* , */ + { ISFUNC, (Function *)0x0 }, /* - */ + { ISFUNC, (Function *)0x0 }, /* . */ + { ISFUNC, (Function *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, (Function *)0x0 }, /* 0 */ + { ISFUNC, (Function *)0x0 }, /* 1 */ + { ISFUNC, (Function *)0x0 }, /* 2 */ + { ISFUNC, (Function *)0x0 }, /* 3 */ + { ISFUNC, (Function *)0x0 }, /* 4 */ + { ISFUNC, (Function *)0x0 }, /* 5 */ + { ISFUNC, (Function *)0x0 }, /* 6 */ + { ISFUNC, (Function *)0x0 }, /* 7 */ + { ISFUNC, (Function *)0x0 }, /* 8 */ + { ISFUNC, (Function *)0x0 }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, (Function *)0x0 }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, (Function *)0x0 }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* [ */ + { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, (Function *)0x0 }, /* ^ */ + { ISFUNC, (Function *)0x0 }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* a */ + { ISFUNC, (Function *)0x0 }, /* b */ + { ISFUNC, (Function *)0x0 }, /* c */ + { ISFUNC, (Function *)0x0 }, /* d */ + { ISFUNC, rl_call_last_kbd_macro }, /* e */ + { ISFUNC, (Function *)0x0 }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, (Function *)0x0 }, /* h */ + { ISFUNC, (Function *)0x0 }, /* i */ + { ISFUNC, (Function *)0x0 }, /* j */ + { ISFUNC, (Function *)0x0 }, /* k */ + { ISFUNC, (Function *)0x0 }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, (Function *)0x0 }, /* n */ + { ISFUNC, (Function *)0x0 }, /* o */ + { ISFUNC, (Function *)0x0 }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, (Function *)0x0 }, /* r */ + { ISFUNC, (Function *)0x0 }, /* s */ + { ISFUNC, (Function *)0x0 }, /* t */ + { ISFUNC, (Function *)0x0 }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, (Function *)0x0 }, /* w */ + { ISFUNC, (Function *)0x0 }, /* x */ + { ISFUNC, (Function *)0x0 }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, (Function *)0x0 }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, (Function *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_line }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; diff --git a/lib/readline/examples/Inputrc b/lib/readline/examples/Inputrc new file mode 100644 index 0000000..5b71bd7 --- /dev/null +++ b/lib/readline/examples/Inputrc @@ -0,0 +1,65 @@ +# My ~/.inputrc file is in -*- text -*- for easy editing with Emacs. +# +# Notice the various bindings which are conditionalized depending +# on which program is running, or what terminal is active. +# + +# In all programs, all terminals, make sure this is bound. +"\C-x\C-r": re-read-init-file + +# Hp terminals (and some others) have ugly default behaviour for C-h. +"\C-h": backward-delete-char +"\e\C-h": backward-kill-word +"\C-xd": dump-functions + +# In xterm windows, make the arrow keys do the right thing. +$if TERM=xterm +"\e[A": previous-history +"\e[B": next-history +"\e[C": forward-char +"\e[D": backward-char + +# alternate arrow key prefix +"\eOA": previous-history +"\eOB": next-history +"\eOC": forward-char +"\eOD": backward-char + +# Under Xterm in Bash, we bind local Function keys to do something useful. +$if Bash +"\e[11~": "Function Key 1" +"\e[12~": "Function Key 2" +"\e[13~": "Function Key 3" +"\e[14~": "Function Key 4" +"\e[15~": "Function Key 5" + +# I know the following escape sequence numbers are 1 greater than +# the function key. Don't ask me why, I didn't design the xterm terminal. +"\e[17~": "Function Key 6" +"\e[18~": "Function Key 7" +"\e[19~": "Function Key 8" +"\e[20~": "Function Key 9" +"\e[21~": "Function Key 10" +$endif +$endif + +# For Bash, all terminals, add some Bash specific hacks. +$if Bash +"\C-xv": show-bash-version +"\C-x\C-e": shell-expand-line + +# Here is one for editing my path. +"\C-xp": "$PATH\C-x\C-e\C-e\"\C-aPATH=\":\C-b" + +# Make C-x r read my mail in emacs. +# "\C-xr": "emacs -f rmail\C-j" +$endif + +# For FTP, different hacks: +$if Ftp +"\C-xg": "get \M-?" +"\C-xt": "put \M-?" +"\M-.": yank-last-arg +$endif + +" ": self-insert diff --git a/lib/readline/examples/Makefile b/lib/readline/examples/Makefile new file mode 100644 index 0000000..3d1fc52 --- /dev/null +++ b/lib/readline/examples/Makefile @@ -0,0 +1,12 @@ +# This is the Makefile for the examples subdirectory of readline. -*- text -*- +# + +EXECUTABLES = fileman +CFLAGS = -g -I../.. +LDFLAGS = -g -L.. + +fileman: fileman.o + $(CC) $(LDFLAGS) -o fileman fileman.o -lreadline -ltermcap + +fileman.o: fileman.c + diff --git a/lib/readline/examples/fileman.c b/lib/readline/examples/fileman.c new file mode 100644 index 0000000..3ecb9f1 --- /dev/null +++ b/lib/readline/examples/fileman.c @@ -0,0 +1,425 @@ +/* fileman.c -- A tiny application which demonstrates how to use the + GNU Readline library. This application interactively allows users + to manipulate files and their modes. */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/errno.h> + +#include <readline/readline.h> +#include <readline/history.h> + +extern char *getwd (); +extern char *xmalloc (); + +/* The names of functions that actually do the manipulation. */ +int com_list (), com_view (), com_rename (), com_stat (), com_pwd (); +int com_delete (), com_help (), com_cd (), com_quit (); + +/* A structure which contains information on the commands this program + can understand. */ + +typedef struct { + char *name; /* User printable name of the function. */ + Function *func; /* Function to call to do the job. */ + char *doc; /* Documentation for this function. */ +} COMMAND; + +COMMAND commands[] = { + { "cd", com_cd, "Change to directory DIR" }, + { "delete", com_delete, "Delete FILE" }, + { "help", com_help, "Display this text" }, + { "?", com_help, "Synonym for `help'" }, + { "list", com_list, "List files in DIR" }, + { "ls", com_list, "Synonym for `list'" }, + { "pwd", com_pwd, "Print the current working directory" }, + { "quit", com_quit, "Quit using Fileman" }, + { "rename", com_rename, "Rename FILE to NEWNAME" }, + { "stat", com_stat, "Print out statistics on FILE" }, + { "view", com_view, "View the contents of FILE" }, + { (char *)NULL, (Function *)NULL, (char *)NULL } +}; + +/* Forward declarations. */ +char *stripwhite (); +COMMAND *find_command (); + +/* The name of this program, as taken from argv[0]. */ +char *progname; + +/* When non-zero, this global means the user is done using this program. */ +int done; + +char * +dupstr (s) + int s; +{ + char *r; + + r = xmalloc (strlen (s) + 1); + strcpy (r, s); + return (r); +} + +main (argc, argv) + int argc; + char **argv; +{ + char *line, *s; + + progname = argv[0]; + + initialize_readline (); /* Bind our completer. */ + + /* Loop reading and executing lines until the user quits. */ + for ( ; done == 0; ) + { + line = readline ("FileMan: "); + + if (!line) + break; + + /* Remove leading and trailing whitespace from the line. + Then, if there is anything left, add it to the history list + and execute it. */ + s = stripwhite (line); + + if (*s) + { + add_history (s); + execute_line (s); + } + + free (line); + } + exit (0); +} + +/* Execute a command line. */ +int +execute_line (line) + char *line; +{ + register int i; + COMMAND *command; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && whitespace (line[i])) + i++; + word = line + i; + + while (line[i] && !whitespace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + command = find_command (word); + + if (!command) + { + fprintf (stderr, "%s: No such command for FileMan.\n", word); + return (-1); + } + + /* Get argument to command, if any. */ + while (whitespace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + return ((*(command->func)) (word)); +} + +/* Look up NAME as the name of a command, and return a pointer to that + command. Return a NULL pointer if NAME isn't a command name. */ +COMMAND * +find_command (name) + char *name; +{ + register int i; + + for (i = 0; commands[i].name; i++) + if (strcmp (name, commands[i].name) == 0) + return (&commands[i]); + + return ((COMMAND *)NULL); +} + +/* Strip whitespace from the start and end of STRING. Return a pointer + into STRING. */ +char * +stripwhite (string) + char *string; +{ + register char *s, *t; + + for (s = string; whitespace (*s); s++) + ; + + if (*s == 0) + return (s); + + t = s + strlen (s) - 1; + while (t > s && whitespace (*t)) + t--; + *++t = '\0'; + + return s; +} + +/* **************************************************************** */ +/* */ +/* Interface to Readline Completion */ +/* */ +/* **************************************************************** */ + +char *command_generator (); +char **fileman_completion (); + +/* Tell the GNU Readline library how to complete. We want to try to complete + on command names if this is the first word in the line, or on filenames + if not. */ +initialize_readline () +{ + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "FileMan"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (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. */ +char ** +fileman_completion (text, start, end) + char *text; + int start, end; +{ + char **matches; + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + to complete. Otherwise it is the name of a file in the current + directory. */ + if (start == 0) + matches = completion_matches (text, command_generator); + + return (matches); +} + +/* Generator function for command completion. STATE lets us know whether + to start from scratch; without any state (i.e. STATE == 0), then we + start at the top of the list. */ +char * +command_generator (text, state) + char *text; + int state; +{ + static int list_index, len; + char *name; + + /* If this is a new word to complete, initialize now. This includes + saving the length of TEXT for efficiency, and initializing the index + variable to 0. */ + if (!state) + { + list_index = 0; + len = strlen (text); + } + + /* Return the next name which partially matches from the command list. */ + while (name = commands[list_index].name) + { + list_index++; + + if (strncmp (name, text, len) == 0) + return (dupstr(name)); + } + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +} + +/* **************************************************************** */ +/* */ +/* FileMan Commands */ +/* */ +/* **************************************************************** */ + +/* String to pass to system (). This is for the LIST, VIEW and RENAME + commands. */ +static char syscom[1024]; + +/* List the file(s) named in arg. */ +com_list (arg) + char *arg; +{ + if (!arg) + arg = ""; + + sprintf (syscom, "ls -FClg %s", arg); + return (system (syscom)); +} + +com_view (arg) + char *arg; +{ + if (!valid_argument ("view", arg)) + return 1; + + sprintf (syscom, "more %s", arg); + return (system (syscom)); +} + +com_rename (arg) + char *arg; +{ + too_dangerous ("rename"); + return (1); +} + +com_stat (arg) + char *arg; +{ + struct stat finfo; + + if (!valid_argument ("stat", arg)) + return (1); + + if (stat (arg, &finfo) == -1) + { + perror (arg); + return (1); + } + + printf ("Statistics for `%s':\n", arg); + + printf ("%s has %d link%s, and is %d byte%s in length.\n", arg, + finfo.st_nlink, + (finfo.st_nlink == 1) ? "" : "s", + finfo.st_size, + (finfo.st_size == 1) ? "" : "s"); + printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime)); + printf (" Last access at: %s", ctime (&finfo.st_atime)); + printf (" Last modified at: %s", ctime (&finfo.st_mtime)); + return (0); +} + +com_delete (arg) + char *arg; +{ + too_dangerous ("delete"); + return (1); +} + +/* Print out help for ARG, or for all of the commands if ARG is + not present. */ +com_help (arg) + char *arg; +{ + register int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) + { + if (!*arg || (strcmp (arg, commands[i].name) == 0)) + { + printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); + printed++; + } + } + + if (!printed) + { + printf ("No commands match `%s'. Possibilties are:\n", arg); + + for (i = 0; commands[i].name; i++) + { + /* Print in six columns. */ + if (printed == 6) + { + printed = 0; + printf ("\n"); + } + + printf ("%s\t", commands[i].name); + printed++; + } + + if (printed) + printf ("\n"); + } + return (0); +} + +/* Change to the directory ARG. */ +com_cd (arg) + char *arg; +{ + if (chdir (arg) == -1) + { + perror (arg); + return 1; + } + + com_pwd (""); + return (0); +} + +/* Print out the current working directory. */ +com_pwd (ignore) + char *ignore; +{ + char dir[1024], *s; + + s = getwd (dir); + if (s == 0) + { + printf ("Error getting pwd: %s\n", dir); + return 1; + } + + printf ("Current directory is %s\n", dir); + return 0; +} + +/* The user wishes to quit using this program. Just set DONE non-zero. */ +com_quit (arg) + char *arg; +{ + done = 1; + return (0); +} + +/* Function which tells you that you can't do this. */ +too_dangerous (caller) + char *caller; +{ + fprintf (stderr, + "%s: Too dangerous for me to distribute. Write it yourself.\n", + caller); +} + +/* Return non-zero if ARG is a valid argument for CALLER, else print + an error message and return zero. */ +int +valid_argument (caller, arg) + char *caller, *arg; +{ + if (!arg || !*arg) + { + fprintf (stderr, "%s: Argument required.\n", caller); + return (0); + } + + return (1); +} diff --git a/lib/readline/examples/histexamp.c b/lib/readline/examples/histexamp.c new file mode 100644 index 0000000..eceb66d --- /dev/null +++ b/lib/readline/examples/histexamp.c @@ -0,0 +1,82 @@ +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; + + using_history (); + + 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"); + } + } + } +} diff --git a/lib/readline/examples/manexamp.c b/lib/readline/examples/manexamp.c new file mode 100644 index 0000000..3496efa --- /dev/null +++ b/lib/readline/examples/manexamp.c @@ -0,0 +1,94 @@ +/* manexamp.c -- The examples which appear in the documentation are here. */ + +#include <stdio.h> +#include <readline/readline.h> + + +/* **************************************************************** */ +/* */ +* How to Emulate gets () */ +/* */ +/* **************************************************************** */ + +/* A static variable for holding the line. */ +static char *line_read = (char *)NULL; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +rl_gets () +{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read) + { + free (line_read); + line_read = (char *)NULL; + } + + /* Get a line from the user. */ + line_read = readline (""); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +} + +/* **************************************************************** */ +/* */ +/* Writing a Function to be Called by Readline. */ +/* */ +/* **************************************************************** */ + +/* Invert the case of the COUNT following characters. */ +invert_case_line (count, key) + int count, key; +{ + register int start, end; + + start = rl_point; + + if (count < 0) + { + direction = -1; + count = -count; + } + else + direction = 1; + + /* Find the end of the range to modify. */ + end = start + (count * direction); + + /* Force it to be within range. */ + if (end > rl_end) + end = rl_end; + else if (end < 0) + end = -1; + + if (start > end) + { + int temp = start; + start = end; + end = temp; + } + + if (start == end) + return; + + /* Tell readline that we are modifying the line, so save the undo + information. */ + rl_modifying (start, end); + + for (; start != end; start += direction) + { + if (uppercase_p (rl_line_buffer[start])) + rl_line_buffer[start] = to_lower (rl_line_buffer[start]); + else if (lowercase_p (rl_line_buffer[start])) + rl_line_buffer[start] = to_upper (rl_line_buffer[start]); + } + + /* Move point to on top of the last character changed. */ + rl_point = end - direction; +} + diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c new file mode 100644 index 0000000..9255974 --- /dev/null +++ b/lib/readline/funmap.c @@ -0,0 +1,299 @@ +/* funmap.c -- attach names to 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 (STATIC_MALLOC) +static char *xmalloc (), *xrealloc (); +#else +extern char *xmalloc (), *xrealloc (); +#endif /* STATIC_MALLOC */ + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* BUFSIZ */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "rlconf.h" +#include "readline.h" + +static int qsort_string_compare (); + +FUNMAP **funmap = (FUNMAP **)NULL; +static int funmap_size = 0; +static int funmap_entry = 0; + +/* 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 }, + { "backward-char", rl_backward }, + { "backward-delete-char", rl_rubout }, + { "backward-kill-line", rl_backward_kill_line }, + { "backward-kill-word", rl_backward_kill_word }, + { "backward-word", rl_backward_word }, + { "beginning-of-history", rl_beginning_of_history }, + { "beginning-of-line", rl_beg_of_line }, + { "call-last-kbd-macro", rl_call_last_kbd_macro }, + { "capitalize-word", rl_capitalize_word }, + { "clear-screen", rl_clear_screen }, + { "complete", rl_complete }, + { "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 }, + { "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 }, + { "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-completions", rl_insert_completions }, + { "kill-whole-line", rl_kill_full_line }, + { "kill-line", rl_kill_line }, + { "kill-word", rl_kill_word }, + { "next-history", rl_get_next_history }, + { "non-incremental-forward-search-history", rl_noninc_forward_search }, + { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, + { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again }, + { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again }, + { "possible-completions", rl_possible_completions }, + { "previous-history", rl_get_previous_history }, + { "quoted-insert", rl_quoted_insert }, + { "re-read-init-file", rl_re_read_init_file }, + { "redraw-current-line", rl_refresh_line}, + { "reverse-search-history", rl_reverse_search_history }, + { "revert-line", rl_revert_line }, + { "self-insert", rl_insert }, + { "start-kbd-macro", rl_start_kbd_macro }, + { "tab-insert", rl_tab_insert }, + { "tilde-expand", rl_tilde_expand }, + { "transpose-chars", rl_transpose_chars }, + { "transpose-words", rl_transpose_words }, + { "tty-status", rl_tty_status }, + { "undo", rl_undo_command }, + { "universal-argument", rl_universal_argument }, + { "unix-line-discard", rl_unix_line_discard }, + { "unix-word-rubout", rl_unix_word_rubout }, + { "upcase-word", rl_upcase_word }, + { "yank", rl_yank }, + { "yank-last-arg", rl_yank_last_arg }, + { "yank-nth-arg", rl_yank_nth_arg }, + { "yank-pop", rl_yank_pop }, + +#if defined (VI_MODE) + { "vi-append-eol", rl_vi_append_eol }, + { "vi-append-mode", rl_vi_append_mode }, + { "vi-arg-digit", rl_vi_arg_digit }, + { "vi-bWord", rl_vi_bWord }, + { "vi-bracktype", rl_vi_bracktype }, + { "vi-bword", rl_vi_bword }, + { "vi-change-case", rl_vi_change_case }, + { "vi-change-char", rl_vi_change_char }, + { "vi-change-to", rl_vi_change_to }, + { "vi-char-search", rl_vi_char_search }, + { "vi-column", rl_vi_column }, + { "vi-comment", rl_vi_comment }, + { "vi-complete", rl_vi_complete }, + { "vi-delete", rl_vi_delete }, + { "vi-delete-to", rl_vi_delete_to }, + { "vi-eWord", rl_vi_eWord }, + { "vi-editing-mode", rl_vi_editing_mode }, + { "vi-end-word", rl_vi_end_word }, + { "vi-eof-maybe", rl_vi_eof_maybe }, + { "vi-eword", rl_vi_eword }, + { "vi-fWord", rl_vi_fWord }, + { "vi-first-print", rl_vi_first_print }, + { "vi-fword", rl_vi_fword }, + { "vi-insert-beg", rl_vi_insert_beg }, + { "vi-insertion-mode", rl_vi_insertion_mode }, + { "vi-match", rl_vi_match }, + { "vi-movement-mode", rl_vi_movement_mode }, + { "vi-next-word", rl_vi_next_word }, + { "vi-overstrike", rl_vi_overstrike }, + { "vi-overstrike-delete", rl_vi_overstrike_delete }, + { "vi-prev-word", rl_vi_prev_word }, + { "vi-put", rl_vi_put }, + { "vi-redo", rl_vi_redo }, + { "vi-replace", rl_vi_replace }, + { "vi-search", rl_vi_search }, + { "vi-search-again", rl_vi_search_again }, + { "vi-subst", rl_vi_subst }, + { "vi-tilde-expand", rl_vi_tilde_expand }, + { "vi-yank-arg", rl_vi_yank_arg }, + { "vi-yank-to", rl_vi_yank_to }, +#endif /* VI_MODE */ + + {(char *)NULL, (Function *)NULL } +}; + +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[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); + funmap[funmap_entry]->name = name; + funmap[funmap_entry]->function = function; + + funmap[++funmap_entry] = (FUNMAP *)NULL; + return funmap_entry; +} + +static int funmap_initialized = 0; + +/* Make the funmap contain all of the default entries. */ +void +rl_initialize_funmap () +{ + register int i; + + if (funmap_initialized) + return; + + for (i = 0; default_funmap[i].name; i++) + rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); + + funmap_initialized = 1; + funmap_program_specific_entry_start = i; +} + +/* Produce a NULL terminated array of known function names. The array + is sorted. The array itself is allocated, but not the strings inside. + You should free () the array when you done, but not the pointrs. */ +char ** +rl_funmap_names () +{ + char **result = (char **)NULL; + 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++) + { + 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[result_index] = funmap[result_index]->name; + result[result_index + 1] = (char *)NULL; + } + + qsort (result, result_index, sizeof (char *), 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 +}; + +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/history.c b/lib/readline/history.c new file mode 100644 index 0000000..9172755 --- /dev/null +++ b/lib/readline/history.c @@ -0,0 +1,2218 @@ +/* History.c -- standalone 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. */ + +/* 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 + +#include <stdio.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ +#include <errno.h> + +/* 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" + +#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 + +/* **************************************************************** */ +/* */ +/* History Functions */ +/* */ +/* **************************************************************** */ + +/* An array of HIST_ENTRY. This is where we store the history. */ +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; + +/* If HISTORY_STIFLED is non-zero, then this is the maximum number of + entries to remember. */ +int max_input_history; + +/* The current location of the interactive history pointer. Just makes + life easier for outside callers. */ +static int history_offset = 0; + +/* The number of strings currently stored in the input_history list. */ +int history_length = 0; + +/* 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="; + +/* The logical `base' of the history array. It defaults to 1. */ +int history_base = 1; + +/* Return the current HISTORY_STATE of the history. */ +HISTORY_STATE * +history_get_history_state () +{ + HISTORY_STATE *state; + + state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE)); + state->entries = the_history; + state->offset = history_offset; + state->length = history_length; + state->size = history_size; + state->flags = 0; + if (history_stifled) + state->flags |= HS_STIFLED; + + return (state); +} + +/* Set the state of the current history array to STATE. */ +void +history_set_history_state (state) + HISTORY_STATE *state; +{ + the_history = state->entries; + history_offset = state->offset; + history_length = state->length; + history_size = state->size; + if (state->flags & HS_STIFLED) + history_stifled = 1; +} + +/* Begin a session in which the history functions might be used. This + initializes interactive variables. */ +void +using_history () +{ + history_offset = history_length; +} + +/* Return the number of bytes that the primary history entries are using. + This just adds up the lengths of the_history->lines. */ +int +history_total_bytes () +{ + register int i, result; + + result = 0; + + for (i = 0; the_history && the_history[i]; i++) + result += strlen (the_history[i]->line); + + return (result); +} + +/* Place STRING at the end of the history list. The data field + is set to NULL. */ +void +add_history (string) + char *string; +{ + HIST_ENTRY *temp; + + if (history_stifled && (history_length == max_input_history)) + { + register int i; + + /* If the history is stifled, and history_length is zero, + and it equals max_input_history, we don't save items. */ + if (history_length == 0) + return; + + /* If there is something in the slot, then remove it. */ + if (the_history[0]) + { + free (the_history[0]->line); + free (the_history[0]); + } + + /* Copy the rest of the entries, moving down one slot. */ + for (i = 0; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_base++; + + } + else + { + if (!history_size) + { + history_size = DEFAULT_HISTORY_GROW_SIZE; + the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); + history_length = 1; + + } + else + { + if (history_length == (history_size - 1)) + { + history_size += DEFAULT_HISTORY_GROW_SIZE; + the_history = (HIST_ENTRY **) + xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); + } + history_length++; + } + } + + temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + temp->line = savestring (string); + temp->data = (char *)NULL; + + the_history[history_length] = (HIST_ENTRY *)NULL; + the_history[history_length - 1] = temp; +} + +/* Make the history entry at 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. */ +HIST_ENTRY * +replace_history_entry (which, line, data) + int which; + char *line; + char *data; +{ + HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + HIST_ENTRY *old_value; + + if (which >= history_length) + return ((HIST_ENTRY *)NULL); + + old_value = the_history[which]; + + temp->line = savestring (line); + temp->data = data; + the_history[which] = temp; + + 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. */ +HIST_ENTRY * +remove_history (which) + int which; +{ + HIST_ENTRY *return_value; + + if (which >= history_length || !history_length) + return_value = (HIST_ENTRY *)NULL; + else + { + register int i; + return_value = the_history[which]; + + for (i = which; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_length--; + } + + return (return_value); +} + +/* Stifle the history list, remembering only MAX number of lines. */ +void +stifle_history (max) + int max; +{ + if (max < 0) + max = 0; + + if (history_length > max) + { + register int i, j; + + /* This loses because we cannot free the data. */ + for (i = 0; i < (history_length - max); i++) + { + free (the_history[i]->line); + free (the_history[i]); + } + + history_base = i; + for (j = 0, i = history_length - max; j < max; i++, j++) + the_history[j] = the_history[i]; + the_history[j] = (HIST_ENTRY *)NULL; + history_length = j; + } + + history_stifled = 1; + 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. */ +int +unstifle_history () +{ + int result = max_input_history; + + if (history_stifled) + { + result = -result; + history_stifled = 0; + } + + return (result); +} + +int +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; +{ + 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) + { + if (output) + 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). */ + { + 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]); +} + +/* 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 new file mode 100644 index 0000000..6935efd --- /dev/null +++ b/lib/readline/history.h @@ -0,0 +1,181 @@ +/* History.h -- the names of functions that you can call in history. */ + +/* The structure used to store a history entry. */ +typedef struct _hist_entry { + char *line; + char *data; +} HIST_ENTRY; + +/* 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; + +/* Flag values for the `flags' member of HISTORY_STATE. */ +#define HS_STIFLED 0x01 + +/* Initialization and state management. */ + +/* Begin a session in which the history functions might be used. This + just initializes the interactive variables. */ +extern void using_history (); + +/* Return the current HISTORY_STATE of the history. */ +extern HISTORY_STATE *history_get_history_state (); + +/* Set the state of the current history array to STATE. */ +extern void history_set_history_state (); + +/* Manage the history list. */ + +/* Place STRING at the end of the history list. + The associated data field (if any) is set to NULL. */ +extern void add_history (); + +/* A reasonably useless function, only here for completeness. WHICH + is the magic number that tells us which element to delete. The + elements are numbered from 0. */ +extern HIST_ENTRY *remove_history (); + +/* Make the history entry at 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. */ +extern HIST_ENTRY *replace_history_entry (); + +/* Stifle the history list, remembering only MAX number of entries. */ +extern void stifle_history (); + +/* 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. */ +extern int unstifle_history (); + +/* Return 1 if the history is stifled, 0 if it is not. */ +extern int history_is_stifled (); + +/* Information about the 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. */ +extern HIST_ENTRY **history_list (); + +/* Returns the number which says what history element we are now + looking at. */ +extern int where_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 the history entry which is logically at OFFSET in the history + array. OFFSET is relative to history_base. */ +extern HIST_ENTRY *history_get (); + +/* Return the number of bytes that the primary history entries are using. + This just adds up the lengths of the_history->lines. */ +extern int history_total_bytes (); + +/* Moving around the history list. */ + +/* Set the position in the history list to POS. */ +int history_set_pos (); + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry, return + a NULL pointer. */ +extern HIST_ENTRY *previous_history (); + +/* Move history_offset forward to the next item in the input_history, + and return the a pointer to that entry. If there is no next entry, + return a NULL pointer. */ +extern HIST_ENTRY *next_history (); + +/* Searching the history list. */ + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, + else through subsequent. 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. */ +extern int history_search (); + +/* Search the history for STRING, starting at history_offset. + The search is anchored: matching lines must begin with string. */ +extern int history_search_prefix (); + +/* Search for STRING in the history list, starting at POS, an + absolute index into the list. DIR, if negative, says to search + backwards from POS, else forwards. + Returns the absolute index of the history element where STRING + was found, or -1 otherwise. */ +extern int history_search_pos (); + +/* Managing the history file. */ + +/* 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. */ +extern int read_history (); + +/* 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. */ +extern int read_history_range (); + +/* Write the current history to FILENAME. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history (). */ +extern int write_history (); + +/* 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 (); + +/* Truncate the history file, leaving only the last NLINES lines. */ +extern int history_truncate_file (); + +/* History expansion. */ + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. 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 just be printed. + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ +extern int history_expand (); + +/* Extract a string segment consisting of the FIRST through LAST + arguments present in STRING. Arguments are broken up as in + the shell. */ +extern char *history_arg_extract (); + +/* Return the text of the history event beginning at the current + offset into STRING. */ +extern char *get_history_event (); + +/* Return an array of tokens, much as the shell might. The tokens are + parsed out of STRING. */ +extern char **history_tokenize (); + +/* Exported history variables. */ +extern int history_base; +extern int history_length; +extern int max_input_history; +extern char history_expansion_char; +extern char history_subst_char; +extern char history_comment_char; +extern char *history_no_expand_chars; diff --git a/lib/readline/isearch.c b/lib/readline/isearch.c new file mode 100644 index 0000000..1a0193f --- /dev/null +++ b/lib/readline/isearch.c @@ -0,0 +1,378 @@ +/* **************************************************************** */ +/* */ +/* I-Search and Searching */ +/* */ +/* **************************************************************** */ + +/* Copyright (C) 1987,1989 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. */ +#define READLINE_LIBRARY + +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include "memalloc.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; +extern int rl_line_buffer_len; +extern int rl_point, rl_end; +extern char *rl_line_buffer; + +extern char *xmalloc (), *xrealloc (); + +static int rl_search_history (); + +/* Last line found by the current incremental search, so we don't `find' + identical lines many times in a row. */ +static char *prev_line_found; + +/* Search backwards through the history looking for a string which is typed + interactively. Start with the current line. */ +rl_reverse_search_history (sign, key) + int sign; + int 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. */ +rl_forward_search_history (sign, key) + int sign; + int key; +{ + return (rl_search_history (sign, key)); +} + +/* Display the current state of the search in the echo-area. + SEARCH_STRING contains the string that is being searched for, + DIRECTION is zero for forward, or 1 for reverse, + WHERE is the history list number of the current line. If it is + -1, then this line is the starting one. */ +static void +rl_display_search (search_string, reverse_p, where) + char *search_string; + int reverse_p, where; +{ + char *message; + + message = xmalloc (1 + (search_string ? strlen (search_string) : 0) + 30); + *message = '\0'; + +#if defined (NOTDEF) + if (where != -1) + sprintf (message, "[%d]", where + history_base); +#endif /* NOTDEF */ + + strcat (message, "("); + + if (reverse_p) + strcat (message, "reverse-"); + + strcat (message, "i-search)`"); + + if (search_string) + strcat (message, search_string); + + strcat (message, "': "); + rl_message ("%s", message, 0); + free (message); + rl_redisplay (); +} + +/* Search through the history looking for an interactively typed string. + This is analogous to i-search. We start the search in the current line. + DIRECTION is which direction to search; >= 0 means forward, < 0 means + backwards. */ +static int +rl_search_history (direction, invoking_key) + int direction; + int invoking_key; +{ + /* The string that the user types in to search for. */ + char *search_string; + + /* The current length of SEARCH_STRING. */ + int search_string_index; + + /* The amount of space that SEARCH_STRING has allocated to it. */ + int search_string_size; + + /* The list of lines to search through. */ + char **lines, *allocated_line = (char *)NULL; + + /* The length of LINES. */ + int hlen; + + /* Where we get LINES from. */ + HIST_ENTRY **hlist = history_list (); + + 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; + + /* The line currently being searched. */ + char *sline; + + /* Offset in that line. */ + int line_index; + + /* Non-zero if we are doing a reverse search. */ + int reverse = (direction < 0); + + /* Create an arrary of pointers to the lines that we want to search. */ + maybe_replace_line (); + if (hlist) + for (i = 0; hlist[i]; i++); + + /* Allocate space for this many lines, +1 for the current input line, + and remember those lines. */ + lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); + for (i = 0; i < hlen; i++) + lines[i] = hlist[i]->line; + + if (saved_line_for_history) + lines[i] = saved_line_for_history->line; + else + { + /* Keep track of this so we can free it. */ + allocated_line = xmalloc (1 + strlen (rl_line_buffer)); + strcpy (allocated_line, &rl_line_buffer[0]); + lines[i] = allocated_line; + } + + hlen++; + + /* The line where we start the search. */ + i = orig_line; + + /* Initialize search parameters. */ + search_string = xmalloc (search_string_size = 128); + *search_string = '\0'; + search_string_index = 0; + prev_line_found = (char *)0; /* XXX */ + + /* Normalize DIRECTION into 1 or -1. */ + direction = (direction >= 0) ? 1 : -1; + + rl_display_search (search_string, reverse, -1); + + sline = rl_line_buffer; + sline_len = strlen (sline); + line_index = rl_point; + + found = failed = 0; + while (!done) + { + 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; + + if (f == rl_reverse_search_history) + c = reverse ? -1 : -2; + else if (f == rl_forward_search_history) + c = !reverse ? -1 : -2; + } + + switch (c) + { + case ESC: + done = 1; + continue; + + case -1: + if (!search_string_index) + continue; + else + { + if (reverse) + --line_index; + else + { + if (line_index != sline_len) + ++line_index; + else + ding (); + } + } + break; + + /* switch directions */ + case -2: + direction = -direction; + 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_clear_message (); + free (allocated_line); + free (lines); + return 0; + + default: + if (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) + { + 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; + } + } + + found = failed = 0; + while (1) + { + 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; + } + else + line_index += direction; + } + if (found) + break; + + /* Move to the next line, but skip new copies of the line + we just found and lines shorter than the string we're + searching for. */ + do + { + /* Move to the next line. */ + i += direction; + + /* At limit for direction? */ + if (reverse ? (i < 0) : (i == hlen)) + { + failed++; + break; + } + + /* We will need these later. */ + sline = lines[i]; + sline_len = strlen (sline); + } + while ((prev_line_found && STREQ (prev_line_found, lines[i])) || + (search_string_index > sline_len)); + + if (failed) + break; + + /* Now set up the line for searching... */ + if (reverse) + line_index = sline_len - search_string_index; + else + line_index = 0; + } + + if (failed) + { + /* We cannot find the search string. Ding the bell. */ + ding (); + i = last_found_line; + continue; /* XXX - was break */ + } + + /* We have found the search string. Just display it. But don't + actually move there in the history list until the user accepts + the location. */ + if (found) + { + int line_len; + + prev_line_found = lines[i]; + line_len = strlen (lines[i]); + + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + + strcpy (rl_line_buffer, lines[i]); + rl_point = line_index; + rl_end = line_len; + last_found_line = i; + rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); + } + } + + /* The searching is over. The user may have found the string that she + was looking for, or else she may have exited a failing search. If + LINE_INDEX is -1, then that shows that the string searched for was + not found. We use this to determine where to place rl_point. */ + + /* First put back the original state. */ + strcpy (rl_line_buffer, lines[orig_line]); + + /* Free the search string. */ + free (search_string); + + if (last_found_line < orig_line) + rl_get_previous_history (orig_line - last_found_line); + else + rl_get_next_history (last_found_line - orig_line); + + /* If the string was not found, put point at the end of the line. */ + if (line_index < 0) + line_index = strlen (rl_line_buffer); + rl_point = line_index; + rl_clear_message (); + + free (allocated_line); + free (lines); + + return 0; +} diff --git a/lib/readline/keymaps.c b/lib/readline/keymaps.c new file mode 100644 index 0000000..e1be552 --- /dev/null +++ b/lib/readline/keymaps.c @@ -0,0 +1,200 @@ +/* keymaps.c -- Functions and keymaps for the GNU Readline library. */ + +/* Copyright (C) 1988,1989 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. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "rlconf.h" +#include "keymaps.h" +#include "emacs_keymap.c" + +#if defined (VI_MODE) +#include "vi_keymap.c" +#endif + +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 */ + +/* **************************************************************** */ +/* */ +/* Functions for manipulating Keymaps. */ +/* */ +/* **************************************************************** */ + + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap +rl_make_bare_keymap () +{ + register int i; + Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY)); + + for (i = 0; i < KEYMAP_SIZE; i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = (Function *)NULL; + } + + for (i = 'A'; i < ('Z' + 1); i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = rl_do_lowercase_version; + } + + return (keymap); +} + +/* Return a new keymap which is a copy of MAP. */ +Keymap +rl_copy_keymap (map) + Keymap map; +{ + register int i; + Keymap temp = rl_make_bare_keymap (); + + for (i = 0; i < KEYMAP_SIZE; i++) + { + temp[i].type = map[i].type; + temp[i].function = map[i].function; + } + return (temp); +} + +/* Return a new keymap with the printing characters bound to rl_insert, + the uppercase Meta characters bound to run their lowercase equivalents, + and the Meta digits bound to produce numeric arguments. */ +Keymap +rl_make_keymap () +{ + register int i; + Keymap newmap; + + newmap = rl_make_bare_keymap (); + + /* All ASCII printing characters are self-inserting. */ + for (i = ' '; i < 127; i++) + newmap[i].function = rl_insert; + + newmap[TAB].function = rl_insert; + newmap[RUBOUT].function = rl_rubout; + newmap[CTRL('H')].function = rl_rubout; + +#if KEYMAP_SIZE > 128 + /* Printing characters in some 8-bit character sets. */ + for (i = 128; i < 160; i++) + newmap[i].function = rl_insert; + + /* ISO Latin-1 printing characters should self-insert. */ + for (i = 160; i < 256; i++) + newmap[i].function = rl_insert; +#endif /* KEYMAP_SIZE > 128 */ + + return (newmap); +} + +/* Free the storage associated with MAP. */ +void +rl_discard_keymap (map) + Keymap (map); +{ + int i; + + if (!map) + return; + + for (i = 0; i < KEYMAP_SIZE; i++) + { + switch (map[i].type) + { + case ISFUNC: + break; + + case ISKMAP: + rl_discard_keymap ((Keymap)map[i].function); + break; + + case ISMACR: + free ((char *)map[i].function); + break; + } + } +} + +#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 new file mode 100644 index 0000000..f0eda3d --- /dev/null +++ b/lib/readline/keymaps.h @@ -0,0 +1,95 @@ +/* keymaps.h -- Manipulation of readline keymaps. */ + +/* 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. */ + +#ifndef _KEYMAPS_H_ +#define _KEYMAPS_H_ + +#if defined (READLINE_LIBRARY) +# include "chardefs.h" +#else +# include <readline/chardefs.h> +#endif + +#if !defined (__FUNCTION_DEF) +# define __FUNCTION_DEF +typedef int Function (); +typedef void VFunction (); +typedef char *CPFunction (); +typedef char **CPPFunction (); +#endif + +/* A keymap contains one entry for each key in the ASCII set. + Each entry consists of a type and a pointer. + POINTER is the address of a function to run, or the + address of a keymap to indirect through. + TYPE says which kind of thing POINTER is. */ +typedef struct _keymap_entry { + char type; + Function *function; +} KEYMAP_ENTRY; + +/* This must be large enough to hold bindings for all of the characters + in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x, + and so on). */ +#define KEYMAP_SIZE 256 + +/* I wanted to make the above structure contain a union of: + union { Function *function; struct _keymap_entry *keymap; } value; + but this made it impossible for me to create a static array. + Maybe I need C lessons. */ + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; +typedef KEYMAP_ENTRY *Keymap; + +/* The values that TYPE can have in a keymap entry. */ +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; +extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +extern Keymap rl_make_bare_keymap (); + +/* Return a new keymap which is a copy of MAP. */ +extern Keymap rl_copy_keymap (); + +/* Return a new keymap with the printing characters bound to rl_insert, + the lowercase Meta characters bound to run their equivalents, and + the Meta digits bound to produce numeric arguments. */ +extern Keymap rl_make_keymap (); + +extern void rl_discard_keymap (); + +/* Return the keymap corresponding to a given name. Names look like + `emacs' or `emacs-meta' or `vi-insert'. */ +extern Keymap rl_get_keymap_by_name (); + +/* Return the current keymap. */ +extern Keymap rl_get_keymap (); + +/* Set the current keymap to MAP. */ +extern void rl_set_keymap (); + +#endif /* _KEYMAPS_H_ */ diff --git a/lib/readline/memalloc.h b/lib/readline/memalloc.h new file mode 100644 index 0000000..750d53d --- /dev/null +++ b/lib/readline/memalloc.h @@ -0,0 +1,56 @@ +/* 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 <malloc.h> +# else /* !IBMESA */ +# include <alloca.h> +# endif /* !IBMESA */ +# else +extern char *alloca (); +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/lib/readline/parens.c b/lib/readline/parens.c new file mode 100644 index 0000000..57a9777 --- /dev/null +++ b/lib/readline/parens.c @@ -0,0 +1,130 @@ +/* parens.c -- Implemenation of matching parenthesis feature. */ + +/* 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 + +#include "rlconf.h" + +#if !defined (PAREN_MATCHING) + +rl_insert_close (count, invoking_key) + int count, invoking_key; +{ + return (rl_insert (count, invoking_key)); +} + +#else /* PAREN_MATCHING */ + +#include <stdio.h> +#include <sys/types.h> +#if defined (FD_SET) +# include <sys/time.h> +#endif /* FD_SET */ +#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) +int rl_blink_matching_paren = 1; +#else /* !FD_SET */ +int rl_blink_matching_paren = 0; +#endif /* !FD_SET */ + +static int find_matching_open (); + +rl_insert_close (count, invoking_key) + int count, invoking_key; +{ + if (rl_explicit_arg || !rl_blink_matching_paren) + rl_insert (count, invoking_key); + else + { +#if defined (FD_SET) + int orig_point, match_point, ready; + struct timeval timer; + fd_set readfds; + + rl_insert (1, invoking_key); + rl_redisplay (); + match_point = + find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); + + /* Emacs might message or ring the bell here, but I don't. */ + if (match_point < 0) + return -1; + + FD_ZERO (&readfds); + FD_SET (fileno (rl_instream), &readfds); + timer.tv_sec = 1; + timer.tv_usec = 500; + + orig_point = rl_point; + rl_point = match_point; + rl_redisplay (); + ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); + rl_point = orig_point; +#else /* !FD_SET */ + rl_insert (count, invoking_key); +#endif /* !FD_SET */ + } + return 0; +} + +static int +find_matching_open (string, from, closer) + char *string; + int from, closer; +{ + register int i; + int opener, level, delimiter; + + switch (closer) + { + case ']': opener = '['; break; + case '}': opener = '{'; break; + case ')': opener = '('; break; + default: + return (-1); + } + + level = 1; /* The closer passed in counts as 1. */ + delimiter = 0; /* Delimited state unknown. */ + + for (i = from; i > -1; i--) + { + if (delimiter && (string[i] == delimiter)) + delimiter = 0; + else if ((string[i] == '\'') || (string[i] == '"')) + delimiter = rl_line_buffer[i]; + else if (!delimiter && (string[i] == closer)) + level++; + else if (!delimiter && (string[i] == opener)) + level--; + + if (!level) + break; + } + return (i); +} + +#endif /* PAREN_MATCHING */ diff --git a/lib/readline/posixstat.h b/lib/readline/posixstat.h new file mode 100644 index 0000000..7d1cece --- /dev/null +++ b/lib/readline/posixstat.h @@ -0,0 +1,149 @@ +/* posixstat.h -- Posix stat(2) definitions for systems that + don't have them. */ + +/* 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 <sys/stat.h>. + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include <sys/stat.h> + +#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) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */ + +/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but + do not provide the S_IS* macros that Posix requires. */ + +#if defined (_S_IFMT) && !defined (S_IFMT) +#define S_IFMT _S_IFMT +#endif +#if defined (_S_IFIFO) && !defined (S_IFIFO) +#define S_IFIFO _S_IFIFO +#endif +#if defined (_S_IFCHR) && !defined (S_IFCHR) +#define S_IFCHR _S_IFCHR +#endif +#if defined (_S_IFDIR) && !defined (S_IFDIR) +#define S_IFDIR _S_IFDIR +#endif +#if defined (_S_IFBLK) && !defined (S_IFBLK) +#define S_IFBLK _S_IFBLK +#endif +#if defined (_S_IFREG) && !defined (S_IFREG) +#define S_IFREG _S_IFREG +#endif +#if defined (_S_IFLNK) && !defined (S_IFLNK) +#define S_IFLNK _S_IFLNK +#endif +#if defined (_S_IFSOCK) && !defined (S_IFSOCK) +#define S_IFSOCK _S_IFSOCK +#endif + +/* Test for each symbol individually and define the ones necessary (some + systems claiming Posix compatibility define some but not all). */ + +#if defined (S_IFBLK) && !defined (S_ISBLK) +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */ +#endif + +#if defined (S_IFCHR) && !defined (S_ISCHR) +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */ +#endif + +#if defined (S_IFDIR) && !defined (S_ISDIR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */ +#endif + +#if defined (S_IFREG) && !defined (S_ISREG) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */ +#endif + +#if defined (S_IFIFO) && !defined (S_ISFIFO) +#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */ +#endif + +#if defined (S_IFLNK) && !defined (S_ISLNK) +#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */ +#endif + +#if defined (S_IFSOCK) && !defined (S_ISSOCK) +#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */ +#endif + +/* + * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes + */ + +#if !defined (S_IRWXU) +# if !defined (S_IREAD) +# define S_IREAD 00400 +# define S_IWRITE 00200 +# define S_IEXEC 00100 +# endif /* S_IREAD */ + +# if !defined (S_IRUSR) +# define S_IRUSR S_IREAD /* read, owner */ +# define S_IWUSR S_IWRITE /* write, owner */ +# define S_IXUSR S_IEXEC /* execute, owner */ + +# define S_IRGRP (S_IREAD >> 3) /* read, group */ +# define S_IWGRP (S_IWRITE >> 3) /* write, group */ +# define S_IXGRP (S_IEXEC >> 3) /* execute, group */ + +# define S_IROTH (S_IREAD >> 6) /* read, other */ +# define S_IWOTH (S_IWRITE >> 6) /* write, other */ +# define S_IXOTH (S_IEXEC >> 6) /* execute, other */ +# endif /* !S_IRUSR */ + +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif /* !S_IRWXU */ + +/* These are non-standard, but are used in builtins.c$symbolic_umask() */ +#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) +#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) + +#endif /* _POSIXSTAT_H */ diff --git a/lib/readline/readline.c b/lib/readline/readline.c new file mode 100644 index 0000000..6040cbb --- /dev/null +++ b/lib/readline/readline.c @@ -0,0 +1,3539 @@ +/* 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 + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#if !defined (NO_SYS_FILE) +# include <sys/file.h> +#endif /* !NO_SYS_FILE */ +#include <signal.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <errno.h> +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include <setjmp.h> + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) || (defined (VSTATUS) && !defined (SunOS4)) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL || VSTATUS */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +/* 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 (); +extern void rl_prep_terminal (), rl_deprep_terminal (); + +extern void _rl_bind_if_unbound (); + +/* External redisplay functions and variables from display.c */ +extern void _rl_move_vert (); +extern void _rl_update_final (); + +extern void _rl_erase_at_end_of_line (); +extern void _rl_move_cursor_relative (); + +extern int _rl_vis_botlin; +extern int _rl_last_c_pos; +extern int _rl_horizontal_scroll_mode; +extern int rl_display_fixed; +extern char *rl_display_prompt; + +/* Variables imported from complete.c. */ +extern char *rl_completer_word_break_characters; +extern char *rl_basic_word_break_characters; +extern int rl_completion_query_items; +extern int rl_complete_with_tilde_expansion; + +#if defined (VI_MODE) +extern void _rl_vi_set_last (); +extern void _rl_vi_reset_last (); +extern void _rl_vi_done_inserting (); +#endif /* VI_MODE */ + +/* Forward declarations used in this file. */ +void _rl_free_history_entry (); + +int _rl_dispatch (); +void _rl_set_screen_size (); +int _rl_output_character_function (); + +static char *readline_internal (); +static void readline_initialize_everything (); +static int init_terminal_io (); +static void start_using_history (); +static void bind_arrow_keys (); + +#if !defined (__GO32__) +static void readline_default_bindings (); +#endif /* !__GO32__ */ + +#if defined (__GO32__) +# include <sys/pc.h> +# 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"; + +/* A pointer to the keymap that is currently in use. + By default, it is the standard emacs keymap. */ +Keymap _rl_keymap = emacs_standard_keymap; + +/* The current style of editing. */ +int rl_editing_mode = emacs_mode; + +/* Non-zero if the previous command was a kill command. */ +static int last_command_was_kill = 0; + +/* The current value of the numeric argument specified by the user. */ +int rl_numeric_arg = 1; + +/* Non-zero if an argument was typed. */ +int rl_explicit_arg = 0; + +/* Temporary value used while generating the argument. */ +int rl_arg_sign = 1; + +/* Non-zero means we have been called at least once before. */ +static int rl_initialized = 0; + +/* If non-zero, this program is running in an EMACS buffer. */ +static int running_in_emacs = 0; + +/* The current offset in the current input line. */ +int rl_point; + +/* Mark in the current input line. */ +int rl_mark; + +/* Length of the current input line. */ +int rl_end; + +/* Make this non-zero to return the current input_line. */ +int rl_done; + +/* The last function executed by readline. */ +Function *rl_last_func = (Function *)NULL; + +/* Top level environment for readline_internal (). */ +static jmp_buf readline_top_level; + +/* The streams we interact with. */ +static FILE *in_stream, *out_stream; + +/* The names of the streams that we do input and output to. */ +FILE *rl_instream = (FILE *)NULL; +FILE *rl_outstream = (FILE *)NULL; + +/* Non-zero means echo characters as they are read. */ +int readline_echoing_p = 1; + +/* Current prompt. */ +char *rl_prompt; +int rl_visible_prompt_length = 0; + +/* The number of characters read in order to type this complete command. */ +int rl_key_sequence_length = 0; + +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +Function *rl_startup_hook = (Function *)NULL; + +/* What we use internally. You should always refer to RL_LINE_BUFFER. */ +static char *the_line; + +/* The character that can generate an EOF. Really read from + the terminal driver... just defaulted here. */ +int _rl_eof_char = CTRL ('D'); + +/* Non-zero makes this the next keystroke to read. */ +int rl_pending_input = 0; + +/* Pointer to a useful terminal name. */ +char *rl_terminal_name = (char *)NULL; + +/* Non-zero means to always use horizontal scrolling in line display. */ +int _rl_horizontal_scroll_mode = 0; + +/* Non-zero means to display an asterisk at the starts of history lines + which have been modified. */ +int _rl_mark_modified_lines = 0; + +/* The style of `bell' notification preferred. This can be set to NO_BELL, + AUDIBLE_BELL, or VISIBLE_BELL. */ +int _rl_bell_preference = AUDIBLE_BELL; + +/* 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 */ +/* */ +/* **************************************************************** */ + +/* Non-zero means do not parse any lines other than comments and + 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. */ +int _rl_convert_meta_chars_to_ascii = 1; + +/* Non-zero means to output characters with the meta bit set directly + 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 */ +/* */ +/* **************************************************************** */ + +/* 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 + none. A return value of NULL means that EOF was encountered. */ +char * +readline (prompt) + char *prompt; +{ + char *value; + + rl_prompt = prompt; + + /* If we are at EOF return a NULL string. */ + if (rl_pending_input == EOF) + { + rl_pending_input = 0; + return ((char *)NULL); + } + + rl_visible_prompt_length = rl_expand_prompt (rl_prompt); + + rl_initialize (); + rl_prep_terminal (_rl_meta_flag); + +#if defined (HANDLE_SIGNALS) + rl_set_signals (); +#endif + + value = readline_internal (); + rl_deprep_terminal (); + +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + + 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; + + lastc = -1; + eof_found = 0; + + if (rl_startup_hook) + (*rl_startup_hook) (); + + if (!readline_echoing_p) + { + if (rl_prompt) + { + fprintf (out_stream, "%s", rl_prompt); + fflush (out_stream); + } + } + else + { + rl_on_new_line (); + rl_redisplay (); +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_vi_insertion_mode (); +#endif /* VI_MODE */ + } + + while (!rl_done) + { + int lk = last_command_was_kill; + int code; + + code = setjmp (readline_top_level); + + if (code) + rl_redisplay (); + + if (!rl_pending_input) + { + /* Then initialize the argument and number of keys read. */ + rl_init_argument (); + rl_key_sequence_length = 0; + } + + c = rl_read_key (); + + /* EOF typed to a non-blank line is a <NL>. */ + if (c == EOF && rl_end) + c = NEWLINE; + + /* The character _rl_eof_char typed to blank line, and not as the + previous character is interpreted as EOF. */ + if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) + { + eof_found = 1; + break; + } + + lastc = c; + _rl_dispatch (c, _rl_keymap); + + /* If there was no change in 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 defined (VI_MODE) + /* In vi mode, when you exit insert mode, the cursor moves back + over the previous character. We explicitly check for that here. */ + if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) + 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]; + +/* 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; + } + 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)); +} + +/* 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 (push_index == pop_index) + return (0); + + *key = ibuffer[pop_index++]; + + if (pop_index >= ibuffer_len) + pop_index = 0; + + return (1); +} + +/* Stuff KEY into the *front* of the input buffer. + Returns non-zero if successful, zero if there is + no space left in the buffer. */ +int +rl_unget_char (key) + int key; +{ + if (ibuffer_space ()) + { + pop_index--; + if (pop_index < 0) + pop_index = ibuffer_len - 1; + ibuffer[pop_index] = key; + return (1); + } + return (0); +} + +/* If a character is available to be read, then read it + and stuff it into IBUFFER. Otherwise, just return. */ +void +rl_gather_tyi () +{ +#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); + + 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__ */ +} + +static int next_macro_key (); +/* 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 = 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); +} + +/* 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. */ +int +_rl_dispatch (key, map) + register int key; + Keymap map; +{ + int r = 0; + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type == ISKMAP) + { + if (defining_kbd_macro) + add_macro_char (ESC); + map = FUNCTION_TO_KEYMAP (map, ESC); + key = UNMETA (key); + rl_key_sequence_length += 2; + return (_rl_dispatch (key, map)); + } + else + ding (); + return 0; + } + + if (defining_kbd_macro) + add_macro_char (key); + + 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; + } + } + 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 (); + return -1; + } + break; + + case ISMACR: + if (map[key].function != (Function *)NULL) + { + char *macro; + + macro = savestring ((char *)map[key].function); + 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_set_last (key, rl_numeric_arg, rl_arg_sign); +#endif + return (r); +} + + +/* **************************************************************** */ +/* */ +/* Hacking Keyboard Macros */ +/* */ +/* **************************************************************** */ + +/* 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; + +/* The offset in the above string to the next character to be read. */ +static int executing_macro_index = 0; + +/* 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 = 0; + +/* The index at which characters are being added to current_macro. */ +static int current_macro_index = 0; + +/* 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. */ +struct saved_macro *macro_list = (struct saved_macro *)NULL; + +/* Forward declarations of static functions. Thank you C. */ +static void push_executing_macro (), pop_executing_macro (); + +/* This one has to be declared earlier in the file. */ +/* static void add_macro_char (); */ + +/* Set up to read subsequent input from STRING. + STRING is free ()'ed when we are done with it. */ +static void +with_macro_input (string) + char *string; +{ + push_executing_macro (); + executing_macro = string; + executing_macro_index = 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); + + if (!executing_macro[executing_macro_index]) + { + pop_executing_macro (); + return (next_macro_key ()); + } + + return (executing_macro[executing_macro_index++]); +} + +/* Save the currently executing macro on a stack of saved macros. */ +static void +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 = executing_macro; + + macro_list = saver; +} + +/* 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); + + executing_macro = (char *)NULL; + executing_macro_index = 0; + + if (macro_list) + { + struct saved_macro *disposer = macro_list; + executing_macro = macro_list->string; + executing_macro_index = macro_list->sindex; + macro_list = macro_list->next; + free (disposer); + } +} + +/* 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 (); + + /* Try to bind a common arrow key prefix, if not already bound. */ + bind_arrow_keys (); + + /* 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) + rl_completer_word_break_characters = rl_basic_word_break_characters; +} + +/* If this system allows us to look at the values of the regular + input editing characters, then bind them to their readline + equivalents, iff the characters are not bound to keymaps. */ +static void +readline_default_bindings () +{ + rltty_set_default_bindings (_rl_keymap); +} + +static void +bind_arrow_keys_internal () +{ + Function *f; + + f = rl_function_of_keyseq ("\033[A", _rl_keymap, (int *)NULL); + if (!f || f == rl_do_lowercase_version) + { + _rl_bind_if_unbound ("\033[A", rl_get_previous_history); + _rl_bind_if_unbound ("\033[B", rl_get_next_history); + _rl_bind_if_unbound ("\033[C", rl_forward); + _rl_bind_if_unbound ("\033[D", rl_backward); + } + + f = rl_function_of_keyseq ("\033OA", _rl_keymap, (int *)NULL); + if (!f || f == rl_do_lowercase_version) + { + _rl_bind_if_unbound ("\033OA", rl_get_previous_history); + _rl_bind_if_unbound ("\033OB", rl_get_next_history); + _rl_bind_if_unbound ("\033OC", rl_forward); + _rl_bind_if_unbound ("\033OD", rl_backward); + } +} + +/* Try and bind the common arrow key prefix after giving termcap and + the inputrc file a chance to bind them and create `real' keymaps + for the arrow key prefix. */ +static void +bind_arrow_keys () +{ + Keymap xkeymap; + + xkeymap = _rl_keymap; + + _rl_keymap = emacs_standard_keymap; + bind_arrow_keys_internal (); + +#if defined (VI_MODE) + _rl_keymap = vi_movement_keymap; + bind_arrow_keys_internal (); +#endif + + _rl_keymap = xkeymap; +} + + +/* **************************************************************** */ +/* */ +/* Numeric Arguments */ +/* */ +/* **************************************************************** */ + +/* Handle C-u style numeric args, as well as M--, and M-digits. */ +static int +rl_digit_loop () +{ + int key, c; + + while (1) + { + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); + key = c = rl_read_key (); + + if (_rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + rl_numeric_arg *= 4; + continue; + } + c = UNMETA (c); + if (digit_p (c)) + { + if (rl_explicit_arg) + rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); + else + rl_numeric_arg = (c - '0'); + rl_explicit_arg = 1; + } + else + { + if (c == '-' && !rl_explicit_arg) + { + rl_numeric_arg = 1; + rl_arg_sign = -1; + } + else + { + rl_clear_message (); + return (_rl_dispatch (key, _rl_keymap)); + } + } + } + return 0; +} + +/* Add the current digit to the argument in progress. */ +rl_digit_argument (ignore, key) + int ignore, key; +{ + rl_pending_input = key; + return (rl_digit_loop ()); +} + +/* What to do when you abort reading an argument. */ +rl_discard_argument () +{ + ding (); + rl_clear_message (); + rl_init_argument (); + return 0; +} + +/* Create a default argument. */ +rl_init_argument () +{ + rl_numeric_arg = rl_arg_sign = 1; + rl_explicit_arg = 0; + return 0; +} + +/* 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 () +{ + rl_numeric_arg *= 4; + return (rl_digit_loop ()); +} + +/* **************************************************************** */ +/* */ +/* Terminal and Termcap */ +/* */ +/* **************************************************************** */ + +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; + +/* The key sequences output by the arrow keys, if this terminal has any. */ +char *term_ku, *term_kd, *term_kr, *term_kl; + +/* How to initialize and reset the arrow keys, if this terminal has any. */ +char *term_ks, *term_ke; + +/* 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; +} + +/* 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; +{ +#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) + { + char *sw; + + if (!ignore_env && (sw = getenv ("COLUMNS"))) + screenwidth = atoi (sw); + + if (screenwidth <= 0 && term_string_buffer) + screenwidth = tgetnum ("co"); + } + + /* Environment variable LINES overrides setting of "li" if IGNORE_ENV + is unset. */ + if (screenheight <= 0) + { + char *sh; + + if (!ignore_env && (sh = getenv ("LINES"))) + screenheight = atoi (sh); + + 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 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 + + if (!term_xn) + 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, + "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; +} + +static int +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 = term_xn = 0; + return; +#else /* !__GO32__ */ + + char *term, *buffer; + int tty; + Keymap xkeymap; + + term = terminal_name ? terminal_name : getenv ("TERM"); + + if (!term_string_buffer) + term_string_buffer = xmalloc (2048); + + if (!term_buffer) + term_buffer = xmalloc (2048); + + buffer = term_string_buffer; + + term_clrpag = term_cr = term_clreol = (char *)NULL; + + if (!term) + 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"; + + if (rl_instream) + tty = fileno (rl_instream); + else + tty = 0; + + screenwidth = screenheight = 0; + + term_xn = tgetflag ("am") && tgetflag ("xn"); + + _rl_set_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 = (char *)NULL; + 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); + +#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 */ + + _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, 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); + else +#endif /* !__GO32__ */ + for (i = 0; i < count; i++) + putc ('\b', out_stream); + return 0; +} + +/* 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; +{ +#if defined (TIOCSTAT) + ioctl (1, TIOCSTAT, (char *)0); + rl_refresh_line (); +#else + ding (); +#endif + return 0; +} + + +/* **************************************************************** */ +/* */ +/* 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 allow_pathname_alphabetic_chars = 0; +char *pathname_alphabetic_chars = "/-_=~.#$"; + +int +alphabetic (c) + int c; +{ + if (pure_alphabetic (c) || (digit_p (c))) + return (1); + + if (allow_pathname_alphabetic_chars) + return (strchr (pathname_alphabetic_chars, c) != NULL); + else + 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); +} + +/* How to abort things. */ +rl_abort (count, key) + int count, key; +{ + ding (); + rl_clear_message (); + rl_init_argument (); + rl_pending_input = 0; + + 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); +} + +/* Perhaps put back the current line if it has changed. */ +maybe_replace_line () +{ + HIST_ENTRY *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; +} + +/* Put back the saved_line_for_history if there is one. */ +maybe_unsave_line () +{ + if (saved_line_for_history) + { + int line_len; + + 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; +} + +/* Save the current line in saved_line_for_history. */ +maybe_save_line () +{ + if (!saved_line_for_history) + { + 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; +} + +/* **************************************************************** */ +/* */ +/* History Commands */ +/* */ +/* **************************************************************** */ + +/* Meta-< goes to the start of the history. */ +rl_beginning_of_history (count, key) + int count, key; +{ + return (rl_get_previous_history (1 + where_history ())); +} + +/* Meta-> goes to the end of the history. (The current line). */ +rl_end_of_history (count, key) + int count, key; +{ + maybe_replace_line (); + using_history (); + maybe_unsave_line (); + return 0; +} + +/* Move down to the next history line. */ +rl_get_next_history (count, key) + int count, key; +{ + HIST_ENTRY *temp = (HIST_ENTRY *)NULL; + + if (count < 0) + return (rl_get_previous_history (-count)); + + if (!count) + return 0; + + maybe_replace_line (); + + while (count) + { + temp = next_history (); + if (!temp) + break; + --count; + } + + if (!temp) + maybe_unsave_line (); + else + { + 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 = strlen (the_line); +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_point = 0; +#endif /* VI_MODE */ + } + 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) + 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 (); + + /* If the current line has changed, save the changes. */ + maybe_replace_line (); + + while (count) + { + temp = previous_history (); + if (!temp) + break; + else + 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) + ding (); + else + { + 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 */ + } + return 0; +} + +/* Make C be the next command to be executed. */ +rl_execute_next (c) + int c; +{ + rl_pending_input = c; + return 0; +} + +/* **************************************************************** */ +/* */ +/* The Mark and the Region. */ +/* */ +/* **************************************************************** */ + +/* Set the mark at POSITION. */ +rl_set_mark (position) + int position; +{ + if (position > rl_end) + return -1; + + rl_mark = position; + return 0; +} + +/* 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; + + if (rl_mark == -1) + { + ding (); + return -1; + } + else + { + int temp = rl_point; + + rl_point = rl_mark; + rl_mark = temp; + } + return 0; +} + + +/* **************************************************************** */ +/* */ +/* 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. */ +int rl_max_kills = DEFAULT_MAX_KILLS; + +/* Where to store killed text. */ +char **rl_kill_ring = (char **)NULL; + +/* Where we are in the kill ring. */ +int rl_kill_index = 0; + +/* How many slots we have in the kill ring. */ +int rl_kill_ring_length = 0; + +/* How to say that you only want to save a certain amount + of kill material. */ +rl_set_retained_kills (num) + int num; +{ + 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. */ +rl_kill_text (from, to) + int from, to; +{ + int slot; + char *text; + + /* Is there anything to kill? */ + if (from == to) + { + last_command_was_kill++; + return 0; + } + + text = rl_copy_text (from, to); + + /* Delete the copied text from the line. */ + rl_delete_text (from, to); + + /* First, find the slot to work with. */ + if (!last_command_was_kill) + { + /* 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 + { + /* 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 (last_command_was_kill && rl_editing_mode != vi_mode) + { + char *old = rl_kill_ring[slot]; + char *new = xmalloc (1 + strlen (old) + strlen (text)); + + if (from < to) + { + 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; + 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. */ +rl_kill_word (count, key) + int count, key; +{ + int orig_point = rl_point; + + if (count < 0) + return (rl_backward_kill_word (-count)); + else + { + rl_forward_word (count); + + 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. */ +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; +} + +/* 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; + + 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; +} + +/* 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; + + 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; +} + +/* 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); + 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; + } + + 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) + 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; + + 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)); +} + +/* 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_emacs_editing_mode (count, key) + int count, key; +{ + rl_editing_mode = emacs_mode; + _rl_keymap = emacs_standard_keymap; + return 0; +} + + +/* **************************************************************** */ +/* */ +/* USG (System V) Support */ +/* */ +/* **************************************************************** */ + +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); + +#if defined (EWOULDBLOCK) + if (errno == EWOULDBLOCK) + { + 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; + } +#endif /* EWOULDBLOCK */ + +#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK) + if (errno == EAGAIN) + { + int flags; + + 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__ */ + } +} + +#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; +{ + return ((char *)strcpy (xmalloc (1 + (int)strlen (s)), (s))); +} +#endif + +/* Function equivalents for the macros defined in chartypes.h. */ +#undef uppercase_p +int +uppercase_p (c) + int c; +{ + return (isupper (c)); +} + +#undef lowercase_p +int +lowercase_p (c) + int c; +{ + return (islower (c)); +} + +#undef pure_alphabetic +int +pure_alphabetic (c) + int c; +{ + return (isupper (c) || islower (c)); +} + +#undef digit_p +int +digit_p (c) + int c; +{ + return (isdigit (c)); +} + +#undef to_lower +int +to_lower (c) + int c; +{ + return (isupper (c) ? tolower (c) : c); +} + +#undef to_upper +int +to_upper (c) + int c; +{ + return (islower (c) ? toupper (c) : c); +} + +#undef digit_value +int +digit_value (c) + int c; +{ + return (isdigit (c) ? c - '0' : c); +} + +#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 */ + + +/* **************************************************************** */ +/* */ +/* Testing Readline */ +/* */ +/* **************************************************************** */ + +#if defined (TEST) + +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); + } +} + +#endif /* TEST */ + + +/* + * Local variables: + * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap" + * end: + */ diff --git a/lib/readline/readline.h b/lib/readline/readline.h new file mode 100644 index 0000000..b397177 --- /dev/null +++ b/lib/readline/readline.h @@ -0,0 +1,289 @@ +/* Readline.h -- the names of functions callable from within readline. */ + +/* 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. */ + +#if !defined (_READLINE_H_) +#define _READLINE_H_ + +#if defined (READLINE_LIBRARY) +# include "keymaps.h" +# include "tilde.h" +#else +# include <readline/keymaps.h> +# include <readline/tilde.h> +#endif + +/* The functions for manipulating the text of the line within readline. +Most of these functions are bound to keys by default. */ +extern int + rl_tilde_expand (), + rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), + rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), + 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_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 (), + rl_complete (), rl_possible_completions (), rl_insert_completions (), + rl_do_lowercase_version (), rl_kill_full_line (), + rl_digit_argument (), rl_universal_argument (), rl_abort (), + 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_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 (); + +/* Not available unless readline is compiled -DPAREN_MATCHING. */ +extern int rl_insert_close (); + +/* These are *both* defined even when VI_MODE is not. */ +extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); + +/* Non incremental history searching. */ +extern int + rl_noninc_forward_search (), rl_noninc_reverse_search (), + rl_noninc_forward_search_again (), rl_noninc_reverse_search_again (); + +/* 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_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_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 (), + rl_vi_change_char (), rl_vi_yank_arg (), rl_vi_search (), + 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 (); + +/* Keyboard macro commands. */ +extern int rl_start_kbd_macro (), rl_end_kbd_macro (); +extern int rl_call_last_kbd_macro (); + +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. */ + +/* 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 { + char *name; + Function *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* **************************************************************** */ +/* */ +/* Well Published Variables */ +/* */ +/* **************************************************************** */ + +/* 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; + +/* The line buffer that is in use. */ +extern char *rl_line_buffer; + +/* The location of point, and end. */ +extern int rl_point, rl_end; + +/* 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; + +/* 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 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; + +/* Pointer to the generator function for completion_matches (). + NULL means to use filename_entry_function (), the default filename + completer. */ +extern Function *rl_completion_entry_function; + +/* If rl_ignore_some_completions_function is non-NULL it is the address + of a function to call after all of the possible matches have been + generated, but before the actual completion is done to the input line. + The function is called with one argument; a NULL terminated array + of (char *). If your function removes any of the elements, they + must be free()'ed. */ +extern Function *rl_ignore_some_completions_function; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +extern 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; + +/* 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. */ +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. */ +extern int rl_filename_completion_desired; + +/* Non-zero means that the results of the matches are to be quoted using + double quotes (or an application-specific quoting mechanism) if the + filename contains any characters in rl_word_break_chars. This is + ALWAYS non-zero on entry, and can only be changed within a completion + entry finder function. */ +extern int rl_filename_quoting_desired; + +/* 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 */ +/* */ +/* **************************************************************** */ + +/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ +extern char *readline (); + +/* 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 (); + +/* 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 (); + +/* Functions in funmap.c */ +extern void rl_list_funmap_names (); +extern void rl_initialize_funmap (); + +/* 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 (); + +/* Definitions available for use by readline clients. */ +#define RL_PROMPT_START_IGNORE '\001' +#define RL_PROMPT_END_IGNORE '\002' + +#if !defined (savestring) +extern char *savestring (); /* XXX backwards compatibility */ +#endif + +#endif /* _READLINE_H_ */ diff --git a/lib/readline/rlconf.h b/lib/readline/rlconf.h new file mode 100644 index 0000000..0035b93 --- /dev/null +++ b/lib/readline/rlconf.h @@ -0,0 +1,57 @@ +/* rlconf.h -- readline configuration definitions */ + +/* Copyright (C) 1994 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 (_RLCONF_H_) +#define _RLCONF_H_ + +/* Define this if you want the vi-mode editing available. */ +#define VI_MODE + +/* Define this to get an indication of file type when listing completions. */ +#define VISIBLE_STATS + +/* If defined, readline shows opening parens and braces when closing + paren or brace entered. */ +/* #define PAREN_MATCHING */ + +/* This definition is needed by readline.c, rltty.c, and signals.c. */ +/* If on, then readline handles signals in a way that doesn't screw. */ +#define HANDLE_SIGNALS + +/* Ugly but working hack for binding prefix meta. */ +#define PREFIX_META_HACK + +/* The final, last-ditch effort file name for an init file. */ +#define DEFAULT_INPUTRC "~/.inputrc" + +/* If defined, expand tabs to spaces. */ +#define DISPLAY_TABS + +/* If defined, use the terminal escape sequence to move the cursor forward + 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 "#" + +#endif /* _RLCONF_H_ */ diff --git a/lib/readline/rldefs.h b/lib/readline/rldefs.h new file mode 100644 index 0000000..683f8b5 --- /dev/null +++ b/lib/readline/rldefs.h @@ -0,0 +1,212 @@ +/* rldefs.h -- an attempt to isolate some of the system-specific defines + for readline. This should be included after any files that define + system-specific constants like _POSIX_VERSION or USG. */ + +/* Copyright (C) 1987,1989 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 (_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 <termcap.h> +#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 +# define TERMIO_TTY_DRIVER +# include <termio.h> +# 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 <termios.h> +# 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 <sgtty.h> +#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 <dirent.h> +# 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 <sys/ndir.h> +# else /* !Xenix (but USG...) */ +# include "ndir.h" +# endif /* !Xenix */ +# else /* !USG */ +# include <sys/dir.h> +# 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 <sys/stream.h> +# endif /* HAVE_SYS_STREAM_H */ +# if defined (HAVE_SYS_PTEM_H) +# include <sys/ptem.h> +# endif /* HAVE_SYS_PTEM_H */ +# if defined (HAVE_SYS_PTE_H) +# include <sys/pte.h> +# endif /* HAVE_SYS_PTE_H */ +#endif /* USG && TIOCGWINSZ && !Linux */ + +/* Posix macro to check file in statbuf for directory-ness. + This requires that <sys/stat.h> be included before this test. */ +#if defined (S_IFDIR) && !defined (S_ISDIR) +# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#endif + +/* 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 <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#if defined (HAVE_VARARGS_H) +# include <varargs.h> +#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 +#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 (emacs_mode) +# define no_mode -1 +# define vi_mode 0 +# define emacs_mode 1 +#endif + +/* If you cast map[key].function to type (Keymap) on a Cray, + the compiler takes the value of map[key].function and + divides it by 4 to convert between pointer types (pointers + to functions and pointers to structs are different sizes). + This is not what is wanted. */ +#if defined (CRAY) +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function) +# define KEYMAP_TO_FUNCTION(data) (Function *)((int)(data)) +#else +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function) +# define KEYMAP_TO_FUNCTION(data) (Function *)(data) +#endif + +#ifndef savestring +extern char *xmalloc (); +#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +/* Possible values for _rl_bell_preference. */ +#define NO_BELL 0 +#define AUDIBLE_BELL 1 +#define VISIBLE_BELL 2 + +/* CONFIGURATION SECTION */ +#include "rlconf.h" + +#endif /* !_RLDEFS_H */ diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c new file mode 100644 index 0000000..02c036d --- /dev/null +++ b/lib/readline/rltty.c @@ -0,0 +1,705 @@ +/* rltty.c -- functions to prepare and restore the terminal for readline's + use. */ + +/* Copyright (C) 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 "config.h" +#endif + +#include <sys/types.h> +#include <signal.h> +#include <errno.h> +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include "rldefs.h" +#include "readline.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +extern int readline_echoing_p; +extern int _rl_eof_char; + +#if defined (__GO32__) +# include <sys/pc.h> +# undef HANDLE_SIGNALS +#endif /* __GO32__ */ + +/* **************************************************************** */ +/* */ +/* Signal Management */ +/* */ +/* **************************************************************** */ + +#if defined (HAVE_POSIX_SIGNALS) +static sigset_t sigint_set, sigint_oset; +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) +static int sigint_oldmask; +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + +static int sigint_blocked = 0; + +/* Cause SIGINT to not be delivered until the corresponding call to + release_sigint(). */ +static void +block_sigint () +{ + if (sigint_blocked) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&sigint_set); + sigemptyset (&sigint_oset); + sigaddset (&sigint_set, SIGINT); + sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + sigint_oldmask = sigblock (sigmask (SIGINT)); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sighold (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + sigint_blocked = 1; +} + +/* Allow SIGINT to be delivered. */ +static void +release_sigint () +{ + if (!sigint_blocked) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL); +#else +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (sigint_oldmask); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sigrelse (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + sigint_blocked = 0; +} + +/* **************************************************************** */ +/* */ +/* 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; + +/* If non-zero, means that this process has called tcflow(fd, TCOOFF) + and output is suspended. */ +#if defined (__ksr1__) +static int ksrflow = 0; +#endif +#if defined (NEW_TTY_DRIVER) + +/* Values for the `flags' field of a struct bsdtty. This tells which + elements of the struct bsdtty have been fetched from the system and + are valid. */ +#define SGTTY_SET 0x01 +#define LFLAG_SET 0x02 +#define TCHARS_SET 0x04 +#define LTCHARS_SET 0x08 + +struct bsdtty { + struct sgttyb sgttyb; /* Basic BSD tty driver information. */ + int lflag; /* Local mode flags, like LPASS8. */ +#if defined (TIOCGETC) + struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ +#endif +#if defined (TIOCGLTC) + struct ltchars ltchars; /* 4.2 BSD editing characters */ +#endif + int flags; /* Bitmap saying which parts of the struct are valid. */ +}; + +#define TIOTYPE struct bsdtty + +static TIOTYPE otio; + +static int +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 + + tiop->flags = tiop->lflag = 0; + + ioctl (tty, TIOCGETP, &(tiop->sgttyb)); + tiop->flags |= SGTTY_SET; + +#if defined (TIOCLGET) + ioctl (tty, TIOCLGET, &(tiop->lflag)); + tiop->flags |= LFLAG_SET; +#endif + +#if defined (TIOCGETC) + ioctl (tty, TIOCGETC, &(tiop->tchars)); + tiop->flags |= TCHARS_SET; +#endif + +#if defined (TIOCGLTC) + ioctl (tty, TIOCGLTC, &(tiop->ltchars)); + tiop->flags |= LTCHARS_SET; +#endif + + return 0; +} + +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + if (tiop->flags & SGTTY_SET) + { + ioctl (tty, TIOCSETN, &(tiop->sgttyb)); + tiop->flags &= ~SGTTY_SET; + } + readline_echoing_p = 1; + +#if defined (TIOCLSET) + if (tiop->flags & LFLAG_SET) + { + ioctl (tty, TIOCLSET, &(tiop->lflag)); + tiop->flags &= ~LFLAG_SET; + } +#endif + +#if defined (TIOCSETC) + if (tiop->flags & TCHARS_SET) + { + ioctl (tty, TIOCSETC, &(tiop->tchars)); + tiop->flags &= ~TCHARS_SET; + } +#endif + +#if defined (TIOCSLTC) + if (tiop->flags & LTCHARS_SET) + { + ioctl (tty, TIOCSLTC, &(tiop->ltchars)); + tiop->flags &= ~LTCHARS_SET; + } +#endif + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, otio, tiop) + int meta_flag; + TIOTYPE otio, *tiop; +{ +#if !defined (__GO32__) + readline_echoing_p = (otio.sgttyb.sg_flags & ECHO); + + /* Copy the original settings to the structure we're going to use for + our settings. */ + tiop->sgttyb = otio.sgttyb; + tiop->lflag = otio.lflag; +#if defined (TIOCGETC) + tiop->tchars = otio.tchars; +#endif +#if defined (TIOCGLTC) + tiop->ltchars = otio.ltchars; +#endif + tiop->flags = otio.flags; + + /* First, the basic settings to put us into character-at-a-time, no-echo + input mode. */ + tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); + tiop->sgttyb.sg_flags |= CBREAK; + + /* If this terminal doesn't care how the 8th bit is used, then we can + use it for the meta-key. If only one of even or odd parity is + specified, then the terminal is using parity, and we cannot. */ +#if !defined (ANYP) +# define ANYP (EVENP | ODDP) +#endif + if (((otio.sgttyb.sg_flags & ANYP) == ANYP) || + ((otio.sgttyb.sg_flags & ANYP) == 0)) + { + tiop->sgttyb.sg_flags |= ANYP; + + /* Hack on local mode flags if we can. */ +#if defined (TIOCLGET) +# if defined (LPASS8) + tiop->lflag |= LPASS8; +# endif /* LPASS8 */ +#endif /* TIOCLGET */ + } + +#if defined (TIOCGETC) +# if defined (USE_XON_XOFF) + /* Get rid of terminal output start and stop characters. */ + tiop->tchars.t_stopc = -1; /* C-s */ + tiop->tchars.t_startc = -1; /* C-q */ + + /* If there is an XON character, bind it to restart the output. */ + if (otio.tchars.t_startc != -1) + rl_bind_key (otio.tchars.t_startc, rl_restart_output); +# endif /* USE_XON_XOFF */ + + /* If there is an EOF char, bind _rl_eof_char to it. */ + if (otio.tchars.t_eofc != -1) + _rl_eof_char = otio.tchars.t_eofc; + +# if defined (NO_KILL_INTR) + /* Get rid of terminal-generated SIGQUIT and SIGINT. */ + tiop->tchars.t_quitc = -1; /* C-\ */ + tiop->tchars.t_intrc = -1; /* C-c */ +# endif /* NO_KILL_INTR */ +#endif /* TIOCGETC */ + +#if defined (TIOCGLTC) + /* Make the interrupt keys go away. Just enough to make people happy. */ + tiop->ltchars.t_dsuspc = -1; /* C-y */ + tiop->ltchars.t_lnextc = -1; /* C-v */ +#endif /* TIOCGLTC */ +#endif /* !__GO32__ */ +} + +#else /* !defined (NEW_TTY_DRIVER) */ + +#if !defined (VMIN) +# define VMIN VEOF +#endif + +#if !defined (VTIME) +# define VTIME VEOL +#endif + +#if defined (TERMIOS_TTY_DRIVER) +# 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)) +#else +# define TIOTYPE struct termio +# define DRAIN_OUTPUT(fd) +# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) +# define SETATTR(tty, tiop) (ioctl (tty, TCSETA, tiop)) +#endif /* !TERMIOS_TTY_DRIVER */ + +static TIOTYPE otio; + +#if defined (FLUSHO) +# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) +#else +# define OUTPUT_BEING_FLUSHED(tp) 0 +#endif + +static int +get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + int ioctl_ret; +#if !defined (SHELL) && defined (TIOCGWINSZ) + struct winsize w; + + 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)) + { + if (ioctl_ret < 0 && errno != EINTR) + return -1; + if (OUTPUT_BEING_FLUSHED (tiop)) + continue; + errno = 0; + } + return 0; +} + +static int +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + while (SETATTR (tty, tiop) < 0) + { + if (errno != EINTR) + return -1; + errno = 0; + } + +#if 0 + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (tty, TCOON); + } +# else /* !ksr1 */ + tcflow (tty, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +#else + ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ +#endif /* !TERMIOS_TTY_DRIVER */ + +#endif + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, otio, tiop) + int meta_flag; + TIOTYPE otio, *tiop; +{ + readline_echoing_p = (otio.c_lflag & ECHO); + + tiop->c_lflag &= ~(ICANON | ECHO); + + if ((unsigned char) otio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) + _rl_eof_char = otio.c_cc[VEOF]; + +#if defined (USE_XON_XOFF) +#if defined (IXANY) + tiop->c_iflag &= ~(IXON | IXOFF | IXANY); +#else + /* `strict' Posix systems do not define IXANY. */ + tiop->c_iflag &= ~(IXON | IXOFF); +#endif /* IXANY */ +#endif /* USE_XON_XOFF */ + + /* Only turn this off if we are using all 8 bits. */ + if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) + tiop->c_iflag &= ~(ISTRIP | INPCK); + + /* Make sure we differentiate between CR and NL on input. */ + tiop->c_iflag &= ~(ICRNL | INLCR); + +#if !defined (HANDLE_SIGNALS) + tiop->c_lflag &= ~ISIG; +#else + tiop->c_lflag |= ISIG; +#endif + + tiop->c_cc[VMIN] = 1; + tiop->c_cc[VTIME] = 0; + +#if defined (FLUSHO) + if (OUTPUT_BEING_FLUSHED (tiop)) + { + tiop->c_lflag &= ~FLUSHO; + otio.c_lflag &= ~FLUSHO; + } +#endif + + /* Turn off characters that we need on Posix systems with job control, + just to be sure. This includes ^Y and ^V. This should not really + be necessary. */ +#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) + +#if defined (VLNEXT) + tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; +#endif + +#if defined (VDSUSP) + tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif + +#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ +} +#endif /* NEW_TTY_DRIVER */ + +/* Put the terminal in CBREAK mode so that we can detect key presses. */ +void +rl_prep_terminal (meta_flag) + int meta_flag; +{ +#if !defined (__GO32__) + int tty = fileno (rl_instream); + TIOTYPE tio; + + if (terminal_prepped) + return; + + /* Try to keep this function from being INTerrupted. */ + block_sigint (); + + if (get_tty_settings (tty, &tio) < 0) + { + release_sigint (); + return; + } + + otio = tio; + + prepare_terminal_settings (meta_flag, otio, &tio); + + if (set_tty_settings (tty, &tio) < 0) + { + release_sigint (); + return; + } + + control_meta_key (1); +#if 0 + control_keypad (1); +#endif + fflush (rl_outstream); + terminal_prepped = 1; + + release_sigint (); +#endif /* !__GO32__ */ +} + +/* Restore the terminal's normal settings and modes. */ +void +rl_deprep_terminal () +{ +#if !defined (__GO32__) + int tty = fileno (rl_instream); + + if (!terminal_prepped) + return; + + /* Try to keep this function from being INTerrupted. */ + block_sigint (); + + control_meta_key (0); +#if 0 + control_keypad (0); +#endif + fflush (rl_outstream); + + if (set_tty_settings (tty, &otio) < 0) + { + release_sigint (); + return; + } + + terminal_prepped = 0; + + release_sigint (); +#endif /* !__GO32__ */ +} + +/* **************************************************************** */ +/* */ +/* Bogus Flow Control */ +/* */ +/* **************************************************************** */ + +rl_restart_output (count, key) + int count, key; +{ + int fildes = fileno (rl_outstream); +#if defined (TIOCSTART) +#if defined (apollo) + ioctl (&fildes, TIOCSTART, 0); +#else + ioctl (fildes, TIOCSTART, 0); +#endif /* apollo */ + +#else /* !TIOCSTART */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (fildes, TCOON); + } +# else /* !ksr1 */ + tcflow (fildes, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +# else /* !TERMIOS_TTY_DRIVER */ +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTART */ + + return 0; +} + +rl_stop_output (count, key) + int count, key; +{ + int fildes = fileno (rl_instream); + +#if defined (TIOCSTOP) +# if defined (apollo) + ioctl (&fildes, TIOCSTOP, 0); +# else + ioctl (fildes, TIOCSTOP, 0); +# endif /* apollo */ +#else /* !TIOCSTOP */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + ksrflow = 1; +# endif /* ksr1 */ + tcflow (fildes, TCOOFF); +# else +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTOP */ + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Default Key Bindings */ +/* */ +/* **************************************************************** */ +void +rltty_set_default_bindings (kmap) + Keymap kmap; +{ + TIOTYPE ttybuff; + int tty = fileno (rl_instream); + +#if defined (NEW_TTY_DRIVER) + +#define SET_SPECIAL(sc, func) \ + do \ + { \ + int ic; \ + ic = sc; \ + if (ic != -1 && kmap[ic].type == ISFUNC) \ + kmap[ic].function = func; \ + } \ + while (0) + + if (get_tty_settings (tty, &ttybuff) == 0) + { + if (ttybuff.flags & SGTTY_SET) + { + SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); + SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); + } + +# if defined (TIOCGLTC) + if (ttybuff.flags & LTCHARS_SET) + { + SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); + SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); + } +# endif /* TIOCGLTC */ + } + +#else /* !NEW_TTY_DRIVER */ + +#define SET_SPECIAL(sc, func) \ + do \ + { \ + unsigned char uc; \ + uc = ttybuff.c_cc[sc]; \ + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ + kmap[uc].function = func; \ + } \ + while (0) + + if (get_tty_settings (tty, &ttybuff) == 0) + { + SET_SPECIAL (VERASE, rl_rubout); + SET_SPECIAL (VKILL, rl_unix_line_discard); + +# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VLNEXT, rl_quoted_insert); +# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ + +# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VWERASE, rl_unix_word_rubout); +# endif /* VWERASE && TERMIOS_TTY_DRIVER */ + } +#endif /* !NEW_TTY_DRIVER */ +} diff --git a/lib/readline/search.c b/lib/readline/search.c new file mode 100644 index 0000000..d56e554 --- /dev/null +++ b/lib/readline/search.c @@ -0,0 +1,370 @@ +/* search.c - code for non-incremental searching in emacs and vi modes. */ + +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file is part of 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. */ +#define READLINE_LIBRARY + +#include <sys/types.h> +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#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)) + +#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; +extern HIST_ENTRY *saved_line_for_history; +extern Function *rl_last_func; + +/* Functions imported from the rest of the library. */ +extern int _rl_free_history_entry (); + +static char *noninc_search_string = (char *) NULL; +static int noninc_history_pos = 0; +static char *prev_line_found = (char *) NULL; + +/* Search the history list for STRING starting at absolute history position + POS. If STRING begins with `^', the search must match STRING at the + beginning of a history line, otherwise a full substring match is performed + for STRING. DIR < 0 means to search backwards through the history list, + DIR >= 0 means to search forward. */ +static int +noninc_search_from_pos (string, pos, dir) + char *string; + int pos, dir; +{ + int ret, old; + + old = where_history (); + history_set_pos (pos); + + if (*string == '^') + ret = history_search_prefix (string + 1, dir); + else + ret = history_search (string, dir); + + if (ret != -1) + ret = where_history (); + + history_set_pos (old); + return (ret); +} + +/* Search for a line in the history containing STRING. If DIR is < 0, the + search is backwards through previous entries, else through subsequent + entries. */ +static void +noninc_dosearch (string, dir) + char *string; + int dir; +{ + int oldpos, pos; + HIST_ENTRY *entry; + + if (string == 0 || *string == '\0' || noninc_history_pos < 0) + { + ding (); + return; + } + + pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); + if (pos == -1) + { + /* Search failed, current history position unchanged. */ + maybe_unsave_line (); + rl_clear_message (); + rl_point = 0; + ding (); + return; + } + + noninc_history_pos = pos; + + oldpos = where_history (); + history_set_pos (noninc_history_pos); + entry = current_history (); +#if defined (VI_MODE) + if (rl_editing_mode != vi_mode) +#endif + history_set_pos (oldpos); + + { + 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); + } + + rl_undo_list = (UNDO_LIST *)entry->data; + rl_end = strlen (rl_line_buffer); + rl_point = 0; + rl_clear_message (); + + if (saved_line_for_history) + _rl_free_history_entry (saved_line_for_history); + saved_line_for_history = (HIST_ENTRY *)NULL; +} + +/* Search non-interactively through the history list. DIR < 0 means to + search backwards through the history of previous commands; otherwise + the search is for commands subsequent to the current position in the + history list. PCHAR is the character to use for prompting when reading + the search string; if not specified (0), it defaults to `:'. */ +static void +noninc_search (dir, pchar) + int dir; + int pchar; +{ + int saved_point, c, pmtlen; + char *p; + + maybe_save_line (); + saved_point = rl_point; + + /* Use the line buffer to read the search string. */ + 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'; + + rl_message (p, 0, 0); + free (p); + + /* Read the search string. */ + while (c = rl_read_key ()) + { + switch (c) + { + case CTRL('H'): + case RUBOUT: + if (rl_point == 0) + { + maybe_unsave_line (); + rl_clear_message (); + rl_point = saved_point; + return; + } + rl_rubout (1); + break; + + case CTRL('W'): + rl_unix_word_rubout (1, c); + break; + + case CTRL('U'): + rl_unix_line_discard (1, c); + break; + + case RETURN: + case NEWLINE: + goto dosearch; + /* NOTREACHED */ + break; + + case CTRL('C'): + case CTRL('G'): + maybe_unsave_line (); + rl_clear_message (); + rl_point = saved_point; + ding (); + return; + + default: + rl_insert (1, c); + break; + } + rl_redisplay (); + } + + dosearch: + /* If rl_point == 0, we want to re-use the previous search string and + start from the saved history position. If there's no previous search + string, punt. */ + if (rl_point == 0) + { + if (!noninc_search_string) + { + ding (); + return; + } + } + else + { + /* We want to start the search from the current history position. */ + noninc_history_pos = where_history (); + if (noninc_search_string) + free (noninc_search_string); + noninc_search_string = savestring (rl_line_buffer); + } + + 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 `?'. */ +rl_noninc_forward_search (count, key) + int count, key; +{ + if (key == '?') + noninc_search (1, '?'); + else + noninc_search (1, 0); + return 0; +} + +/* Reverse search the history list for a string. If the vi-mode code + calls this, KEY will be `/'. */ +rl_noninc_reverse_search (count, key) + int count, key; +{ + if (key == '/') + noninc_search (-1, '/'); + else + noninc_search (-1, 0); + return 0; +} + +/* Search forward through the history list for the last string searched + for. If there is no saved search string, abort. */ +rl_noninc_forward_search_again (count, key) + int count, key; +{ + if (!noninc_search_string) + { + ding (); + return (-1); + } + noninc_dosearch (noninc_search_string, 1); + return 0; +} + +/* Reverse search in the history list for the last string searched + for. If there is no saved search string, abort. */ +rl_noninc_reverse_search_again (count, key) + int count, key; +{ + if (!noninc_search_string) + { + ding (); + return (-1); + } + noninc_dosearch (noninc_search_string, -1); + return 0; +} + +static int +rl_history_search_internal (count, direction) + int count, direction; +{ + HIST_ENTRY *temp, *old_temp; + int line_len; + + maybe_save_line (); + + temp = old_temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = (direction < 0) ? previous_history () : next_history (); + if (!temp) + break; + if (STREQN (rl_line_buffer, temp->line, rl_point)) + { + /* Don't find multiple instances of the same line. */ + if (prev_line_found && STREQ (prev_line_found, temp->line)) + continue; + if (direction < 0) + old_temp = temp; + prev_line_found = temp->line; + count--; + } + } + + if (!temp) + { + if (direction < 0 && old_temp) + temp = old_temp; + else + { + maybe_unsave_line (); + ding (); + return 1; + } + } + + line_len = strlen (temp->line); + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + strcpy (rl_line_buffer, temp->line); + rl_undo_list = (UNDO_LIST *)temp->data; + rl_end = line_len; + return 0; +} + +/* Search forward in the history for the string of characters + from the start of the line to rl_point. This is a non-incremental + search. */ +int +rl_history_search_forward (count, ignore) + int count, ignore; +{ + if (count == 0) + return (0); + if (rl_last_func != rl_history_search_forward) + prev_line_found = (char *)NULL; + return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); +} + +/* Search backward through the history for the string of characters + from the start of the line to rl_point. This is a non-incremental + search. */ +int +rl_history_search_backward (count, ignore) + int count, ignore; +{ + if (count == 0) + return (0); + if (rl_last_func != rl_history_search_backward) + prev_line_found = (char *)NULL; + return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); +} diff --git a/lib/readline/signals.c b/lib/readline/signals.c new file mode 100644 index 0000000..e3d93a0 --- /dev/null +++ b/lib/readline/signals.c @@ -0,0 +1,287 @@ +/* signals.c -- signal handling support for readline. */ + +/* 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 + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#if !defined (NO_SYS_FILE) +# include <sys/file.h> +#endif /* !NO_SYS_FILE */ +#include <signal.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <errno.h> +/* 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" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +extern int readline_echoing_p; +extern int rl_pending_input; +extern int _rl_meta_flag; + +extern void free_undo_list (); + +#if defined (VOID_SIGHANDLER) +# define sighandler void +#else +# define sighandler int +#endif /* VOID_SIGHANDLER */ + +/* This typedef is equivalant to the one for Function; it allows us + to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ +typedef sighandler SigHandler (); + +#if defined (__GO32__) +# undef HANDLE_SIGNALS +#endif /* __GO32__ */ + +#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 (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 */ + +#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; +#endif /* !SHELL */ + +/* Handle an interrupt character. */ +static sighandler +rl_signal_handler (sig) + int sig; +{ +#if defined (HAVE_POSIX_SIGNALS) + sigset_t set; +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + long omask; +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + +#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 */ + + switch (sig) + { + case SIGINT: + { + register HIST_ENTRY *entry; + + free_undo_list (); + + entry = current_history (); + if (entry) + entry->data = (char *)NULL; + } + _rl_kill_kbd_macro (); + rl_clear_message (); + rl_init_argument (); + +#if defined (SIGTSTP) + case SIGTSTP: + case SIGTTOU: + case SIGTTIN: +#endif /* SIGTSTP */ + case SIGALRM: + rl_clean_up_for_exit (); + rl_deprep_terminal (); + rl_clear_signals (); + rl_pending_input = 0; + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set); + sigdelset (&set, sig); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + omask = sigblock (0); +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + kill (getpid (), sig); + + /* Let the signal that we just sent through. */ +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (omask & ~(sigmask (sig))); +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + rl_prep_terminal (_rl_meta_flag); + rl_set_signals (); + } + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* !VOID_SIGHANDLER */ +} + +#if defined (HAVE_POSIX_SIGNALS) +static SigHandler * +rl_set_sighandler (sig, handler) + int sig; + SigHandler *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 /* !HAVE_POSIX_SIGNALS */ +# define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler) +#endif /* !HAVE_POSIX_SIGNALS */ + +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); + + old_alrm = (SigHandler *)rl_set_sighandler (SIGALRM, rl_signal_handler); + if (old_alrm == (SigHandler *)SIG_IGN) + rl_set_sighandler (SIGALRM, SIG_IGN); + +#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); +#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); + + if (old_tstp == (SigHandler *)SIG_IGN) + { + rl_set_sighandler (SIGTTOU, SIG_IGN); + rl_set_sighandler (SIGTTIN, SIG_IGN); + } +#endif /* SIGTTOU */ + +#endif /* !SHELL */ + +#if defined (SIGWINCH) + old_sigwinch = + (SigHandler *) rl_set_sighandler (SIGWINCH, rl_handle_sigwinch); +#endif /* SIGWINCH */ + return 0; +} + +rl_clear_signals () +{ + rl_set_sighandler (SIGINT, old_int); + rl_set_sighandler (SIGALRM, old_alrm); + +#if !defined (SHELL) + +#if defined (SIGTSTP) + rl_set_sighandler (SIGTSTP, old_tstp); +#endif + +#if defined (SIGTTOU) + rl_set_sighandler (SIGTTOU, old_ttou); + rl_set_sighandler (SIGTTIN, old_ttin); +#endif /* SIGTTOU */ + +#endif /* !SHELL */ + +#if defined (SIGWINCH) + rl_set_sighandler (SIGWINCH, old_sigwinch); +#endif + + return 0; +} +#endif /* HANDLE_SIGNALS */ diff --git a/lib/readline/tilde.c b/lib/readline/tilde.c new file mode 100644 index 0000000..da75d95 --- /dev/null +++ b/lib/readline/tilde.c @@ -0,0 +1,380 @@ +/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */ + +/* Copyright (C) 1988,1989 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_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "tilde.h" +#include <sys/types.h> +#include <pwd.h> + +#if defined (USG) && !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwuid (), *getpwnam (); +#endif /* USG && !defined (HAVE_GETPW_DECLS) */ + +#if !defined (savestring) +extern char *xmalloc (); +# ifndef strcpy +extern char *strcpy (); +# endif +#define savestring(x) 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 */ + +#if defined (TEST) || defined (STATIC_MALLOC) +static char *xmalloc (), *xrealloc (); +#else +extern char *xmalloc (), *xrealloc (); +#endif /* TEST || STATIC_MALLOC */ + +/* The default value of tilde_additional_prefixes. This is set to + whitespace preceding a tilde so that simple programs which do not + perform any word separation get desired behaviour. */ +static char *default_prefixes[] = + { " ~", "\t~", (char *)NULL }; + +/* The default value of tilde_additional_suffixes. This is set to + whitespace or newline so that simple programs which do not + perform any word separation get desired behaviour. */ +static char *default_suffixes[] = + { " ", "\n", (char *)NULL }; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +char **tilde_additional_prefixes = default_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +char **tilde_additional_suffixes = default_suffixes; + +/* Find the start of a tilde expansion in STRING, and return the index of + the tilde which starts the expansion. Place the length of the text + which identified this tilde starter in LEN, excluding the tilde itself. */ +static int +tilde_find_prefix (string, len) + char *string; + int *len; +{ + register int i, j, string_len; + register char **prefixes = tilde_additional_prefixes; + + string_len = strlen (string); + *len = 0; + + if (!*string || *string == '~') + return (0); + + if (prefixes) + { + for (i = 0; i < string_len; i++) + { + for (j = 0; prefixes[j]; j++) + { + if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0) + { + *len = strlen (prefixes[j]) - 1; + return (i + *len); + } + } + } + } + return (string_len); +} + +/* Find the end of a tilde expansion in STRING, and return the index of + the character which ends the tilde definition. */ +static int +tilde_find_suffix (string) + char *string; +{ + register int i, j, string_len; + register char **suffixes = tilde_additional_suffixes; + + string_len = strlen (string); + + for (i = 0; i < string_len; i++) + { + if (string[i] == '/' || !string[i]) + break; + + for (j = 0; suffixes && suffixes[j]; j++) + { + if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0) + return (i); + } + } + return (i); +} + +/* Return a new string which is the result of tilde expanding STRING. */ +char * +tilde_expand (string) + char *string; +{ + char *result, *tilde_expand_word (); + int result_size, result_index; + + result_size = result_index = 0; + result = (char *)NULL; + + /* Scan through STRING expanding tildes as we come to them. */ + while (1) + { + register int start, end; + char *tilde_word, *expansion; + int len; + + /* Make START point to the tilde which starts the expansion. */ + start = tilde_find_prefix (string, &len); + + /* Copy the skipped text into the result. */ + if ((result_index + start + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); + + strncpy (result + result_index, string, start); + result_index += start; + + /* Advance STRING to the starting tilde. */ + string += start; + + /* Make END be the index of one after the last character of the + username. */ + end = tilde_find_suffix (string); + + /* If both START and END are zero, we are all done. */ + if (!start && !end) + break; + + /* Expand the entire tilde word, and copy it into RESULT. */ + tilde_word = (char *)xmalloc (1 + end); + strncpy (tilde_word, string, end); + tilde_word[end] = '\0'; + string += end; + + expansion = tilde_expand_word (tilde_word); + free (tilde_word); + + len = strlen (expansion); + if ((result_index + len + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); + + strcpy (result + result_index, expansion); + result_index += len; + free (expansion); + } + + result[result_index] = '\0'; + + return (result); +} + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. */ +char * +tilde_expand_word (filename) + char *filename; +{ + char *dirname; + + dirname = filename ? savestring (filename) : (char *)NULL; + + if (dirname && *dirname == '~') + { + char *temp_name; + if (!dirname[1] || dirname[1] == '/') + { + /* Prepend $HOME to the rest of the string. */ + char *temp_home = (char *)getenv ("HOME"); + + /* 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; + } + + 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 + { + char *username; + struct passwd *user_entry; + int i; + + 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)) == 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) + { + 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; + } + } + /* 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); + } + } + return (dirname); +} + + +#if defined (TEST) +#undef NULL +#include <stdio.h> + +main (argc, argv) + int argc; + char **argv; +{ + char *result, line[512]; + int done = 0; + + while (!done) + { + printf ("~expand: "); + fflush (stdout); + + if (!gets (line)) + strcpy (line, "done"); + + if ((strcmp (line, "done") == 0) || + (strcmp (line, "quit") == 0) || + (strcmp (line, "exit") == 0)) + { + done = 1; + break; + } + + result = tilde_expand (line); + printf (" --> %s\n", result); + free (result); + } + exit (0); +} + +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 (); +} + +/* + * Local variables: + * compile-command: "gcc -g -DTEST -o tilde tilde.c" + * end: + */ +#endif /* TEST */ diff --git a/lib/readline/tilde.h b/lib/readline/tilde.h new file mode 100644 index 0000000..726d081 --- /dev/null +++ b/lib/readline/tilde.h @@ -0,0 +1,38 @@ +/* tilde.h: Externally available variables and function in libtilde.a. */ + +#if !defined (__TILDE_H__) +# define __TILDE_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 */ + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern CPFunction *tilde_expansion_failure_hook; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +extern char **tilde_additional_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +extern char **tilde_additional_suffixes; + +/* Return a new string which is the result of tilde expanding STRING. */ +extern char *tilde_expand (); + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. */ +extern char *tilde_expand_word (); + +#endif /* __TILDE_H__ */ diff --git a/lib/readline/vi_keymap.c b/lib/readline/vi_keymap.c new file mode 100644 index 0000000..b8b3123 --- /dev/null +++ b/lib/readline/vi_keymap.c @@ -0,0 +1,877 @@ +/* vi_keymap.c -- the keymap for vi_mode in readline (). */ + +/* 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. */ + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* !BUFSIZ */ + +#include "readline.h" + +#if 0 +extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; +#endif + +/* The keymap arrays for handling vi mode. */ +KEYMAP_ENTRY_ARRAY vi_movement_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, (Function *)0x0 }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + + { ISFUNC, (Function *)0x0 }, /* Control-[ */ /* vi_escape_keymap */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_forward }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, rl_vi_comment }, /* # */ + { ISFUNC, rl_end_of_line }, /* $ */ + { ISFUNC, rl_vi_match }, /* % */ + { ISFUNC, rl_vi_tilde_expand }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, (Function *)0x0 }, /* ( */ + { ISFUNC, (Function *)0x0 }, /* ) */ + { ISFUNC, rl_vi_complete }, /* * */ + { ISFUNC, rl_get_next_history}, /* + */ + { ISFUNC, rl_vi_char_search }, /* , */ + { ISFUNC, rl_get_previous_history }, /* - */ + { ISFUNC, rl_vi_redo }, /* . */ + { ISFUNC, rl_vi_search }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_beg_of_line }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, rl_vi_char_search }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, rl_vi_complete }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, rl_vi_search }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_vi_append_eol }, /* A */ + { ISFUNC, rl_vi_prev_word}, /* B */ + { ISFUNC, rl_vi_change_to }, /* C */ + { ISFUNC, rl_vi_delete_to }, /* D */ + { ISFUNC, rl_vi_end_word }, /* E */ + { ISFUNC, rl_vi_char_search }, /* F */ + { ISFUNC, rl_vi_fetch_history }, /* G */ + { ISFUNC, (Function *)0x0 }, /* H */ + { ISFUNC, rl_vi_insert_beg }, /* I */ + { ISFUNC, (Function *)0x0 }, /* J */ + { ISFUNC, (Function *)0x0 }, /* K */ + { ISFUNC, (Function *)0x0 }, /* L */ + { ISFUNC, (Function *)0x0 }, /* M */ + { ISFUNC, rl_vi_search_again }, /* N */ + { ISFUNC, (Function *)0x0 }, /* O */ + { ISFUNC, rl_vi_put }, /* P */ + { ISFUNC, (Function *)0x0 }, /* Q */ + { ISFUNC, rl_vi_replace }, /* R */ + { ISFUNC, rl_vi_subst }, /* S */ + { ISFUNC, rl_vi_char_search }, /* T */ + { ISFUNC, rl_revert_line }, /* U */ + { ISFUNC, (Function *)0x0 }, /* V */ + { ISFUNC, rl_vi_next_word }, /* W */ + { ISFUNC, rl_rubout }, /* X */ + { ISFUNC, rl_vi_yank_to }, /* Y */ + { ISFUNC, (Function *)0x0 }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* [ */ + { ISFUNC, rl_vi_complete }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, rl_vi_first_print }, /* ^ */ + { ISFUNC, rl_vi_yank_arg }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_vi_append_mode }, /* a */ + { ISFUNC, rl_vi_prev_word }, /* b */ + { ISFUNC, rl_vi_change_to }, /* c */ + { ISFUNC, rl_vi_delete_to }, /* d */ + { ISFUNC, rl_vi_end_word }, /* e */ + { ISFUNC, rl_vi_char_search }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, rl_backward }, /* h */ + { ISFUNC, rl_vi_insertion_mode }, /* i */ + { ISFUNC, rl_get_next_history }, /* j */ + { ISFUNC, rl_get_previous_history }, /* k */ + { ISFUNC, rl_forward }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, rl_vi_search_again }, /* n */ + { ISFUNC, (Function *)0x0 }, /* o */ + { ISFUNC, rl_vi_put }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, rl_vi_change_char }, /* r */ + { ISFUNC, rl_vi_subst }, /* s */ + { ISFUNC, rl_vi_char_search }, /* t */ + { ISFUNC, rl_undo_command }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, rl_vi_next_word }, /* w */ + { ISFUNC, rl_vi_delete }, /* x */ + { ISFUNC, rl_vi_yank_to }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, rl_vi_column }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, rl_vi_change_case }, /* ~ */ + { ISFUNC, (Function *)0x0 }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; + + +KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, rl_insert }, /* Control-a */ + { ISFUNC, rl_insert }, /* Control-b */ + { ISFUNC, rl_insert }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_insert }, /* Control-e */ + { ISFUNC, rl_insert }, /* Control-f */ + { ISFUNC, rl_insert }, /* Control-g */ + { ISFUNC, rl_rubout }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_insert }, /* Control-k */ + { ISFUNC, rl_insert }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_insert }, /* Control-n */ + { ISFUNC, rl_insert }, /* Control-o */ + { ISFUNC, rl_insert }, /* Control-p */ + { ISFUNC, rl_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, rl_insert }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, rl_insert }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, rl_insert }, /* Control-\ */ + { ISFUNC, rl_insert }, /* Control-] */ + { ISFUNC, rl_insert }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ + { ISFUNC, rl_insert }, /* ) */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ + { ISFUNC, rl_insert }, /* ] */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ + { ISFUNC, rl_insert }, /* } */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Pure 8-bit characters (128 - 159). + These might be used in some + character sets. */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + + /* ISO Latin-1 characters (160 - 255) */ + { ISFUNC, rl_insert }, /* No-break space */ + { ISFUNC, rl_insert }, /* Inverted exclamation mark */ + { ISFUNC, rl_insert }, /* Cent sign */ + { ISFUNC, rl_insert }, /* Pound sign */ + { ISFUNC, rl_insert }, /* Currency sign */ + { ISFUNC, rl_insert }, /* Yen sign */ + { ISFUNC, rl_insert }, /* Broken bar */ + { ISFUNC, rl_insert }, /* Section sign */ + { ISFUNC, rl_insert }, /* Diaeresis */ + { ISFUNC, rl_insert }, /* Copyright sign */ + { ISFUNC, rl_insert }, /* Feminine ordinal indicator */ + { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Not sign */ + { ISFUNC, rl_insert }, /* Soft hyphen */ + { ISFUNC, rl_insert }, /* Registered sign */ + { ISFUNC, rl_insert }, /* Macron */ + { ISFUNC, rl_insert }, /* Degree sign */ + { ISFUNC, rl_insert }, /* Plus-minus sign */ + { ISFUNC, rl_insert }, /* Superscript two */ + { ISFUNC, rl_insert }, /* Superscript three */ + { ISFUNC, rl_insert }, /* Acute accent */ + { ISFUNC, rl_insert }, /* Micro sign */ + { ISFUNC, rl_insert }, /* Pilcrow sign */ + { ISFUNC, rl_insert }, /* Middle dot */ + { ISFUNC, rl_insert }, /* Cedilla */ + { ISFUNC, rl_insert }, /* Superscript one */ + { ISFUNC, rl_insert }, /* Masculine ordinal indicator */ + { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */ + { ISFUNC, rl_insert }, /* Vulgar fraction one half */ + { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */ + { ISFUNC, rl_insert }, /* Inverted questionk mark */ + { ISFUNC, rl_insert }, /* Latin capital letter a with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter a with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin capital letter ae */ + { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin capital letter e with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter e with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter i with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter i with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter o with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Multiplication sign */ + { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin capital letter u with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter u with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */ + { ISFUNC, rl_insert }, /* Latin small letter a with grave */ + { ISFUNC, rl_insert }, /* Latin small letter a with acute */ + { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin small letter ae */ + { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin small letter e with grave */ + { ISFUNC, rl_insert }, /* Latin small letter e with acute */ + { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter i with grave */ + { ISFUNC, rl_insert }, /* Latin small letter i with acute */ + { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with grave */ + { ISFUNC, rl_insert }, /* Latin small letter o with acute */ + { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Division sign */ + { ISFUNC, rl_insert }, /* Latin small letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin small letter u with grave */ + { ISFUNC, rl_insert }, /* Latin small letter u with acute */ + { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter y with acute */ + { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */ + { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */ +#endif /* KEYMAP_SIZE > 128 */ +}; + +/* Unused for the time being. */ +#if 0 +KEYMAP_ENTRY_ARRAY vi_escape_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, (Function *)0x0 }, /* Control-d */ + { ISFUNC, (Function *)0x0 }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, (Function *)0x0 }, /* Control-g */ + { ISFUNC, (Function *)0x0 }, /* Control-h */ + { ISFUNC, rl_tab_insert}, /* Control-i */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, (Function *)0x0 }, /* Control-l */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-m */ + { ISFUNC, (Function *)0x0 }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, (Function *)0x0 }, /* Control-p */ + { ISFUNC, (Function *)0x0 }, /* Control-q */ + { ISFUNC, (Function *)0x0 }, /* Control-r */ + { ISFUNC, (Function *)0x0 }, /* Control-s */ + { ISFUNC, (Function *)0x0 }, /* Control-t */ + { ISFUNC, (Function *)0x0 }, /* Control-u */ + { ISFUNC, (Function *)0x0 }, /* Control-v */ + { ISFUNC, (Function *)0x0 }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, (Function *)0x0 }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, (Function *)0x0 }, /* # */ + { ISFUNC, (Function *)0x0 }, /* $ */ + { ISFUNC, (Function *)0x0 }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, (Function *)0x0 }, /* ( */ + { ISFUNC, (Function *)0x0 }, /* ) */ + { ISFUNC, (Function *)0x0 }, /* * */ + { ISFUNC, (Function *)0x0 }, /* + */ + { ISFUNC, (Function *)0x0 }, /* , */ + { ISFUNC, (Function *)0x0 }, /* - */ + { ISFUNC, (Function *)0x0 }, /* . */ + { ISFUNC, (Function *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_vi_arg_digit }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, (Function *)0x0 }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, (Function *)0x0 }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_arrow_keys }, /* [ */ + { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, (Function *)0x0 }, /* ^ */ + { ISFUNC, (Function *)0x0 }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* a */ + { ISFUNC, (Function *)0x0 }, /* b */ + { ISFUNC, (Function *)0x0 }, /* c */ + { ISFUNC, (Function *)0x0 }, /* d */ + { ISFUNC, (Function *)0x0 }, /* e */ + { ISFUNC, (Function *)0x0 }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, (Function *)0x0 }, /* h */ + { ISFUNC, (Function *)0x0 }, /* i */ + { ISFUNC, (Function *)0x0 }, /* j */ + { ISFUNC, (Function *)0x0 }, /* k */ + { ISFUNC, (Function *)0x0 }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, (Function *)0x0 }, /* n */ + { ISFUNC, rl_arrow_keys }, /* o */ + { ISFUNC, (Function *)0x0 }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, (Function *)0x0 }, /* r */ + { ISFUNC, (Function *)0x0 }, /* s */ + { ISFUNC, (Function *)0x0 }, /* t */ + { ISFUNC, (Function *)0x0 }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, (Function *)0x0 }, /* w */ + { ISFUNC, (Function *)0x0 }, /* x */ + { ISFUNC, (Function *)0x0 }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, (Function *)0x0 }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, (Function *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_word }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 }, + { ISFUNC, (Function *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; +#endif diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c new file mode 100644 index 0000000..d0b9310 --- /dev/null +++ b/lib/readline/vi_mode.c @@ -0,0 +1,1329 @@ +/* vi_mode.c -- A vi emulation mode for Bash. + Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ + +/* 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 + +/* **************************************************************** */ +/* */ +/* VI Emulation Mode */ +/* */ +/* **************************************************************** */ +#include "rlconf.h" + +#if defined (VI_MODE) + +#include <sys/types.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <stdio.h> + +/* Some standard library routines. */ +#include "rldefs.h" +#include "readline.h" +#include "history.h" + +#ifndef digit_p +#define digit_p(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef digit_value +#define digit_value(c) ((c) - '0') +#endif + +#ifndef member +#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) +#endif + +#ifndef isident +#define isident(c) ((pure_alphabetic (c) || 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; +extern FILE *rl_instream; +extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg; +extern Keymap _rl_keymap; +extern char *rl_prompt; +extern char *rl_line_buffer; +extern int rl_arg_sign; + +extern void _rl_dispatch (); + +extern void rl_extend_line_buffer (); +extern int rl_vi_check (); + +/* Non-zero means enter insertion mode. */ +static int _rl_vi_doing_insert = 0; + +/* 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; + +/* The number of characters inserted in the last replace operation. */ +static int vi_replace_count = 0; + +/* 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 _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 vi_redoing = 0; + +/* Text modification commands. These are the `redoable' commands. */ +static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; + +static int rl_digit_loop1 (); + +void +_rl_vi_reset_last () +{ + _rl_vi_last_command = 'i'; + _rl_vi_last_repeat = 1; + _rl_vi_last_arg_sign = 1; + _rl_vi_last_motion = 0; +} + +void +_rl_vi_set_last (key, repeat, sign) + int key, repeat, sign; +{ + _rl_vi_last_command = key; + _rl_vi_last_repeat = repeat; + _rl_vi_last_arg_sign = sign; +} + +/* Is the command C a VI mode text modification command? */ +int +rl_vi_textmod_command (c) + int c; +{ + return (member (c, vi_textmod)); +} + +/* 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. */ +rl_vi_redo (count, c) + int count, c; +{ + if (!rl_explicit_arg) + { + rl_numeric_arg = _rl_vi_last_repeat; + rl_arg_sign = _rl_vi_last_arg_sign; + } + + vi_redoing = 1; + _rl_dispatch (_rl_vi_last_command, _rl_keymap); + vi_redoing = 0; + + return (0); +} + +/* Yank the nth arg from the previous line into this line at point. */ +rl_vi_yank_arg (count, key) + int count, key; +{ + /* Readline thinks that the first word on a line is the 0th, while vi + thinks the first word on a line is the 1st. Compensate. */ + if (rl_explicit_arg) + rl_yank_nth_arg (count - 1, 0); + else + rl_yank_nth_arg ('$', 0); + + return (0); +} + +/* With an argument, move back that many history lines, else move to the + beginning of history. */ +rl_vi_fetch_history (count, c) + int count, c; +{ + int current = where_history (); + + /* 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 + `history' command does it -- that is, giving an argument count of 450 + to this command would get the command listed as number 450 in the + output of `history'. */ + if (rl_explicit_arg) + { + int wanted = history_base + current - count; + if (wanted <= 0) + rl_beginning_of_history (0, 0); + else + rl_get_previous_history (wanted); + } + else + rl_beginning_of_history (count, 0); + return (0); +} + +/* Search again for the last thing searched for. */ +rl_vi_search_again (count, key) + int count, key; +{ + switch (key) + { + case 'n': + rl_noninc_reverse_search_again (count, key); + break; + + case 'N': + rl_noninc_forward_search_again (count, key); + break; + } + return (0); +} + +/* Do a vi style search. */ +rl_vi_search (count, key) + int count, key; +{ + switch (key) + { + case '?': + rl_noninc_forward_search (count, key); + break; + + case '/': + rl_noninc_reverse_search (count, key); + break; + + default: + ding (); + break; + } + return (0); +} + +/* Completion, from vi's point of view. */ +rl_vi_complete (ignore, key) + int ignore, key; +{ + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) + { + if (!whitespace (rl_line_buffer[rl_point + 1])) + rl_vi_end_word (1, 'E'); + rl_point++; + } + + if (key == '*') + rl_complete_internal ('*'); /* Expansion and replacement. */ + else if (key == '=') + rl_complete_internal ('?'); /* List possible completions. */ + else if (key == '\\') + rl_complete_internal (TAB); /* Standard Readline completion. */ + else + rl_complete (0, key); + + if (key == '*' || key == '\\') + { + _rl_vi_set_last (key, 1, rl_arg_sign); + rl_vi_insertion_mode (1, key); + } + return (0); +} + +/* Tilde expansion for vi mode. */ +rl_vi_tilde_expand (ignore, key) + int ignore, key; +{ + rl_tilde_expand (0, key); + _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ + rl_vi_insertion_mode (1, key); + return (0); +} + +/* Previous word in vi mode. */ +rl_vi_prev_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_next_word (-count, key)); + + if (rl_point == 0) + { + ding (); + return (0); + } + + if (uppercase_p (key)) + rl_vi_bWord (count); + else + rl_vi_bword (count); + + return (0); +} + +/* Next word in vi mode. */ +rl_vi_next_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_prev_word (-count, key)); + + if (rl_point >= (rl_end - 1)) + { + ding (); + return (0); + } + + if (uppercase_p (key)) + rl_vi_fWord (count); + else + rl_vi_fword (count); + return (0); +} + +/* Move to the end of the ?next? word. */ +rl_vi_end_word (count, key) + int count, key; +{ + if (count < 0) + { + ding (); + return -1; + } + + if (uppercase_p (key)) + rl_vi_eWord (count); + else + rl_vi_eword (count); + return (0); +} + +/* Move forward a word the way that 'W' does. */ +rl_vi_fWord (count) + int count; +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Skip until whitespace. */ + while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + + /* Now skip whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +rl_vi_bWord (count) + int count; +{ + while (count-- && rl_point > 0) + { + /* If we are at the start of a word, move back to whitespace so + we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +rl_vi_eWord (count) + int count; +{ + while (count-- && rl_point < (rl_end - 1)) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move to the next non-whitespace character (to the start of the + next word). */ + while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); + + if (rl_point && rl_point < rl_end) + { + /* Skip whitespace. */ + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Skip until whitespace. */ + while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move back to the last character of the word. */ + rl_point--; + } + } + return (0); +} + +rl_vi_fword (count) + int count; +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Move to white space (really non-identifer). */ + if (isident (rl_line_buffer[rl_point])) + { + while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + else /* if (!whitespace (rl_line_buffer[rl_point])) */ + { + while (!isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + + /* Move past whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +rl_vi_bword (count) + int count; +{ + while (count-- && rl_point > 0) + { + int last_is_ident; + + /* If we are at the start of a word, move back to whitespace + so we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + /* If this character and the previous character are `opposite', move + back so we don't get messed up by the rl_point++ down there in + the while loop. Without this code, words like `l;' screw up the + function. */ + last_is_ident = isident (rl_line_buffer[rl_point - 1]); + if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) || + (!isident (rl_line_buffer[rl_point]) && last_is_ident)) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + if (isident (rl_line_buffer[rl_point])) + while (--rl_point >= 0 && isident (rl_line_buffer[rl_point])); + else + while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +rl_vi_eword (count) + int count; +{ + while (count-- && rl_point < rl_end - 1) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (rl_point < rl_end) + { + if (isident (rl_line_buffer[rl_point])) + while (++rl_point < rl_end && isident (rl_line_buffer[rl_point])); + else + while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point]) + && !whitespace (rl_line_buffer[rl_point])); + } + rl_point--; + } + return (0); +} + +rl_vi_insert_beg (count, key) + int count, key; +{ + rl_beg_of_line (1, key); + rl_vi_insertion_mode (1, key); + return (0); +} + +rl_vi_append_mode (count, key) + int count, key; +{ + if (rl_point < rl_end) + rl_point++; + rl_vi_insertion_mode (1, key); + return (0); +} + +rl_vi_append_eol (count, key) + int count, key; +{ + rl_end_of_line (1, key); + rl_vi_append_mode (1, key); + return (0); +} + +/* What to do in the case of C-d. */ +rl_vi_eof_maybe (count, c) + int count, c; +{ + return (rl_newline (1, '\n')); +} + +/* Insertion mode stuff. */ + +/* Switching from one mode to the other really just involves + switching keymaps. */ +rl_vi_insertion_mode (count, key) + int count, key; +{ + _rl_keymap = vi_insertion_keymap; + return (0); +} + +void +_rl_vi_done_inserting () +{ + if (_rl_vi_doing_insert) + { + 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. */ + _rl_vi_doing_insert = 0; + vi_continued_command = 1; + } + else + vi_continued_command = 0; +} + +rl_vi_movement_mode (count, key) + int count, key; +{ + if (rl_point > 0) + rl_backward (1); + +#if 0 + _rl_vi_reset_last (); +#endif + + _rl_keymap = vi_movement_keymap; + _rl_vi_done_inserting (); + return (0); +} + +rl_vi_arg_digit (count, c) + int count, c; +{ + if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) + return (rl_beg_of_line ()); + else + return (rl_digit_argument (count, c)); +} + +rl_vi_change_case (count, ignore) + int count, ignore; +{ + char c = 0; + + /* Don't try this on an empty line. */ + if (rl_point >= rl_end) + return (0); + + 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]); + else + { + /* Just skip over characters neither upper nor lower case. */ + rl_forward (1); + continue; + } + + /* Vi is kind of strange here. */ + if (c) + { + rl_begin_undo_group (); + rl_delete (1, c); + rl_insert (1, c); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward (1); + } + return (0); +} + +rl_vi_put (count, key) + int count, key; +{ + if (!uppercase_p (key) && (rl_point + 1 <= rl_end)) + rl_point++; + + rl_yank (); + rl_backward (1); + return (0); +} + +rl_vi_check () +{ + if (rl_point && rl_point == rl_end) + rl_point--; + return (0); +} + +rl_vi_column (count, key) + int count, key; +{ + if (count > rl_end) + rl_end_of_line (); + else + rl_point = count - 1; + return (0); +} + +int +rl_vi_domove (key, nextkey) + int key, *nextkey; +{ + int c, save; + int old_end; + + rl_mark = rl_point; + c = rl_read_key (); + *nextkey = c; + + if (!member (c, vi_motion)) + { + if (digit_p (c)) + { + save = rl_numeric_arg; + rl_numeric_arg = digit_value (c); + rl_digit_loop1 (); + rl_numeric_arg *= save; + c = rl_read_key (); /* real command */ + *nextkey = c; + } + else if (key == c && (key == 'd' || key == 'y' || key == 'c')) + { + rl_mark = rl_end; + rl_beg_of_line (); + _rl_vi_last_motion = c; + return (0); + } + else + return (-1); + } + + _rl_vi_last_motion = c; + + /* Append a blank character temporarily so that the motion routines + work right at the end of the line. */ + old_end = rl_end; + rl_line_buffer[rl_end++] = ' '; + rl_line_buffer[rl_end] = '\0'; + + _rl_dispatch (c, _rl_keymap); + + /* Remove the blank that we added. */ + rl_end = old_end; + rl_line_buffer[rl_end] = '\0'; + if (rl_point > rl_end) + rl_point = rl_end; + + /* No change in position means the command failed. */ + if (rl_mark == rl_point) + return (-1); + + /* 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 && + !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')) + { + /* Don't move farther back than where we started. */ + while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + /* Posix.2 says that if cw or cW moves the cursor towards the end of + the line, the character under the cursor should be deleted. */ + if (rl_point == rl_mark) + rl_point++; + else + { + /* Move past the end of the word so that the kill doesn't + remove the last letter of the previous word. Only do this + if we are not at the end of the line. */ + if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + } + } + + if (rl_mark < rl_point) + exchange (rl_point, rl_mark); + + return (0); +} + +/* A simplified loop for vi. Don't dispatch key at end. + Don't recognize minus sign? */ +static int +rl_digit_loop1 () +{ + int key, c; + + while (1) + { + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); + key = c = rl_read_key (); + + if (_rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + rl_numeric_arg *= 4; + continue; + } + + c = UNMETA (c); + if (digit_p (c)) + { + if (rl_explicit_arg) + rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c); + else + rl_numeric_arg = digit_value (c); + rl_explicit_arg = 1; + } + else + { + rl_clear_message (); + rl_stuff_char (key); + break; + } + } + return (0); +} + +rl_vi_delete_to (count, key) + int count, key; +{ + int c; + + if (uppercase_p (key)) + rl_stuff_char ('$'); + else if (vi_redoing) + rl_stuff_char (_rl_vi_last_motion); + + if (rl_vi_domove (key, &c)) + { + ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. */ + if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + rl_kill_text (rl_point, rl_mark); + return (0); +} + +rl_vi_change_to (count, key) + int count, key; +{ + int c, start_pos; + + if (uppercase_p (key)) + rl_stuff_char ('$'); + else if (vi_redoing) + rl_stuff_char (_rl_vi_last_motion); + + start_pos = rl_point; + + if (rl_vi_domove (key, &c)) + { + ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. c[wW] are handled by special-case code in rl_vi_domove(), + and already leave the mark at the correct location. */ + if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + /* The cursor never moves with c[wW]. */ + if ((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); + + return (0); +} + +rl_vi_yank_to (count, key) + int count, key; +{ + int c, save = rl_point; + + if (uppercase_p (key)) + rl_stuff_char ('$'); + + if (rl_vi_domove (key, &c)) + { + ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. */ + if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + rl_begin_undo_group (); + rl_kill_text (rl_point, rl_mark); + rl_end_undo_group (); + rl_do_undo (); + rl_point = save; + + return (0); +} + +rl_vi_delete (count, key) + int count, key; +{ + int end; + + if (rl_end == 0) + { + ding (); + return -1; + } + + end = rl_point + count; + + if (end >= rl_end) + end = rl_end; + + rl_kill_text (rl_point, end); + + if (rl_point > 0 && rl_point == rl_end) + rl_backward (1); + return (0); +} + +/* Turn the current line into a comment in shell history. + A K*rn shell style function. */ +rl_vi_comment (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'); + return (0); +} + +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); +} + +/* 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 */ + +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); + else + { + if (vi_redoing) + target = _rl_vi_last_search_char; + else + _rl_vi_last_search_char = target = rl_getc (rl_instream); + + switch (key) + { + case 't': + orig_dir = dir = FTO; + break; + + case 'T': + orig_dir = dir = BTO; + break; + + case 'f': + orig_dir = dir = FFIND; + break; + + case 'F': + orig_dir = dir = BFIND; + break; + } + } + + 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); +} + +/* Match brackets */ +rl_vi_match (ignore, key) + int ignore, key; +{ + int count = 1, brack, pos; + + pos = rl_point; + if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && + rl_point < rl_end - 1) + rl_forward (1); + + if (brack <= 0) + { + rl_point = pos; + ding (); + return -1; + } + } + + pos = rl_point; + + if (brack < 0) + { + while (count) + { + if (--pos >= 0) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + ding (); + return -1; + } + } + } + else + { /* brack > 0 */ + while (count) + { + if (++pos < rl_end) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + ding (); + return -1; + } + } + } + rl_point = pos; + return (0); +} + +int +rl_vi_bracktype (c) + int c; +{ + switch (c) + { + case '(': return 1; + case ')': return -1; + case '[': return 2; + case ']': return -2; + case '{': return 3; + case '}': return -3; + default: return 0; + } +} + +rl_vi_change_char (count, key) + int count, key; +{ + int c; + + if (vi_redoing) + c = _rl_vi_last_replacement; + else + _rl_vi_last_replacement = c = rl_getc (rl_instream); + + if (c == '\033' || c == CTRL ('C')) + return -1; + + while (count-- && rl_point < rl_end) + { + rl_begin_undo_group (); + + rl_delete (1, c); + rl_insert (1, c); + if (count == 0) + rl_backward (1); + + rl_end_undo_group (); + } + return (0); +} + +rl_vi_subst (count, key) + int count, key; +{ + rl_begin_undo_group (); + + if (uppercase_p (key)) + { + rl_beg_of_line (); + rl_kill_line (1); + } + else + rl_delete_text (rl_point, rl_point+count); + + rl_end_undo_group (); + + _rl_vi_set_last (key, count, rl_arg_sign); + + rl_begin_undo_group (); + _rl_vi_doing_insert = 1; + rl_vi_insertion_mode (1, key); + + return (0); +} + +rl_vi_overstrike (count, key) + int count, key; +{ + int i; + + if (_rl_vi_doing_insert == 0) + { + _rl_vi_doing_insert = 1; + rl_begin_undo_group (); + } + + for (i = 0; i < count; i++) + { + vi_replace_count++; + rl_begin_undo_group (); + + if (rl_point < rl_end) + { + rl_delete (1, key); + rl_insert (1, key); + } + else + rl_insert (1, key); + + rl_end_undo_group (); + } + return (0); +} + +rl_vi_overstrike_delete (count) + int count; +{ + int i, s; + + for (i = 0; i < count; i++) + { + if (vi_replace_count == 0) + { + ding (); + break; + } + s = rl_point; + + if (rl_do_undo ()) + vi_replace_count--; + + if (rl_point == s) + rl_backward (1); + } + + if (vi_replace_count == 0 && _rl_vi_doing_insert) + { + rl_end_undo_group (); + rl_do_undo (); + _rl_vi_doing_insert = 0; + } + return (0); +} + +rl_vi_replace (count, key) + int count, key; +{ + int i; + + vi_replace_count = 0; + + if (!vi_replace_map) + { + vi_replace_map = rl_make_bare_keymap (); + + for (i = ' '; i < KEYMAP_SIZE; i++) + vi_replace_map[i].function = rl_vi_overstrike; + + vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; + vi_replace_map[ESC].function = rl_vi_movement_mode; + vi_replace_map[RETURN].function = rl_newline; + vi_replace_map[NEWLINE].function = rl_newline; + + /* If the normal vi insertion keymap has ^H bound to erase, do the + same here. Probably should remove the assignment to RUBOUT up + there, but I don't think it will make a difference in real life. */ + if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && + vi_insertion_keymap[CTRL ('H')].function == rl_rubout) + vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; + + } + _rl_keymap = vi_replace_map; + return (0); +} + +#if 0 +/* 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 ;. */ +rl_vi_possible_completions() +{ + int save_pos = rl_point; + + if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') + { + while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && + rl_line_buffer[rl_point] != ';') + rl_point++; + } + else if (rl_line_buffer[rl_point - 1] == ';') + { + ding (); + return (0); + } + + rl_possible_completions (); + rl_point = save_pos; + + return (0); +} +#endif + +#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, "readline: Out of virtual memory!\n"); + abort (); +} +#endif /* STATIC_MALLOC */ + +#endif /* VI_MODE */ diff --git a/lib/readline/xmalloc.c b/lib/readline/xmalloc.c new file mode 100644 index 0000000..4f6dc76 --- /dev/null +++ b/lib/readline/xmalloc.c @@ -0,0 +1,78 @@ +/* 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 (ALREADY_HAVE_XMALLOC) +#else +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +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 (); +} +#endif /* !ALREADY_HAVE_XMALLOC */ diff --git a/lib/termcap/Makefile b/lib/termcap/Makefile new file mode 100644 index 0000000..b87de8d --- /dev/null +++ b/lib/termcap/Makefile @@ -0,0 +1,67 @@ +## -*- 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/grot/COPYING b/lib/termcap/grot/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/lib/termcap/grot/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + 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. + + Preamble + + 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. 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. 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 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 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, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +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 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.) + +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 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. +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. + + 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 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 +this License, you may choose any version ever published by the Free Software +Foundation. + + 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 +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 +of promoting the sharing and reuse of software generally. + + 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 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +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. + + 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 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + 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 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + +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) 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. + +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 is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +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/termcap/grot/ChangeLog b/lib/termcap/grot/ChangeLog new file mode 100644 index 0000000..3a8b844 --- /dev/null +++ b/lib/termcap/grot/ChangeLog @@ -0,0 +1,48 @@ +Thu Apr 15 12:45:10 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * Version 1.2. + + * tparam.c [!emacs] (xmalloc, xrealloc, memory_out): New functions. + (tparam1): Use them. + + * termcap.c, tparam.c: Use NULL or '\0' where appropriate + instead of 0. Rename some vars. + * termcap.c (tgetent): If EOF is reached on termcap file, + free allocated resources before returning. + + * termcap.c (tgetent): Use /etc/termcap if TERMCAP is an entry + for a term type other than TERM. + From pjr@jet.UK (Paul J Rippin). + +Sat Apr 10 23:55:12 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * tparam.c (tparam1): Don't set the 0200 bit on a non-0 character code. + From junio@twinsun.COM (Junio Hamano). + +Tue Dec 8 22:02:15 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * termcap.c, tparam.c: Use HAVE_STRING_H instead of USG. + +Thu Dec 3 13:47:56 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * termcap.c, tparam.c [HAVE_CONFIG_H]: Include config.h. + +Fri Oct 23 12:35:29 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * termcap.h [__STDC__]: Add consts. From Franc,ois Pinard. + +Tue Oct 13 15:52:21 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * Version 1.1. + +Tue Sep 29 21:04:39 1992 David J. MacKenzie (djm@geech.gnu.ai.mit.edu) + + * termcap.[ch], tparam.c: Fix some lint. + + * version.c: New file. + +Local Variables: +mode: indented-text +left-margin: 8 +version-control: never +End: diff --git a/lib/termcap/grot/INSTALL b/lib/termcap/grot/INSTALL new file mode 100644 index 0000000..014e0f7 --- /dev/null +++ b/lib/termcap/grot/INSTALL @@ -0,0 +1,117 @@ +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 +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'. diff --git a/lib/termcap/grot/Makefile.in b/lib/termcap/grot/Makefile.in new file mode 100644 index 0000000..309603d --- /dev/null +++ b/lib/termcap/grot/Makefile.in @@ -0,0 +1,118 @@ +# Makefile for GNU termcap library. +# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ + +# 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 + +CFLAGS = -g + +prefix = /usr/local +exec_prefix = $(prefix) + +# Directory in which to install libtermcap.a. +libdir = $(exec_prefix)/lib + +# Directory in which to install termcap.h. +includedir = $(prefix)/include + +# Directory in which to optionally also install termcap.h, +# so compilers besides gcc can find it by default. +# If it is empty or not defined, termcap.h will only be installed in +# includedir. +oldincludedir = /usr/include + +# Directory in which to install the documentation info files. +infodir = $(prefix)/info + +#### End of system configuration section. #### + +SHELL = /bin/sh + +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 + +all: libtermcap.a termcap.info + +.c.o: + $(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir) $(CFLAGS) $< + +install: all + $(INSTALL_DATA) libtermcap.a $(libdir)/libtermcap.a + -ranlib $(libdir)/libtermcap.a + test -d $(includedir) || mkdir $(includedir) + 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: + rm -f $(libdir)/libtermcap.a $(includedir)/termcap.h + test -z "$(oldincludedir)" || rm -f $(oldincludedir)/termcap.h + rm -f $(infodir)/termcap.info* + +libtermcap.a: $(OBJS) + ar rc $@ $(OBJS) + -ranlib $@ + +termcap.info: termcap.texi + $(MAKEINFO) $(srcdir)/termcap.texi --output=$(srcdir)/termcap.info + +TAGS: $(SRCS) + etags $(SRCS) + +clean: + rm -f *.a *.o core + +mostlyclean: clean + +distclean: clean + rm -f Makefile config.status + +realclean: distclean + rm -f TAGS *.info* + +dist: $(DISTFILES) + echo termcap-`sed -e '/version_string/!d' -e 's/[^0-9]*\([0-9a-z.]*\).*/\1/' -e q version.c` > .fname + rm -rf `cat .fname` + mkdir `cat .fname` + ln $(DISTFILES) `cat .fname` + tar chzf `cat .fname`.tar.z `cat .fname` + rm -rf `cat .fname` .fname diff --git a/lib/termcap/grot/NEWS b/lib/termcap/grot/NEWS new file mode 100644 index 0000000..c696fdf --- /dev/null +++ b/lib/termcap/grot/NEWS @@ -0,0 +1,12 @@ +Major changes in release 1.2: + +For `%.', only set the high bit on NUL. +Fix a file descriptor and memory leak. +Add const in termcap.h prototypes. +Configuration improvements. + +Major changes in release 1.1: + +Fix portability problems. +Improve configuration and installation. +Fix compiler warnings. diff --git a/lib/termcap/grot/README b/lib/termcap/grot/README new file mode 100644 index 0000000..9db9095 --- /dev/null +++ b/lib/termcap/grot/README @@ -0,0 +1,14 @@ +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. + +The GNU termcap library does not place an arbitrary limit on the size +of termcap entries, unlike most other termcap libraries. + +See the file INSTALL for compilation and installation instructions. + +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 +`ident' command on libtermcap.a. diff --git a/lib/termcap/grot/configure b/lib/termcap/grot/configure new file mode 100755 index 0000000..bc34d0a --- /dev/null +++ b/lib/termcap/grot/configure @@ -0,0 +1,346 @@ +#!/bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf. +# Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# 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. + + +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 ;; + + *) ;; + esac + fi +done + +trap 'rm -f conftest* core; exit 1' 1 3 15 + +rm -f conftest* +compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' + +# 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 + +# 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 + srcdir=.. + fi +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 + else + echo "configure: Can not find sources in \`${srcdir}'." 1>&2 + 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" + break + fi + done + IFS="$saveifs" +fi +test -z "$CC" && CC="cc" + +# Find out if we are using GNU C, under whatever name. +cat > conftest.c <<EOF +#ifdef __GNUC__ + yes +#endif +EOF +${CC-cc} -E conftest.c > conftest.out 2>&1 +if egrep yes conftest.out >/dev/null 2>&1; then + GCC=1 # For later tests. +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 +#include <stdio.h> +EOF +err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + : +else + CPP=/lib/cpp +fi +rm -f conftest* +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.) +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 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 + fi + fi + ;; + esac + done + IFS="$saveifs" +fi +INSTALL=${INSTALL-cp} +INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'} +INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'} + +for hdr in string.h +do +trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` +echo checking for ${hdr} +cat > conftest.c <<EOF +#include <${hdr}> +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" +} + +fi +rm -f conftest* +done + +echo checking for unistd.h +cat > conftest.c <<EOF +#include <unistd.h> +EOF +err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + { +test -n "$verbose" && \ +echo ' defining' HAVE_UNISTD_H +DEFS="$DEFS -DHAVE_UNISTD_H=1" +} + +fi +rm -f conftest* + +echo checking for ANSI C header files +cat > conftest.c <<EOF +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +echo '#include <string.h>' > 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 <<EOF +#include <ctype.h> +#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 +eval $compile +if test -s conftest && (./conftest; exit) 2>/dev/null; then + { +test -n "$verbose" && \ +echo ' defining' STDC_HEADERS +DEFS="$DEFS -DSTDC_HEADERS=1" +} + +fi +rm -f conftest* +fi +rm -f conftest* + +fi +rm -f conftest* + +if test -n "$prefix"; then + test -z "$exec_prefix" && exec_prefix='${prefix}' + prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%" +fi +if test -n "$exec_prefix"; then + prsub="$prsub +s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%\ +exec_prefix\\1=\\2$exec_prefix%" +fi + +trap 'rm -f config.status; exit 1' 1 3 15 +echo creating config.status +rm -f config.status +cat > config.status <<EOF +#!/bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $* + +for arg +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 ;; + 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' +EOF +cat >> config.status <<\EOF + +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 + 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 +s%@srcdir@%$srcdir%g +s%@DEFS@%$DEFS% +" $top_srcdir/${file}.in >> $file +fi; done + +exit 0 +EOF +chmod +x config.status +test -n "$no_create" || ./config.status + diff --git a/lib/termcap/grot/configure.in b/lib/termcap/grot/configure.in new file mode 100644 index 0000000..1c2aaf2 --- /dev/null +++ b/lib/termcap/grot/configure.in @@ -0,0 +1,10 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(termcap.h) +AC_SUBST(PROGS)dnl +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_HAVE_HEADERS(string.h) +AC_UNISTD_H +AC_STDC_HEADERS +AC_OUTPUT(Makefile) diff --git a/lib/termcap/grot/termcap.info b/lib/termcap/grot/termcap.info new file mode 100644 index 0000000..f8515f1 --- /dev/null +++ b/lib/termcap/grot/termcap.info @@ -0,0 +1,80 @@ +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 file documents the termcap library of the GNU system. + + Copyright (C) 1988 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. + + +Indirect: +termcap.info-1: 912 +termcap.info-2: 47539 +termcap.info-3: 90314 +termcap.info-4: 138449 + +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 + +End Tag Table diff --git a/lib/termcap/grot/termcap.info-1 b/lib/termcap/grot/termcap.info-1 new file mode 100644 index 0000000..8390359 --- /dev/null +++ b/lib/termcap/grot/termcap.info-1 @@ -0,0 +1,1115 @@ +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 file documents the termcap library of the GNU system. + + Copyright (C) 1988 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: termcap.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: What is termcap? Why this manual? +* Library:: The termcap library functions. +* Data Base:: What terminal descriptions in `/etc/termcap' look like. +* Capabilities:: Definitions of the individual terminal capabilities: + how to write them in descriptions, and how to use + their values to do display updating. +* Summary:: Brief table of capability names and their meanings. +* Var Index:: Index of C functions and variables. +* Cap Index:: Index of termcap capabilities. +* Index:: Concept index. + + -- The Detailed Node Listing -- + +The Termcap Library + +* Preparation:: Preparing to use the termcap library. +* Find:: Finding the description of the terminal being used. +* Interrogate:: Interrogating the description for particular capabilities. +* Initialize:: Initialization for output using termcap. +* Padding:: Outputting padding. +* Parameters:: Encoding parameters such as cursor positions. + +Padding + +* Why Pad:: Explanation of padding. +* Not Enough:: When there is not enough padding. +* Describe Padding:: The data base says how much padding a terminal needs. +* Output Padding:: Using `tputs' to output the needed padding. + +Filling In Parameters + +* Encode Parameters:: The language for encoding parameters. +* Using Parameters:: Outputting a string command with parameters. + +Sending Display Commands with Parameters + +* tparam:: The general case, for GNU termcap only. +* tgoto:: The special case of cursor motion. + +The Format of the Data Base + +* Format:: Overall format of a terminal description. +* Capability Format:: Format of capabilities within a description. +* Naming:: Naming conventions for terminal types. +* Inheriting:: Inheriting part of a description from +a related terminal type. +* Changing:: When changes in the data base take effect. + +Definitions of the Terminal Capabilities + +* Basic:: Basic characteristics. +* Screen Size:: Screen size, and what happens when it changes. +* Cursor Motion:: Various ways to move the cursor. +* Wrapping:: What happens if you write a character in the last column. +* Scrolling:: Pushing text up and down on the screen. +* Windows:: Limiting the part of the window that output affects. +* Clearing:: Erasing one or many lines. +* Insdel Line:: Making new blank lines in mid-screen; deleting lines. +* Insdel Char:: Inserting and deleting characters within a line. +* Standout:: Highlighting some of the text. +* Underlining:: Underlining some of the text. +* Cursor Visibility:: Making the cursor more or less easy to spot. +* Bell:: Attracts user's attention; not localized on the screen. +* Keypad:: Recognizing when function keys or arrows are typed. +* Meta Key:: META acts like an extra shift key. +* Initialization:: Commands used to initialize or reset the terminal. +* Pad Specs:: Info for the kernel on how much padding is needed. +* Status Line:: A status line displays "background" information. +* Half-Line:: Moving by half-lines, for superscripts and subscripts. +* Printer:: Controlling auxiliary printers of display terminals. + + +File: termcap.info, Node: Introduction, Next: Library, Prev: Top, Up: Top + +Introduction +************ + + "Termcap" is a library and data base that enables programs to use +display terminals in a terminal-independent manner. It originated in +Berkeley Unix. + + The termcap data base describes the capabilities of hundreds of +different display terminals in great detail. Some examples of the +information recorded for a terminal could include how many columns wide +it is, what string to send to move the cursor to an arbitrary position +(including how to encode the row and column numbers), how to scroll the +screen up one or several lines, and how much padding is needed for such +a scrolling operation. + + The termcap library is provided for easy access this data base in +programs that want to do terminal-independent character-based display +output. + + This manual describes the GNU version of the termcap library, which +has some extensions over the Unix version. All the extensions are +identified as such, so this manual also tells you how to use the Unix +termcap. + + The GNU version of the termcap library is available free as source +code, for use in free programs, and runs on Unix and VMS systems (at +least). You can find it in the GNU Emacs distribution in the files +`termcap.c' and `tparam.c'. + + This manual was written for the GNU project, whose goal is to +develop a complete free operating system upward-compatible with Unix +for user programs. The project is approximately two thirds complete. +For more information on the GNU project, including the GNU Emacs editor +and the mostly-portable optimizing C compiler, send one dollar to + + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + + +File: termcap.info, Node: Library, Next: Data Base, Prev: Introduction, Up: Top + +The Termcap Library +******************* + + The termcap library is the application programmer's interface to the +termcap data base. It contains functions for the following purposes: + + * Finding the description of the user's terminal type (`tgetent'). + + * Interrogating the description for information on various topics + (`tgetnum', `tgetflag', `tgetstr'). + + * Computing and performing padding (`tputs'). + + * Encoding numeric parameters such as cursor positions into the + terminal-specific form required for display commands (`tparam', + `tgoto'). + +* Menu: + +* Preparation:: Preparing to use the termcap library. +* Find:: Finding the description of the terminal being used. +* Interrogate:: Interrogating the description for particular capabilities. +* Initialize:: Initialization for output using termcap. +* Padding:: Outputting padding. +* Parameters:: Encoding parameters such as cursor positions. + + +File: termcap.info, Node: Preparation, Next: Find, Up: Library + +Preparing to Use the Termcap Library +==================================== + + To use the termcap library in a program, you need two kinds of +preparation: + + * The compiler needs declarations of the functions and variables in + the library. + + On GNU systems, it suffices to include the header file `termcap.h' + in each source file that uses these functions and variables. + + On Unix systems, there is often no such header file. Then you must + explictly declare the variables as external. You can do likewise + for the functions, or let them be implicitly declared and cast + their values from type `int' to the appropriate type. + + We illustrate the declarations of the individual termcap library + functions with ANSI C prototypes because they show how to pass the + arguments. If you are not using the GNU C compiler, you probably + cannot use function prototypes, so omit the argument types and + names from your declarations. + + * The linker needs to search the library. Usually either + `-ltermcap' or `-ltermlib' as an argument when linking will do + this. + + +File: termcap.info, Node: Find, Next: Interrogate, Prev: Preparation, Up: Library + +Finding a Terminal Description: `tgetent' +========================================= + + An application program that is going to use termcap must first look +up the description of the terminal type in use. This is done by calling +`tgetent', whose declaration in ANSI Standard C looks like: + + int tgetent (char *BUFFER, char *TERMTYPE); + +This function finds the description and remembers it internally so that +you can interrogate it about specific terminal capabilities (*note +Interrogate::.). + + The argument TERMTYPE is a string which is the name for the type of +terminal to look up. Usually you would obtain this from the environment +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. + + With the Unix version of termcap, you must allocate space for the +description yourself and pass the address of the space as the argument +BUFFER. There is no way you can tell how much space is needed, so the +convention is to allocate a buffer 2048 characters long and assume that +is enough. (Formerly the convention was to allocate 1024 characters and +assume that was enough. But one day, for one kind of terminal, that was +not enough.) + + No matter how the space to store the description has been obtained, +termcap records its address internally for use when you later +interrogate the description with `tgetnum', `tgetstr' or `tgetflag'. If +the buffer was allocated by termcap, it will be freed by termcap too if +you call `tgetent' again. If the buffer was provided by you, you must +make sure that its contents remain unchanged for as long as you still +plan to interrogate the description. + + The return value of `tgetent' is -1 if there is some difficulty +accessing the data base of terminal types, 0 if the data base is +accessible but the specified type is not defined in it, and some other +value otherwise. + + Here is how you might use the function `tgetent': + + #ifdef unix + static char term_buffer[2048]; + #else + #define term_buffer 0 + #endif + + init_terminal_data () + { + char *termtype = getenv ("TERM"); + int success; + + if (termtype == 0) + fatal ("Specify a terminal type with `setenv TERM <yourtype>'.\n"); + + success = tgetent (term_buffer, termtype); + if (success < 0) + fatal ("Could not access the termcap data base.\n"); + if (success == 0) + fatal ("Terminal type `%s' is not defined.\n", termtype); + } + +Here we assume the function `fatal' prints an error message and exits. + + If the environment variable `TERMCAP' is defined, its value is used +to override the terminal type data base. The function `tgetent' checks +the value of `TERMCAP' automatically. If the value starts with `/' +then it is taken as a file name to use as the data base file, instead +of `/etc/termcap' which is the standard data base. If the value does +not start with `/' then it is itself used as the terminal description, +provided that the terminal type TERMTYPE is among the types it claims +to apply to. *Note Data Base::, for information on the format of a +terminal description. + + +File: termcap.info, Node: Interrogate, Next: Initialize, Prev: Find, Up: Library + +Interrogating the Terminal Description +====================================== + + Each piece of information recorded in a terminal description is +called a "capability". Each defined terminal capability has a +two-letter code name and a specific meaning. For example, the number +of columns is named `co'. *Note Capabilities::, for definitions of all +the standard capability names. + + Once you have found the proper terminal description with `tgetent' +(*note Find::.), your application program must "interrogate" it for +various terminal capabilities. You must specify the two-letter code of +the capability whose value you seek. + + Capability values can be numeric, boolean (capability is either +present or absent) or strings. Any particular capability always has +the same value type; for example, `co' always has a numeric value, +while `am' (automatic wrap at margin) is always a flag, and `cm' +(cursor motion command) always has a string value. The documentation +of each capability says which type of value it has. + + There are three functions to use to get the value of a capability, +depending on the type of value the capability has. Here are their +declarations in ANSI C: + + int tgetnum (char *NAME); + int tgetflag (char *NAME); + char *tgetstr (char *NAME, char **AREA); + +`tgetnum' + Use `tgetnum' to get a capability value that is numeric. The + argument NAME is the two-letter code name of the capability. If + the capability is present, `tgetnum' returns the numeric value + (which is nonnegative). If the capability is not mentioned in the + terminal description, `tgetnum' returns -1. + +`tgetflag' + Use `tgetflag' to get a boolean value. If the capability NAME is + present in the terminal description, `tgetflag' returns 1; + otherwise, it returns 0. + +`tgetstr' + Use `tgetstr' to get a string value. It returns a pointer to a + string which is the capability value, or a null pointer if the + capability is not present in the terminal description. + + There are two ways `tgetstr' can find space to store the string + value: + + * You can ask `tgetstr' to allocate the space. Pass a null + pointer for the argument AREA, and `tgetstr' will use + `malloc' to allocate storage big enough for the value. + Termcap will never free this storage or refer to it again; you + should free it when you are finished with it. + + This method is more robust, since there is no need to guess + how much space is needed. But it is supported only by the GNU + termcap library. + + * You can provide the space. Provide for the argument AREA the + address of a pointer variable of type `char *'. Before + calling `tgetstr', initialize the variable to point at + available space. Then `tgetstr' will store the string value + in that space and will increment the pointer variable to + point after the space that has been used. You can use the + same pointer variable for many calls to `tgetstr'. + + There is no way to determine how much space is needed for a + single string, and no way for you to prevent or handle + overflow of the area you have provided. However, you can be + sure that the total size of all the string values you will + obtain from the terminal description is no greater than the + size of the description (unless you get the same capability + twice). You can determine that size with `strlen' on the + buffer you provided to `tgetent'. See below for an example. + + Providing the space yourself is the only method supported by + the Unix version of termcap. + + Note that you do not have to specify a terminal type or terminal +description for the interrogation functions. They automatically use the +description found by the most recent call to `tgetent'. + + Here is an example of interrogating a terminal description for +various capabilities, with conditionals to select between the Unix and +GNU methods of providing buffer space. + + char *tgetstr (); + + char *cl_string, *cm_string; + int height; + int width; + int auto_wrap; + + char PC; /* For tputs. */ + char *BC; /* For tgoto. */ + char *UP; + + interrogate_terminal () + { + #ifdef UNIX + /* Here we assume that an explicit term_buffer + was provided to tgetent. */ + char *buffer + = (char *) malloc (strlen (term_buffer)); + #define BUFFADDR &buffer + #else + #define BUFFADDR 0 + #endif + + char *temp; + + /* Extract information we will use. */ + cl_string = tgetstr ("cl", BUFFADDR); + cm_string = tgetstr ("cm", BUFFADDR); + auto_wrap = tgetflag ("am"); + height = tgetnum ("li"); + width = tgetnum ("co"); + + /* Extract information that termcap functions use. */ + temp = tgetstr ("pc", BUFFADDR); + PC = temp ? *temp : 0; + BC = tgetstr ("le", BUFFADDR); + UP = tgetstr ("up", BUFFADDR); + } + +*Note Padding::, for information on the variable `PC'. *Note Using +Parameters::, for information on `UP' and `BC'. + + +File: termcap.info, Node: Initialize, Next: Padding, Prev: Interrogate, Up: Library + +Initialization for Use of Termcap +================================= + + Before starting to output commands to a terminal using termcap, an +application program should do two things: + + * Initialize various global variables which termcap library output + functions refer to. These include `PC' and `ospeed' for padding + (*note Output Padding::.) and `UP' and `BC' for cursor motion + (*note tgoto::.). + + * Tell the kernel to turn off alteration and padding of + horizontal-tab characters sent to the terminal. + + To turn off output processing in Berkeley Unix you would use `ioctl' +with code `TIOCLSET' to set the bit named `LLITOUT', and clear the bits +`ANYDELAY' using `TIOCSETN'. In POSIX or System V, you must clear the +bit named `OPOST'. Refer to the system documentation for details. + + If you do not set the terminal flags properly, some older terminals +will not work. This is because their commands may contain the +characters that normally signify newline, carriage return and +horizontal tab--characters which the kernel thinks it ought to modify +before output. + + When you change the kernel's terminal flags, you must arrange to +restore them to their normal state when your program exits. This +implies that the program must catch fatal signals such as `SIGQUIT' and +`SIGINT' and restore the old terminal flags before actually terminating. + + Modern terminals' commands do not use these special characters, so +if you do not care about problems with old terminals, you can leave the +kernel's terminal flags unaltered. + + +File: termcap.info, Node: Padding, Next: Parameters, Prev: Initialize, Up: Library + +Padding +======= + + "Padding" means outputting null characters following a terminal +display command that takes a long time to execute. The terminal +description says which commands require padding and how much; the +function `tputs', described below, outputs a terminal command while +extracting from it the padding information, and then outputs the +padding that is necessary. + +* Menu: + +* Why Pad:: Explanation of padding. +* Not Enough:: When there is not enough padding. +* Describe Padding:: The data base says how much padding a terminal needs. +* Output Padding:: Using `tputs' to output the needed padding. + + +File: termcap.info, Node: Why Pad, Next: Not Enough, Up: Padding + +Why Pad, and How +---------------- + + Most types of terminal have commands that take longer to execute +than they do to send over a high-speed line. For example, clearing the +screen may take 20msec once the entire command is received. During +that time, on a 9600 bps line, the terminal could receive about 20 +additional output characters while still busy clearing the screen. +Every terminal has a certain amount of buffering capacity to remember +output characters that cannot be processed yet, but too many slow +commands in a row can cause the buffer to fill up. Then any additional +output that cannot be processed immediately will be lost. + + To avoid this problem, we normally follow each display command with +enough useless charaters (usually null characters) to fill up the time +that the display command needs to execute. This does the job if the +terminal throws away null characters without using up space in the +buffer (which most terminals do). If enough padding is used, no output +can ever be lost. The right amount of padding avoids loss of output +without slowing down operation, since the time used to transmit padding +is time that nothing else could be done. + + The number of padding characters needed for an operation depends on +the line speed. In fact, it is proportional to the line speed. A 9600 +baud line transmits about one character per msec, so the clear screen +command in the example above would need about 20 characters of padding. +At 1200 baud, however, only about 3 characters of padding are needed +to fill up 20msec. + + +File: termcap.info, Node: Not Enough, Next: Describe Padding, Prev: Why Pad, Up: Padding + +When There Is Not Enough Padding +-------------------------------- + + There are several common manifestations of insufficient padding. + + * Emacs displays `I-search: ^Q-' at the bottom of the screen. + + This means that the terminal thought its buffer was getting full of + display commands, so it tried to tell the computer to stop sending + any. + + * The screen is garbled intermittently, or the details of garbling + vary when you repeat the action. (A garbled screen could be due + to a command which is simply incorrect, or to user option in the + terminal which doesn't match the assumptions of the terminal + description, but this usually leads to reproducible failure.) + + This means that the buffer did get full, and some commands were + lost. Many changeable factors can change which ones are lost. + + * Screen is garbled at high output speeds but not at low speeds. + Padding problems nearly always go away at low speeds, usually even + at 1200 baud. + + This means that a high enough speed permits commands to arrive + faster than they can be executed. + + Although any obscure command on an obscure terminal might lack +padding, in practice problems arise most often from the clearing +commands `cl' and `cd' (*note Clearing::.), the scrolling commands `sf' +and `sr' (*note Scrolling::.), and the line insert/delete commands `al' +and `dl' (*note Insdel Line::.). + + Occasionally the terminal description fails to define `sf' and some +programs will use `do' instead, so you may get a problem with `do'. If +so, first define `sf' just like `do', then add some padding to `sf'. + + The best strategy is to add a lot of padding at first, perhaps 200 +msec. This is much more than enough; in fact, it should cause a +visible slowdown. (If you don't see a slowdown, the change has not +taken effect; *note Changing::..) If this makes the problem go away, +you have found the right place to add padding; now reduce the amount +until the problem comes back, then increase it again. If the problem +remains, either it is in some other capability or it is not a matter of +padding at all. + + Keep in mind that on many terminals the correct padding for +insert/delete line or for scrolling is cursor-position dependent. If +you get problems from scrolling a large region of the screen but not +from scrolling a small part (just a few lines moving), it may mean that +fixed padding should be replaced with position-dependent padding. + + +File: termcap.info, Node: Describe Padding, Next: Output Padding, Prev: Not Enough, Up: Padding + +Specifying Padding in a Terminal Description +-------------------------------------------- + + In the terminal description, the amount of padding required by each +display command is recorded as a sequence of digits at the front of the +command. These digits specify the padding time in milliseconds (msec). +They can be followed optionally by a decimal point and one more digit, +which is a number of tenths of msec. + + Sometimes the padding needed by a command depends on the cursor +position. For example, the time taken by an "insert line" command is +usually proportional to the number of lines that need to be moved down +or cleared. An asterisk (`*') following the padding time says that the +time should be multiplied by the number of screen lines affected by the +command. + + :al=1.3*\E[L: + +is used to describe the "insert line" command for a certain terminal. +The padding required is 1.3 msec per line affected. The command itself +is `ESC [ L'. + + The padding time specified in this way tells `tputs' how many pad +characters to output. *Note Output Padding::. + + Two special capability values affect padding for all commands. +These are the `pc' and `pb'. The variable `pc' specifies the character +to pad with, and `pb' the speed below which no padding is needed. The +defaults for these variables, a null character and 0, are correct for +most terminals. *Note Pad Specs::. + + +File: termcap.info, Node: Output Padding, Prev: Describe Padding, Up: Padding + +Performing Padding with `tputs' +------------------------------- + + Use the termcap function `tputs' to output a string containing an +optional padding spec of the form described above (*note Describe +Padding::.). The function `tputs' strips off and decodes the padding +spec, outputs the rest of the string, and then outputs the appropriate +padding. Here is its declaration in ANSI C: + + char PC; + short ospeed; + + int tputs (char *STRING, int NLINES, int (*OUTFUN) ()); + + Here STRING is the string (including padding spec) to be output; +NLINES is the number of lines affected by the operation, which is used +to multiply the amount of padding if the padding spec ends with a `*'. +Finally, OUTFUN is a function (such as `fputchar') that is called to +output each character. When actually called, OUTFUN should expect one +argument, a character. + + The operation of `tputs' is controlled by two global variables, +`ospeed' and `PC'. The value of `ospeed' is supposed to be the +terminal output speed, encoded as in the `ioctl' system call which gets +the speed information. This is needed to compute the number of padding +characters. The value of `PC' is the character used for padding. + + You are responsible for storing suitable values into these variables +before using `tputs'. The value stored into the `PC' variable should be +taken from the `pc' capability in the terminal description (*note Pad +Specs::.). Store zero in `PC' if there is no `pc' capability. + + The argument NLINES requires some thought. Normally, it should be +the number of lines whose contents will be cleared or moved by the +command. For cursor motion commands, or commands that do editing +within one line, use the value 1. For most commands that affect +multiple lines, such as `al' (insert a line) and `cd' (clear from the +cursor to the end of the screen), NLINES should be the screen height +minus the current vertical position (origin 0). For multiple insert +and scroll commands such as `AL' (insert multiple lines), that same +value for NLINES is correct; the number of lines being inserted is not +correct. + + If a "scroll window" feature is used to reduce the number of lines +affected by a command, the value of NLINES should take this into +account. This is because the delay time required depends on how much +work the terminal has to do, and the scroll window feature reduces the +work. *Note Scrolling::. + + Commands such as `ic' and `dc' (insert or delete characters) are +problematical because the padding needed by these commands is +proportional to the number of characters affected, which is the number +of columns from the cursor to the end of the line. It would be nice to +have a way to specify such a dependence, and there is no need for +dependence on vertical position in these commands, so it is an obvious +idea to say that for these commands NLINES should really be the number +of columns affected. However, the definition of termcap clearly says +that NLINES is always the number of lines affected, even in this case, +where it is always 1. It is not easy to change this rule now, because +too many programs and terminal descriptions have been written to follow +it. + + Because NLINES is always 1 for the `ic' and `dc' strings, there is +no reason for them to use `*', but some of them do. These should be +corrected by deleting the `*'. If, some day, such entries have +disappeared, it may be possible to change to a more useful convention +for the NLINES argument for these operations without breaking any +programs. + + +File: termcap.info, Node: Parameters, Prev: Padding, Up: Library + +Filling In Parameters +===================== + + Some terminal control strings require numeric "parameters". For +example, when you move the cursor, you need to say what horizontal and +vertical positions to move it to. The value of the terminal's `cm' +capability, which says how to move the cursor, cannot simply be a +string of characters; it must say how to express the cursor position +numbers and where to put them within the command. + + The specifications of termcap include conventions as to which +string-valued capabilities require parameters, how many parameters, and +what the parameters mean; for example, it defines the `cm' string to +take two parameters, the vertical and horizontal positions, with 0,0 +being the upper left corner. These conventions are described where the +individual commands are documented. + + Termcap also defines a language used within the capability +definition for specifying how and where to encode the parameters for +output. This language uses character sequences starting with `%'. +(This is the same idea as `printf', but the details are different.) +The language for parameter encoding is described in this section. + + A program that is doing display output calls the functions `tparam' +or `tgoto' to encode parameters according to the specifications. These +functions produce a string containing the actual commands to be output +(as well a padding spec which must be processed with `tputs'; *note +Padding::.). + +* Menu: + +* Encode Parameters:: The language for encoding parameters. +* Using Parameters:: Outputting a string command with parameters. + + +File: termcap.info, Node: Encode Parameters, Next: Using Parameters, Up: Parameters + +Describing the Encoding +----------------------- + + A terminal command string that requires parameters contains special +character sequences starting with `%' to say how to encode the +parameters. These sequences control the actions of `tparam' and +`tgoto'. + + The parameters values passed to `tparam' or `tgoto' are considered +to form a vector. A pointer into this vector determines the next +parameter to be processed. Some of the `%'-sequences encode one +parameter and advance the pointer to the next parameter. Other +`%'-sequences alter the pointer or alter the parameter values without +generating output. + + For example, the `cm' string for a standard ANSI terminal is written +as `\E[%i%d;%dH'. (`\E' stands for ESC.) `cm' by convention always +requires two parameters, the vertical and horizontal goal positions, so +this string specifies the encoding of two parameters. Here `%i' +increments the two values supplied, and each `%d' encodes one of the +values in decimal. If the cursor position values 20,58 are encoded +with this string, the result is `\E[21;59H'. + + First, here are the `%'-sequences that generate output. Except for +`%%', each of them encodes one parameter and advances the pointer to +the following parameter. + +`%%' + Output a single `%'. This is the only way to represent a literal + `%' in a terminal command with parameters. `%%' does not use up a + parameter. + +`%d' + As in `printf', output the next parameter in decimal. + +`%2' + Like `%02d' in `printf': output the next parameter in decimal, and + always use at least two digits. + +`%3' + Like `%03d' in `printf': output the next parameter in decimal, and + always use at least three digits. Note that `%4' and so on are + *not* defined. + +`%.' + Output the next parameter as a single character whose ASCII code is + the parameter value. Like `%c' in `printf'. + +`%+CHAR' + Add the next parameter to the character CHAR, and output the + resulting character. For example, `%+ ' represents 0 as a space, + 1 as `!', etc. + + The following `%'-sequences specify alteration of the parameters +(their values, or their order) rather than encoding a parameter for +output. They generate no output; they are used only for their side +effects on the parameters. Also, they do not advance the "next +parameter" pointer except as explicitly stated. Only `%i', `%r' and +`%>' are defined in standard Unix termcap. The others are GNU +extensions. + +`%i' + Increment the next two parameters. This is used for terminals that + expect cursor positions in origin 1. For example, `%i%d,%d' would + output two parameters with `1' for 0, `2' for 1, etc. + +`%r' + Interchange the next two parameters. This is used for terminals + whose cursor positioning command expects the horizontal position + first. + +`%s' + Skip the next parameter. Do not output anything. + +`%b' + Back up one parameter. The last parameter used will become once + again the next parameter to be output, and the next output command + will use it. Using `%b' more than once, you can back up any + number of parameters, and you can refer to each parameter any + number of times. + +`%>C1C2' + Conditionally increment the next parameter. Here C1 and C2 are + characters which stand for their ASCII codes as numbers. If the + next parameter is greater than the ASCII code of C1, the ASCII + code of C2 is added to it. + +`%a OP TYPE POS' + Perform arithmetic on the next parameter, do not use it up, and do + not output anything. Here OP specifies the arithmetic operation, + while TYPE and POS together specify the other operand. + + Spaces are used above to separate the operands for clarity; the + spaces don't appear in the data base, where this sequence is + exactly five characters long. + + The character OP says what kind of arithmetic operation to + perform. It can be any of these characters: + + `=' + assign a value to the next parameter, ignoring its old value. + The new value comes from the other operand. + + `+' + add the other operand to the next parameter. + + `-' + subtract the other operand from the next parameter. + + `*' + multiply the next parameter by the other operand. + + `/' + divide the next parameter by the other operand. + + The "other operand" may be another parameter's value or a constant; + the character TYPE says which. It can be: + + `p' + Use another parameter. The character POS says which + parameter to use. Subtract 64 from its ASCII code to get the + position of the desired parameter relative to this one. Thus, + the character `A' as POS means the parameter after the next + one; the character `?' means the parameter before the next + one. + + `c' + Use a constant value. The character POS specifies the value + of the constant. The 0200 bit is cleared out, so that 0200 + can be used to represent zero. + + The following `%'-sequences are special purpose hacks to compensate +for the weird designs of obscure terminals. They modify the next +parameter or the next two parameters but do not generate output and do +not use up any parameters. `%m' is a GNU extension; the others are +defined in standard Unix termcap. + +`%n' + Exclusive-or the next parameter with 0140, and likewise the + parameter after next. + +`%m' + Complement all the bits of the next parameter and the parameter + after next. + +`%B' + Encode the next parameter in BCD. It alters the value of the + parameter by adding six times the quotient of the parameter by ten. + Here is a C statement that shows how the new value is computed: + + PARM = (PARM / 10) * 16 + PARM % 10; + +`%D' + Transform the next parameter as needed by Delta Data terminals. + This involves subtracting twice the remainder of the parameter by + 16. + + PARM -= 2 * (PARM % 16); + + +File: termcap.info, Node: Using Parameters, Prev: Encode Parameters, Up: Parameters + +Sending Display Commands with Parameters +---------------------------------------- + + The termcap library functions `tparam' and `tgoto' serve as the +analog of `printf' for terminal string parameters. The newer function +`tparam' is a GNU extension, more general but missing from Unix +termcap. The original parameter-encoding function is `tgoto', which is +preferable for cursor motion. + +* Menu: + +* tparam:: The general case, for GNU termcap only. +* tgoto:: The special case of 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 +preferred function for encoding parameters for all but the `cm' +capability. Its ANSI C declaration is as follows: + + char *tparam (char *CTLSTRING, char *BUFFER, int SIZE, int PARM1,...) + + The arguments are a control string CTLSTRING (the value of a terminal +capability, presumably), an output buffer BUFFER and SIZE, and any +number of integer parameters to be encoded. The effect of `tparam' is +to copy the control string into the buffer, encoding parameters +according to the `%' sequences in the control string. + + You describe the output buffer by its address, BUFFER, and its size +in bytes, SIZE. If the buffer is not big enough for the data to be +stored in it, `tparam' calls `malloc' to get a larger buffer. In +either case, `tparam' returns the address of the buffer it ultimately +uses. If the value equals BUFFER, your original buffer was used. +Otherwise, a new buffer was allocated, and you must free it after you +are done with printing the results. If you pass zero for SIZE and +BUFFER, `tparam' always allocates the space with `malloc'. + + All capabilities that require parameters also have the ability to +specify padding, so you should use `tputs' to output the string +produced by `tparam'. *Note Padding::. Here is an example. + + { + char *buf; + char buffer[40]; + + buf = tparam (command, buffer, 40, parm); + tputs (buf, 1, fputchar); + if (buf != buffer) + free (buf); + } + + If a parameter whose value is zero is encoded with `%.'-style +encoding, the result is a null character, which will confuse `tputs'. +This would be a serious problem, but luckily `%.' encoding is used only +by a few old models of terminal, and only for the `cm' capability. To +solve the problem, use `tgoto' rather than `tparam' to encode the `cm' +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': + + * For Unix compatibility, because Unix termcap does not have + `tparam'. + + * For the `cm' capability, since `tgoto' has a special feature to + avoid problems with null characters, tabs and newlines on certain + old terminal types that use `%.' encoding for that capability. + + Here is how `tgoto' might be declared in ANSI C: + + char *tgoto (char *CSTRING, int HPOS, int VPOS) + + There are three arguments, the terminal description's `cm' string and +the two cursor position numbers; `tgoto' computes the parametrized +string in an internal static buffer and returns the address of that +buffer. The next time you use `tgoto' the same buffer will be reused. + + Parameters encoded with `%.' encoding can generate null characters, +tabs or newlines. These might cause trouble: the null character because +`tputs' would think that was the end of the string, the tab because the +kernel or other software might expand it into spaces, and the newline +becaue the kernel might add a carriage-return, or padding characters +normally used for a newline. To prevent such problems, `tgoto' is +careful to avoid these characters. Here is how this works: if the +target cursor position value is such as to cause a problem (that is to +say, zero, nine or ten), `tgoto' increments it by one, then compensates +by appending a string to move the cursor back or up one position. + + The compensation strings to use for moving back or up are found in +global variables named `BC' and `UP'. These are actual external C +variables with upper case names; they are declared `char *'. It is up +to you to store suitable values in them, normally obtained from the +`le' and `up' terminal capabilities in the terminal description with +`tgetstr'. Alternatively, if these two variables are both zero, the +feature of avoiding nulls, tabs and newlines is turned off. + + It is safe to use `tgoto' for commands other than `cm' only if you +have stored zero in `BC' and `UP'. + + Note that `tgoto' reverses the order of its operands: the horizontal +position comes before the vertical position in the arguments to +`tgoto', even though the vertical position comes before the horizontal +in the parameters of the `cm' string. If you use `tgoto' with a +command such as `AL' that takes one parameter, you must pass the +parameter to `tgoto' as the "vertical position". + + +File: termcap.info, Node: Data Base, Next: Capabilities, Prev: Library, Up: Top + +The Format of the Data Base +*************************** + + The termcap data base of terminal descriptions is stored in the file +`/etc/termcap'. It contains terminal descriptions, blank lines, and +comments. + + A terminal description starts with one or more names for the +terminal type. The information in the description is a series of +"capability names" and values. The capability names have standard +meanings (*note Capabilities::.) and their values describe the terminal. + +* Menu: + +* Format:: Overall format of a terminal description. +* Capability Format:: Format of capabilities within a description. +* Naming:: Naming conventions for terminal types. +* Inheriting:: Inheriting part of a description from +a related terminal type. +* Changing:: When changes in the data base take effect. + + +File: termcap.info, Node: Format, Next: Capability Format, Up: Data Base + +Terminal Description Format +=========================== + + Aside from comments (lines starting with `#', which are ignored), +each nonblank line in the termcap data base is a terminal description. +A terminal description is nominally a single line, but it can be split +into multiple lines by inserting the two characters `\ newline'. This +sequence is ignored wherever it appears in a description. + + The preferred way to split the description is between capabilities: +insert the four characters `: \ newline tab' immediately before any +colon. This allows each sub-line to start with some indentation. This +works because, after the `\ newline' are ignored, the result is `: tab +:'; the first colon ends the preceding capability and the second colon +starts the next capability. If you split with `\ newline' alone, you +may not add any indentation after them. + + Here is a real example of a terminal description: + + dw|vt52|DEC vt52:\ + :cr=^M:do=^J:nl=^J:bl=^G:\ + :le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:\ + :cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:ta=^I:pt:sr=\EI:up=\EA:\ + :ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: + + Each terminal description begins with several names for the terminal +type. The names are separated by `|' characters, and a colon ends the +last name. The first name should be two characters long; it exists +only for the sake of very old Unix systems and is never used in modern +systems. The last name should be a fully verbose name such as "DEC +vt52" or "Ann Arbor Ambassador with 48 lines". The other names should +include whatever the user ought to be able to specify to get this +terminal type, such as `vt52' or `aaa-48'. *Note Naming::, for +information on how to choose terminal type names. + + After the terminal type names come the terminal capabilities, +separated by colons and with a colon after the last one. Each +capability has a two-letter name, such as `cm' for "cursor motion +string" or `li' for "number of display lines". + + +File: termcap.info, Node: Capability Format, Next: Naming, Prev: Format, Up: Data Base + +Writing the Capabilities +======================== + + There are three kinds of capabilities: flags, numbers, and strings. +Each kind has its own way of being written in the description. Each +defined capability has by convention a particular kind of value; for +example, `li' always has a numeric value and `cm' always a string value. + + A flag capability is thought of as having a boolean value: the value +is true if the capability is present, false if not. When the +capability is present, just write its name between two colons. + + A numeric capability has a value which is a nonnegative number. +Write the capability name, a `#', and the number, between two colons. +For example, `...:li#48:...' is how you specify the `li' capability for +48 lines. + + A string-valued capability has a value which is a sequence of +characters. Usually these are the characters used to perform some +display operation. Write the capability name, a `=', and the +characters of the value, between two colons. For example, +`...:cm=\E[%i%d;%dH:...' is how the cursor motion command for a +standard ANSI terminal would be specified. + + Special characters in the string value can be expressed using +`\'-escape sequences as in C; in addition, `\E' stands for ESC. `^' is +also a kind of escape character; `^' followed by CHAR stands for the +control-equivalent of CHAR. Thus, `^a' stands for the character +control-a, just like `\001'. `\' and `^' themselves can be represented +as `\\' and `\^'. + + To include a colon in the string, you must write `\072'. You might +ask, "Why can't `\:' be used to represent a colon?" The reason is that +the interrogation functions do not count slashes while looking for a +capability. Even if `:ce=ab\:cd:' were interpreted as giving the `ce' +capability the value `ab:cd', it would also appear to define `cd' as a +flag. + + The string value will often contain digits at the front to specify +padding (*note Padding::.) and/or `%'-sequences within to specify how +to encode parameters (*note Parameters::.). Although these things are +not to be output literally to the terminal, they are considered part of +the value of the capability. They are special only when the string +value is processed by `tputs', `tparam' or `tgoto'. By contrast, `\' +and `^' are considered part of the syntax for specifying the characters +in the string. + + Let's look at the VT52 example again: + + dw|vt52|DEC vt52:\ + :cr=^M:do=^J:nl=^J:bl=^G:\ + :le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:\ + :cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:ta=^I:pt:sr=\EI:up=\EA:\ + :ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: + + Here we see the numeric-valued capabilities `co' and `li', the flags +`bs' and `pt', and many string-valued capabilities. Most of the +strings start with ESC represented as `\E'. The rest contain control +characters represented using `^'. The meanings of the individual +capabilities are defined elsewhere (*note Capabilities::.). + diff --git a/lib/termcap/grot/termcap.info-2 b/lib/termcap/grot/termcap.info-2 new file mode 100644 index 0000000..7142dc8 --- /dev/null +++ b/lib/termcap/grot/termcap.info-2 @@ -0,0 +1,969 @@ +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 file documents the termcap library of the GNU system. + + Copyright (C) 1988 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: termcap.info, Node: Naming, Next: Inheriting, Prev: Capability Format, Up: Data Base + +Terminal Type Name Conventions +============================== + + There are conventions for choosing names of terminal types. For one +thing, all letters should be in lower case. The terminal type for a +terminal in its most usual or most fundamental mode of operation should +not have a hyphen in it. + + If the same terminal has other modes of operation which require +different terminal descriptions, these variant descriptions are given +names made by adding suffixes with hyphens. Such alternate descriptions +are used for two reasons: + + * When the terminal has a switch that changes its behavior. Since + the computer cannot tell how the switch is set, the user must tell + the computer by choosing the appropriate terminal type name. + + For example, the VT-100 has a setup flag that controls whether the + cursor wraps at the right margin. If this flag is set to "wrap", + you must use the terminal type `vt100-am'. Otherwise you must use + `vt100-nam'. Plain `vt100' is defined as a synonym for either + `vt100-am' or `vt100-nam' depending on the preferences of the + local site. + + The standard suffix `-am' stands for "automatic margins". + + * To give the user a choice in how to use the terminal. This is done + when the terminal has a switch that the computer normally controls. + + For example, the Ann Arbor Ambassador can be configured with many + screen sizes ranging from 20 to 60 lines. Fewer lines make bigger + characters but more lines let you see more of what you are editing. + As a result, users have different preferences. Therefore, termcap + provides terminal types for many screen sizes. If you choose type + `aaa-30', the terminal will be configured to use 30 lines; if you + choose `aaa-48', 48 lines will be used, and so on. + + Here is a list of standard suffixes and their conventional meanings: + +`-w' + Short for "wide". This is a mode that gives the terminal more + columns than usual. This is normally a user option. + +`-am' + "Automatic margins". This is an alternate description for use when + the terminal's margin-wrap switch is on; it contains the `am' + flag. The implication is that normally the switch is off and the + usual description for the terminal says that the switch is off. + +`-nam' + "No automatic margins". The opposite of `-am', this names an + alternative description which lacks the `am' flag. This implies + that the terminal is normally operated with the margin-wrap switch + turned on, and the normal description of the terminal says so. + +`-na' + "No arrows". This terminal description initializes the terminal to + keep its arrow keys in local mode. This is a user option. + +`-rv' + "Reverse video". This terminal description causes text output for + normal video to appear as reverse, and text output for reverse + video to come out as normal. Often this description differs from + the usual one by interchanging the two strings which turn reverse + video on and off. + + This is a user option; you can choose either the "reverse video" + variant terminal type or the normal terminal type, and termcap will + obey. + +`-s' + "Status". Says to enable use of a status line which ordinary + output does not touch (*note Status Line::.). + + Some terminals have a special line that is used only as a status + line. For these terminals, there is no need for an `-s' variant; + the status line commands should be defined by default. On other + terminals, enabling a status line means removing one screen line + from ordinary use and reducing the effective screen height. For + these terminals, the user can choose the `-s' variant type to + request use of a status line. + +`-NLINES' + Says to operate with NLINES lines on the screen, for terminals + such as the Ambassador which provide this as an option. Normally + this is a user option; by choosing the terminal type, you control + how many lines termcap will use. + +`-NPAGESp' + Says that the terminal has NPAGES pages worth of screen memory, + for terminals where this is a hardware option. + +`-unk' + Says that description is not for direct use, but only for + reference in `tc' capabilities. Such a description is a kind of + subroutine, because it describes the common characteristics of + several variant descriptions that would use other suffixes in + place of `-unk'. + + +File: termcap.info, Node: Inheriting, Next: Changing, Prev: Naming, Up: Data Base + +Inheriting from Related Descriptions +==================================== + + When two terminal descriptions are similar, their identical parts do +not need to be given twice. Instead, one of the two can be defined in +terms of the other, using the `tc' capability. We say that one +description "refers to" the other, or "inherits from" the other. + + The `tc' capability must be the last one in the terminal description, +and its value is a string which is the name of another terminal type +which is referred to. For example, + + N9|aaa|ambassador|aaa-30|ann arbor ambassador/30 lines:\ + :ti=\E[2J\E[30;0;0;30p:\ + :te=\E[60;0;0;30p\E[30;1H\E[J:\ + :li#30:tc=aaa-unk: + +defines the terminal type `aaa-30' (also known as plain `aaa') in terms +of `aaa-unk', which defines everything about the Ambassador that is +independent of screen height. The types `aaa-36', `aaa-48' and so on +for other screen heights are likewise defined to inherit from `aaa-unk'. + + The capabilities overridden by `aaa-30' include `li', which says how +many lines there are, and `ti' and `te', which configure the terminal +to use that many lines. + + The effective terminal description for type `aaa' consists of the +text shown above followed by the text of the description of `aaa-unk'. +The `tc' capability is handled automatically by `tgetent', which finds +the description thus referenced and combines the two descriptions +(*note Find::.). Therefore, only the implementor of the terminal +descriptions needs to think about using `tc'. Users and application +programmers do not need to be concerned with it. + + Since the reference terminal description is used last, capabilities +specified in the referring description override any specifications of +the same capabilities in the reference description. + + The referring description can cancel out a capability without +specifying any new value for it by means of a special trick. Write the +capability in the referring description, with the character `@' after +the capability name, as follows: + + NZ|aaa-30-nam|ann arbor ambassador/30 lines/no automatic-margins:\ + :am@:tc=aaa-30: + + +File: termcap.info, Node: Changing, Prev: Inheriting, Up: Data Base + +When Changes in the Data Base Take Effect +========================================= + + Each application program must read the terminal description from the +data base, so a change in the data base is effective for all jobs +started after the change is made. + + The change will usually have no effect on a job that have been in +existence since before the change. The program probably read the +terminal description once, when it was started, and is continuing to +use what it read then. If the program does not have a feature for +reexamining the data base, then you will need to run it again (probably +killing the old job). + + If the description in use is coming from the `TERMCAP' environment +variable, then the data base file is effectively overridden, and +changes in it will have no effect until you change the `TERMCAP' +variable as well. For example, some users' `.login' files +automatically copy the terminal description into `TERMCAP' to speed +startup of applications. If you have done this, you will need to +change the `TERMCAP' variable to make the changed data base take effect. + + +File: termcap.info, Node: Capabilities, Next: Summary, Prev: Data Base, Up: Top + +Definitions of the Terminal Capabilities +**************************************** + + This section is divided into many subsections, each for one aspect of +use of display terminals. For writing a display program, you usually +need only check the subsections for the operations you want to use. +For writing a terminal description, you must read each subsection and +fill in the capabilities described there. + + String capabilities that are display commands may require numeric +parameters (*note Parameters::.). Most such capabilities do not use +parameters. When a capability requires parameters, this is explicitly +stated at the beginning of its definition. In simple cases, the first +or second sentence of the definition mentions all the parameters, in +the order they should be given, using a name in upper case for each +one. For example, the `rp' capability is a command that requires two +parameters; its definition begins as follows: + + String of commands to output a graphic character C, repeated N + times. + + In complex cases or when there are many parameters, they are +described explicitly. + + When a capability is described as obsolete, this means that programs +should not be written to look for it, but terminal descriptions should +still be written to provide it. + + When a capability is described as very obsolete, this means that it +should be omitted from terminal descriptions as well. + +* Menu: + +* Basic:: Basic characteristics. +* Screen Size:: Screen size, and what happens when it changes. +* Cursor Motion:: Various ways to move the cursor. +* Wrapping:: What happens if you write a character in the last column. +* Scrolling:: Pushing text up and down on the screen. +* Windows:: Limiting the part of the window that output affects. +* Clearing:: Erasing one or many lines. +* Insdel Line:: Making new blank lines in mid-screen; deleting lines. +* Insdel Char:: Inserting and deleting characters within a line. +* Standout:: Highlighting some of the text. +* Underlining:: Underlining some of the text. +* Cursor Visibility:: Making the cursor more or less easy to spot. +* Bell:: Attracts user's attention; not localized on the screen. +* Keypad:: Recognizing when function keys or arrows are typed. +* Meta Key:: META acts like an extra shift key. +* Initialization:: Commands used to initialize or reset the terminal. +* Pad Specs:: Info for the kernel on how much padding is needed. +* Status Line:: A status line displays "background" information. +* Half-Line:: Moving by half-lines, for superscripts and subscripts. +* Printer:: Controlling auxiliary printers of display terminals. + + +File: termcap.info, Node: Basic, Next: Screen Size, Up: Capabilities + +Basic Characteristics +===================== + + This section documents the capabilities that describe the basic and +nature of the terminal, and also those that are relevant to the output +of graphic characters. + +`os' + Flag whose presence means that the terminal can overstrike. This + means that outputting a graphic character does not erase whatever + was present in the same character position before. The terminals + that can overstrike include printing terminals, storage tubes (all + obsolete nowadays), and many bit-map displays. + +`eo' + Flag whose presence means that outputting a space erases a + character position even if the terminal supports overstriking. If + this flag is not present and overstriking is supported, output of + a space has no effect except to move the cursor. + + (On terminals that do not support overstriking, you can always + assume that outputting a space at a position erases whatever + character was previously displayed there.) + +`gn' + Flag whose presence means that this terminal type is a generic type + which does not really describe any particular terminal. Generic + types are intended for use as the default type assigned when the + user connects to the system, with the intention that the user + should specify what type he really has. One example of a generic + type is the type `network'. + + Since the generic type cannot say how to do anything interesting + with the terminal, termcap-using programs will always find that the + terminal is too weak to be supported if the user has failed to + specify a real terminal type in place of the generic one. The + `gn' flag directs these programs to use a different error message: + "You have not specified your real terminal type", rather than + "Your terminal is not powerful enough to be used". + +`hc' + Flag whose presence means this is a hardcopy terminal. + +`rp' + String of commands to output a graphic character C, repeated N + times. The first parameter value is the ASCII code for the desired + character, and the second parameter is the number of times to + repeat the character. Often this command requires padding + proportional to the number of times the character is repeated. + This effect can be had by using parameter arithmetic with + `%'-sequences to compute the amount of padding, then generating + the result as a number at the front of the string so that `tputs' + will treat it as padding. + +`hz' + Flag whose presence means that the ASCII character `~' cannot be + output on this terminal because it is used for display commands. + + Programs handle this flag by checking all text to be output and + replacing each `~' with some other character(s). If this is not + done, the screen will be thoroughly garbled. + + The old Hazeltine terminals that required such treatment are + probably very rare today, so you might as well not bother to + support this flag. + +`CC' + String whose presence means the terminal has a settable command + character. The value of the string is the default command + character (which is usually ESC). + + All the strings of commands in the terminal description should be + written to use the default command character. If you are writing + an application program that changes the command character, use the + `CC' capability to figure out how to translate all the display + commands to work with the new command character. + + Most programs have no reason to look at the `CC' capability. + +`xb' + Flag whose presence identifies Superbee terminals which are unable + to transmit the characters ESC and `Control-C'. Programs which + support this flag are supposed to check the input for the code + sequences sent by the F1 and F2 keys, and pretend that ESC or + `Control-C' (respectively) had been read. But this flag is + obsolete, and not worth supporting. + + +File: termcap.info, Node: Screen Size, Next: Cursor Motion, Prev: Basic, Up: Capabilities + +Screen Size +=========== + + A terminal description has two capabilities, `co' and `li', that +describe the screen size in columns and lines. But there is more to +the question of screen size than this. + + On some operating systems the "screen" is really a window and the +effective width can vary. On some of these systems, `tgetnum' uses the +actual width of the window to decide what value to return for the `co' +capability, overriding what is actually written in the terminal +description. On other systems, it is up to the application program to +check the actual window width using a system call. For example, on BSD +4.3 systems, the system call `ioctl' with code `TIOCGWINSZ' will tell +you the current screen size. + + On all window systems, termcap is powerless to advise the application +program if the user resizes the window. Application programs must deal +with this possibility in a system-dependent fashion. On some systems +the C shell handles part of the problem by detecting changes in window +size and setting the `TERMCAP' environment variable appropriately. +This takes care of application programs that are started subsequently. +It does not help application programs already running. + + On some systems, including BSD 4.3, all programs using a terminal get +a signal named `SIGWINCH' whenever the screen size changes. Programs +that use termcap should handle this signal by using `ioctl TIOCGWINSZ' +to learn the new screen size. + +`co' + Numeric value, the width of the screen in character positions. + Even hardcopy terminals normally have a `co' capability. + +`li' + Numeric value, the height of the screen in lines. + + +File: termcap.info, Node: Cursor Motion, Next: Wrapping, Prev: Screen Size, Up: Capabilities + +Cursor Motion +============= + + Termcap assumes that the terminal has a "cursor", a spot on the +screen where a visible mark is displayed, and that most display +commands take effect at the position of the cursor. It follows that +moving the cursor to a specified location is very important. + + There are many terminal capabilities for different cursor motion +operations. A terminal description should define as many as possible, +but most programs do not need to use most of them. One capability, +`cm', moves the cursor to an arbitrary place on the screen; this by +itself is sufficient for any application as long as there is no need to +support hardcopy terminals or certain old, weak displays that have only +relative motion commands. Use of other cursor motion capabilities is an +optimization, enabling the program to output fewer characters in some +common cases. + + If you plan to use the relative cursor motion commands in an +application program, you must know what the starting cursor position +is. To do this, you must keep track of the cursor position and update +the records each time anything is output to the terminal, including +graphic characters. In addition, it is necessary to know whether the +terminal wraps after writing in the rightmost column. *Note Wrapping::. + + One other motion capability needs special mention: `nw' moves the +cursor to the beginning of the following line, perhaps clearing all the +starting line after the cursor, or perhaps not clearing at all. This +capability is a least common denominator that is probably supported +even by terminals that cannot do most other things such as `cm' or `do'. +Even hardcopy terminals can support `nw'. + +`cm' + String of commands to position the cursor at line L, column C. + Both parameters are origin-zero, and are defined relative to the + screen, not relative to display memory. + + All display terminals except a few very obsolete ones support `cm', + so it is acceptable for an application program to refuse to + operate on terminals lacking `cm'. + +`ho' + String of commands to move the cursor to the upper left corner of + the screen (this position is called the "home position"). In + terminals where the upper left corner of the screen is not the + same as the beginning of display memory, this command must go to + the upper left corner of the screen, not the beginning of display + memory. + + Every display terminal supports this capability, and many + application programs refuse to operate if the `ho' capability is + missing. + +`ll' + String of commands to move the cursor to the lower left corner of + the screen. On some terminals, moving up from home position does + this, but programs should never assume that will work. Just + output the `ll' string (if it is provided); if moving to home + position and then moving up is the best way to get there, the `ll' + command will do that. + +`cr' + String of commands to move the cursor to the beginning of the line + it is on. If this capability is not specified, many programs + assume they can use the ASCII carriage return character for this. + +`le' + String of commands to move the cursor left one column. Unless the + `bw' flag capability is specified, the effect is undefined if the + cursor is at the left margin; do not use this command there. If + `bw' is present, this command may be used at the left margin, and + it wraps the cursor to the last column of the preceding line. + +`nd' + String of commands to move the cursor right one column. The + effect is undefined if the cursor is at the right margin; do not + use this command there, not even if `am' is present. + +`up' + String of commands to move the cursor vertically up one line. The + effect of sending this string when on the top line is undefined; + programs should never use it that way. + +`do' + String of commands to move the cursor vertically down one line. + The effect of sending this string when on the bottom line is + undefined; programs should never use it that way. + + Some programs do use `do' to scroll up one line if used at the + bottom line, if `sf' is not defined but `sr' is. This is only to + compensate for certain old, incorrect terminal descriptions. (In + principle this might actually lead to incorrect behavior on other + terminals, but that seems to happen rarely if ever.) But the + proper solution is that the terminal description should define + `sf' as well as `do' if the command is suitable for scrolling. + + The original idea was that this string would not contain a newline + character and therefore could be used without disabling the + kernel's usual habit of converting of newline into a + carriage-return newline sequence. But many terminal descriptions + do use newline in the `do' string, so this is not possible; a + program which sends the `do' string must disable output conversion + in the kernel (*note Initialize::.). + +`bw' + Flag whose presence says that `le' may be used in column zero to + move to the last column of the preceding line. If this flag is + not present, `le' should not be used in column zero. + +`nw' + String of commands to move the cursor to start of next line, + possibly clearing rest of line (following the cursor) before + moving. + +`DO', `UP', `LE', `RI' + Strings of commands to move the cursor N lines down vertically, up + vertically, or N columns left or right. Do not attempt to move + past any edge of the screen with these commands; the effect of + trying that is undefined. Only a few terminal descriptions provide + these commands, and most programs do not use them. + +`CM' + String of commands to position the cursor at line L, column C, + relative to display memory. Both parameters are origin-zero. + This capability is present only in terminals where there is a + difference between screen-relative and memory-relative addressing, + and not even in all such terminals. + +`ch' + String of commands to position the cursor at column C in the same + line it is on. This is a special case of `cm' in which the + vertical position is not changed. The `ch' capability is provided + only when it is faster to output than `cm' would be in this + special case. Programs should not assume most display terminals + have `ch'. + +`cv' + String of commands to position the cursor at line L in the same + column. This is a special case of `cm' in which the horizontal + position is not changed. The `cv' capability is provided only + when it is faster to output than `cm' would be in this special + case. Programs should not assume most display terminals have `cv'. + +`sc' + String of commands to make the terminal save the current cursor + position. Only the last saved position can be used. If this + capability is present, `rc' should be provided also. Most + terminals have neither. + +`rc' + String of commands to make the terminal restore the last saved + cursor position. If this capability is present, `sc' should be + provided also. Most terminals have neither. + +`ff' + String of commands to advance to the next page, for a hardcopy + terminal. + +`ta' + String of commands to move the cursor right to the next hardware + tab stop column. Missing if the terminal does not have any kind of + hardware tabs. Do not send this command if the kernel's terminal + modes say that the kernel is expanding tabs into spaces. + +`bt' + String of commands to move the cursor left to the previous hardware + tab stop column. Missing if the terminal has no such ability; many + terminals do not. Do not send this command if the kernel's + terminal modes say that the kernel is expanding tabs into spaces. + + The following obsolete capabilities should be included in terminal +descriptions when appropriate, but should not be looked at by new +programs. + +`nc' + Flag whose presence means the terminal does not support the ASCII + carriage return character as `cr'. This flag is needed because + old programs assume, when the `cr' capability is missing, that + ASCII carriage return can be used for the purpose. We use `nc' to + tell the old programs that carriage return may not be used. + + New programs should not assume any default for `cr', so they need + not look at `nc'. However, descriptions should contain `nc' + whenever they do not contain `cr'. + +`xt' + Flag whose presence means that the ASCII tab character may not be + used for cursor motion. This flag exists because old programs + assume, when the `ta' capability is missing, that ASCII tab can be + used for the purpose. We use `xt' to tell the old programs not to + use tab. + + New programs should not assume any default for `ta', so they need + not look at `xt' in connection with cursor motion. Note that `xt' + also has implications for standout mode (*note Standout::.). It + is obsolete in regard to cursor motion but not in regard to + standout. + + In fact, `xt' means that the terminal is a Teleray 1061. + +`bc' + Very obsolete alternative name for the `le' capability. + +`bs' + Flag whose presence means that the ASCII character backspace may be + used to move the cursor left. Obsolete; look at `le' instead. + +`nl' + Obsolete capability which is a string that can either be used to + move the cursor down or to scroll. The same string must scroll + when used on the bottom line and move the cursor when used on any + other line. New programs should use `do' or `sf', and ignore `nl'. + + If there is no `nl' capability, some old programs assume they can + use the newline character for this purpose. These programs follow + a bad practice, but because they exist, it is still desirable to + define the `nl' capability in a terminal description if the best + way to move down is *not* a newline. + + +File: termcap.info, Node: Wrapping, Next: Scrolling, Prev: Cursor Motion, Up: Capabilities + +Wrapping +======== + + "Wrapping" means moving the cursor from the right margin to the left +margin of the following line. Some terminals wrap automatically when a +graphic character is output in the last column, while others do not. +Most application programs that use termcap need to know whether the +terminal wraps. There are two special flag capabilities to describe +what the terminal does when a graphic character is output in the last +column. + +`am' + Flag whose presence means that writing a character in the last + column causes the cursor to wrap to the beginning of the next line. + + If `am' is not present, writing in the last column leaves the + cursor at the place where the character was written. + + Writing in the last column of the last line should be avoided on + terminals with `am', as it may or may not cause scrolling to occur + (*note Scrolling::.). Scrolling is surely not what you would + intend. + + If your program needs to check the `am' flag, then it also needs + to check the `xn' flag which indicates that wrapping happens in a + strange way. Many common terminals have the `xn' flag. + +`xn' + Flag whose presence means that the cursor wraps in a strange way. + At least two distinct kinds of strange behavior are known; the + termcap data base does not contain anything to distinguish the two. + + On Concept-100 terminals, output in the last column wraps the + cursor almost like an ordinary `am' terminal. But if the next + thing output is a newline, it is ignored. + + DEC VT-100 terminals (when the wrap switch is on) do a different + strange thing: the cursor wraps only if the next thing output is + another graphic character. In fact, the wrap occurs when the + following graphic character is received by the terminal, before the + character is placed on the screen. + + On both of these terminals, after writing in the last column a + following graphic character will be displayed in the first column + of the following line. But the effect of relative cursor motion + characters such as newline or backspace at such a time depends on + the terminal. The effect of erase or scrolling commands also + depends on the terminal. You can't assume anything about what + they will do on a terminal that has `xn'. So, to be safe, you + should never do these things at such a time on such a terminal. + + To be sure of reliable results on a terminal which has the `xn' + flag, output a `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. + + +File: termcap.info, Node: Scrolling, Next: Windows, Prev: Wrapping, Up: Capabilities + +Scrolling +========= + + "Scrolling" means moving the contents of the screen up or down one or +more lines. Moving the contents up is "forward scrolling"; moving them +down is "reverse scrolling". + + Scrolling happens after each line of output during ordinary output +on most display terminals. But in an application program that uses +termcap for random-access output, scrolling happens only when +explicitly requested with the commands in this section. + + Some terminals have a "scroll region" feature. This lets you limit +the effect of scrolling to a specified range of lines. Lines outside +the range are unaffected when scrolling happens. The scroll region +feature is available if either `cs' or `cS' is present. + +`sf' + String of commands to scroll the screen one line up, assuming it is + output with the cursor at the beginning of the bottom line. + +`sr' + String of commands to scroll the screen one line down, assuming it + is output with the cursor at the beginning of the top line. + +`do' + A few programs will try to use `do' to do the work of `sf'. This + is not really correct--it is an attempt to compensate for the + absence of a `sf' command in some old terminal descriptions. + + Since these terminal descriptions do define `sr', perhaps at one + time the definition of `do' was different and it could be used for + scrolling as well. But it isn't desirable to combine these two + functions in one capability, since scrolling often requires more + padding than simply moving the cursor down. Defining `sf' and + `do' separately allows you to specify the padding properly. Also, + all sources agree that `do' should not be relied on to do + scrolling. + + So the best approach is to add `sf' capabilities to the + descriptions of these terminals, copying the definition of `do' if + that does scroll. + +`SF' + String of commands to scroll the screen N lines up, assuming it is + output with the cursor at the beginning of the bottom line. + +`SR' + String of commands to scroll the screen N lines down, assuming it + is output with the cursor at the beginning of the top line. + +`cs' + String of commands to set the scroll region. This command takes + two parameters, START and END, which are the line numbers + (origin-zero) of the first line to include in the scroll region + and of the last line to include in it. When a scroll region is + set, scrolling is limited to the specified range of lines; lines + outside the range are not affected by scroll commands. + + Do not try to move the cursor outside the scroll region. The + region remains set until explicitly removed. To remove the scroll + region, use another `cs' command specifying the full height of the + screen. + + The cursor position is undefined after the `cs' command is set, so + position the cursor with `cm' immediately afterward. + +`cS' + String of commands to set the scroll region using parameters in + different form. The effect is the same as if `cs' were used. + Four parameters are required: + + 1. Total number of lines on the screen. + + 2. Number of lines above desired scroll region. + + 3. Number of lines below (outside of) desired scroll region. + + 4. Total number of lines on the screen, the same as the first + parameter. + + This capability is a GNU extension that was invented to allow the + Ann Arbor Ambassador's scroll-region command to be described; it + could also be done by putting non-Unix `%'-sequences into a `cs' + string, but that would have confused Unix programs that used the + `cs' capability with the Unix termcap. Currently only GNU Emacs + uses the `cS' capability. + +`ns' + Flag which means that the terminal does not normally scroll for + ordinary sequential output. For modern terminals, this means that + outputting a newline in ordinary sequential output with the cursor + on the bottom line wraps to the top line. For some obsolete + terminals, other things may happen. + + The terminal may be able to scroll even if it does not normally do + so. If the `sf' capability is provided, it can be used for + scrolling regardless of `ns'. + +`da' + Flag whose presence means that lines scrolled up off the top of the + screen may come back if scrolling down is done subsequently. + + The `da' and `db' flags do not, strictly speaking, affect how to + scroll. But programs that scroll usually need to clear the lines + scrolled onto the screen, if these flags are present. + +`db' + Flag whose presence means that lines scrolled down off the bottom + of the screen may come back if scrolling up is done subsequently. + +`lm' + Numeric value, the number of lines of display memory that the + terminal has. A value of zero means that the terminal has more + display memory than can fit on the screen, but no fixed number of + lines. (The number of lines may depend on the amount of text in + each line.) + + Any terminal description that defines `SF' should also define `sf'; +likewise for `SR' and `sr'. However, many terminals can only scroll by +one line at a time, so it is common to find `sf' and not `SF', or `sr' +without `SR'. + + Therefore, all programs that use the scrolling facilities should be +prepared to work with `sf' in the case that `SF' is absent, and +likewise with `sr'. On the other hand, an application program that +uses only `sf' and not `SF' is acceptable, though slow on some +terminals. + + When outputting a scroll command with `tputs', the NLINES argument +should be the total number of lines in the portion of the screen being +scrolled. Very often these commands require padding proportional to +this number of lines. *Note Padding::. + + +File: termcap.info, Node: Windows, Next: Clearing, Prev: Scrolling, Up: Capabilities + +Windows +======= + + A "window", in termcap, is a rectangular portion of the screen to +which all display operations are restricted. Wrapping, clearing, +scrolling, insertion and deletion all operate as if the specified +window were all the screen there was. + +`wi' + String of commands to set the terminal output screen window. This + string requires four parameters, all origin-zero: + 1. The first line to include in the window. + + 2. The last line to include in the window. + + 3. The first column to include in the window. + + 4. The last column to include in the window. + + Most terminals do not support windows. + + +File: termcap.info, Node: Clearing, Next: Insdel Line, Prev: Windows, Up: Capabilities + +Clearing Parts of the Screen +============================ + + There are several terminal capabilities for clearing parts of the +screen to blank. All display terminals support the `cl' string, and +most display terminals support all of these capabilities. + +`cl' + String of commands to clear the entire screen and position the + cursor at the upper left corner. + +`cd' + String of commands to clear the line the cursor is on, and all the + lines below it, down to the bottom of the screen. This command + string should be used only with the cursor in column zero; their + effect is undefined if the cursor is elsewhere. + +`ce' + String of commands to clear from the cursor to the end of the + current line. + +`ec' + String of commands to clear N characters, starting with the + character that the cursor is on. This command string is expected + to leave the cursor position unchanged. The parameter N should + never be large enough to reach past the right margin; the effect + of such a large parameter would be undefined. + + Clear to end of line (`ce') is extremely important in programs that +maintain an updating display. Nearly all display terminals support this +operation, so it is acceptable for a an application program to refuse to +work if `ce' is not present. However, if you do not want this +limitation, you can accomplish clearing to end of line by outputting +spaces until you reach the right margin. In order to do this, you must +know the current horizontal position. Also, this technique assumes +that writing a space will erase. But this happens to be true on all +the display terminals that fail to support `ce'. + + +File: termcap.info, Node: Insdel Line, Next: Insdel Char, Prev: Clearing, Up: Capabilities + +Insert/Delete Line +================== + + "Inserting a line" means creating a blank line in the middle of the +screen, and pushing the existing lines of text apart. In fact, the +lines above the insertion point do not change, while the lines below +move down, and one is normally lost at the bottom of the screen. + + "Deleting a line" means causing the line to disappear from the +screen, closing up the gap by moving the lines below it upward. A new +line appears at the bottom of the screen. Usually this line is blank, +but on terminals with the `db' flag it may be a line previously moved +off the screen bottom by scrolling or line insertion. + + Insertion and deletion of lines is useful in programs that maintain +an updating display some parts of which may get longer or shorter. +They are also useful in editors for scrolling parts of the screen, and +for redisplaying after lines of text are killed or inserted. + + Many terminals provide commands to insert or delete a single line at +the cursor position. Some provide the ability to insert or delete +several lines with one command, using the number of lines to insert or +delete as a parameter. Always move the cursor to column zero before +using any of these commands. + +`al' + String of commands to insert a blank line before the line the + cursor is on. The existing line, and all lines below it, are + moved down. The last line in the screen (or in the scroll region, + if one is set) disappears and in most circumstances is discarded. + It may not be discarded if the `db' is present (*note + Scrolling::.). + + The cursor must be at the left margin before this command is used. + This command does not move the cursor. + +`dl' + String of commands to delete the line the cursor is on. The + following lines move up, and a blank line appears at the bottom of + the screen (or bottom of the scroll region). If the terminal has + the `db' flag, a nonblank line previously pushed off the screen + bottom may reappear at the bottom. + + The cursor must be at the left margin before this command is used. + This command does not move the cursor. + +`AL' + String of commands to insert N blank lines before the line that + the cursor is on. It is like `al' repeated N times, except that + it is as fast as one `al'. + +`DL' + String of commands to delete N lines starting with the line that + the cursor is on. It is like `dl' repeated N times, except that + it is as fast as one `dl'. + + Any terminal description that defines `AL' should also define `al'; +likewise for `DL' and `dl'. However, many terminals can only insert or +delete one line at a time, so it is common to find `al' and not `AL', +or `dl' without `DL'. + + Therefore, all programs that use the insert and delete facilities +should be prepared to work with `al' in the case that `AL' is absent, +and likewise with `dl'. On the other hand, it is acceptable to write +an application that uses only `al' and `dl' and does not look for `AL' +or `DL' at all. + + If a terminal does not support line insertion and deletion directly, +but does support a scroll region, the effect of insertion and deletion +can be obtained with scrolling. However, it is up to the individual +user program to check for this possibility and use the scrolling +commands to get the desired result. It is fairly important to implement +this alternate strategy, since it is the only way to get the effect of +line insertion and deletion on the popular VT100 terminal. + + Insertion and deletion of lines is affected by the scroll region on +terminals that have a settable scroll region. This is useful when it is +desirable to move any few consecutive lines up or down by a few lines. +*Note Scrolling::. + + The line pushed off the bottom of the screen is not lost if the +terminal has the `db' flag capability; instead, it is pushed into +display memory that does not appear on the screen. This is the same +thing that happens when scrolling pushes a line off the bottom of the +screen. Either reverse scrolling or deletion of a line can bring the +apparently lost line back onto the bottom of the screen. If the +terminal has the scroll region feature as well as `db', the pushed-out +line really is lost if a scroll region is in effect. + + When outputting an insert or delete command with `tputs', the NLINES +argument should be the total number of lines from the cursor to the +bottom of the screen (or scroll region). Very often these commands +require padding proportional to this number of lines. *Note Padding::. + + For `AL' and `DL' the NLINES argument should *not* depend on the +number of lines inserted or deleted; only the total number of lines +affected. This is because it is just as fast to insert two or N lines +with `AL' as to insert one line with `al'. + diff --git a/lib/termcap/grot/termcap.info-3 b/lib/termcap/grot/termcap.info-3 new file mode 100644 index 0000000..c1e6af9 --- /dev/null +++ b/lib/termcap/grot/termcap.info-3 @@ -0,0 +1,1469 @@ +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 file documents the termcap library of the GNU system. + + Copyright (C) 1988 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: termcap.info, Node: Insdel Char, Next: Standout, Prev: Insdel Line, Up: Capabilities + +Insert/Delete Character +======================= + + "Inserting a character" means creating a blank space in the middle +of a line, and pushing the rest of the line rightward. The character +in the rightmost column is lost. + + "Deleting a character" means causing the character to disappear from +the screen, closing up the gap by moving the rest of the line leftward. +A blank space appears in the rightmost column. + + Insertion and deletion of characters is useful in programs that +maintain an updating display some parts of which may get longer or +shorter. It is also useful in editors for redisplaying the results of +editing within a line. + + Many terminals provide commands to insert or delete a single +character at the cursor position. Some provide the ability to insert +or delete several characters with one command, using the number of +characters to insert or delete as a parameter. + + Many terminals provide an insert mode in which outputting a graphic +character has the added effect of inserting a position for that +character. A special command string is used to enter insert mode and +another is used to exit it. The reason for designing a terminal with +an insert mode rather than an insert command is that inserting +character positions is usually followed by writing characters into +them. With insert mode, this is as fast as simply writing the +characters, except for the fixed overhead of entering and leaving +insert mode. However, when the line speed is great enough, padding may +be required for the graphic characters output in insert mode. + + Some terminals require you to enter insert mode and then output a +special command for each position to be inserted. Or they may require +special commands to be output before or after each graphic character to +be inserted. + + Deletion of characters is usually accomplished by a straightforward +command to delete one or several positions; but on some terminals, it +is necessary to enter a special delete mode before using the delete +command, and leave delete mode afterward. Sometimes delete mode and +insert mode are the same mode. + + Some terminals make a distinction between character positions in +which a space character has been output and positions which have been +cleared. On these terminals, the effect of insert or delete character +runs to the first cleared position rather than to the end of the line. +In fact, the effect may run to more than one line if there is no +cleared position to stop the shift on the first line. These terminals +are identified by the `in' flag capability. + + On terminals with the `in' flag, the technique of skipping over +characters that you know were cleared, and then outputting text later +on in the same line, causes later insert and delete character +operations on that line to do nonstandard things. A program that has +any chance of doing this must check for the `in' flag and must be +careful to write explicit space characters into the intermediate +columns when `in' is present. + + A plethora of terminal capabilities are needed to describe all of +this complexity. Here is a list of them all. Following the list, we +present an algorithm for programs to use to take proper account of all +of these capabilities. + +`im' + String of commands to enter insert mode. + + If the terminal has no special insert mode, but it can insert + characters with a special command, `im' should be defined with a + null value, because the `vi' editor assumes that insertion of a + character is impossible if `im' is not provided. + + New programs should not act like `vi'. They should pay attention + to `im' only if it is defined. + +`ei' + String of commands to leave insert mode. This capability must be + present if `im' is. + + On a few old terminals the same string is used to enter and exit + insert mode. This string turns insert mode on if it was off, and + off it it was on. You can tell these terminals because the `ei' + string equals the `im' string. If you want to support these + terminals, you must always remember accurately whether insert mode + is in effect. However, these terminals are obsolete, and it is + reasonable to refuse to support them. On all modern terminals, you + can safely output `ei' at any time to ensure that insert mode is + turned off. + +`ic' + String of commands to insert one character position at the cursor. + The cursor does not move. + + If outputting a graphic character while in insert mode is + sufficient to insert the character, then the `ic' capability + should be defined with a null value. + + If your terminal offers a choice of ways to insert--either use + insert mode or use a special command--then define `im' and do not + define `ic', since this gives the most efficient operation when + several characters are to be inserted. *Do not* define both + strings, for that means that *both* must be used each time + insertion is done. + +`ip' + String of commands to output following an inserted graphic + character in insert mode. Often it is used just for a padding + spec, when padding is needed after an inserted character (*note + Padding::.). + +`IC' + String of commands to insert N character positions at and after + the cursor. It has the same effect as repeating the `ic' string + and a space, N times. + + If `IC' is provided, application programs may use it without first + entering insert mode. + +`mi' + Flag whose presence means it is safe to move the cursor while in + insert mode and assume the terminal remains in insert mode. + +`in' + Flag whose presence means that the terminal distinguishes between + character positions in which space characters have been output and + positions which have been cleared. + + 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. + + To insert N blank character positions, move the cursor to the place +to insert them and follow this algorithm: + + 1. If an `IC' string is provided, output it with parameter N and you + are finished. Otherwise (or if you don't want to bother to look + for an `IC' string) follow the remaining steps. + + 2. Output the `im' string, if there is one, unless the terminal is + already in insert mode. + + 3. Repeat steps 4 through 6, N times. + + 4. Output the `ic' string if any. + + 5. Output a space. + + 6. Output the `ip' string if any. + + 7. Output the `ei' string, eventually, to exit insert mode. There is + no need to do this right away. If the `mi' flag is present, you + can move the cursor and the cursor will remain in insert mode; + then you can do more insertion elsewhere without reentering insert + mode. + + To insert N graphic characters, position the cursor and follow this +algorithm: + + 1. If an `IC' string is provided, output it with parameter N, then + output the graphic characters, and you are finished. Otherwise + (or if you don't want to bother to look for an `IC' string) follow + the remaining steps. + + 2. Output the `im' string, if there is one, unless the terminal is + already in insert mode. + + 3. For each character to be output, repeat steps 4 through 6. + + 4. Output the `ic' string if any. + + 5. Output the next graphic character. + + 6. Output the `ip' string if any. + + 7. Output the `ei' string, eventually, to exit insert mode. There is + no need to do this right away. If the `mi' flag is present, you + can move the cursor and the cursor will remain in insert mode; + then you can do more insertion elsewhere without reentering insert + mode. + + Note that this is not the same as the original Unix termcap +specifications in one respect: it assumes that the `IC' string can be +used without entering insert mode. This is true as far as I know, and +it allows you be able to avoid entering and leaving insert mode, and +also to be able to avoid the inserted-character padding after the +characters that go into the inserted positions. + + Deletion of characters is less complicated; deleting one column is +done by outputting the `dc' string. However, there may be a delete +mode that must be entered with `dm' in order to make `dc' work. + +`dc' + String of commands to delete one character position at the cursor. + If `dc' is not present, the terminal cannot delete characters. + +`DC' + String of commands to delete N characters starting at the cursor. + It has the same effect as repeating the `dc' string N times. Any + terminal description that has `DC' also has `dc'. + +`dm' + String of commands to enter delete mode. If not present, there is + no delete mode, and `dc' can be used at any time (assuming there is + a `dc'). + +`ed' + String of commands to exit delete mode. This must be present if + `dm' is. + + To delete N character positions, position the cursor and follow these +steps: + + 1. If the `DC' string is present, output it with parameter N and you + are finished. Otherwise, follow the remaining steps. + + 2. Output the `dm' string, unless you know the terminal is already in + delete mode. + + 3. Output the `dc' string N times. + + 4. Output the `ed' string eventually. If the flag capability `mi' is + present, you can move the cursor and do more deletion without + leaving and reentering delete mode. + + As with the `IC' string, we have departed from the original termcap +specifications by assuming that `DC' works without entering delete mode +even though `dc' would not. + + If the `dm' and `im' capabilities are both present and have the same +value, it means that the terminal has one mode for both insertion and +deletion. It is useful for a program to know this, because then it can +do insertions after deletions, or vice versa, without leaving +insert/delete mode and reentering it. + + +File: termcap.info, Node: Standout, Next: Underlining, Prev: Insdel Char, Up: Capabilities + +Standout and Appearance Modes +============================= + + "Appearance modes" are modifications to the ways characters are +displayed. Typical appearance modes include reverse video, dim, bright, +blinking, underlined, invisible, and alternate character set. Each +kind of terminal supports various among these, or perhaps none. + + For each type of terminal, one appearance mode or combination of +them that looks good for highlighted text is chosen as the "standout +mode". The capabilities `so' and `se' say how to enter and leave +standout mode. Programs that use appearance modes only to highlight +some text generally use the standout mode so that they can work on as +many terminals as possible. Use of specific appearance modes other +than "underlined" and "alternate character set" is rare. + + Terminals that implement appearance modes fall into two general +classes as to how they do it. + + In some terminals, the presence or absence of any appearance mode is +recorded separately for each character position. In these terminals, +each graphic character written is given the appearance modes current at +the time it is written, and keeps those modes until it is erased or +overwritten. There are special commands to turn the appearance modes +on or off for characters to be written in the future. + + In other terminals, the change of appearance modes is represented by +a marker that belongs to a certain screen position but affects all +following screen positions until the next marker. These markers are +traditionally called "magic cookies". + + The same capabilities (`so', `se', `mb' and so on) for turning +appearance modes on and off are used for both magic-cookie terminals +and per-character terminals. On magic cookie terminals, these give the +commands to write the magic cookies. On per-character terminals, they +change the current modes that affect future output and erasure. Some +simple applications can use these commands without knowing whether or +not they work by means of cookies. + + However, a program that maintains and updates a display needs to know +whether the terminal uses magic cookies, and exactly what their effect +is. This information comes from the `sg' capability. + + The `sg' capability is a numeric capability whose presence indicates +that the terminal uses magic cookies for appearance modes. Its value is +the number of character positions that a magic cookie occupies. Usually +the cookie occupies one or more character positions on the screen, and +these character positions are displayed as blank, but in some terminals +the cookie has zero width. + + The `sg' capability describes both the magic cookie to turn standout +on and the cookie to turn it off. This makes the assumption that both +kinds of cookie have the same width on the screen. If that is not true, +the narrower cookie must be "widened" with spaces until it has the same +width as the other. + + On some magic cookie terminals, each line always starts with normal +display; in other words, the scope of a magic cookie never extends over +more than one line. But on other terminals, one magic cookie affects +all the lines below it unless explicitly canceled. Termcap does not +define any way to distinguish these two ways magic cookies can work. +To be safe, it is best to put a cookie at the beginning of each line. + + On some per-character terminals, standout mode or other appearance +modes may be canceled by moving the cursor. On others, moving the +cursor has no effect on the state of the appearance modes. The latter +class of terminals are given the flag capability `ms' ("can move in +standout"). All programs that might have occasion to move the cursor +while appearance modes are turned on must check for this flag; if it is +not present, they should reset appearance modes to normal before doing +cursor motion. + + A program that has turned on only standout mode should use `se' to +reset the standout mode to normal. A program that has turned on only +alternate character set mode should use `ae' to return it to normal. +If it is possible that any other appearance modes are turned on, use the +`me' capability to return them to normal. + + Note that the commands to turn on one appearance mode, including `so' +and `mb' ... `mr', if used while some other appearance modes are turned +on, may combine the two modes on some terminals but may turn off the +mode previously enabled on other terminals. This is because some +terminals do not have a command to set or clear one appearance mode +without changing the others. Programs should not attempt to use +appearance modes in combination except with `sa', and when switching +from one single mode to another should always turn off the previously +enabled mode and then turn on the new desired mode. + + On some old terminals, the `so' and `se' commands may be the same +command, which has the effect of turning standout on if it is off, or +off it is on. It is therefore risky for a program to output extra `se' +commands for good measure. Fortunately, all these terminals are +obsolete. + + Programs that update displays in which standout-text may be replaced +with non-standout text must check for the `xs' flag. In a per-character +terminal, this flag says that the only way to remove standout once +written is to clear that portion of the line with the `ce' string or +something even more powerful (*note Clearing::.); just writing new +characters at those screen positions will not change the modes in +effect there. In a magic cookie terminal, `xs' says that the only way +to remove a cookie is to clear a portion of the line that includes the +cookie; writing a different cookie at the same position does not work. + + Such programs must also check for the `xt' flag, which means that the +terminal is a Teleray 1061. On this terminal it is impossible to +position the cursor at the front of a magic cookie, so the only two +ways to remove a cookie are (1) to delete the line it is on or (2) to +position the cursor at least one character before it (possibly on a +previous line) and output the `se' string, which on these terminals +finds and removes the next `so' magic cookie on the screen. (It may +also be possible to remove a cookie which is not at the beginning of a +line by clearing that line.) The `xt' capability also has implications +for the use of tab characters, but in that regard it is obsolete (*Note +Cursor Motion::). + +`so' + String of commands to enter standout mode. + +`se' + String of commands to leave standout mode. + +`sg' + Numeric capability, the width on the screen of the magic cookie. + This capability is absent in terminals that record appearance modes + character by character. + +`ms' + Flag whose presence means that it is safe to move the cursor while + the appearance modes are not in the normal state. If this flag is + absent, programs should always reset the appearance modes to + normal before moving the cursor. + +`xs' + Flag whose presence means that the only way to reset appearance + modes already on the screen is to clear to end of line. On a + per-character terminal, you must clear the area where the modes + are set. On a magic cookie terminal, you must clear an area + containing the cookie. See the discussion above. + +`xt' + Flag whose presence means that the cursor cannot be positioned + right in front of a magic cookie, and that `se' is a command to + delete the next magic cookie following the cursor. See discussion + above. + +`mb' + String of commands to enter blinking mode. + +`md' + String of commands to enter double-bright mode. + +`mh' + String of commands to enter half-bright mode. + +`mk' + String of commands to enter invisible mode. + +`mp' + String of commands to enter protected mode. + +`mr' + String of commands to enter reverse-video mode. + +`me' + String of commands to turn off all appearance modes, including + standout mode and underline mode. On some terminals it also turns + off alternate character set mode; on others, it may not. This + capability must be present if any of `mb' ... `mr' is present. + +`as' + String of commands to turn on alternate character set mode. This + mode assigns some or all graphic characters an alternate picture + on the screen. There is no standard as to what the alternate + pictures look like. + +`ae' + String of commands to turn off alternate character set mode. + +`sa' + String of commands to turn on an arbitrary combination of + appearance modes. It accepts 9 parameters, each of which controls + a particular kind of appearance mode. A parameter should be 1 to + turn its appearance mode on, or zero to turn that mode off. Most + terminals do not support the `sa' capability, even among those + that do have various appearance modes. + + The nine parameters are, in order, STANDOUT, UNDERLINE, REVERSE, + BLINK, HALF-BRIGHT, DOUBLE-BRIGHT, BLANK, PROTECT, ALT CHAR SET. + + +File: termcap.info, Node: Underlining, Next: Cursor Visibility, Prev: Standout, Up: Capabilities + +Underlining +=========== + + Underlining on most terminals is a kind of appearance mode, much like +standout mode. Therefore, it may be implemented using magic cookies or +as a flag in the terminal whose current state affects each character +that is output. *Note Standout::, for a full explanation. + + The `ug' capability is a numeric capability whose presence indicates +that the terminal uses magic cookies for underlining. Its value is the +number of character positions that a magic cookie for underlining +occupies; it is used for underlining just as `sg' is used for standout. +Aside from the simplest applications, it is impossible to use +underlining correctly without paying attention to the value of `ug'. + +`us' + String of commands to turn on underline mode or to output a magic + cookie to start underlining. + +`ue' + String of commands to turn off underline mode or to output a magic + cookie to stop underlining. + +`ug' + Width of magic cookie that represents a change of underline mode; + or missing, if the terminal does not use a magic cookie for this. + +`ms' + Flag whose presence means that it is safe to move the cursor while + the appearance modes are not in the normal state. Underlining is + an appearance mode. If this flag is absent, programs should + always turn off underlining before moving the cursor. + + There are two other, older ways of doing underlining: there can be a +command to underline a single character, or the output of `_', the +ASCII underscore character, as an overstrike could cause a character to +be underlined. New programs need not bother to handle these +capabilities unless the author cares strongly about the obscure +terminals which support them. However, terminal descriptions should +provide these capabilities when appropriate. + +`uc' + String of commands to underline the character under the cursor, and + move the cursor right. + +`ul' + Flag whose presence means that the terminal can underline by + overstriking an underscore character (`_'); some terminals can do + this even though they do not support overstriking in general. An + implication of this flag is that when outputting new text to + overwrite old text, underscore characters must be treated + specially lest they underline the old text instead. + + +File: termcap.info, Node: Cursor Visibility, Next: Bell, Prev: Underlining, Up: Capabilities + +Cursor Visibility +================= + + Some terminals have the ability to make the cursor invisible, or to +enhance it. Enhancing the cursor is often done by programs that plan +to use the cursor to indicate to the user a position of interest that +may be anywhere on the screen--for example, the Emacs editor enhances +the cursor on entry. Such programs should always restore the cursor to +normal on exit. + +`vs' + String of commands to enhance the cursor. + +`vi' + String of commands to make the cursor invisible. + +`ve' + String of commands to return the cursor to normal. + + If you define either `vs' or `vi', you must also define `ve'. + + +File: termcap.info, Node: Bell, Next: Keypad, Prev: Cursor Visibility, Up: Capabilities + +Bell +==== + + Here we describe commands to make the terminal ask for the user to +pay attention to it. + +`bl' + String of commands to cause the terminal to make an audible sound. + If this capability is absent, the terminal has no way to make a + suitable sound. + +`vb' + String of commands to cause the screen to flash to attract + attention ("visible bell"). If this capability is absent, the + terminal has no way to do such a thing. + + +File: termcap.info, Node: Keypad, Next: Meta Key, Prev: Bell, Up: Capabilities + +Keypad and Function Keys +======================== + + Many terminals have arrow and function keys that transmit specific +character sequences to the computer. Since the precise sequences used +depend on the terminal, termcap defines capabilities used to say what +the sequences are. Unlike most termcap string-valued capabilities, +these are not strings of commands to be sent to the terminal, rather +strings that are received from the terminal. + + Programs that expect to use keypad keys should check, initially, for +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 + capability is not provided, but the others in this section are, + programs may assume that the function keys always transmit. + +`ke' + String of commands to make the function keys work locally. This + capability is provided only if `ks' is. + +`kl' + String of input characters sent by typing the left-arrow key. If + this capability is missing, you cannot expect the terminal to have + a left-arrow key that transmits anything to the computer. + +`kr' + String of input characters sent by typing the right-arrow key. + +`ku' + String of input characters sent by typing the up-arrow key. + +`kd' + String of input characters sent by typing the down-arrow key. + +`kh' + String of input characters sent by typing the "home-position" key. + +`K1' ... `K5' + Strings of input characters sent by the five other keys in a 3-by-3 + array that includes the arrow keys, if the keyboard has such a + 3-by-3 array. Note that one of these keys may be the + "home-position" key, in which case one of these capabilities will + have the same value as the `kh' key. + +`k0' + String of input characters sent by function key 10 (or 0, if the + terminal has one labeled 0). + +`k1' ... `k9' + Strings of input characters sent by function keys 1 through 9, + provided for those function keys that exist. + +`kn' + Number: the number of numbered function keys, if there are more + than 10. + +`l0' ... `l9' + Strings which are the labels appearing on the keyboard on the keys + described by the capabilities `k0' ... `l9'. These capabilities + should be left undefined if the labels are `f0' or `f10' and `f1' + ... `f9'. + +`kH' + String of input characters sent by the "home down" key, if there is + one. + +`kb' + String of input characters sent by the "backspace" key, if there is + one. + +`ka' + String of input characters sent by the "clear all tabs" key, if + there is one. + +`kt' + String of input characters sent by the "clear tab stop this column" + key, if there is one. + +`kC' + String of input characters sent by the "clear screen" key, if + there is one. + +`kD' + String of input characters sent by the "delete character" key, if + there is one. + +`kL' + String of input characters sent by the "delete line" key, if there + is one. + +`kM' + String of input characters sent by the "exit insert mode" key, if + there is one. + +`kE' + String of input characters sent by the "clear to end of line" key, + if there is one. + +`kS' + String of input characters sent by the "clear to end of screen" + key, if there is one. + +`kI' + String of input characters sent by the "insert character" or "enter + insert mode" key, if there is one. + +`kA' + String of input characters sent by the "insert line" key, if there + is one. + +`kN' + String of input characters sent by the "next page" key, if there is + one. + +`kP' + String of input characters sent by the "previous page" key, if + there is one. + +`kF' + String of input characters sent by the "scroll forward" key, if + there is one. + +`kR' + String of input characters sent by the "scroll reverse" key, if + there is one. + +`kT' + String of input characters sent by the "set tab stop in this + column" key, if there is one. + +`ko' + String listing the other function keys the terminal has. This is a + very obsolete way of describing the same information found in the + `kH' ... `kT' keys. The string contains a list of two-character + termcap capability names, separated by commas. The meaning is + that for each capability name listed, the terminal has a key which + sends the string which is the value of that capability. For + example, the value `:ko=cl,ll,sf,sr:' says that the terminal has + four function keys which mean "clear screen", "home down", "scroll + forward" and "scroll reverse". + + +File: termcap.info, Node: Meta Key, Next: Initialization, Prev: Keypad, Up: Capabilities + +Meta Key +======== + + A Meta key is a key on the keyboard that modifies each character you +type by controlling the 0200 bit. This bit is on if and only if the +Meta key is held down when the character is typed. Characters typed +using the Meta key are called Meta characters. Emacs uses Meta +characters as editing commands. + +`km' + Flag whose presence means that the terminal has a Meta key. + +`mm' + String of commands to enable the functioning of the Meta key. + +`mo' + String of commands to disable the functioning of the Meta key. + + If the terminal has `km' but does not have `mm' and `mo', it means +that the Meta key always functions. If it has `mm' and `mo', it means +that the Meta key can be turned on or off. Send the `mm' string to +turn it on, and the `mo' string to turn it off. I do not know why one +would ever not want it to be on. + + +File: termcap.info, Node: Initialization, Next: Pad Specs, Prev: Meta Key, Up: Capabilities + +Initialization +============== + +`ti' + String of commands to put the terminal into whatever special modes + are needed or appropriate for programs that move the cursor + nonsequentially around the screen. Programs that use termcap to do + full-screen display should output this string when they start up. + +`te' + String of commands to undo what is done by the `ti' string. + Programs that output the `ti' string on entry should output this + string when they exit. + +`is' + String of commands to initialize the terminal for each login + session. + +`if' + String which is the name of a file containing the string of + commands to initialize the terminal for each session of use. + Normally `is' and `if' are not both used. + +`i1' +`i3' + Two more strings of commands to initialize the terminal for each + login session. The `i1' string (if defined) is output before `is' + or `if', and the `i3' string (if defined) is output after. + + The reason for having three separate initialization strings is to + make it easier to define a group of related terminal types with + slightly different initializations. Define two or three of the + strings in the basic type; then the other types can override one + or two of the strings. + +`rs' + String of commands to reset the terminal from any strange mode it + may be in. Normally this includes the `is' string (or other + commands with the same effects) and more. What would go in the + `rs' string but not in the `is' string are annoying or slow + commands to bring the terminal back from strange modes that nobody + would normally use. + +`it' + Numeric value, the initial spacing between hardware tab stop + columns when the terminal is powered up. Programs to initialize + the terminal can use this to decide whether there is a need to set + the tab stops. If the initial width is 8, well and good; if it is + not 8, then the tab stops should be set; if they cannot be set, + the kernel is told to convert tabs to spaces, and other programs + will observe this and do likewise. + +`ct' + String of commands to clear all tab stops. + +`st' + String of commands to set tab stop at current cursor column on all + lines. + + +File: termcap.info, Node: Pad Specs, Next: Status Line, Prev: Initialization, Up: Capabilities + +Padding Capabilities +==================== + + There are two terminal capabilities that exist just to explain the +proper way to obey the padding specifications in all the command string +capabilities. One, `pc', must be obeyed by all termcap-using programs. + +`pb' + Numeric value, the lowest baud rate at which padding is actually + needed. Programs may check this and refrain from doing any + padding at lower speeds. + +`pc' + String of commands for padding. The first character of this + string is to be used as the pad character, instead of using null + characters for padding. If `pc' is not provided, use null + characters. Every program that uses termcap must look up this + capability and use it to set the variable `PC' that is used by + `tputs'. *Note Padding::. + + Some termcap capabilities exist just to specify the amount of +padding that the kernel should give to cursor motion commands used in +ordinary sequential output. + +`dC' + Numeric value, the number of msec of padding needed for the + carriage-return character. + +`dN' + Numeric value, the number of msec of padding needed for the newline + (linefeed) character. + +`dB' + Numeric value, the number of msec of padding needed for the + backspace character. + +`dF' + Numeric value, the number of msec of padding needed for the + formfeed character. + +`dT' + Numeric value, the number of msec of padding needed for the tab + character. + + In some systems, the kernel uses the above capabilities; in other +systems, the kernel uses the paddings specified in the string +capabilities `cr', `sf', `le', `ff' and `ta'. Descriptions of +terminals which require such padding should contain the `dC' ... `dT' +capabilities and also specify the appropriate padding in the +corresponding string capabilities. Since no modern terminals require +padding for ordinary sequential output, you probably won't need to do +either of these things. + + +File: termcap.info, Node: Status Line, Next: Half-Line, Prev: Pad Specs, Up: Capabilities + +Status Line +=========== + + A "status line" is a line on the terminal that is not used for +ordinary display output but instead used for a special message. The +intended use is for a continuously updated description of what the +user's program is doing, and that is where the name "status line" comes +from, but in fact it could be used for anything. The distinguishing +characteristic of a status line is that ordinary output to the terminal +does not affect it; it changes only if the special status line commands +of this section are used. + +`hs' + Flag whose presence means that the terminal has a status line. If + a terminal description specifies that there is a status line, it + must provide the `ts' and `fs' capabilities. + +`ts' + String of commands to move the terminal cursor into the status + line. Usually these commands must specifically record the old + cursor position for the sake of the `fs' string. + +`fs' + String of commands to move the cursor back from the status line to + its previous position (outside the status line). + +`es' + Flag whose presence means that other display commands work while + writing the status line. In other words, one can clear parts of + it, insert or delete characters, move the cursor within it using + `ch' if there is a `ch' capability, enter and leave standout mode, + and so on. + +`ds' + String of commands to disable the display of the status line. This + may be absent, if there is no way to disable the status line + display. + +`ws' + Numeric value, the width of the status line. If this capability is + absent in a terminal that has a status line, it means the status + line is the same width as the other lines. + + Note that the value of `ws' is sometimes as small as 8. + + +File: termcap.info, Node: Half-Line, Next: Printer, Prev: Status Line, Up: Capabilities + +Half-Line Motion +================ + + Some terminals have commands for moving the cursor vertically by +half-lines, useful for outputting subscripts and superscripts. Mostly +it is hardcopy terminals that have such features. + +`hu' + String of commands to move the cursor up half a line. If the + terminal is a display, it is your responsibility to avoid moving + up past the top line; however, most likely the terminal that + supports this is a hardcopy terminal and there is nothing to be + concerned about. + +`hd' + String of commands to move the cursor down half a line. If the + terminal is a display, it is your responsibility to avoid moving + down past the bottom line, etc. + + +File: termcap.info, Node: Printer, Prev: Half-Line, Up: Capabilities + +Controlling Printers Attached to Terminals +========================================== + + Some terminals have attached hardcopy printer ports. They may be +able to copy the screen contents to the printer; they may also be able +to redirect output to the printer. Termcap does not have anything to +tell the program whether the redirected output appears also on the +screen; it does on some terminals but not all. + +`ps' + String of commands to cause the contents of the screen to be + printed. If it is absent, the screen contents cannot be printed. + +`po' + String of commands to redirect further output to the printer. + +`pf' + String of commands to terminate redirection of output to the + printer. This capability must be present in the description if + `po' is. + +`pO' + String of commands to redirect output to the printer for next N + characters of output, regardless of what they are. Redirection + will end automatically after N characters of further output. Until + then, nothing that is output can end redirection, not even the + `pf' string if there is one. The number N should not be more than + 255. + + One use of this capability is to send non-text byte sequences + (such as bit-maps) to the printer. + + Most terminals with printers do not support all of `ps', `po' and +`pO'; any one or two of them may be supported. To make a program that +can send output to all kinds of printers, it is necessary to check for +all three of these capabilities, choose the most convenient of the ones +that are provided, and use it in its own appropriate fashion. + + +File: termcap.info, Node: Summary, Next: Var Index, Prev: Capabilities, Up: Top + +Summary of Capability Names +*************************** + + Here are all the terminal capability names in alphabetical order +with a brief description of each. For cross references to their +definitions, see the index of capability names (*note Cap Index::.). + +`ae' + String to turn off alternate character set mode. + +`al' + String to insert a blank line before the cursor. + +`AL' + String to insert N blank lines before the cursor. + +`am' + Flag: output to last column wraps cursor to next line. + +`as' + String to turn on alternate character set mode.like. + +`bc' + Very obsolete alternative name for the `le' capability. + +`bl' + String to sound the bell. + +`bs' + Obsolete flag: ASCII backspace may be used for leftward motion. + +`bt' + String to move the cursor left to the previous hardware tab stop + column. + +`bw' + Flag: `le' at left margin wraps to end of previous line. + +`CC' + String to change terminal's command character. + +`cd' + String to clear the line the cursor is on, and following lines. + +`ce' + String to clear from the cursor to the end of the line. + +`ch' + String to position the cursor at column C in the same line. + +`cl' + String to clear the entire screen and put cursor at upper left + corner. + +`cm' + String to position the cursor at line L, column C. + +`CM' + String to position the cursor at line L, column C, relative to + display memory. + +`co' + Number: width of the screen. + +`cr' + String to move cursor sideways to left margin. + +`cs' + String to set the scroll region. + +`cS' + Alternate form of string to set the scroll region. + +`ct' + String to clear all tab stops. + +`cv' + String to position the cursor at line L in the same column. + +`da' + Flag: data scrolled off top of screen may be scrolled back. + +`db' + Flag: data scrolled off bottom of screen may be scrolled back. + +`dB' + Obsolete number: msec of padding needed for the backspace + character. + +`dc' + String to delete one character position at the cursor. + +`dC' + Obsolete number: msec of padding needed for the carriage-return + character. + +`DC' + String to delete N characters starting at the cursor. + +`dF' + Obsolete number: msec of padding needed for the formfeed character. + +`dl' + String to delete the line the cursor is on. + +`DL' + String to delete N lines starting with the cursor's line. + +`dm' + String to enter delete mode. + +`dN' + Obsolete number: msec of padding needed for the newline character. + +`do' + String to move the cursor vertically down one line. + +`DO' + String to move cursor vertically down N lines. + +`ds' + String to disable the display of the status line. + +`dT' + Obsolete number: msec of padding needed for the tab character. + +`ec' + String of commands to clear N characters at cursor. + +`ed' + String to exit delete mode. + +`ei' + String to leave insert mode. + +`eo' + Flag: output of a space can erase an overstrike. + +`es' + Flag: other display commands work while writing the status line. + +`ff' + String to advance to the next page, for a hardcopy terminal. + +`fs' + String to move the cursor back from the status line to its + previous position (outside the status line). + +`gn' + Flag: this terminal type is generic, not real. + +`hc' + Flag: hardcopy terminal. + +`hd' + String to move the cursor down half a line. + +`ho' + String to position cursor at upper left corner. + +`hs' + Flag: the terminal has a status line. + +`hu' + String to move the cursor up half a line. + +`hz' + Flag: terminal cannot accept `~' as output. + +`i1' + String to initialize the terminal for each login session. + +`i3' + String to initialize the terminal for each login session. + +`ic' + String to insert one character position at the cursor. + +`IC' + String to insert N character positions at the cursor. + +`if' + String naming a file of commands to initialize the terminal. + +`im' + String to enter insert mode. + +`in' + Flag: outputting a space is different from moving over empty + positions. + +`ip' + String to output following an inserted character in insert mode. + +`is' + String to initialize the terminal for each login session. + +`it' + Number: initial spacing between hardware tab stop columns. + +`k0' + String of input sent by function key 0 or 10. + +`k1 ... k9' + Strings of input sent by function keys 1 through 9. + +`K1 ... K5' + Strings sent by the five other keys in 3-by-3 array with arrows. + +`ka' + String of input sent by the "clear all tabs" key. + +`kA' + String of input sent by the "insert line" key. + +`kb' + String of input sent by the "backspace" key. + +`kC' + String of input sent by the "clear screen" key. + +`kd' + String of input sent by typing the down-arrow key. + +`kD' + String of input sent by the "delete character" key. + +`ke' + String to make the function keys work locally. + +`kE' + String of input sent by the "clear to end of line" key. + +`kF' + String of input sent by the "scroll forward" key. + +`kh' + String of input sent by typing the "home-position" key. + +`kH' + String of input sent by the "home down" key. + +`kI' + String of input sent by the "insert character" or "enter insert + mode" key. + +`kl' + String of input sent by typing the left-arrow key. + +`kL' + String of input sent by the "delete line" key. + +`km' + Flag: the terminal has a Meta key. + +`kM' + String of input sent by the "exit insert mode" key. + +`kn' + Numeric value, the number of numbered function keys. + +`kN' + String of input sent by the "next page" key. + +`ko' + Very obsolete string listing the terminal's named function keys. + +`kP' + String of input sent by the "previous page" key. + +`kr' + String of input sent by typing the right-arrow key. + +`kR' + String of input sent by the "scroll reverse" key. + +`ks' + String to make the function keys transmit. + +`kS' + String of input sent by the "clear to end of screen" key. + +`kt' + String of input sent by the "clear tab stop this column" key. + +`kT' + String of input sent by the "set tab stop in this column" key. + +`ku' + String of input sent by typing the up-arrow key. + +`l0' + String on keyboard labelling function key 0 or 10. + +`l1 ... l9' + Strings on keyboard labelling function keys 1 through 9. + +`le' + String to move the cursor left one column. + +`LE' + String to move cursor left N columns. + +`li' + Number: height of the screen. + +`ll' + String to position cursor at lower left corner. + +`lm' + Number: lines of display memory. + +`mb' + String to enter blinking mode. + +`md' + String to enter double-bright mode. + +`me' + String to turn off all appearance modes + +`mh' + String to enter half-bright mode. + +`mi' + Flag: cursor motion in insert mode is safe. + +`mk' + String to enter invisible mode. + +`mm' + String to enable the functioning of the Meta key. + +`mo' + String to disable the functioning of the Meta key. + +`mp' + String to enter protected mode. + +`mr' + String to enter reverse-video mode. + +`ms' + Flag: cursor motion in standout mode is safe. + +`nc' + Obsolete flag: do not use ASCII carriage-return on this terminal. + +`nd' + String to move the cursor right one column. + +`nl' + Obsolete alternative name for the `do' and `sf' capabilities. + +`ns' + Flag: the terminal does not normally scroll for sequential output. + +`nw' + String to move to start of next line, possibly clearing rest of + old line. + +`os' + Flag: terminal can overstrike. + +`pb' + Number: the lowest baud rate at which padding is actually needed. + +`pc' + String containing character for padding. + +`pf' + String to terminate redirection of output to the printer. + +`po' + String to redirect further output to the printer. + +`pO' + String to redirect N characters ofoutput to the printer. + +`ps' + String to print the screen on the attached printer. + +`rc' + String to move to last saved cursor position. + +`RI' + String to move cursor right N columns. + +`rp' + String to output character C repeated N times. + +`rs' + String to reset the terminal from any strange modes. + +`sa' + String to turn on an arbitrary combination of appearance modes. + +`sc' + String to save the current cursor position. + +`se' + String to leave standout mode. + +`sf' + String to scroll the screen one line up. + +`SF' + String to scroll the screen N lines up. + +`sg' + Number: width of magic standout cookie. Absent if magic cookies + are not used. + +`so' + String to enter standout mode. + +`sr' + String to scroll the screen one line down. + +`SR' + String to scroll the screen N line down. + +`st' + String to set tab stop at current cursor column on all lines. + programs. + +`ta' + String to move the cursor right to the next hardware tab stop + column. + +`te' + String to return terminal to settings for sequential output. + +`ti' + String to initialize terminal for random cursor motion. + +`ts' + String to move the terminal cursor into the status line. + +`uc' + String to underline one character and move cursor right. + +`ue' + String to turn off underline mode + +`ug' + Number: width of underlining magic cookie. Absent if underlining + doesn't use magic cookies. + +`ul' + Flag: underline by overstriking with an underscore. + +`up' + String to move the cursor vertically up one line. + +`UP' + String to move cursor vertically up N lines. + +`us' + String to turn on underline mode + +`vb' + String to make the screen flash. + +`ve' + String to return the cursor to normal. + +`vi' + String to make the cursor invisible. + +`vs' + String to enhance the cursor. + +`wi' + String to set the terminal output screen window. + +`ws' + Number: the width of the status line. + +`xb' + Flag: superbee terminal. + +`xn' + Flag: cursor wraps in a strange way. + +`xs' + Flag: clearing a line is the only way to clear the appearance + modes of positions in that line (or, only way to remove magic + cookies on that line). + +`xt' + Flag: Teleray 1061; several strange characteristics. + + +File: termcap.info, Node: Var Index, Next: Cap Index, Prev: Summary, Up: Top + +Variable and Function Index +*************************** + +* Menu: + +* BC: tgoto. +* ospeed: Output Padding. +* PC: Output Padding. +* tgetent: Find. +* tgetflag: Interrogate. +* tgetnum: Interrogate. +* tgetstr: Interrogate. +* tgoto: tgoto. +* tparam: tparam. +* tputs: Output Padding. +* UP: tgoto. + diff --git a/lib/termcap/grot/termcap.info-4 b/lib/termcap/grot/termcap.info-4 new file mode 100644 index 0000000..21dd81c --- /dev/null +++ b/lib/termcap/grot/termcap.info-4 @@ -0,0 +1,218 @@ +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 file documents the termcap library of the GNU system. + + Copyright (C) 1988 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: termcap.info, Node: Cap Index, Next: Index, Prev: Var Index, Up: Top + +Capability Index +**************** + +* Menu: + +* ae: Standout. +* AL: Insdel Line. +* al: Insdel Line. +* am: Wrapping. +* as: Standout. +* bc: Cursor Motion. +* bl: Bell. +* bs: Cursor Motion. +* bt: Cursor Motion. +* bw: Cursor Motion. +* CC: Basic. +* cd: Clearing. +* ce: Clearing. +* ch: Cursor Motion. +* cl: Clearing. +* CM: Cursor Motion. +* cm: Cursor Motion. +* co: Screen Size. +* cr: Cursor Motion. +* cS: Scrolling. +* cs: Scrolling. +* ct: Initialization. +* cv: Cursor Motion. +* da: Scrolling. +* dB: Pad Specs. +* db: Scrolling. +* dC: Pad Specs. +* DC: Insdel Char. +* dc: Insdel Char. +* dF: Pad Specs. +* dl: Insdel Line. +* DL: Insdel Line. +* dm: Insdel Char. +* dN: Pad Specs. +* DO: Cursor Motion. +* do: Cursor Motion. +* ds: Status Line. +* dT: Pad Specs. +* ec: Clearing. +* ed: Insdel Char. +* ei: Insdel Char. +* eo: Basic. +* es: Status Line. +* ff: Cursor Motion. +* fs: Status Line. +* gn: Basic. +* hc: Basic. +* hd: Half-Line. +* ho: Cursor Motion. +* hs: Status Line. +* hu: Half-Line. +* hz: Basic. +* i1: Initialization. +* i3: Initialization. +* IC: Insdel Char. +* ic: Insdel Char. +* if: Initialization. +* im: Insdel Char. +* in: Insdel Char. +* ip: Insdel Char. +* is: Initialization. +* it: Initialization. +* K1...K5: Keypad. +* k1...k9: Keypad. +* kA...kT: Keypad. +* ka...ku: Keypad. +* km: Meta Key. +* l0...l9: Keypad. +* le: Cursor Motion. +* LE: Cursor Motion. +* li: Screen Size. +* ll: Cursor Motion. +* lm: Scrolling. +* mb: Standout. +* md: Standout. +* me: Standout. +* mh: Standout. +* mi: Insdel Char. +* mk: Standout. +* mm: Meta Key. +* mo: Meta Key. +* mp: Standout. +* mr: Standout. +* ms: Standout. +* ms: Underlining. +* nc: Cursor Motion. +* nd: Cursor Motion. +* nl: Cursor Motion. +* ns: Scrolling. +* nw: Cursor Motion. +* os: Basic. +* pb: Pad Specs. +* pc: Pad Specs. +* pf: Printer. +* pO: Printer. +* po: Printer. +* ps: Printer. +* rc: Cursor Motion. +* RI: Cursor Motion. +* rp: Basic. +* rs: Initialization. +* sa: Standout. +* sc: Cursor Motion. +* se: Standout. +* sf: Scrolling. +* SF: Scrolling. +* sg: Standout. +* so: Standout. +* sr: Scrolling. +* SR: Scrolling. +* st: Initialization. +* ta: Cursor Motion. +* te: Initialization. +* ti: Initialization. +* ts: Status Line. +* uc: Underlining. +* ue: Underlining. +* ug: Underlining. +* ul: Underlining. +* up: Cursor Motion. +* UP: Cursor Motion. +* us: Underlining. +* vb: Bell. +* ve: Cursor Visibility. +* vi: Cursor Visibility. +* vs: Cursor Visibility. +* wi: Windows. +* ws: Status Line. +* xb: Basic. +* xn: Wrapping. +* xs: Standout. +* xt: Standout. +* xt: Cursor Motion. + + +File: termcap.info, Node: Index, Prev: Cap Index, Up: Top + +Concept Index +************* + +* Menu: + +* %: Encode Parameters. +* appearance modes: Standout. +* bell: Bell. +* clearing the screen: Clearing. +* command character: Basic. +* cursor motion: Cursor Motion. +* delete character: Insdel Char. +* delete line: Insdel Line. +* delete mode: Insdel Char. +* description format: Format. +* erasing: Clearing. +* generic terminal type: Basic. +* home position: Cursor Motion. +* inheritance: Inheriting. +* initialization: Initialization. +* insert character: Insdel Char. +* insert line: Insdel Line. +* insert mode: Insdel Char. +* line speed: Output Padding. +* magic cookie: Standout. +* meta key: Meta Key. +* names of terminal types: Naming. +* overstrike: Basic. +* padding: Pad Specs. +* padding: Padding. +* parameters: Parameters. +* printer: Printer. +* repeat output: Basic. +* reset: Initialization. +* screen size: Screen Size. +* screen size: Screen Size. +* screen size: Naming. +* scrolling: Scrolling. +* standout: Standout. +* status line: Status Line. +* Superbee: Basic. +* tab stops: Initialization. +* termcap: Introduction. +* terminal flags (kernel): Initialize. +* underlining: Underlining. +* visibility: Cursor Visibility. +* visible bell: Bell. +* window: Windows. +* wrapping: Naming. +* wrapping: Wrapping. + + diff --git a/lib/termcap/grot/termcap.texi b/lib/termcap/grot/termcap.texi new file mode 100644 index 0000000..d991838 --- /dev/null +++ b/lib/termcap/grot/termcap.texi @@ -0,0 +1,3603 @@ +\input texinfo @c -*-texinfo-*- +@setfilename termcap +@settitle The Termcap Library +@smallbook + +@ifinfo +This file documents the termcap library of the GNU system. + +Copyright (C) 1988 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 ifinfo + +@setchapternewpage odd + +@c @shorttitlepage The Termcap Manual + +@titlepage +@ignore +@sp 6 +@center @titlefont{Termcap} +@sp 1 +@center The Termcap Library and Data Base +@sp 4 +@center Second Edition +@sp 1 +@center December 1992 +@sp 5 +@center Richard M. Stallman +@sp 1 +@center Free Software Foundation +@end ignore + +@c Real title page +@title The Termcap Manual +@subtitle The Termcap Library and Data Base +@subtitle Second Edition +@subtitle December 1992 +@author Richard M. Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1988 Free Software Foundation, Inc. + +Published by the Free Software Foundation +(675 Mass Ave, Cambridge MA 02139). +Printed copies are available for $10 each. + +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. +@sp 2 +Cover art by Etienne Suvasa. +@end titlepage +@page + +@synindex vr fn + +@node Top, Introduction, (dir), (dir) + +@menu +* Introduction:: What is termcap? Why this manual? +* Library:: The termcap library functions. +* Data Base:: What terminal descriptions in @file{/etc/termcap} look like. +* Capabilities:: Definitions of the individual terminal capabilities: + how to write them in descriptions, and how to use + their values to do display updating. +* Summary:: Brief table of capability names and their meanings. +* Var Index:: Index of C functions and variables. +* Cap Index:: Index of termcap capabilities. +* Index:: Concept index. + + --- The Detailed Node Listing --- + +The Termcap Library + +* Preparation:: Preparing to use the termcap library. +* Find:: Finding the description of the terminal being used. +* Interrogate:: Interrogating the description for particular capabilities. +* Initialize:: Initialization for output using termcap. +* Padding:: Outputting padding. +* Parameters:: Encoding parameters such as cursor positions. + +Padding + +* Why Pad:: Explanation of padding. +* Not Enough:: When there is not enough padding. +* Describe Padding:: The data base says how much padding a terminal needs. +* Output Padding:: Using @code{tputs} to output the needed padding. + +Filling In Parameters + +* Encode Parameters:: The language for encoding parameters. +* Using Parameters:: Outputting a string command with parameters. + +Sending Display Commands with Parameters + +* tparam:: The general case, for GNU termcap only. +* tgoto:: The special case of cursor motion. + +The Format of the Data Base + +* Format:: Overall format of a terminal description. +* Capability Format:: Format of capabilities within a description. +* Naming:: Naming conventions for terminal types. +* Inheriting:: Inheriting part of a description from +a related terminal type. +* Changing:: When changes in the data base take effect. + +Definitions of the Terminal Capabilities + +* Basic:: Basic characteristics. +* Screen Size:: Screen size, and what happens when it changes. +* Cursor Motion:: Various ways to move the cursor. +* Wrapping:: What happens if you write a character in the last column. +* Scrolling:: Pushing text up and down on the screen. +* Windows:: Limiting the part of the window that output affects. +* Clearing:: Erasing one or many lines. +* Insdel Line:: Making new blank lines in mid-screen; deleting lines. +* Insdel Char:: Inserting and deleting characters within a line. +* Standout:: Highlighting some of the text. +* Underlining:: Underlining some of the text. +* Cursor Visibility:: Making the cursor more or less easy to spot. +* Bell:: Attracts user's attention; not localized on the screen. +* Keypad:: Recognizing when function keys or arrows are typed. +* Meta Key:: @key{META} acts like an extra shift key. +* Initialization:: Commands used to initialize or reset the terminal. +* Pad Specs:: Info for the kernel on how much padding is needed. +* Status Line:: A status line displays ``background'' information. +* Half-Line:: Moving by half-lines, for superscripts and subscripts. +* Printer:: Controlling auxiliary printers of display terminals. +@end menu + +@node Introduction, Library, Top, Top +@unnumbered Introduction + +@cindex termcap +@dfn{Termcap} is a library and data base that enables programs to use +display terminals in a terminal-independent manner. It originated in +Berkeley Unix. + +The termcap data base describes the capabilities of hundreds of different +display terminals in great detail. Some examples of the information +recorded for a terminal could include how many columns wide it is, what +string to send to move the cursor to an arbitrary position (including how +to encode the row and column numbers), how to scroll the screen up one or +several lines, and how much padding is needed for such a scrolling +operation. + +The termcap library is provided for easy access this data base in programs +that want to do terminal-independent character-based display output. + +This manual describes the GNU version of the termcap library, which has +some extensions over the Unix version. All the extensions are identified +as such, so this manual also tells you how to use the Unix termcap. + +The GNU version of the termcap library is available free as source code, +for use in free programs, and runs on Unix and VMS systems (at least). You +can find it in the GNU Emacs distribution in the files @file{termcap.c} and +@file{tparam.c}. + +This manual was written for the GNU project, whose goal is to develop a +complete free operating system upward-compatible with Unix for user +programs. The project is approximately two thirds complete. For more +information on the GNU project, including the GNU Emacs editor and the +mostly-portable optimizing C compiler, send one dollar to + +@display +Free Software Foundation +675 Mass Ave +Cambridge, MA 02139 +@end display + +@node Library, Data Base, Introduction, Top +@chapter The Termcap Library + +The termcap library is the application programmer's interface to the +termcap data base. It contains functions for the following purposes: + +@itemize @bullet +@item +Finding the description of the user's terminal type (@code{tgetent}). + +@item +Interrogating the description for information on various topics +(@code{tgetnum}, @code{tgetflag}, @code{tgetstr}). + +@item +Computing and performing padding (@code{tputs}). + +@item +Encoding numeric parameters such as cursor positions into the +terminal-specific form required for display commands (@code{tparam}, +@code{tgoto}). +@end itemize + +@menu +* Preparation:: Preparing to use the termcap library. +* Find:: Finding the description of the terminal being used. +* Interrogate:: Interrogating the description for particular capabilities. +* Initialize:: Initialization for output using termcap. +* Padding:: Outputting padding. +* Parameters:: Encoding parameters such as cursor positions. +@end menu + +@node Preparation, Find, , Library +@section Preparing to Use the Termcap Library + +To use the termcap library in a program, you need two kinds of preparation: + +@itemize @bullet +@item +The compiler needs declarations of the functions and variables in the +library. + +On GNU systems, it suffices to include the header file +@file{termcap.h} in each source file that uses these functions and +variables.@refill + +On Unix systems, there is often no such header file. Then you must +explictly declare the variables as external. You can do likewise for +the functions, or let them be implicitly declared and cast their +values from type @code{int} to the appropriate type. + +We illustrate the declarations of the individual termcap library +functions with ANSI C prototypes because they show how to pass the +arguments. If you are not using the GNU C compiler, you probably +cannot use function prototypes, so omit the argument types and names +from your declarations. + +@item +The linker needs to search the library. Usually either +@samp{-ltermcap} or @samp{-ltermlib} as an argument when linking will +do this.@refill +@end itemize + +@node Find, Interrogate, Preparation, Library +@section Finding a Terminal Description: @code{tgetent} + +@findex tgetent +An application program that is going to use termcap must first look up the +description of the terminal type in use. This is done by calling +@code{tgetent}, whose declaration in ANSI Standard C looks like: + +@example +int tgetent (char *@var{buffer}, char *@var{termtype}); +@end example + +@noindent +This function finds the description and remembers it internally so that +you can interrogate it about specific terminal capabilities +(@pxref{Interrogate}). + +The argument @var{termtype} is a string which is the name for the type of +terminal to look up. Usually you would obtain this from the environment +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 + +With the Unix version of termcap, you must allocate space for the +description yourself and pass the address of the space as the argument +@var{buffer}. There is no way you can tell how much space is needed, so +the convention is to allocate a buffer 2048 characters long and assume that +is enough. (Formerly the convention was to allocate 1024 characters and +assume that was enough. But one day, for one kind of terminal, that was +not enough.) + +No matter how the space to store the description has been obtained, +termcap records its address internally for use when you later interrogate +the description with @code{tgetnum}, @code{tgetstr} or @code{tgetflag}. If +the buffer was allocated by termcap, it will be freed by termcap too if you +call @code{tgetent} again. If the buffer was provided by you, you must +make sure that its contents remain unchanged for as long as you still plan +to interrogate the description.@refill + +The return value of @code{tgetent} is @minus{}1 if there is some difficulty +accessing the data base of terminal types, 0 if the data base is accessible +but the specified type is not defined in it, and some other value +otherwise. + +Here is how you might use the function @code{tgetent}: + +@smallexample +#ifdef unix +static char term_buffer[2048]; +#else +#define term_buffer 0 +#endif + +init_terminal_data () +@{ + char *termtype = getenv ("TERM"); + int success; + + if (termtype == 0) + fatal ("Specify a terminal type with `setenv TERM <yourtype>'.\n"); + + success = tgetent (term_buffer, termtype); + if (success < 0) + fatal ("Could not access the termcap data base.\n"); + if (success == 0) + fatal ("Terminal type `%s' is not defined.\n", termtype); +@} +@end smallexample + +@noindent +Here we assume the function @code{fatal} prints an error message and exits. + +If the environment variable @code{TERMCAP} is defined, its value is used to +override the terminal type data base. The function @code{tgetent} checks +the value of @code{TERMCAP} automatically. If the value starts with +@samp{/} then it is taken as a file name to use as the data base file, +instead of @file{/etc/termcap} which is the standard data base. If the +value does not start with @samp{/} then it is itself used as the terminal +description, provided that the terminal type @var{termtype} is among the +types it claims to apply to. @xref{Data Base}, for information on the +format of a terminal description.@refill + +@node Interrogate, Initialize, Find, Library +@section Interrogating the Terminal Description + +Each piece of information recorded in a terminal description is called a +@dfn{capability}. Each defined terminal capability has a two-letter code +name and a specific meaning. For example, the number of columns is named +@samp{co}. @xref{Capabilities}, for definitions of all the standard +capability names. + +Once you have found the proper terminal description with @code{tgetent} +(@pxref{Find}), your application program must @dfn{interrogate} it for +various terminal capabilities. You must specify the two-letter code of +the capability whose value you seek. + +Capability values can be numeric, boolean (capability is either present or +absent) or strings. Any particular capability always has the same value +type; for example, @samp{co} always has a numeric value, while @samp{am} +(automatic wrap at margin) is always a flag, and @samp{cm} (cursor motion +command) always has a string value. The documentation of each capability +says which type of value it has.@refill + +There are three functions to use to get the value of a capability, +depending on the type of value the capability has. Here are their +declarations in ANSI C: + +@findex tgetnum +@findex tgetflag +@findex tgetstr +@example +int tgetnum (char *@var{name}); +int tgetflag (char *@var{name}); +char *tgetstr (char *@var{name}, char **@var{area}); +@end example + +@table @code +@item tgetnum +Use @code{tgetnum} to get a capability value that is numeric. The +argument @var{name} is the two-letter code name of the capability. If +the capability is present, @code{tgetnum} returns the numeric value +(which is nonnegative). If the capability is not mentioned in the +terminal description, @code{tgetnum} returns @minus{}1. + +@item tgetflag +Use @code{tgetflag} to get a boolean value. If the capability +@var{name} is present in the terminal description, @code{tgetflag} +returns 1; otherwise, it returns 0. + +@item tgetstr +Use @code{tgetstr} to get a string value. It returns a pointer to a +string which is the capability value, or a null pointer if the +capability is not present in the terminal description. + +There are two ways @code{tgetstr} can find space to store the string value: + +@itemize @bullet +@item +You can ask @code{tgetstr} to allocate the space. Pass a null +pointer for the argument @var{area}, and @code{tgetstr} will use +@code{malloc} to allocate storage big enough for the value. +Termcap will never free this storage or refer to it again; you +should free it when you are finished with it. + +This method is more robust, since there is no need to guess how +much space is needed. But it is supported only by the GNU +termcap library. + +@item +You can provide the space. Provide for the argument @var{area} the +address of a pointer variable of type @code{char *}. Before calling +@code{tgetstr}, initialize the variable to point at available space. +Then @code{tgetstr} will store the string value in that space and will +increment the pointer variable to point after the space that has been +used. You can use the same pointer variable for many calls to +@code{tgetstr}. + +There is no way to determine how much space is needed for a single +string, and no way for you to prevent or handle overflow of the area +you have provided. However, you can be sure that the total size of +all the string values you will obtain from the terminal description is +no greater than the size of the description (unless you get the same +capability twice). You can determine that size with @code{strlen} on +the buffer you provided to @code{tgetent}. See below for an example. + +Providing the space yourself is the only method supported by the Unix +version of termcap. +@end itemize +@end table + +Note that you do not have to specify a terminal type or terminal +description for the interrogation functions. They automatically use the +description found by the most recent call to @code{tgetent}. + +Here is an example of interrogating a terminal description for various +capabilities, with conditionals to select between the Unix and GNU methods +of providing buffer space. + +@example +char *tgetstr (); + +char *cl_string, *cm_string; +int height; +int width; +int auto_wrap; + +char PC; /* For tputs. */ +char *BC; /* For tgoto. */ +char *UP; + +interrogate_terminal () +@{ +#ifdef UNIX + /* Here we assume that an explicit term_buffer + was provided to tgetent. */ + char *buffer + = (char *) malloc (strlen (term_buffer)); +#define BUFFADDR &buffer +#else +#define BUFFADDR 0 +#endif + + char *temp; + + /* Extract information we will use. */ + cl_string = tgetstr ("cl", BUFFADDR); + cm_string = tgetstr ("cm", BUFFADDR); + auto_wrap = tgetflag ("am"); + height = tgetnum ("li"); + width = tgetnum ("co"); + + /* Extract information that termcap functions use. */ + temp = tgetstr ("pc", BUFFADDR); + PC = temp ? *temp : 0; + BC = tgetstr ("le", BUFFADDR); + UP = tgetstr ("up", BUFFADDR); +@} +@end example + +@noindent +@xref{Padding}, for information on the variable @code{PC}. @xref{Using +Parameters}, for information on @code{UP} and @code{BC}. + +@node Initialize, Padding, Interrogate, Library +@section Initialization for Use of Termcap +@cindex terminal flags (kernel) + +Before starting to output commands to a terminal using termcap, +an application program should do two things: + +@itemize @bullet +@item +Initialize various global variables which termcap library output +functions refer to. These include @code{PC} and @code{ospeed} for +padding (@pxref{Output Padding}) and @code{UP} and @code{BC} for +cursor motion (@pxref{tgoto}).@refill + +@item +Tell the kernel to turn off alteration and padding of horizontal-tab +characters sent to the terminal. +@end itemize + +To turn off output processing in Berkeley Unix you would use @code{ioctl} +with code @code{TIOCLSET} to set the bit named @code{LLITOUT}, and clear +the bits @code{ANYDELAY} using @code{TIOCSETN}. In POSIX or System V, you +must clear the bit named @code{OPOST}. Refer to the system documentation +for details.@refill + +If you do not set the terminal flags properly, some older terminals will +not work. This is because their commands may contain the characters that +normally signify newline, carriage return and horizontal tab---characters +which the kernel thinks it ought to modify before output. + +When you change the kernel's terminal flags, you must arrange to restore +them to their normal state when your program exits. This implies that the +program must catch fatal signals such as @code{SIGQUIT} and @code{SIGINT} +and restore the old terminal flags before actually terminating. + +Modern terminals' commands do not use these special characters, so if you +do not care about problems with old terminals, you can leave the kernel's +terminal flags unaltered. + +@node Padding, Parameters, Initialize, Library +@section Padding +@cindex padding + +@dfn{Padding} means outputting null characters following a terminal display +command that takes a long time to execute. The terminal description says +which commands require padding and how much; the function @code{tputs}, +described below, outputs a terminal command while extracting from it the +padding information, and then outputs the padding that is necessary. + +@menu +* Why Pad:: Explanation of padding. +* Not Enough:: When there is not enough padding. +* Describe Padding:: The data base says how much padding a terminal needs. +* Output Padding:: Using @code{tputs} to output the needed padding. +@end menu + +@node Why Pad, Not Enough, , Padding +@subsection Why Pad, and How + +Most types of terminal have commands that take longer to execute than they +do to send over a high-speed line. For example, clearing the screen may +take 20msec once the entire command is received. During that time, on a +9600 bps line, the terminal could receive about 20 additional output +characters while still busy clearing the screen. Every terminal has a +certain amount of buffering capacity to remember output characters that +cannot be processed yet, but too many slow commands in a row can cause the +buffer to fill up. Then any additional output that cannot be processed +immediately will be lost. + +To avoid this problem, we normally follow each display command with enough +useless charaters (usually null characters) to fill up the time that the +display command needs to execute. This does the job if the terminal throws +away null characters without using up space in the buffer (which most +terminals do). If enough padding is used, no output can ever be lost. The +right amount of padding avoids loss of output without slowing down +operation, since the time used to transmit padding is time that nothing +else could be done. + +The number of padding characters needed for an operation depends on the +line speed. In fact, it is proportional to the line speed. A 9600 baud +line transmits about one character per msec, so the clear screen command in +the example above would need about 20 characters of padding. At 1200 baud, +however, only about 3 characters of padding are needed to fill up 20msec. + +@node Not Enough, Describe Padding, Why Pad, Padding +@subsection When There Is Not Enough Padding + +There are several common manifestations of insufficient padding. + +@itemize @bullet +@item +Emacs displays @samp{I-search: ^Q-} at the bottom of the screen. + +This means that the terminal thought its buffer was getting full of +display commands, so it tried to tell the computer to stop sending +any. + +@item +The screen is garbled intermittently, or the details of garbling vary +when you repeat the action. (A garbled screen could be due to a +command which is simply incorrect, or to user option in the terminal +which doesn't match the assumptions of the terminal description, but +this usually leads to reproducible failure.) + +This means that the buffer did get full, and some commands were lost. +Many changeable factors can change which ones are lost. + +@item +Screen is garbled at high output speeds but not at low speeds. +Padding problems nearly always go away at low speeds, usually even at +1200 baud. + +This means that a high enough speed permits commands to arrive faster +than they can be executed. +@end itemize + +Although any obscure command on an obscure terminal might lack padding, +in practice problems arise most often from the clearing commands +@samp{cl} and @samp{cd} (@pxref{Clearing}), the scrolling commands +@samp{sf} and @samp{sr} (@pxref{Scrolling}), and the line insert/delete +commands @samp{al} and @samp{dl} (@pxref{Insdel Line}). + +Occasionally the terminal description fails to define @samp{sf} and some +programs will use @samp{do} instead, so you may get a problem with +@samp{do}. If so, first define @samp{sf} just like @samp{do}, then +add some padding to @samp{sf}. + +The best strategy is to add a lot of padding at first, perhaps 200 msec. +This is much more than enough; in fact, it should cause a visible slowdown. +(If you don't see a slowdown, the change has not taken effect; +@pxref{Changing}.) If this makes the problem go away, you have found the +right place to add padding; now reduce the amount until the problem comes +back, then increase it again. If the problem remains, either it is in some +other capability or it is not a matter of padding at all. + +Keep in mind that on many terminals the correct padding for insert/delete +line or for scrolling is cursor-position dependent. If you get problems +from scrolling a large region of the screen but not from scrolling a small +part (just a few lines moving), it may mean that fixed padding should be +replaced with position-dependent padding. + +@node Describe Padding, Output Padding, Not Enough, Padding +@subsection Specifying Padding in a Terminal Description + +In the terminal description, the amount of padding required by each display +command is recorded as a sequence of digits at the front of the command. +These digits specify the padding time in milliseconds (msec). They can be +followed optionally by a decimal point and one more digit, which is a +number of tenths of msec. + +Sometimes the padding needed by a command depends on the cursor position. +For example, the time taken by an ``insert line'' command is usually +proportional to the number of lines that need to be moved down or cleared. +An asterisk (@samp{*}) following the padding time says that the time +should be multiplied by the number of screen lines affected by the command. + +@example +:al=1.3*\E[L: +@end example + +@noindent +is used to describe the ``insert line'' command for a certain terminal. +The padding required is 1.3 msec per line affected. The command itself is +@samp{@key{ESC} [ L}. + +The padding time specified in this way tells @code{tputs} how many pad +characters to output. @xref{Output Padding}. + +Two special capability values affect padding for all commands. These are +the @samp{pc} and @samp{pb}. The variable @samp{pc} specifies the +character to pad with, and @samp{pb} the speed below which no padding is +needed. The defaults for these variables, a null character and 0, +are correct for most terminals. @xref{Pad Specs}. + +@node Output Padding, , Describe Padding, Padding +@subsection Performing Padding with @code{tputs} +@cindex line speed + +@findex tputs +Use the termcap function @code{tputs} to output a string containing an +optional padding spec of the form described above (@pxref{Describe +Padding}). The function @code{tputs} strips off and decodes the padding +spec, outputs the rest of the string, and then outputs the appropriate +padding. Here is its declaration in ANSI C: + +@example +char PC; +short ospeed; + +int tputs (char *@var{string}, int @var{nlines}, int (*@var{outfun}) ()); +@end example + +Here @var{string} is the string (including padding spec) to be output; +@var{nlines} is the number of lines affected by the operation, which is +used to multiply the amount of padding if the padding spec ends with a +@samp{*}. Finally, @var{outfun} is a function (such as @code{fputchar}) +that is called to output each character. When actually called, +@var{outfun} should expect one argument, a character. + +@vindex ospeed +@vindex PC +The operation of @code{tputs} is controlled by two global variables, +@code{ospeed} and @code{PC}. The value of @code{ospeed} is supposed to be +the terminal output speed, encoded as in the @code{ioctl} system call which +gets the speed information. This is needed to compute the number of +padding characters. The value of @code{PC} is the character used for +padding. + +You are responsible for storing suitable values into these variables before +using @code{tputs}. The value stored into the @code{PC} variable should be +taken from the @samp{pc} capability in the terminal description (@pxref{Pad +Specs}). Store zero in @code{PC} if there is no @samp{pc} +capability.@refill + +The argument @var{nlines} requires some thought. Normally, it should be +the number of lines whose contents will be cleared or moved by the command. +For cursor motion commands, or commands that do editing within one line, +use the value 1. For most commands that affect multiple lines, such as +@samp{al} (insert a line) and @samp{cd} (clear from the cursor to the end +of the screen), @var{nlines} should be the screen height minus the current +vertical position (origin 0). For multiple insert and scroll commands such +as @samp{AL} (insert multiple lines), that same value for @var{nlines} is +correct; the number of lines being inserted is @i{not} correct.@refill + +If a ``scroll window'' feature is used to reduce the number of lines +affected by a command, the value of @var{nlines} should take this into +account. This is because the delay time required depends on how much work +the terminal has to do, and the scroll window feature reduces the work. +@xref{Scrolling}. + +Commands such as @samp{ic} and @samp{dc} (insert or delete characters) are +problematical because the padding needed by these commands is proportional +to the number of characters affected, which is the number of columns from +the cursor to the end of the line. It would be nice to have a way to +specify such a dependence, and there is no need for dependence on vertical +position in these commands, so it is an obvious idea to say that for these +commands @var{nlines} should really be the number of columns affected. +However, the definition of termcap clearly says that @var{nlines} is always +the number of lines affected, even in this case, where it is always 1. It +is not easy to change this rule now, because too many programs and terminal +descriptions have been written to follow it. + +Because @var{nlines} is always 1 for the @samp{ic} and @samp{dc} strings, +there is no reason for them to use @samp{*}, but some of them do. These +should be corrected by deleting the @samp{*}. If, some day, such entries +have disappeared, it may be possible to change to a more useful convention +for the @var{nlines} argument for these operations without breaking any +programs. + +@node Parameters, , Padding, Library +@section Filling In Parameters +@cindex parameters + +Some terminal control strings require numeric @dfn{parameters}. For +example, when you move the cursor, you need to say what horizontal and +vertical positions to move it to. The value of the terminal's @samp{cm} +capability, which says how to move the cursor, cannot simply be a string of +characters; it must say how to express the cursor position numbers and +where to put them within the command. + +The specifications of termcap include conventions as to which string-valued +capabilities require parameters, how many parameters, and what the +parameters mean; for example, it defines the @samp{cm} string to take +two parameters, the vertical and horizontal positions, with 0,0 being the +upper left corner. These conventions are described where the individual +commands are documented. + +Termcap also defines a language used within the capability definition for +specifying how and where to encode the parameters for output. This language +uses character sequences starting with @samp{%}. (This is the same idea as +@code{printf}, but the details are different.) The language for parameter +encoding is described in this section. + +A program that is doing display output calls the functions @code{tparam} or +@code{tgoto} to encode parameters according to the specifications. These +functions produce a string containing the actual commands to be output (as +well a padding spec which must be processed with @code{tputs}; +@pxref{Padding}). + +@menu +* Encode Parameters:: The language for encoding parameters. +* Using Parameters:: Outputting a string command with parameters. +@end menu + +@node Encode Parameters, Using Parameters, , Parameters +@subsection Describing the Encoding +@cindex % + +A terminal command string that requires parameters contains special +character sequences starting with @samp{%} to say how to encode the +parameters. These sequences control the actions of @code{tparam} and +@code{tgoto}. + +The parameters values passed to @code{tparam} or @code{tgoto} are +considered to form a vector. A pointer into this vector determines +the next parameter to be processed. Some of the @samp{%}-sequences +encode one parameter and advance the pointer to the next parameter. +Other @samp{%}-sequences alter the pointer or alter the parameter +values without generating output. + +For example, the @samp{cm} string for a standard ANSI terminal is written +as @samp{\E[%i%d;%dH}. (@samp{\E} stands for @key{ESC}.) @samp{cm} by +convention always requires two parameters, the vertical and horizontal goal +positions, so this string specifies the encoding of two parameters. Here +@samp{%i} increments the two values supplied, and each @samp{%d} encodes +one of the values in decimal. If the cursor position values 20,58 are +encoded with this string, the result is @samp{\E[21;59H}. + +First, here are the @samp{%}-sequences that generate output. Except for +@samp{%%}, each of them encodes one parameter and advances the pointer +to the following parameter. + +@table @samp +@item %% +Output a single @samp{%}. This is the only way to represent a literal +@samp{%} in a terminal command with parameters. @samp{%%} does not +use up a parameter. + +@item %d +As in @code{printf}, output the next parameter in decimal. + +@item %2 +Like @samp{%02d} in @code{printf}: output the next parameter in +decimal, and always use at least two digits. + +@item %3 +Like @samp{%03d} in @code{printf}: output the next parameter in +decimal, and always use at least three digits. Note that @samp{%4} +and so on are @emph{not} defined. + +@item %. +Output the next parameter as a single character whose ASCII code is +the parameter value. Like @samp{%c} in @code{printf}. + +@item %+@var{char} +Add the next parameter to the character @var{char}, and output the +resulting character. For example, @samp{%+ } represents 0 as a space, +1 as @samp{!}, etc. +@end table + +The following @samp{%}-sequences specify alteration of the parameters +(their values, or their order) rather than encoding a parameter for output. +They generate no output; they are used only for their side effects +on the parameters. Also, they do not advance the ``next parameter'' pointer +except as explicitly stated. Only @samp{%i}, @samp{%r} and @samp{%>} are +defined in standard Unix termcap. The others are GNU extensions.@refill + +@table @samp +@item %i +Increment the next two parameters. This is used for terminals that +expect cursor positions in origin 1. For example, @samp{%i%d,%d} would +output two parameters with @samp{1} for 0, @samp{2} for 1, etc. + +@item %r +Interchange the next two parameters. This is used for terminals whose +cursor positioning command expects the horizontal position first. + +@item %s +Skip the next parameter. Do not output anything. + +@item %b +Back up one parameter. The last parameter used will become once again +the next parameter to be output, and the next output command will use +it. Using @samp{%b} more than once, you can back up any number of +parameters, and you can refer to each parameter any number of times. + +@item %>@var{c1}@var{c2} +Conditionally increment the next parameter. Here @var{c1} and +@var{c2} are characters which stand for their ASCII codes as numbers. +If the next parameter is greater than the ASCII code of @var{c1}, the +ASCII code of @var{c2} is added to it.@refill + +@item %a @var{op} @var{type} @var{pos} +Perform arithmetic on the next parameter, do not use it up, and do not +output anything. Here @var{op} specifies the arithmetic operation, +while @var{type} and @var{pos} together specify the other operand. + +Spaces are used above to separate the operands for clarity; the spaces +don't appear in the data base, where this sequence is exactly five +characters long. + +The character @var{op} says what kind of arithmetic operation to +perform. It can be any of these characters: + +@table @samp +@item = +assign a value to the next parameter, ignoring its old value. +The new value comes from the other operand. + +@item + +add the other operand to the next parameter. + +@item - +subtract the other operand from the next parameter. + +@item * +multiply the next parameter by the other operand. + +@item / +divide the next parameter by the other operand. +@end table + +The ``other operand'' may be another parameter's value or a constant; +the character @var{type} says which. It can be: + +@table @samp +@item p +Use another parameter. The character @var{pos} says which +parameter to use. Subtract 64 from its ASCII code to get the +position of the desired parameter relative to this one. Thus, +the character @samp{A} as @var{pos} means the parameter after the +next one; the character @samp{?} means the parameter before the +next one. + +@item c +Use a constant value. The character @var{pos} specifies the +value of the constant. The 0200 bit is cleared out, so that 0200 +can be used to represent zero. +@end table +@end table + +The following @samp{%}-sequences are special purpose hacks to compensate +for the weird designs of obscure terminals. They modify the next parameter +or the next two parameters but do not generate output and do not use up any +parameters. @samp{%m} is a GNU extension; the others are defined in +standard Unix termcap. + +@table @samp +@item %n +Exclusive-or the next parameter with 0140, and likewise the parameter +after next. + +@item %m +Complement all the bits of the next parameter and the parameter after next. + +@item %B +Encode the next parameter in BCD. It alters the value of the +parameter by adding six times the quotient of the parameter by ten. +Here is a C statement that shows how the new value is computed: + +@example +@var{parm} = (@var{parm} / 10) * 16 + @var{parm} % 10; +@end example + +@item %D +Transform the next parameter as needed by Delta Data terminals. +This involves subtracting twice the remainder of the parameter by 16. + +@example +@var{parm} -= 2 * (@var{parm} % 16); +@end example +@end table + +@node Using Parameters, , Encode Parameters, Parameters +@subsection Sending Display Commands with Parameters + +The termcap library functions @code{tparam} and @code{tgoto} serve as the +analog of @code{printf} for terminal string parameters. The newer function +@code{tparam} is a GNU extension, more general but missing from Unix +termcap. The original parameter-encoding function is @code{tgoto}, which +is preferable for cursor motion. + +@menu +* tparam:: The general case, for GNU termcap only. +* tgoto:: The special case of cursor motion. +@end menu + +@node tparam, tgoto, , Using Parameters +@subsubsection @code{tparam} + +@findex tparam +The function @code{tparam} can encode display commands with any number of +parameters and allows you to specify the buffer space. It is the preferred +function for encoding parameters for all but the @samp{cm} capability. Its +ANSI C declaration is as follows: + +@smallexample +char *tparam (char *@var{ctlstring}, char *@var{buffer}, int @var{size}, int @var{parm1},...) +@end smallexample + +The arguments are a control string @var{ctlstring} (the value of a terminal +capability, presumably), an output buffer @var{buffer} and @var{size}, and +any number of integer parameters to be encoded. The effect of +@code{tparam} is to copy the control string into the buffer, encoding +parameters according to the @samp{%} sequences in the control string. + +You describe the output buffer by its address, @var{buffer}, and its size +in bytes, @var{size}. If the buffer is not big enough for the data to be +stored in it, @code{tparam} calls @code{malloc} to get a larger buffer. In +either case, @code{tparam} returns the address of the buffer it ultimately +uses. If the value equals @var{buffer}, your original buffer was used. +Otherwise, a new buffer was allocated, and you must free it after you are +done with printing the results. If you pass zero for @var{size} and +@var{buffer}, @code{tparam} always allocates the space with @code{malloc}. + +All capabilities that require parameters also have the ability to specify +padding, so you should use @code{tputs} to output the string produced by +@code{tparam}. @xref{Padding}. Here is an example. + +@example +@{ +char *buf; +char buffer[40]; + +buf = tparam (command, buffer, 40, parm); +tputs (buf, 1, fputchar); +if (buf != buffer) +free (buf); +@} +@end example + +If a parameter whose value is zero is encoded with @samp{%.}-style +encoding, the result is a null character, which will confuse @code{tputs}. +This would be a serious problem, but luckily @samp{%.} encoding is used +only by a few old models of terminal, and only for the @samp{cm} +capability. To solve the problem, use @code{tgoto} rather than +@code{tparam} to encode the @samp{cm} capability.@refill + +@node tgoto, , tparam, Using Parameters +@subsubsection @code{tgoto} + +@findex tgoto +The special case of cursor motion is handled by @code{tgoto}. There +are two reasons why you might choose to use @code{tgoto}: + +@itemize @bullet +@item +For Unix compatibility, because Unix termcap does not have @code{tparam}. + +@item +For the @samp{cm} capability, since @code{tgoto} has a special feature +to avoid problems with null characters, tabs and newlines on certain old +terminal types that use @samp{%.} encoding for that capability. +@end itemize + +Here is how @code{tgoto} might be declared in ANSI C: + +@example +char *tgoto (char *@var{cstring}, int @var{hpos}, int @var{vpos}) +@end example + +There are three arguments, the terminal description's @samp{cm} string and +the two cursor position numbers; @code{tgoto} computes the parametrized +string in an internal static buffer and returns the address of that buffer. +The next time you use @code{tgoto} the same buffer will be reused. + +@vindex UP +@vindex BC +Parameters encoded with @samp{%.} encoding can generate null characters, +tabs or newlines. These might cause trouble: the null character because +@code{tputs} would think that was the end of the string, the tab because +the kernel or other software might expand it into spaces, and the newline +becaue the kernel might add a carriage-return, or padding characters +normally used for a newline. To prevent such problems, @code{tgoto} is +careful to avoid these characters. Here is how this works: if the target +cursor position value is such as to cause a problem (that is to say, zero, +nine or ten), @code{tgoto} increments it by one, then compensates by +appending a string to move the cursor back or up one position. + +The compensation strings to use for moving back or up are found in global +variables named @code{BC} and @code{UP}. These are actual external C +variables with upper case names; they are declared @code{char *}. It is up +to you to store suitable values in them, normally obtained from the +@samp{le} and @samp{up} terminal capabilities in the terminal description +with @code{tgetstr}. Alternatively, if these two variables are both zero, +the feature of avoiding nulls, tabs and newlines is turned off. + +It is safe to use @code{tgoto} for commands other than @samp{cm} only if +you have stored zero in @code{BC} and @code{UP}. + +Note that @code{tgoto} reverses the order of its operands: the horizontal +position comes before the vertical position in the arguments to +@code{tgoto}, even though the vertical position comes before the horizontal +in the parameters of the @samp{cm} string. If you use @code{tgoto} with a +command such as @samp{AL} that takes one parameter, you must pass the +parameter to @code{tgoto} as the ``vertical position''.@refill + +@node Data Base, Capabilities, Library, Top +@chapter The Format of the Data Base + +The termcap data base of terminal descriptions is stored in the file +@file{/etc/termcap}. It contains terminal descriptions, blank lines, and +comments. + +A terminal description starts with one or more names for the terminal type. +The information in the description is a series of @dfn{capability names} +and values. The capability names have standard meanings +(@pxref{Capabilities}) and their values describe the terminal. + +@menu +* Format:: Overall format of a terminal description. +* Capability Format:: Format of capabilities within a description. +* Naming:: Naming conventions for terminal types. +* Inheriting:: Inheriting part of a description from +a related terminal type. +* Changing:: When changes in the data base take effect. +@end menu + +@node Format, Capability Format, , Data Base +@section Terminal Description Format +@cindex description format + +Aside from comments (lines starting with @samp{#}, which are ignored), each +nonblank line in the termcap data base is a terminal description. +A terminal description is nominally a single line, but it can be split +into multiple lines by inserting the two characters @samp{\ newline}. +This sequence is ignored wherever it appears in a description. + +The preferred way to split the description is between capabilities: insert +the four characters @samp{: \ newline tab} immediately before any colon. +This allows each sub-line to start with some indentation. This works +because, after the @samp{\ newline} are ignored, the result is @samp{: tab +:}; the first colon ends the preceding capability and the second colon +starts the next capability. If you split with @samp{\ newline} alone, you +may not add any indentation after them. + +Here is a real example of a terminal description: + +@example +dw|vt52|DEC vt52:\ + :cr=^M:do=^J:nl=^J:bl=^G:\ + :le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:\ + :cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:ta=^I:pt:sr=\EI:up=\EA:\ + :ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: +@end example + +Each terminal description begins with several names for the terminal type. +The names are separated by @samp{|} characters, and a colon ends the last +name. The first name should be two characters long; it exists only for the +sake of very old Unix systems and is never used in modern systems. The +last name should be a fully verbose name such as ``DEC vt52'' or ``Ann +Arbor Ambassador with 48 lines''. The other names should include whatever +the user ought to be able to specify to get this terminal type, such as +@samp{vt52} or @samp{aaa-48}. @xref{Naming}, for information on how to +choose terminal type names. + +After the terminal type names come the terminal capabilities, separated by +colons and with a colon after the last one. Each capability has a +two-letter name, such as @samp{cm} for ``cursor motion string'' or @samp{li} +for ``number of display lines''. + +@node Capability Format, Naming, Format, Data Base +@section Writing the Capabilities + +There are three kinds of capabilities: flags, numbers, and strings. Each +kind has its own way of being written in the description. Each defined +capability has by convention a particular kind of value; for example, +@samp{li} always has a numeric value and @samp{cm} always a string value. + +A flag capability is thought of as having a boolean value: the value is +true if the capability is present, false if not. When the capability is +present, just write its name between two colons. + +A numeric capability has a value which is a nonnegative number. Write the +capability name, a @samp{#}, and the number, between two colons. For +example, @samp{@dots{}:li#48:@dots{}} is how you specify the @samp{li} +capability for 48 lines.@refill + +A string-valued capability has a value which is a sequence of characters. +Usually these are the characters used to perform some display operation. +Write the capability name, a @samp{=}, and the characters of the value, +between two colons. For example, @samp{@dots{}:cm=\E[%i%d;%dH:@dots{}} is +how the cursor motion command for a standard ANSI terminal would be +specified.@refill + +Special characters in the string value can be expressed using +@samp{\}-escape sequences as in C; in addition, @samp{\E} stands for +@key{ESC}. @samp{^} is also a kind of escape character; @samp{^} followed +by @var{char} stands for the control-equivalent of @var{char}. Thus, +@samp{^a} stands for the character control-a, just like @samp{\001}. +@samp{\} and @samp{^} themselves can be represented as @samp{\\} and +@samp{\^}.@refill + +To include a colon in the string, you must write @samp{\072}. You might +ask, ``Why can't @samp{\:} be used to represent a colon?'' The reason is +that the interrogation functions do not count slashes while looking for a +capability. Even if @samp{:ce=ab\:cd:} were interpreted as giving the +@samp{ce} capability the value @samp{ab:cd}, it would also appear to define +@samp{cd} as a flag. + +The string value will often contain digits at the front to specify padding +(@pxref{Padding}) and/or @samp{%}-sequences within to specify how to encode +parameters (@pxref{Parameters}). Although these things are not to be +output literally to the terminal, they are considered part of the value of +the capability. They are special only when the string value is processed +by @code{tputs}, @code{tparam} or @code{tgoto}. By contrast, @samp{\} and +@samp{^} are considered part of the syntax for specifying the characters +in the string. + +Let's look at the VT52 example again: + +@example +dw|vt52|DEC vt52:\ + :cr=^M:do=^J:nl=^J:bl=^G:\ + :le=^H:bs:cd=\EJ:ce=\EK:cl=\EH\EJ:\ + :cm=\EY%+ %+ :co#80:li#24:\ + :nd=\EC:ta=^I:pt:sr=\EI:up=\EA:\ + :ku=\EA:kd=\EB:kr=\EC:kl=\ED:kb=^H: +@end example + +Here we see the numeric-valued capabilities @samp{co} and @samp{li}, the +flags @samp{bs} and @samp{pt}, and many string-valued capabilities. Most +of the strings start with @key{ESC} represented as @samp{\E}. The rest +contain control characters represented using @samp{^}. The meanings of the +individual capabilities are defined elsewhere (@pxref{Capabilities}). + +@node Naming, Inheriting, Capability Format, Data Base +@section Terminal Type Name Conventions +@cindex names of terminal types + +There are conventions for choosing names of terminal types. For one thing, +all letters should be in lower case. The terminal type for a terminal in +its most usual or most fundamental mode of operation should not have a +hyphen in it. + +If the same terminal has other modes of operation which require +different terminal descriptions, these variant descriptions are given +names made by adding suffixes with hyphens. Such alternate descriptions +are used for two reasons: + +@itemize @bullet +@item +When the terminal has a switch that changes its behavior. Since the +computer cannot tell how the switch is set, the user must tell the +computer by choosing the appropriate terminal type name. + +@cindex wrapping +For example, the VT-100 has a setup flag that controls whether the +cursor wraps at the right margin. If this flag is set to ``wrap'', +you must use the terminal type @samp{vt100-am}. Otherwise you must +use @samp{vt100-nam}. Plain @samp{vt100} is defined as a synonym for +either @samp{vt100-am} or @samp{vt100-nam} depending on the +preferences of the local site.@refill + +The standard suffix @samp{-am} stands for ``automatic margins''. + +@item +To give the user a choice in how to use the terminal. This is done +when the terminal has a switch that the computer normally controls. + +@cindex screen size +For example, the Ann Arbor Ambassador can be configured with many +screen sizes ranging from 20 to 60 lines. Fewer lines make bigger +characters but more lines let you see more of what you are editing. +As a result, users have different preferences. Therefore, termcap +provides terminal types for many screen sizes. If you choose type +@samp{aaa-30}, the terminal will be configured to use 30 lines; if you +choose @samp{aaa-48}, 48 lines will be used, and so on. +@end itemize + +Here is a list of standard suffixes and their conventional meanings: + +@table @samp +@item -w +Short for ``wide''. This is a mode that gives the terminal more +columns than usual. This is normally a user option. + +@item -am +``Automatic margins''. This is an alternate description for use when +the terminal's margin-wrap switch is on; it contains the @samp{am} +flag. The implication is that normally the switch is off and the +usual description for the terminal says that the switch is off. + +@item -nam +``No automatic margins''. The opposite of @samp{-am}, this names an +alternative description which lacks the @samp{am} flag. This implies +that the terminal is normally operated with the margin-wrap switch +turned on, and the normal description of the terminal says so. + +@item -na +``No arrows''. This terminal description initializes the terminal to +keep its arrow keys in local mode. This is a user option. + +@item -rv +``Reverse video''. This terminal description causes text output for +normal video to appear as reverse, and text output for reverse video +to come out as normal. Often this description differs from the usual +one by interchanging the two strings which turn reverse video on and +off.@refill + +This is a user option; you can choose either the ``reverse video'' +variant terminal type or the normal terminal type, and termcap will +obey. + +@item -s +``Status''. Says to enable use of a status line which ordinary output +does not touch (@pxref{Status Line}). + +Some terminals have a special line that is used only as a status line. +For these terminals, there is no need for an @samp{-s} variant; the +status line commands should be defined by default. On other +terminals, enabling a status line means removing one screen line from +ordinary use and reducing the effective screen height. For these +terminals, the user can choose the @samp{-s} variant type to request +use of a status line. + +@item -@var{nlines} +Says to operate with @var{nlines} lines on the screen, for terminals +such as the Ambassador which provide this as an option. Normally this +is a user option; by choosing the terminal type, you control how many +lines termcap will use. + +@item -@var{npages}p +Says that the terminal has @var{npages} pages worth of screen memory, +for terminals where this is a hardware option. + +@item -unk +Says that description is not for direct use, but only for reference in +@samp{tc} capabilities. Such a description is a kind of subroutine, +because it describes the common characteristics of several variant +descriptions that would use other suffixes in place of @samp{-unk}. +@end table + +@node Inheriting, Changing, Naming, Data Base +@section Inheriting from Related Descriptions + +@cindex inheritance +When two terminal descriptions are similar, their identical parts do not +need to be given twice. Instead, one of the two can be defined in terms of +the other, using the @samp{tc} capability. We say that one description +@dfn{refers to} the other, or @dfn{inherits from} the other. + +The @samp{tc} capability must be the last one in the terminal description, +and its value is a string which is the name of another terminal type which +is referred to. For example, + +@example +N9|aaa|ambassador|aaa-30|ann arbor ambassador/30 lines:\ + :ti=\E[2J\E[30;0;0;30p:\ + :te=\E[60;0;0;30p\E[30;1H\E[J:\ + :li#30:tc=aaa-unk: +@end example + +@noindent +defines the terminal type @samp{aaa-30} (also known as plain @samp{aaa}) in +terms of @samp{aaa-unk}, which defines everything about the Ambassador that +is independent of screen height. The types @samp{aaa-36}, @samp{aaa-48} +and so on for other screen heights are likewise defined to inherit from +@samp{aaa-unk}. + +The capabilities overridden by @samp{aaa-30} include @samp{li}, which says +how many lines there are, and @samp{ti} and @samp{te}, which configure the +terminal to use that many lines. + +The effective terminal description for type @samp{aaa} consists of the text +shown above followed by the text of the description of @samp{aaa-unk}. The +@samp{tc} capability is handled automatically by @code{tgetent}, which +finds the description thus referenced and combines the two descriptions +(@pxref{Find}). Therefore, only the implementor of the terminal +descriptions needs to think about using @samp{tc}. Users and application +programmers do not need to be concerned with it. + +Since the reference terminal description is used last, capabilities +specified in the referring description override any specifications of the +same capabilities in the reference description. + +The referring description can cancel out a capability without specifying +any new value for it by means of a special trick. Write the capability in +the referring description, with the character @samp{@@} after the capability +name, as follows: + +@smallexample +NZ|aaa-30-nam|ann arbor ambassador/30 lines/no automatic-margins:\ + :am@@:tc=aaa-30: +@end smallexample + +@node Changing, , Inheriting, Data Base +@section When Changes in the Data Base Take Effect + +Each application program must read the terminal description from the +data base, so a change in the data base is effective for all jobs started +after the change is made. + +The change will usually have no effect on a job that have been in existence +since before the change. The program probably read the terminal description +once, when it was started, and is continuing to use what it read then. +If the program does not have a feature for reexamining the data base, then +you will need to run it again (probably killing the old job). + +If the description in use is coming from the @code{TERMCAP} environment +variable, then the data base file is effectively overridden, and changes in +it will have no effect until you change the @code{TERMCAP} variable as +well. For example, some users' @file{.login} files automatically copy the +terminal description into @code{TERMCAP} to speed startup of applications. +If you have done this, you will need to change the @code{TERMCAP} variable +to make the changed data base take effect. + +@node Capabilities, Summary, Data Base, Top +@chapter Definitions of the Terminal Capabilities + +This section is divided into many subsections, each for one aspect of +use of display terminals. For writing a display program, you usually need +only check the subsections for the operations you want to use. For writing +a terminal description, you must read each subsection and fill in the +capabilities described there. + +String capabilities that are display commands may require numeric +parameters (@pxref{Parameters}). Most such capabilities do not use +parameters. When a capability requires parameters, this is explicitly +stated at the beginning of its definition. In simple cases, the first or +second sentence of the definition mentions all the parameters, in the order +they should be given, using a name +@iftex +in italics +@end iftex +@ifinfo +in upper case +@end ifinfo +for each one. For example, the @samp{rp} capability is a command that +requires two parameters; its definition begins as follows: + +@quotation +String of commands to output a graphic character @var{c}, repeated @var{n} +times. +@end quotation + +In complex cases or when there are many parameters, they are described +explicitly. + +When a capability is described as obsolete, this means that programs should +not be written to look for it, but terminal descriptions should still be +written to provide it. + +When a capability is described as very obsolete, this means that it should +be omitted from terminal descriptions as well. + +@menu +* Basic:: Basic characteristics. +* Screen Size:: Screen size, and what happens when it changes. +* Cursor Motion:: Various ways to move the cursor. +* Wrapping:: What happens if you write a character in the last column. +* Scrolling:: Pushing text up and down on the screen. +* Windows:: Limiting the part of the window that output affects. +* Clearing:: Erasing one or many lines. +* Insdel Line:: Making new blank lines in mid-screen; deleting lines. +* Insdel Char:: Inserting and deleting characters within a line. +* Standout:: Highlighting some of the text. +* Underlining:: Underlining some of the text. +* Cursor Visibility:: Making the cursor more or less easy to spot. +* Bell:: Attracts user's attention; not localized on the screen. +* Keypad:: Recognizing when function keys or arrows are typed. +* Meta Key:: @key{META} acts like an extra shift key. +* Initialization:: Commands used to initialize or reset the terminal. +* Pad Specs:: Info for the kernel on how much padding is needed. +* Status Line:: A status line displays ``background'' information. +* Half-Line:: Moving by half-lines, for superscripts and subscripts. +* Printer:: Controlling auxiliary printers of display terminals. +@end menu + +@node Basic, Screen Size, , Capabilities +@section Basic Characteristics + +This section documents the capabilities that describe the basic and +nature of the terminal, and also those that are relevant to the output +of graphic characters. + +@table @samp +@item os +@kindex os +@cindex overstrike +Flag whose presence means that the terminal can overstrike. This +means that outputting a graphic character does not erase whatever was +present in the same character position before. The terminals that can +overstrike include printing terminals, storage tubes (all obsolete +nowadays), and many bit-map displays. + +@item eo +@kindex eo +Flag whose presence means that outputting a space erases a character +position even if the terminal supports overstriking. If this flag is +not present and overstriking is supported, output of a space has no +effect except to move the cursor. + +(On terminals that do not support overstriking, you can always assume +that outputting a space at a position erases whatever character was +previously displayed there.) + +@item gn +@kindex gn +@cindex generic terminal type +Flag whose presence means that this terminal type is a generic type +which does not really describe any particular terminal. Generic types +are intended for use as the default type assigned when the user +connects to the system, with the intention that the user should +specify what type he really has. One example of a generic type +is the type @samp{network}. + +Since the generic type cannot say how to do anything interesting with +the terminal, termcap-using programs will always find that the +terminal is too weak to be supported if the user has failed to specify +a real terminal type in place of the generic one. The @samp{gn} flag +directs these programs to use a different error message: ``You have +not specified your real terminal type'', rather than ``Your terminal +is not powerful enough to be used''. + +@item hc +@kindex hc +Flag whose presence means this is a hardcopy terminal. + +@item rp +@kindex rp +@cindex repeat output +String of commands to output a graphic character @var{c}, repeated @var{n} +times. The first parameter value is the ASCII code for the desired +character, and the second parameter is the number of times to repeat the +character. Often this command requires padding proportional to the +number of times the character is repeated. This effect can be had by +using parameter arithmetic with @samp{%}-sequences to compute the +amount of padding, then generating the result as a number at the front +of the string so that @code{tputs} will treat it as padding. + +@item hz +@kindex hz +Flag whose presence means that the ASCII character @samp{~} cannot be +output on this terminal because it is used for display commands. + +Programs handle this flag by checking all text to be output and +replacing each @samp{~} with some other character(s). If this is not +done, the screen will be thoroughly garbled. + +The old Hazeltine terminals that required such treatment are probably +very rare today, so you might as well not bother to support this flag. + +@item CC +@kindex CC +@cindex command character +String whose presence means the terminal has a settable command +character. The value of the string is the default command character +(which is usually @key{ESC}). + +All the strings of commands in the terminal description should be +written to use the default command character. If you are writing an +application program that changes the command character, use the +@samp{CC} capability to figure out how to translate all the display +commands to work with the new command character. + +Most programs have no reason to look at the @samp{CC} capability. + +@item xb +@kindex xb +@cindex Superbee +Flag whose presence identifies Superbee terminals which are unable to +transmit the characters @key{ESC} and @kbd{Control-C}. Programs which +support this flag are supposed to check the input for the code sequences +sent by the @key{F1} and @key{F2} keys, and pretend that @key{ESC} +or @kbd{Control-C} (respectively) had been read. But this flag is +obsolete, and not worth supporting. +@end table + +@node Screen Size, Cursor Motion, Basic, Capabilities +@section Screen Size +@cindex screen size + +A terminal description has two capabilities, @samp{co} and @samp{li}, +that describe the screen size in columns and lines. But there is more +to the question of screen size than this. + +On some operating systems the ``screen'' is really a window and the +effective width can vary. On some of these systems, @code{tgetnum} +uses the actual width of the window to decide what value to return for +the @samp{co} capability, overriding what is actually written in the +terminal description. On other systems, it is up to the application +program to check the actual window width using a system call. For +example, on BSD 4.3 systems, the system call @code{ioctl} with code +@code{TIOCGWINSZ} will tell you the current screen size. + +On all window systems, termcap is powerless to advise the application +program if the user resizes the window. Application programs must +deal with this possibility in a system-dependent fashion. On some +systems the C shell handles part of the problem by detecting changes +in window size and setting the @code{TERMCAP} environment variable +appropriately. This takes care of application programs that are +started subsequently. It does not help application programs already +running. + +On some systems, including BSD 4.3, all programs using a terminal get +a signal named @code{SIGWINCH} whenever the screen size changes. +Programs that use termcap should handle this signal by using +@code{ioctl TIOCGWINSZ} to learn the new screen size. + +@table @samp +@item co +@kindex co +@cindex screen size +Numeric value, the width of the screen in character positions. Even +hardcopy terminals normally have a @samp{co} capability. + +@item li +@kindex li +Numeric value, the height of the screen in lines. +@end table + +@node Cursor Motion, Wrapping, Screen Size, Capabilities +@section Cursor Motion +@cindex cursor motion + +Termcap assumes that the terminal has a @dfn{cursor}, a spot on the screen +where a visible mark is displayed, and that most display commands take +effect at the position of the cursor. It follows that moving the cursor +to a specified location is very important. + +There are many terminal capabilities for different cursor motion +operations. A terminal description should define as many as possible, but +most programs do not need to use most of them. One capability, @samp{cm}, +moves the cursor to an arbitrary place on the screen; this by itself is +sufficient for any application as long as there is no need to support +hardcopy terminals or certain old, weak displays that have only relative +motion commands. Use of other cursor motion capabilities is an +optimization, enabling the program to output fewer characters in some +common cases. + +If you plan to use the relative cursor motion commands in an application +program, you must know what the starting cursor position is. To do this, +you must keep track of the cursor position and update the records each +time anything is output to the terminal, including graphic characters. +In addition, it is necessary to know whether the terminal wraps after +writing in the rightmost column. @xref{Wrapping}. + +One other motion capability needs special mention: @samp{nw} moves the +cursor to the beginning of the following line, perhaps clearing all the +starting line after the cursor, or perhaps not clearing at all. This +capability is a least common denominator that is probably supported even by +terminals that cannot do most other things such as @samp{cm} or @samp{do}. +Even hardcopy terminals can support @samp{nw}. + +@table @asis +@item @samp{cm} +@kindex cm +String of commands to position the cursor at line @var{l}, column @var{c}. +Both parameters are origin-zero, and are defined relative to the +screen, not relative to display memory. + +All display terminals except a few very obsolete ones support @samp{cm}, +so it is acceptable for an application program to refuse to operate on +terminals lacking @samp{cm}. + +@item @samp{ho} +@kindex ho +@cindex home position +String of commands to move the cursor to the upper left corner of the +screen (this position is called the @dfn{home position}). In +terminals where the upper left corner of the screen is not the same as +the beginning of display memory, this command must go to the upper +left corner of the screen, not the beginning of display memory. + +Every display terminal supports this capability, and many application +programs refuse to operate if the @samp{ho} capability is missing. + +@item @samp{ll} +@kindex ll +String of commands to move the cursor to the lower left corner of the +screen. On some terminals, moving up from home position does this, +but programs should never assume that will work. Just output the +@samp{ll} string (if it is provided); if moving to home position and +then moving up is the best way to get there, the @samp{ll} command +will do that. + +@item @samp{cr} +@kindex cr +String of commands to move the cursor to the beginning of the line it +is on. If this capability is not specified, many programs assume +they can use the ASCII carriage return character for this. + +@item @samp{le} +@kindex le +String of commands to move the cursor left one column. Unless the +@samp{bw} flag capability is specified, the effect is undefined if the +cursor is at the left margin; do not use this command there. If +@samp{bw} is present, this command may be used at the left margin, and +it wraps the cursor to the last column of the preceding line. + +@item @samp{nd} +@kindex nd +String of commands to move the cursor right one column. The effect is +undefined if the cursor is at the right margin; do not use this +command there, not even if @samp{am} is present. + +@item @samp{up} +@kindex up +String of commands to move the cursor vertically up one line. The +effect of sending this string when on the top line is undefined; +programs should never use it that way. + +@item @samp{do} +@kindex do +String of commands to move the cursor vertically down one line. The +effect of sending this string when on the bottom line is undefined; +programs should never use it that way. + +Some programs do use @samp{do} to scroll up one line if used at the +bottom line, if @samp{sf} is not defined but @samp{sr} is. This is +only to compensate for certain old, incorrect terminal descriptions. +(In principle this might actually lead to incorrect behavior on other +terminals, but that seems to happen rarely if ever.) But the proper +solution is that the terminal description should define @samp{sf} as +well as @samp{do} if the command is suitable for scrolling. + +The original idea was that this string would not contain a newline +character and therefore could be used without disabling the kernel's +usual habit of converting of newline into a carriage-return newline +sequence. But many terminal descriptions do use newline in the +@samp{do} string, so this is not possible; a program which sends the +@samp{do} string must disable output conversion in the kernel +(@pxref{Initialize}). + +@item @samp{bw} +@kindex bw +Flag whose presence says that @samp{le} may be used in column zero +to move to the last column of the preceding line. If this flag +is not present, @samp{le} should not be used in column zero. + +@item @samp{nw} +@kindex nw +String of commands to move the cursor to start of next line, possibly +clearing rest of line (following the cursor) before moving. + +@item @samp{DO}, @samp{UP}, @samp{LE}, @samp{RI} +@kindex DO +@kindex LE +@kindex RI +@kindex UP +Strings of commands to move the cursor @var{n} lines down vertically, +up vertically, or @var{n} columns left or right. Do not attempt to +move past any edge of the screen with these commands; the effect of +trying that is undefined. Only a few terminal descriptions provide +these commands, and most programs do not use them. + +@item @samp{CM} +@kindex CM +String of commands to position the cursor at line @var{l}, column +@var{c}, relative to display memory. Both parameters are origin-zero. +This capability is present only in terminals where there is a +difference between screen-relative and memory-relative addressing, and +not even in all such terminals. + +@item @samp{ch} +@kindex ch +String of commands to position the cursor at column @var{c} in the +same line it is on. This is a special case of @samp{cm} in which the +vertical position is not changed. The @samp{ch} capability is +provided only when it is faster to output than @samp{cm} would be in +this special case. Programs should not assume most display terminals +have @samp{ch}. + +@item @samp{cv} +@kindex cv +String of commands to position the cursor at line @var{l} in the same +column. This is a special case of @samp{cm} in which the horizontal +position is not changed. The @samp{cv} capability is provided only +when it is faster to output than @samp{cm} would be in this special +case. Programs should not assume most display terminals have +@samp{cv}. + +@item @samp{sc} +@kindex sc +String of commands to make the terminal save the current cursor +position. Only the last saved position can be used. If this +capability is present, @samp{rc} should be provided also. Most +terminals have neither. + +@item @samp{rc} +@kindex rc +String of commands to make the terminal restore the last saved cursor +position. If this capability is present, @samp{sc} should be provided +also. Most terminals have neither. + +@item @samp{ff} +@kindex ff +String of commands to advance to the next page, for a hardcopy +terminal. + +@item @samp{ta} +@kindex ta +String of commands to move the cursor right to the next hardware tab +stop column. Missing if the terminal does not have any kind of +hardware tabs. Do not send this command if the kernel's terminal +modes say that the kernel is expanding tabs into spaces. + +@item @samp{bt} +@kindex bt +String of commands to move the cursor left to the previous hardware +tab stop column. Missing if the terminal has no such ability; many +terminals do not. Do not send this command if the kernel's terminal +modes say that the kernel is expanding tabs into spaces. +@end table + +The following obsolete capabilities should be included in terminal +descriptions when appropriate, but should not be looked at by new programs. + +@table @samp +@item nc +@kindex nc +Flag whose presence means the terminal does not support the ASCII +carriage return character as @samp{cr}. This flag is needed because +old programs assume, when the @samp{cr} capability is missing, that +ASCII carriage return can be used for the purpose. We use @samp{nc} +to tell the old programs that carriage return may not be used. + +New programs should not assume any default for @samp{cr}, so they need +not look at @samp{nc}. However, descriptions should contain @samp{nc} +whenever they do not contain @samp{cr}. + +@item xt +@kindex xt +Flag whose presence means that the ASCII tab character may not be used +for cursor motion. This flag exists because old programs assume, when +the @samp{ta} capability is missing, that ASCII tab can be used for +the purpose. We use @samp{xt} to tell the old programs not to use tab. + +New programs should not assume any default for @samp{ta}, so they need +not look at @samp{xt} in connection with cursor motion. Note that +@samp{xt} also has implications for standout mode (@pxref{Standout}). +It is obsolete in regard to cursor motion but not in regard to +standout. + +In fact, @samp{xt} means that the terminal is a Teleray 1061. + +@item bc +@kindex bc +Very obsolete alternative name for the @samp{le} capability. + +@item bs +@kindex bs +Flag whose presence means that the ASCII character backspace may be +used to move the cursor left. Obsolete; look at @samp{le} instead. + +@item nl +@kindex nl +Obsolete capability which is a string that can either be used to move +the cursor down or to scroll. The same string must scroll when used +on the bottom line and move the cursor when used on any other line. +New programs should use @samp{do} or @samp{sf}, and ignore @samp{nl}. + +If there is no @samp{nl} capability, some old programs assume they can +use the newline character for this purpose. These programs follow a +bad practice, but because they exist, it is still desirable to define +the @samp{nl} capability in a terminal description if the best way to +move down is @emph{not} a newline. +@end table + +@node Wrapping, Scrolling, Cursor Motion, Capabilities +@section Wrapping +@cindex wrapping + +@dfn{Wrapping} means moving the cursor from the right margin to the left +margin of the following line. Some terminals wrap automatically when a +graphic character is output in the last column, while others do not. Most +application programs that use termcap need to know whether the terminal +wraps. There are two special flag capabilities to describe what the +terminal does when a graphic character is output in the last column. + +@table @samp +@item am +@kindex am +Flag whose presence means that writing a character in the last column +causes the cursor to wrap to the beginning of the next line. + +If @samp{am} is not present, writing in the last column leaves the +cursor at the place where the character was written. + +Writing in the last column of the last line should be avoided on +terminals with @samp{am}, as it may or may not cause scrolling to +occur (@pxref{Scrolling}). Scrolling is surely not what you would +intend. + +If your program needs to check the @samp{am} flag, then it also needs +to check the @samp{xn} flag which indicates that wrapping happens in a +strange way. Many common terminals have the @samp{xn} flag. + +@item xn +@kindex xn +Flag whose presence means that the cursor wraps in a strange way. At +least two distinct kinds of strange behavior are known; the termcap +data base does not contain anything to distinguish the two. + +On Concept-100 terminals, output in the last column wraps the cursor +almost like an ordinary @samp{am} terminal. But if the next thing +output is a newline, it is ignored. + +DEC VT-100 terminals (when the wrap switch is on) do a different +strange thing: the cursor wraps only if the next thing output is +another graphic character. In fact, the wrap occurs when the +following graphic character is received by the terminal, before the +character is placed on the screen. + +On both of these terminals, after writing in the last column a +following graphic character will be displayed in the first column of +the following line. But the effect of relative cursor motion +characters such as newline or backspace at such a time depends on the +terminal. The effect of erase or scrolling commands also depends on +the terminal. You can't assume anything about what they will do on a +terminal that has @samp{xn}. So, to be safe, you should never do +these things at such a time on such a terminal. + +To be sure of reliable results on a terminal which has the @samp{xn} +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. +@end table + +@node Scrolling, Windows, Wrapping, Capabilities +@section Scrolling +@cindex scrolling + +@dfn{Scrolling} means moving the contents of the screen up or down one or +more lines. Moving the contents up is @dfn{forward scrolling}; moving them +down is @dfn{reverse scrolling}. + +Scrolling happens after each line of output during ordinary output on most +display terminals. But in an application program that uses termcap for +random-access output, scrolling happens only when explicitly requested with +the commands in this section. + +Some terminals have a @dfn{scroll region} feature. This lets you limit +the effect of scrolling to a specified range of lines. Lines outside the +range are unaffected when scrolling happens. The scroll region feature +is available if either @samp{cs} or @samp{cS} is present. + +@table @samp +@item sf +@kindex sf +String of commands to scroll the screen one line up, assuming it is +output with the cursor at the beginning of the bottom line. + +@item sr +@kindex sr +String of commands to scroll the screen one line down, assuming it is +output with the cursor at the beginning of the top line. + +@item do +A few programs will try to use @samp{do} to do the work of @samp{sf}. +This is not really correct---it is an attempt to compensate for the +absence of a @samp{sf} command in some old terminal descriptions. + +Since these terminal descriptions do define @samp{sr}, perhaps at one +time the definition of @samp{do} was different and it could be used +for scrolling as well. But it isn't desirable to combine these two +functions in one capability, since scrolling often requires more +padding than simply moving the cursor down. Defining @samp{sf} and +@samp{do} separately allows you to specify the padding properly. +Also, all sources agree that @samp{do} should not be relied on to do +scrolling. + +So the best approach is to add @samp{sf} capabilities to the +descriptions of these terminals, copying the definition of @samp{do} +if that does scroll. + +@item SF +@kindex SF +String of commands to scroll the screen @var{n} lines up, assuming it +is output with the cursor at the beginning of the bottom line. + +@item SR +@kindex SR +String of commands to scroll the screen @var{n} lines down, assuming it +is output with the cursor at the beginning of the top line. + +@item cs +@kindex cs +String of commands to set the scroll region. This command takes two +parameters, @var{start} and @var{end}, which are the line numbers +(origin-zero) of the first line to include in the scroll region and of +the last line to include in it. When a scroll region is set, +scrolling is limited to the specified range of lines; lines outside +the range are not affected by scroll commands. + +Do not try to move the cursor outside the scroll region. The region +remains set until explicitly removed. To remove the scroll region, +use another @samp{cs} command specifying the full height of the +screen. + +The cursor position is undefined after the @samp{cs} command is set, +so position the cursor with @samp{cm} immediately afterward. + +@item cS +@kindex cS +String of commands to set the scroll region using parameters in +different form. The effect is the same as if @samp{cs} were used. +Four parameters are required: + +@enumerate +@item +Total number of lines on the screen. +@item +Number of lines above desired scroll region. +@item +Number of lines below (outside of) desired scroll region. +@item +Total number of lines on the screen, the same as the first parameter. +@end enumerate + +This capability is a GNU extension that was invented to allow the Ann +Arbor Ambassador's scroll-region command to be described; it could +also be done by putting non-Unix @samp{%}-sequences into a @samp{cs} +string, but that would have confused Unix programs that used the +@samp{cs} capability with the Unix termcap. Currently only GNU Emacs +uses the @samp{cS} capability. + +@item ns +@kindex ns +Flag which means that the terminal does not normally scroll for +ordinary sequential output. For modern terminals, this means that +outputting a newline in ordinary sequential output with the cursor on +the bottom line wraps to the top line. For some obsolete terminals, +other things may happen. + +The terminal may be able to scroll even if it does not normally do so. +If the @samp{sf} capability is provided, it can be used for scrolling +regardless of @samp{ns}. + +@item da +@kindex da +Flag whose presence means that lines scrolled up off the top of the +screen may come back if scrolling down is done subsequently. + +The @samp{da} and @samp{db} flags do not, strictly speaking, affect +how to scroll. But programs that scroll usually need to clear the +lines scrolled onto the screen, if these flags are present. + +@item db +@kindex db +Flag whose presence means that lines scrolled down off the bottom of +the screen may come back if scrolling up is done subsequently. + +@item lm +@kindex lm +Numeric value, the number of lines of display memory that the terminal +has. A value of zero means that the terminal has more display memory +than can fit on the screen, but no fixed number of lines. (The number +of lines may depend on the amount of text in each line.) +@end table + +Any terminal description that defines @samp{SF} should also define @samp{sf}; +likewise for @samp{SR} and @samp{sr}. However, many terminals can only +scroll by one line at a time, so it is common to find @samp{sf} and not +@samp{SF}, or @samp{sr} without @samp{SR}.@refill + +Therefore, all programs that use the scrolling facilities should be +prepared to work with @samp{sf} in the case that @samp{SF} is absent, and +likewise with @samp{sr}. On the other hand, an application program that +uses only @samp{sf} and not @samp{SF} is acceptable, though slow on some +terminals.@refill + +When outputting a scroll command with @code{tputs}, the @var{nlines} +argument should be the total number of lines in the portion of the screen +being scrolled. Very often these commands require padding proportional to +this number of lines. @xref{Padding}. + +@node Windows, Clearing, Scrolling, Capabilities +@section Windows +@cindex window + +A @dfn{window}, in termcap, is a rectangular portion of the screen to which +all display operations are restricted. Wrapping, clearing, scrolling, +insertion and deletion all operate as if the specified window were all the +screen there was. + +@table @samp +@item wi +@kindex wi +String of commands to set the terminal output screen window. +This string requires four parameters, all origin-zero: +@enumerate +@item +The first line to include in the window. +@item +The last line to include in the window. +@item +The first column to include in the window. +@item +The last column to include in the window. +@end enumerate +@end table + +Most terminals do not support windows. + +@node Clearing, Insdel Line, Windows, Capabilities +@section Clearing Parts of the Screen +@cindex erasing +@cindex clearing the screen + +There are several terminal capabilities for clearing parts of the screen +to blank. All display terminals support the @samp{cl} string, and most +display terminals support all of these capabilities. + +@table @samp +@item cl +@kindex cl +String of commands to clear the entire screen and position the cursor +at the upper left corner. + +@item cd +@kindex cd +String of commands to clear the line the cursor is on, and all the +lines below it, down to the bottom of the screen. This command string +should be used only with the cursor in column zero; their effect is +undefined if the cursor is elsewhere. + +@item ce +@kindex ce +String of commands to clear from the cursor to the end of the current +line. + +@item ec +@kindex ec +String of commands to clear @var{n} characters, starting with the +character that the cursor is on. This command string is expected to +leave the cursor position unchanged. The parameter @var{n} should never +be large enough to reach past the right margin; the effect of such a +large parameter would be undefined. +@end table + +Clear to end of line (@samp{ce}) is extremely important in programs that +maintain an updating display. Nearly all display terminals support this +operation, so it is acceptable for a an application program to refuse to +work if @samp{ce} is not present. However, if you do not want this +limitation, you can accomplish clearing to end of line by outputting spaces +until you reach the right margin. In order to do this, you must know the +current horizontal position. Also, this technique assumes that writing a +space will erase. But this happens to be true on all the display terminals +that fail to support @samp{ce}. + +@node Insdel Line, Insdel Char, Clearing, Capabilities +@section Insert/Delete Line + +@cindex insert line +@cindex delete line +@dfn{Inserting a line} means creating a blank line in the middle +of the screen, and pushing the existing lines of text apart. In fact, +the lines above the insertion point do not change, while the lines below +move down, and one is normally lost at the bottom of the screen. + +@dfn{Deleting a line} means causing the line to disappear from the screen, +closing up the gap by moving the lines below it upward. A new line +appears at the bottom of the screen. Usually this line is blank, but +on terminals with the @samp{db} flag it may be a line previously moved +off the screen bottom by scrolling or line insertion. + +Insertion and deletion of lines is useful in programs that maintain an +updating display some parts of which may get longer or shorter. They are +also useful in editors for scrolling parts of the screen, and for +redisplaying after lines of text are killed or inserted. + +Many terminals provide commands to insert or delete a single line at the +cursor position. Some provide the ability to insert or delete several +lines with one command, using the number of lines to insert or delete as a +parameter. Always move the cursor to column zero before using any of +these commands. + +@table @samp +@item al +@kindex al +String of commands to insert a blank line before the line the cursor +is on. The existing line, and all lines below it, are moved down. +The last line in the screen (or in the scroll region, if one is set) +disappears and in most circumstances is discarded. It may not be +discarded if the @samp{db} is present (@pxref{Scrolling}). + +The cursor must be at the left margin before this command is used. +This command does not move the cursor. + +@item dl +@kindex dl +String of commands to delete the line the cursor is on. The following +lines move up, and a blank line appears at the bottom of the screen +(or bottom of the scroll region). If the terminal has the @samp{db} +flag, a nonblank line previously pushed off the screen bottom may +reappear at the bottom. + +The cursor must be at the left margin before this command is used. +This command does not move the cursor. + +@item AL +@kindex AL +String of commands to insert @var{n} blank lines before the line that +the cursor is on. It is like @samp{al} repeated @var{n} times, except +that it is as fast as one @samp{al}. + +@item DL +@kindex DL +String of commands to delete @var{n} lines starting with the line that +the cursor is on. It is like @samp{dl} repeated @var{n} times, except +that it is as fast as one @samp{dl}. +@end table + +Any terminal description that defines @samp{AL} should also define +@samp{al}; likewise for @samp{DL} and @samp{dl}. However, many terminals +can only insert or delete one line at a time, so it is common to find +@samp{al} and not @samp{AL}, or @samp{dl} without @samp{DL}.@refill + +Therefore, all programs that use the insert and delete facilities should be +prepared to work with @samp{al} in the case that @samp{AL} is absent, and +likewise with @samp{dl}. On the other hand, it is acceptable to write +an application that uses only @samp{al} and @samp{dl} and does not look +for @samp{AL} or @samp{DL} at all.@refill + +If a terminal does not support line insertion and deletion directly, +but does support a scroll region, the effect of insertion and deletion +can be obtained with scrolling. However, it is up to the individual +user program to check for this possibility and use the scrolling +commands to get the desired result. It is fairly important to implement +this alternate strategy, since it is the only way to get the effect of +line insertion and deletion on the popular VT100 terminal. + +Insertion and deletion of lines is affected by the scroll region on +terminals that have a settable scroll region. This is useful when it is +desirable to move any few consecutive lines up or down by a few lines. +@xref{Scrolling}. + +The line pushed off the bottom of the screen is not lost if the terminal +has the @samp{db} flag capability; instead, it is pushed into display +memory that does not appear on the screen. This is the same thing that +happens when scrolling pushes a line off the bottom of the screen. +Either reverse scrolling or deletion of a line can bring the apparently +lost line back onto the bottom of the screen. If the terminal has the +scroll region feature as well as @samp{db}, the pushed-out line really +is lost if a scroll region is in effect. + +When outputting an insert or delete command with @code{tputs}, the +@var{nlines} argument should be the total number of lines from the cursor +to the bottom of the screen (or scroll region). Very often these commands +require padding proportional to this number of lines. @xref{Padding}. + +For @samp{AL} and @samp{DL} the @var{nlines} argument should @emph{not} +depend on the number of lines inserted or deleted; only the total number of +lines affected. This is because it is just as fast to insert two or +@var{n} lines with @samp{AL} as to insert one line with @samp{al}. + +@node Insdel Char, Standout, Insdel Line, Capabilities +@section Insert/Delete Character +@cindex insert character +@cindex delete character + +@dfn{Inserting a character} means creating a blank space in the middle of a +line, and pushing the rest of the line rightward. The character in the +rightmost column is lost. + +@dfn{Deleting a character} means causing the character to disappear from +the screen, closing up the gap by moving the rest of the line leftward. A +blank space appears in the rightmost column. + +Insertion and deletion of characters is useful in programs that maintain an +updating display some parts of which may get longer or shorter. It is also +useful in editors for redisplaying the results of editing within a line. + +Many terminals provide commands to insert or delete a single character at +the cursor position. Some provide the ability to insert or delete several +characters with one command, using the number of characters to insert or +delete as a parameter. + +@cindex insert mode +Many terminals provide an insert mode in which outputting a graphic +character has the added effect of inserting a position for that character. +A special command string is used to enter insert mode and another is used +to exit it. The reason for designing a terminal with an insert mode rather +than an insert command is that inserting character positions is usually +followed by writing characters into them. With insert mode, this is as +fast as simply writing the characters, except for the fixed overhead of +entering and leaving insert mode. However, when the line speed is great +enough, padding may be required for the graphic characters output in insert +mode. + +Some terminals require you to enter insert mode and then output a special +command for each position to be inserted. Or they may require special +commands to be output before or after each graphic character to be +inserted. + +@cindex delete mode +Deletion of characters is usually accomplished by a straightforward command +to delete one or several positions; but on some terminals, it is necessary +to enter a special delete mode before using the delete command, and leave +delete mode afterward. Sometimes delete mode and insert mode are the same +mode. + +Some terminals make a distinction between character positions in which a +space character has been output and positions which have been cleared. On +these terminals, the effect of insert or delete character runs to the first +cleared position rather than to the end of the line. In fact, the effect +may run to more than one line if there is no cleared position to stop the +shift on the first line. These terminals are identified by the @samp{in} +flag capability. + +On terminals with the @samp{in} flag, the technique of skipping over +characters that you know were cleared, and then outputting text later on in +the same line, causes later insert and delete character operations on that +line to do nonstandard things. A program that has any chance of doing this +must check for the @samp{in} flag and must be careful to write explicit +space characters into the intermediate columns when @samp{in} is present. + +A plethora of terminal capabilities are needed to describe all of this +complexity. Here is a list of them all. Following the list, we present +an algorithm for programs to use to take proper account of all of these +capabilities. + +@table @samp +@item im +@kindex im +String of commands to enter insert mode. + +If the terminal has no special insert mode, but it can insert +characters with a special command, @samp{im} should be defined with a +null value, because the @samp{vi} editor assumes that insertion of a +character is impossible if @samp{im} is not provided. + +New programs should not act like @samp{vi}. They should pay attention +to @samp{im} only if it is defined. + +@item ei +@kindex ei +String of commands to leave insert mode. This capability must be +present if @samp{im} is. + +On a few old terminals the same string is used to enter and exit +insert mode. This string turns insert mode on if it was off, and off +it it was on. You can tell these terminals because the @samp{ei} +string equals the @samp{im} string. If you want to support these +terminals, you must always remember accurately whether insert mode is +in effect. However, these terminals are obsolete, and it is +reasonable to refuse to support them. On all modern terminals, you +can safely output @samp{ei} at any time to ensure that insert mode is +turned off. + +@item ic +@kindex ic +String of commands to insert one character position at the cursor. +The cursor does not move. + +If outputting a graphic character while in insert mode is sufficient +to insert the character, then the @samp{ic} capability should be +defined with a null value. + +If your terminal offers a choice of ways to insert---either use insert +mode or use a special command---then define @samp{im} and do not define +@samp{ic}, since this gives the most efficient operation when several +characters are to be inserted. @emph{Do not} define both strings, for +that means that @emph{both} must be used each time insertion is done. + +@item ip +@kindex ip +String of commands to output following an inserted graphic character +in insert mode. Often it is used just for a padding spec, when padding +is needed after an inserted character (@pxref{Padding}). + +@item IC +@kindex IC +String of commands to insert @var{n} character positions at and after +the cursor. It has the same effect as repeating the @samp{ic} string +and a space, @var{n} times. + +If @samp{IC} is provided, application programs may use it without first +entering insert mode. + +@item mi +@kindex mi +Flag whose presence means it is safe to move the cursor while in insert +mode and assume the terminal remains in insert mode. + +@item in +@kindex in +Flag whose presence means that the terminal distinguishes between +character positions in which space characters have been output and +positions which have been cleared. +@end table + +An application program can assume that the terminal can do character +insertion if @emph{any one of} the capabilities @samp{IC}, @samp{im}, +@samp{ic} or @samp{ip} is provided. + +To insert @var{n} blank character positions, move the cursor to the place +to insert them and follow this algorithm: + +@enumerate +@item +If an @samp{IC} string is provided, output it with parameter @var{n} +and you are finished. Otherwise (or if you don't want to bother to +look for an @samp{IC} string) follow the remaining steps. + +@item +Output the @samp{im} string, if there is one, unless the terminal is +already in insert mode. + +@item +Repeat steps 4 through 6, @var{n} times. + +@item +Output the @samp{ic} string if any. + +@item +Output a space. + +@item +Output the @samp{ip} string if any. + +@item +Output the @samp{ei} string, eventually, to exit insert mode. There +is no need to do this right away. If the @samp{mi} flag is present, +you can move the cursor and the cursor will remain in insert mode; +then you can do more insertion elsewhere without reentering insert +mode. +@end enumerate + +To insert @var{n} graphic characters, position the cursor and follow this +algorithm: + +@enumerate +@item +If an @samp{IC} string is provided, output it with parameter @var{n}, +then output the graphic characters, and you are finished. Otherwise +(or if you don't want to bother to look for an @samp{IC} string) +follow the remaining steps. + +@item +Output the @samp{im} string, if there is one, unless the terminal is +already in insert mode. + +@item +For each character to be output, repeat steps 4 through 6. + +@item +Output the @samp{ic} string if any. + +@item +Output the next graphic character. + +@item +Output the @samp{ip} string if any. + +@item +Output the @samp{ei} string, eventually, to exit insert mode. There +is no need to do this right away. If the @samp{mi} flag is present, +you can move the cursor and the cursor will remain in insert mode; +then you can do more insertion elsewhere without reentering insert +mode. +@end enumerate + +Note that this is not the same as the original Unix termcap specifications +in one respect: it assumes that the @samp{IC} string can be used without +entering insert mode. This is true as far as I know, and it allows you be +able to avoid entering and leaving insert mode, and also to be able to +avoid the inserted-character padding after the characters that go into the +inserted positions. + +Deletion of characters is less complicated; deleting one column is done by +outputting the @samp{dc} string. However, there may be a delete mode that +must be entered with @samp{dm} in order to make @samp{dc} work. + +@table @samp +@item dc +@kindex dc +String of commands to delete one character position at the cursor. If +@samp{dc} is not present, the terminal cannot delete characters. + +@item DC +@kindex DC +String of commands to delete @var{n} characters starting at the cursor. +It has the same effect as repeating the @samp{dc} string @var{n} times. +Any terminal description that has @samp{DC} also has @samp{dc}. + +@item dm +@kindex dm +String of commands to enter delete mode. If not present, there is no +delete mode, and @samp{dc} can be used at any time (assuming there is +a @samp{dc}). + +@item ed +@kindex ed +String of commands to exit delete mode. This must be present if +@samp{dm} is. +@end table + +To delete @var{n} character positions, position the cursor and follow these +steps: + +@enumerate +@item +If the @samp{DC} string is present, output it with parameter @var{n} +and you are finished. Otherwise, follow the remaining steps. + +@item +Output the @samp{dm} string, unless you know the terminal is already +in delete mode. + +@item +Output the @samp{dc} string @var{n} times. + +@item +Output the @samp{ed} string eventually. If the flag capability +@samp{mi} is present, you can move the cursor and do more deletion +without leaving and reentering delete mode. +@end enumerate + +As with the @samp{IC} string, we have departed from the original termcap +specifications by assuming that @samp{DC} works without entering delete +mode even though @samp{dc} would not. + +If the @samp{dm} and @samp{im} capabilities are both present and have the +same value, it means that the terminal has one mode for both insertion and +deletion. It is useful for a program to know this, because then it can do +insertions after deletions, or vice versa, without leaving insert/delete +mode and reentering it. + +@node Standout, Underlining, Insdel Char, Capabilities +@section Standout and Appearance Modes +@cindex appearance modes +@cindex standout +@cindex magic cookie + +@dfn{Appearance modes} are modifications to the ways characters are +displayed. Typical appearance modes include reverse video, dim, bright, +blinking, underlined, invisible, and alternate character set. Each kind of +terminal supports various among these, or perhaps none. + +For each type of terminal, one appearance mode or combination of them that +looks good for highlighted text is chosen as the @dfn{standout mode}. The +capabilities @samp{so} and @samp{se} say how to enter and leave standout +mode. Programs that use appearance modes only to highlight some text +generally use the standout mode so that they can work on as many terminals +as possible. Use of specific appearance modes other than ``underlined'' +and ``alternate character set'' is rare. + +Terminals that implement appearance modes fall into two general classes as +to how they do it. + +In some terminals, the presence or absence of any appearance mode is +recorded separately for each character position. In these terminals, each +graphic character written is given the appearance modes current at the time +it is written, and keeps those modes until it is erased or overwritten. +There are special commands to turn the appearance modes on or off for +characters to be written in the future. + +In other terminals, the change of appearance modes is represented by a +marker that belongs to a certain screen position but affects all following +screen positions until the next marker. These markers are traditionally +called @dfn{magic cookies}. + +The same capabilities (@samp{so}, @samp{se}, @samp{mb} and so on) for +turning appearance modes on and off are used for both magic-cookie +terminals and per-character terminals. On magic cookie terminals, these +give the commands to write the magic cookies. On per-character terminals, +they change the current modes that affect future output and erasure. Some +simple applications can use these commands without knowing whether or not +they work by means of cookies. + +However, a program that maintains and updates a display needs to know +whether the terminal uses magic cookies, and exactly what their effect is. +This information comes from the @samp{sg} capability. + +The @samp{sg} capability is a numeric capability whose presence indicates +that the terminal uses magic cookies for appearance modes. Its value is +the number of character positions that a magic cookie occupies. Usually +the cookie occupies one or more character positions on the screen, and these +character positions are displayed as blank, but in some terminals the +cookie has zero width. + +The @samp{sg} capability describes both the magic cookie to turn standout +on and the cookie to turn it off. This makes the assumption that both +kinds of cookie have the same width on the screen. If that is not true, +the narrower cookie must be ``widened'' with spaces until it has the same +width as the other. + +On some magic cookie terminals, each line always starts with normal +display; in other words, the scope of a magic cookie never extends over +more than one line. But on other terminals, one magic cookie affects all +the lines below it unless explicitly canceled. Termcap does not define any +way to distinguish these two ways magic cookies can work. To be safe, it +is best to put a cookie at the beginning of each line. + +On some per-character terminals, standout mode or other appearance modes +may be canceled by moving the cursor. On others, moving the cursor has no +effect on the state of the appearance modes. The latter class of terminals +are given the flag capability @samp{ms} (``can move in standout''). All +programs that might have occasion to move the cursor while appearance modes +are turned on must check for this flag; if it is not present, they should +reset appearance modes to normal before doing cursor motion. + +A program that has turned on only standout mode should use @samp{se} to +reset the standout mode to normal. A program that has turned on only +alternate character set mode should use @samp{ae} to return it to normal. +If it is possible that any other appearance modes are turned on, use the +@samp{me} capability to return them to normal. + +Note that the commands to turn on one appearance mode, including @samp{so} +and @samp{mb} @dots{} @samp{mr}, if used while some other appearance modes +are turned on, may combine the two modes on some terminals but may turn off +the mode previously enabled on other terminals. This is because some +terminals do not have a command to set or clear one appearance mode without +changing the others. Programs should not attempt to use appearance modes +in combination except with @samp{sa}, and when switching from one single +mode to another should always turn off the previously enabled mode and then +turn on the new desired mode. + +On some old terminals, the @samp{so} and @samp{se} commands may be the same +command, which has the effect of turning standout on if it is off, or off +it is on. It is therefore risky for a program to output extra @samp{se} +commands for good measure. Fortunately, all these terminals are obsolete. + +Programs that update displays in which standout-text may be replaced with +non-standout text must check for the @samp{xs} flag. In a per-character +terminal, this flag says that the only way to remove standout once written is +to clear that portion of the line with the @samp{ce} string or something +even more powerful (@pxref{Clearing}); just writing new characters at those +screen positions will not change the modes in effect there. In a magic +cookie terminal, @samp{xs} says that the only way to remove a cookie is to +clear a portion of the line that includes the cookie; writing a different +cookie at the same position does not work. + +Such programs must also check for the @samp{xt} flag, which means that the +terminal is a Teleray 1061. On this terminal it is impossible to position +the cursor at the front of a magic cookie, so the only two ways to remove a +cookie are (1) to delete the line it is on or (2) to position the cursor at +least one character before it (possibly on a previous line) and output the +@samp{se} string, which on these terminals finds and removes the next +@samp{so} magic cookie on the screen. (It may also be possible to remove a +cookie which is not at the beginning of a line by clearing that line.) The +@samp{xt} capability also has implications for the use of tab characters, +but in that regard it is obsolete (@xref{Cursor Motion}). + +@table @samp +@item so +@kindex so +String of commands to enter standout mode. + +@item se +@kindex se +String of commands to leave standout mode. + +@item sg +@kindex sg +Numeric capability, the width on the screen of the magic cookie. This +capability is absent in terminals that record appearance modes +character by character. + +@item ms +@kindex ms +Flag whose presence means that it is safe to move the cursor while the +appearance modes are not in the normal state. If this flag is absent, +programs should always reset the appearance modes to normal before +moving the cursor. + +@item xs +@kindex xs +Flag whose presence means that the only way to reset appearance modes +already on the screen is to clear to end of line. On a per-character +terminal, you must clear the area where the modes are set. On a magic +cookie terminal, you must clear an area containing the cookie. +See the discussion above. + +@item xt +@kindex xt +Flag whose presence means that the cursor cannot be positioned right +in front of a magic cookie, and that @samp{se} is a command to delete +the next magic cookie following the cursor. See discussion above. + +@item mb +@kindex mb +String of commands to enter blinking mode. + +@item md +@kindex md +String of commands to enter double-bright mode. + +@item mh +@kindex mh +String of commands to enter half-bright mode. + +@item mk +@kindex mk +String of commands to enter invisible mode. + +@item mp +@kindex mp +String of commands to enter protected mode. + +@item mr +@kindex mr +String of commands to enter reverse-video mode. + +@item me +@kindex me +String of commands to turn off all appearance modes, including +standout mode and underline mode. On some terminals it also turns off +alternate character set mode; on others, it may not. This capability +must be present if any of @samp{mb} @dots{} @samp{mr} is present. + +@item as +@kindex as +String of commands to turn on alternate character set mode. This mode +assigns some or all graphic characters an alternate picture on the +screen. There is no standard as to what the alternate pictures look +like. + +@item ae +@kindex ae +String of commands to turn off alternate character set mode. + +@item sa +@kindex sa +String of commands to turn on an arbitrary combination of appearance +modes. It accepts 9 parameters, each of which controls a particular +kind of appearance mode. A parameter should be 1 to turn its appearance +mode on, or zero to turn that mode off. Most terminals do not support +the @samp{sa} capability, even among those that do have various +appearance modes. + +The nine parameters are, in order, @var{standout}, @var{underline}, +@var{reverse}, @var{blink}, @var{half-bright}, @var{double-bright}, +@var{blank}, @var{protect}, @var{alt char set}. +@end table + +@node Underlining, Cursor Visibility, Standout, Capabilities +@section Underlining +@cindex underlining + +Underlining on most terminals is a kind of appearance mode, much like +standout mode. Therefore, it may be implemented using magic cookies or as +a flag in the terminal whose current state affects each character that is +output. @xref{Standout}, for a full explanation. + +The @samp{ug} capability is a numeric capability whose presence indicates +that the terminal uses magic cookies for underlining. Its value is the +number of character positions that a magic cookie for underlining occupies; +it is used for underlining just as @samp{sg} is used for standout. Aside +from the simplest applications, it is impossible to use underlining +correctly without paying attention to the value of @samp{ug}. + +@table @samp +@item us +@kindex us +String of commands to turn on underline mode or to output a magic cookie +to start underlining. + +@item ue +@kindex ue +String of commands to turn off underline mode or to output a magic +cookie to stop underlining. + +@item ug +@kindex ug +Width of magic cookie that represents a change of underline mode; +or missing, if the terminal does not use a magic cookie for this. + +@item ms +@kindex ms +Flag whose presence means that it is safe to move the cursor while the +appearance modes are not in the normal state. Underlining is an +appearance mode. If this flag is absent, programs should always turn +off underlining before moving the cursor. +@end table + +There are two other, older ways of doing underlining: there can be a +command to underline a single character, or the output of @samp{_}, the +ASCII underscore character, as an overstrike could cause a character to be +underlined. New programs need not bother to handle these capabilities +unless the author cares strongly about the obscure terminals which support +them. However, terminal descriptions should provide these capabilities +when appropriate. + +@table @samp +@item uc +@kindex uc +String of commands to underline the character under the cursor, and +move the cursor right. + +@item ul +@kindex ul +Flag whose presence means that the terminal can underline by +overstriking an underscore character (@samp{_}); some terminals can do +this even though they do not support overstriking in general. An +implication of this flag is that when outputting new text to overwrite +old text, underscore characters must be treated specially lest they +underline the old text instead. +@end table + +@node Cursor Visibility, Bell, Underlining, Capabilities +@section Cursor Visibility +@cindex visibility + +Some terminals have the ability to make the cursor invisible, or to enhance +it. Enhancing the cursor is often done by programs that plan to use the +cursor to indicate to the user a position of interest that may be anywhere +on the screen---for example, the Emacs editor enhances the cursor on entry. +Such programs should always restore the cursor to normal on exit. + +@table @samp +@item vs +@kindex vs +String of commands to enhance the cursor. + +@item vi +@kindex vi +String of commands to make the cursor invisible. + +@item ve +@kindex ve +String of commands to return the cursor to normal. +@end table + +If you define either @samp{vs} or @samp{vi}, you must also define @samp{ve}. + +@node Bell, Keypad, Cursor Visibility, Capabilities +@section Bell +@cindex bell +@cindex visible bell + +Here we describe commands to make the terminal ask for the user to pay +attention to it. + +@table @samp +@item bl +@kindex bl +String of commands to cause the terminal to make an audible sound. If +this capability is absent, the terminal has no way to make a suitable +sound. + +@item vb +@kindex vb +String of commands to cause the screen to flash to attract attention +(``visible bell''). If this capability is absent, the terminal has no +way to do such a thing. +@end table + +@node Keypad, Meta Key, Bell, Capabilities +@section Keypad and Function Keys + +Many terminals have arrow and function keys that transmit specific +character sequences to the computer. Since the precise sequences used +depend on the terminal, termcap defines capabilities used to say what the +sequences are. Unlike most termcap string-valued capabilities, these are +not strings of commands to be sent to the terminal, rather strings that +are received from the terminal. + +Programs that expect to use keypad keys should check, initially, for a +@samp{ks} capability and send it, to make the keypad actually transmit. +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 +capability is not provided, but the others in this section are, +programs may assume that the function keys always transmit. + +@item @samp{ke} +String of commands to make the function keys work locally. This +capability is provided only if @samp{ks} is. + +@item @samp{kl} +String of input characters sent by typing the left-arrow key. If this +capability is missing, you cannot expect the terminal to have a +left-arrow key that transmits anything to the computer. + +@item @samp{kr} +String of input characters sent by typing the right-arrow key. + +@item @samp{ku} +String of input characters sent by typing the up-arrow key. + +@item @samp{kd} +String of input characters sent by typing the down-arrow key. + +@item @samp{kh} +String of input characters sent by typing the ``home-position'' key. + +@item @samp{K1} @dots{} @samp{K5} +@kindex K1@dots{}K5 +Strings of input characters sent by the five other keys in a 3-by-3 +array that includes the arrow keys, if the keyboard has such a 3-by-3 +array. Note that one of these keys may be the ``home-position'' key, +in which case one of these capabilities will have the same value as +the @samp{kh} key. + +@item @samp{k0} +String of input characters sent by function key 10 (or 0, if the terminal +has one labeled 0). + +@item @samp{k1} @dots{} @samp{k9} +@kindex k1@dots{}k9 +Strings of input characters sent by function keys 1 through 9, +provided for those function keys that exist. + +@item @samp{kn} +Number: the number of numbered function keys, if there are more than +10. + +@item @samp{l0} @dots{} @samp{l9} +@kindex l0@dots{}l9 +Strings which are the labels appearing on the keyboard on the keys +described by the capabilities @samp{k0} @dots{} @samp{l9}. These +capabilities should be left undefined if the labels are @samp{f0} or +@samp{f10} and @samp{f1} @dots{} @samp{f9}.@refill + +@item @samp{kH} +@kindex kA@dots{}kT +String of input characters sent by the ``home down'' key, if there is +one. + +@item @samp{kb} +String of input characters sent by the ``backspace'' key, if there is +one. + +@item @samp{ka} +String of input characters sent by the ``clear all tabs'' key, if there +is one. + +@item @samp{kt} +String of input characters sent by the ``clear tab stop this column'' +key, if there is one. + +@item @samp{kC} +String of input characters sent by the ``clear screen'' key, if there is +one. + +@item @samp{kD} +String of input characters sent by the ``delete character'' key, if +there is one. + +@item @samp{kL} +String of input characters sent by the ``delete line'' key, if there is +one. + +@item @samp{kM} +String of input characters sent by the ``exit insert mode'' key, if +there is one. + +@item @samp{kE} +String of input characters sent by the ``clear to end of line'' key, if +there is one. + +@item @samp{kS} +String of input characters sent by the ``clear to end of screen'' key, +if there is one. + +@item @samp{kI} +String of input characters sent by the ``insert character'' or ``enter +insert mode'' key, if there is one. + +@item @samp{kA} +String of input characters sent by the ``insert line'' key, if there is +one. + +@item @samp{kN} +String of input characters sent by the ``next page'' key, if there is +one. + +@item @samp{kP} +String of input characters sent by the ``previous page'' key, if there is +one. + +@item @samp{kF} +String of input characters sent by the ``scroll forward'' key, if there +is one. + +@item @samp{kR} +String of input characters sent by the ``scroll reverse'' key, if there +is one. + +@item @samp{kT} +String of input characters sent by the ``set tab stop in this column'' +key, if there is one. + +@item @samp{ko} +String listing the other function keys the terminal has. This is a +very obsolete way of describing the same information found in the +@samp{kH} @dots{} @samp{kT} keys. The string contains a list of +two-character termcap capability names, separated by commas. The +meaning is that for each capability name listed, the terminal has a +key which sends the string which is the value of that capability. For +example, the value @samp{:ko=cl,ll,sf,sr:} says that the terminal has +four function keys which mean ``clear screen'', ``home down'', +``scroll forward'' and ``scroll reverse''.@refill +@end table + +@node Meta Key, Initialization, Keypad, Capabilities +@section Meta Key + +@cindex meta key +A Meta key is a key on the keyboard that modifies each character you type +by controlling the 0200 bit. This bit is on if and only if the Meta key is +held down when the character is typed. Characters typed using the Meta key +are called Meta characters. Emacs uses Meta characters as editing +commands. + +@table @samp +@item km +@kindex km +Flag whose presence means that the terminal has a Meta key. + +@item mm +@kindex mm +String of commands to enable the functioning of the Meta key. + +@item mo +@kindex mo +String of commands to disable the functioning of the Meta key. +@end table + +If the terminal has @samp{km} but does not have @samp{mm} and @samp{mo}, it +means that the Meta key always functions. If it has @samp{mm} and +@samp{mo}, it means that the Meta key can be turned on or off. Send the +@samp{mm} string to turn it on, and the @samp{mo} string to turn it off. +I do not know why one would ever not want it to be on. + +@node Initialization, Pad Specs, Meta Key, Capabilities +@section Initialization +@cindex reset +@cindex initialization +@cindex tab stops + +@table @samp +@item ti +@kindex ti +String of commands to put the terminal into whatever special modes are +needed or appropriate for programs that move the cursor +nonsequentially around the screen. Programs that use termcap to do +full-screen display should output this string when they start up. + +@item te +@kindex te +String of commands to undo what is done by the @samp{ti} string. +Programs that output the @samp{ti} string on entry should output this +string when they exit. + +@item is +@kindex is +String of commands to initialize the terminal for each login session. + +@item if +@kindex if +String which is the name of a file containing the string of commands +to initialize the terminal for each session of use. Normally @samp{is} +and @samp{if} are not both used. + +@item i1 +@itemx i3 +@kindex i1 +@kindex i3 +Two more strings of commands to initialize the terminal for each login +session. The @samp{i1} string (if defined) is output before @samp{is} +or @samp{if}, and the @samp{i3} string (if defined) is output after. + +The reason for having three separate initialization strings is to make +it easier to define a group of related terminal types with slightly +different initializations. Define two or three of the strings in the +basic type; then the other types can override one or two of the +strings. + +@item rs +@kindex rs +String of commands to reset the terminal from any strange mode it may +be in. Normally this includes the @samp{is} string (or other commands +with the same effects) and more. What would go in the @samp{rs} +string but not in the @samp{is} string are annoying or slow commands +to bring the terminal back from strange modes that nobody would +normally use. + +@item it +@kindex it +Numeric value, the initial spacing between hardware tab stop columns +when the terminal is powered up. Programs to initialize the terminal +can use this to decide whether there is a need to set the tab stops. +If the initial width is 8, well and good; if it is not 8, then the +tab stops should be set; if they cannot be set, the kernel is told +to convert tabs to spaces, and other programs will observe this and do +likewise. + +@item ct +@kindex ct +String of commands to clear all tab stops. + +@item st +@kindex st +String of commands to set tab stop at current cursor column on all +lines. +@end table + +@node Pad Specs, Status Line, Initialization, Capabilities +@section Padding Capabilities +@cindex padding + +There are two terminal capabilities that exist just to explain the proper +way to obey the padding specifications in all the command string +capabilities. One, @samp{pc}, must be obeyed by all termcap-using +programs. + +@table @samp +@item pb +@kindex pb +Numeric value, the lowest baud rate at which padding is actually +needed. Programs may check this and refrain from doing any padding at +lower speeds. + +@item pc +@kindex pc +String of commands for padding. The first character of this string is +to be used as the pad character, instead of using null characters for +padding. If @samp{pc} is not provided, use null characters. Every +program that uses termcap must look up this capability and use it to +set the variable @code{PC} that is used by @code{tputs}. +@xref{Padding}. +@end table + +Some termcap capabilities exist just to specify the amount of padding that +the kernel should give to cursor motion commands used in ordinary +sequential output. + +@table @samp +@item dC +@kindex dC +Numeric value, the number of msec of padding needed for the +carriage-return character. + +@item dN +@kindex dN +Numeric value, the number of msec of padding needed for the newline +(linefeed) character. + +@item dB +@kindex dB +Numeric value, the number of msec of padding needed for the backspace +character. + +@item dF +@kindex dF +Numeric value, the number of msec of padding needed for the formfeed +character. + +@item dT +@kindex dT +Numeric value, the number of msec of padding needed for the tab +character. +@end table + +In some systems, the kernel uses the above capabilities; in other systems, +the kernel uses the paddings specified in the string capabilities +@samp{cr}, @samp{sf}, @samp{le}, @samp{ff} and @samp{ta}. Descriptions of +terminals which require such padding should contain the @samp{dC} @dots{} +@samp{dT} capabilities and also specify the appropriate padding in the +corresponding string capabilities. Since no modern terminals require +padding for ordinary sequential output, you probably won't need to do +either of these things. + +@node Status Line, Half-Line, Pad Specs, Capabilities +@section Status Line + +@cindex status line +A @dfn{status line} is a line on the terminal that is not used for ordinary +display output but instead used for a special message. The intended use is +for a continuously updated description of what the user's program is doing, +and that is where the name ``status line'' comes from, but in fact it could +be used for anything. The distinguishing characteristic of a status line +is that ordinary output to the terminal does not affect it; it changes only +if the special status line commands of this section are used. + +@table @samp +@item hs +@kindex hs +Flag whose presence means that the terminal has a status line. If a +terminal description specifies that there is a status line, it must +provide the @samp{ts} and @samp{fs} capabilities. + +@item ts +@kindex ts +String of commands to move the terminal cursor into the status line. +Usually these commands must specifically record the old cursor +position for the sake of the @samp{fs} string. + +@item fs +@kindex fs +String of commands to move the cursor back from the status line to its +previous position (outside the status line). + +@item es +@kindex es +Flag whose presence means that other display commands work while +writing the status line. In other words, one can clear parts of it, +insert or delete characters, move the cursor within it using @samp{ch} +if there is a @samp{ch} capability, enter and leave standout mode, and +so on. + +@item ds +@kindex ds +String of commands to disable the display of the status line. This +may be absent, if there is no way to disable the status line display. + +@item ws +@kindex ws +Numeric value, the width of the status line. If this capability is +absent in a terminal that has a status line, it means the status line +is the same width as the other lines. + +Note that the value of @samp{ws} is sometimes as small as 8. +@end table + +@node Half-Line, Printer, Status Line, Capabilities +@section Half-Line Motion + +Some terminals have commands for moving the cursor vertically by half-lines, +useful for outputting subscripts and superscripts. Mostly it is hardcopy +terminals that have such features. + +@table @samp +@item hu +@kindex hu +String of commands to move the cursor up half a line. If the terminal +is a display, it is your responsibility to avoid moving up past the +top line; however, most likely the terminal that supports this is a +hardcopy terminal and there is nothing to be concerned about. + +@item hd +@kindex hd +String of commands to move the cursor down half a line. If the +terminal is a display, it is your responsibility to avoid moving down +past the bottom line, etc. +@end table + +@node Printer, , Half-Line, Capabilities +@section Controlling Printers Attached to Terminals +@cindex printer + +Some terminals have attached hardcopy printer ports. They may be able to +copy the screen contents to the printer; they may also be able to redirect +output to the printer. Termcap does not have anything to tell the program +whether the redirected output appears also on the screen; it does on some +terminals but not all. + +@table @samp +@item ps +@kindex ps +String of commands to cause the contents of the screen to be printed. +If it is absent, the screen contents cannot be printed. + +@item po +@kindex po +String of commands to redirect further output to the printer. + +@item pf +@kindex pf +String of commands to terminate redirection of output to the printer. +This capability must be present in the description if @samp{po} is. + +@item pO +@kindex pO +String of commands to redirect output to the printer for next @var{n} +characters of output, regardless of what they are. Redirection will +end automatically after @var{n} characters of further output. Until +then, nothing that is output can end redirection, not even the +@samp{pf} string if there is one. The number @var{n} should not be +more than 255. + +One use of this capability is to send non-text byte sequences (such as +bit-maps) to the printer. +@end table + +Most terminals with printers do not support all of @samp{ps}, @samp{po} and +@samp{pO}; any one or two of them may be supported. To make a program that +can send output to all kinds of printers, it is necessary to check for all +three of these capabilities, choose the most convenient of the ones that +are provided, and use it in its own appropriate fashion. + +@node Summary, Var Index, Capabilities, Top +@chapter Summary of Capability Names + +Here are all the terminal capability names in alphabetical order +with a brief description of each. For cross references to their definitions, +see the index of capability names (@pxref{Cap Index}). + +@table @samp +@item ae +String to turn off alternate character set mode. +@item al +String to insert a blank line before the cursor. +@item AL +String to insert @var{n} blank lines before the cursor. +@item am +Flag: output to last column wraps cursor to next line. +@item as +String to turn on alternate character set mode.like. +@item bc +Very obsolete alternative name for the @samp{le} capability. +@item bl +String to sound the bell. +@item bs +Obsolete flag: ASCII backspace may be used for leftward motion. +@item bt +String to move the cursor left to the previous hardware tab stop column. +@item bw +Flag: @samp{le} at left margin wraps to end of previous line. +@item CC +String to change terminal's command character. +@item cd +String to clear the line the cursor is on, and following lines. +@item ce +String to clear from the cursor to the end of the line. +@item ch +String to position the cursor at column @var{c} in the same line. +@item cl +String to clear the entire screen and put cursor at upper left corner. +@item cm +String to position the cursor at line @var{l}, column @var{c}. +@item CM +String to position the cursor at line @var{l}, column +@var{c}, relative to display memory. +@item co +Number: width of the screen. +@item cr +String to move cursor sideways to left margin. +@item cs +String to set the scroll region. +@item cS +Alternate form of string to set the scroll region. +@item ct +String to clear all tab stops. +@item cv +String to position the cursor at line @var{l} in the same column. +@item da +Flag: data scrolled off top of screen may be scrolled back. +@item db +Flag: data scrolled off bottom of screen may be scrolled back. +@item dB +Obsolete number: msec of padding needed for the backspace character. +@item dc +String to delete one character position at the cursor. +@item dC +Obsolete number: msec of padding needed for the carriage-return character. +@item DC +String to delete @var{n} characters starting at the cursor. +@item dF +Obsolete number: msec of padding needed for the formfeed character. +@item dl +String to delete the line the cursor is on. +@item DL +String to delete @var{n} lines starting with the cursor's line. +@item dm +String to enter delete mode. +@item dN +Obsolete number: msec of padding needed for the newline character. +@item do +String to move the cursor vertically down one line. +@item DO +String to move cursor vertically down @var{n} lines. +@item ds +String to disable the display of the status line. +@item dT +Obsolete number: msec of padding needed for the tab character. +@item ec +String of commands to clear @var{n} characters at cursor. +@item ed +String to exit delete mode. +@item ei +String to leave insert mode. +@item eo +Flag: output of a space can erase an overstrike. +@item es +Flag: other display commands work while writing the status line. +@item ff +String to advance to the next page, for a hardcopy terminal. +@item fs +String to move the cursor back from the status line to its +previous position (outside the status line). +@item gn +Flag: this terminal type is generic, not real. +@item hc +Flag: hardcopy terminal. +@item hd +String to move the cursor down half a line. +@item ho +String to position cursor at upper left corner. +@item hs +Flag: the terminal has a status line. +@item hu +String to move the cursor up half a line. +@item hz +Flag: terminal cannot accept @samp{~} as output. +@item i1 +String to initialize the terminal for each login session. +@item i3 +String to initialize the terminal for each login session. +@item ic +String to insert one character position at the cursor. +@item IC +String to insert @var{n} character positions at the cursor. +@item if +String naming a file of commands to initialize the terminal. +@item im +String to enter insert mode. +@item in +Flag: outputting a space is different from moving over empty positions. +@item ip +String to output following an inserted character in insert mode. +@item is +String to initialize the terminal for each login session. +@item it +Number: initial spacing between hardware tab stop columns. +@item k0 +String of input sent by function key 0 or 10. +@item k1 @dots{} k9 +Strings of input sent by function keys 1 through 9. +@item K1 @dots{} K5 +Strings sent by the five other keys in 3-by-3 array with arrows. +@item ka +String of input sent by the ``clear all tabs'' key. +@item kA +String of input sent by the ``insert line'' key. +@item kb +String of input sent by the ``backspace'' key. +@item kC +String of input sent by the ``clear screen'' key. +@item kd +String of input sent by typing the down-arrow key. +@item kD +String of input sent by the ``delete character'' key. +@item ke +String to make the function keys work locally. +@item kE +String of input sent by the ``clear to end of line'' key. +@item kF +String of input sent by the ``scroll forward'' key. +@item kh +String of input sent by typing the ``home-position'' key. +@item kH +String of input sent by the ``home down'' key. +@item kI +String of input sent by the ``insert character'' or ``enter +insert mode'' key. +@item kl +String of input sent by typing the left-arrow key. +@item kL +String of input sent by the ``delete line'' key. +@item km +Flag: the terminal has a Meta key. +@item kM +String of input sent by the ``exit insert mode'' key. +@item kn +Numeric value, the number of numbered function keys. +@item kN +String of input sent by the ``next page'' key. +@item ko +Very obsolete string listing the terminal's named function keys. +@item kP +String of input sent by the ``previous page'' key. +@item kr +String of input sent by typing the right-arrow key. +@item kR +String of input sent by the ``scroll reverse'' key. +@item ks +String to make the function keys transmit. +@item kS +String of input sent by the ``clear to end of screen'' key. +@item kt +String of input sent by the ``clear tab stop this column'' key. +@item kT +String of input sent by the ``set tab stop in this column'' key. +@item ku +String of input sent by typing the up-arrow key. +@item l0 +String on keyboard labelling function key 0 or 10. +@item l1 @dots{} l9 +Strings on keyboard labelling function keys 1 through 9. +@item le +String to move the cursor left one column. +@item LE +String to move cursor left @var{n} columns. +@item li +Number: height of the screen. +@item ll +String to position cursor at lower left corner. +@item lm +Number: lines of display memory. +@item mb +String to enter blinking mode. +@item md +String to enter double-bright mode. +@item me +String to turn off all appearance modes +@item mh +String to enter half-bright mode. +@item mi +Flag: cursor motion in insert mode is safe. +@item mk +String to enter invisible mode. +@item mm +String to enable the functioning of the Meta key. +@item mo +String to disable the functioning of the Meta key. +@item mp +String to enter protected mode. +@item mr +String to enter reverse-video mode. +@item ms +Flag: cursor motion in standout mode is safe. +@item nc +Obsolete flag: do not use ASCII carriage-return on this terminal. +@item nd +String to move the cursor right one column. +@item nl +Obsolete alternative name for the @samp{do} and @samp{sf} capabilities. +@item ns +Flag: the terminal does not normally scroll for sequential output. +@item nw +String to move to start of next line, possibly clearing rest of old line. +@item os +Flag: terminal can overstrike. +@item pb +Number: the lowest baud rate at which padding is actually needed. +@item pc +String containing character for padding. +@item pf +String to terminate redirection of output to the printer. +@item po +String to redirect further output to the printer. +@item pO +String to redirect @var{n} characters ofoutput to the printer. +@item ps +String to print the screen on the attached printer. +@item rc +String to move to last saved cursor position. +@item RI +String to move cursor right @var{n} columns. +@item rp +String to output character @var{c} repeated @var{n} times. +@item rs +String to reset the terminal from any strange modes. +@item sa +String to turn on an arbitrary combination of appearance modes. +@item sc +String to save the current cursor position. +@item se +String to leave standout mode. +@item sf +String to scroll the screen one line up. +@item SF +String to scroll the screen @var{n} lines up. +@item sg +Number: width of magic standout cookie. Absent if magic cookies are +not used. +@item so +String to enter standout mode. +@item sr +String to scroll the screen one line down. +@item SR +String to scroll the screen @var{n} line down. +@item st +String to set tab stop at current cursor column on all lines. +programs. +@item ta +String to move the cursor right to the next hardware tab stop column. +@item te +String to return terminal to settings for sequential output. +@item ti +String to initialize terminal for random cursor motion. +@item ts +String to move the terminal cursor into the status line. +@item uc +String to underline one character and move cursor right. +@item ue +String to turn off underline mode +@item ug +Number: width of underlining magic cookie. Absent if underlining +doesn't use magic cookies. +@item ul +Flag: underline by overstriking with an underscore. +@item up +String to move the cursor vertically up one line. +@item UP +String to move cursor vertically up @var{n} lines. +@item us +String to turn on underline mode +@item vb +String to make the screen flash. +@item ve +String to return the cursor to normal. +@item vi +String to make the cursor invisible. +@item vs +String to enhance the cursor. +@item wi +String to set the terminal output screen window. +@item ws +Number: the width of the status line. +@item xb +Flag: superbee terminal. +@item xn +Flag: cursor wraps in a strange way. +@item xs +Flag: clearing a line is the only way to clear the appearance modes of +positions in that line (or, only way to remove magic cookies on that +line). +@item xt +Flag: Teleray 1061; several strange characteristics. +@end table + +@node Var Index, Cap Index, Summary, Top +@unnumbered Variable and Function Index + +@printindex fn + +@node Cap Index, Index, Var Index, Top +@unnumbered Capability Index + +@printindex ky + +@node Index, , Cap Index, Top +@unnumbered Concept Index + +@printindex cp + +@contents +@bye + diff --git a/lib/termcap/grot/texinfo.tex b/lib/termcap/grot/texinfo.tex new file mode 100644 index 0000000..d10917e --- /dev/null +++ b/lib/termcap/grot/texinfo.tex @@ -0,0 +1,3941 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 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 +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +%USA. + + +%In other words, you are welcome to use, share and improve this program. +%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} +\message{Loading texinfo package [Version \texinfoversion]:} +\message{} + +% Print the version number if in a .fmt file. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexdots=\dots +\let\ptexdot=\. +\let\ptexstar=\* +\let\ptexend=\end +\let\ptexbullet=\bullet +\let\ptexb=\b +\let\ptexc=\c +\let\ptexi=\i +\let\ptext=\t +\let\ptexl=\l +\let\ptexL=\L + +\def\tie{\penalty 10000\ } % Save plain tex definition of ~. + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset \bindingoffset=0pt +\newdimen \normaloffset \normaloffset=\hoffset +\newdimen\pagewidth \newdimen\pageheight +\pagewidth=\hsize \pageheight=\vsize + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% 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 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions itself, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{\hoffset=\normaloffset +\ifodd\pageno \advance\hoffset by \bindingoffset +\else \advance\hoffset by -\bindingoffset\fi +{\escapechar=`\\\relax % makes sure backslash is used in output files. +\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}% +{\let\hsize=\pagewidth \makefootline}}}% +\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% 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 + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% 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 +\def\singlespace{% +{\advance \baselineskip by -\singlespaceskip +\kern \baselineskip}% +\baselineskip=\singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. + +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\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. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% 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 + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % 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. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % 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 + % 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 + % manual), we don't worry about eating any user text. + \comment +} +% +% 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.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \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 + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. + +\def\include{\parsearg\includezzz} +%Use \input\thisfile to avoid blank after \input, which may be an active +%char (in which case the blank would become the \input argument). +%The grouping keeps the value of \thisfile correct even when @include +%is nested. +\def\includezzz #1{\begingroup +\def\thisfile{#1}\input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\par \vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% 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. +% +\def\ignoremorecommands{% + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\include = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\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 + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% 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 + % command, so that nested ignore constructs work. Thus, we put the + % 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 + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % 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 + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @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 +% didn't need it. +% +\def\set{\parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi +} +\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @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 + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @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 + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @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} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% 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. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\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. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% 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} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\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. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\font\textrm=cmr12 +\font\texttt=cmtt12 +\else +\font\textrm=cmr10 scaled \mainmagstep +\font\texttt=cmtt10 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 +\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 +\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, +% 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 +\let\indsl=\indit +\let\indtt=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\let\indsc=\indrm +\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 +\let\chapbf=\chaprm +\font\chapsc=cmcsc10 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 +\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 + +%\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 + +%\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 +\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 +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% 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 + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% 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. +\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\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \resetmathfonts} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \resetmathfonts} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \resetmathfonts} +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy + \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 + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% 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}% + \null +} +\let\ttfont = \t +%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null} +\def\samp #1{`\tclose{#1}'\null} +\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} +\let\code=\tclose +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else\tclose{\look}\fi +\else\tclose{\look}\fi} + +% 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\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \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 + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\par \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\par \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + \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 + % line. We do not start a paragraph here because then if the next + % 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 + \nobreak + \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}% + \fi + \endgroup +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\endgroup\afterenvbreak}% +\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}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Neccessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\endgroup\afterenvbreak}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\endgroup\afterenvbreak}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \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{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % 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 <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% 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 +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\t##1{\realbackslash r {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\def\doind #1#2{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% Expand all macros now EXCEPT \folio +\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now +% so it will be output as is; and it will print as backslash in the indx. +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}}}% +\temp }% +}\penalty\count10}} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{% + \tex + \dobreak \chapheadingskip {10000} + \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other + \catcode`\$=\other\catcode`\_=\other + \catcode`\~=\other + % + % The following don't help, since the chars were translated + % when the raw index was written, and their fonts were discarded + % due to \indexnofonts. + %\catcode`\"=\active + %\catcode`\^=\active + %\catcode`\_=\active + %\catcode`\|=\active + %\catcode`\<=\active + %\catcode`\>=\active + % % + \def\indexbackslash{\rawbackslashxx} + \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \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 + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns + \Etex +} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% 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 + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % 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 + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % 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. + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +%% Define two-column mode, which is used in indexes. +%% Adapted from the TeXbook, page 416. +\catcode `\@=11 + +\newbox\partialpage + +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % 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 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize + \doublecolumnpagegoal +} + +\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} + +\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth + \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage + \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} + \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} + \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi + \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi +} +\def\doublecolumnpagegoal{% + \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ +} +\def\pagesofar{\unvbox\partialpage % + \hsize=\doublecolumnhsize % have to restore this since output routine + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} +\def\doublecolumnout{% + \setbox5=\copy255 + {\vbadness=10000 \doublecolumnsplit} + \ifvbox255 + \setbox0=\vtop to\dimen@{\unvbox0} + \setbox2=\vtop to\dimen@{\unvbox2} + \onepageout\pagesofar \unvbox255 \penalty\outputpenalty + \else + \setbox0=\vbox{\unvbox5} + \ifvbox0 + \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip + \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth + {\vbadness=10000 + \loop \global\setbox5=\copy0 + \setbox1=\vsplit5 to\dimen@ + \setbox3=\vsplit5 to\dimen@ + \ifvbox5 \global\advance\dimen@ by1pt \repeat + \setbox0=\vbox to\dimen@{\unvbox1} + \setbox2=\vbox to\dimen@{\unvbox3} + \global\setbox\partialpage=\vbox{\pagesofar} + \doublecolumnpagegoal + } + \fi + \fi +} + +\catcode `\@=\other +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\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}% +\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}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{Appendix \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{Appendix \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% 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). +% +% 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<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appenixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\heading{\parsearg\secheadingi} + +\def\subheading{\parsearg\subsecheadingi} + +\def\subsubheading{\parsearg\subsubsecheadingi} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain} + +\def\chfplain #1#2{% + \pchapsepmacro + {% + \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #2\enspace #1}% + }% + \bigskip + \penalty5000 +} + +\def\unnchfplain #1{% +\pchapsepmacro % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen} + +% Parameter controlling skip before section headings. + +\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} + +\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} + +% @paragraphindent is defined for the Info formatting commands only. +\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. + +\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} +\def\plainsecheading #1{\secheadingi {#1}} +\def\secheadingi #1{{\advance \secheadingskip by \parskip % +\secheadingbreak}% +{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + + +% 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}} +\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + +\def\subsubsecfonts{\subsecfonts} % Maybe this should change: + % Perhaps make sssec fonts scaled + % magstep half +\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}} +\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000} + + +\message{toc printing,} + +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + \pagealignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % 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 + \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}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{Short Contents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% 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 } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in in \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + + +% 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 +% page number. +% +% 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 + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% 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.) +% +\def\tocentry#1#2{\begingroup + \hyphenpenalty = 10000 + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% 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 +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +\let\ptexequiv = \equiv + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +\def\point{$\star$} + +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl +\let\L=\ptexL +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% 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}} + +% 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 % +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \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 + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +\def\Elisp{\endgroup\afterenvbreak}% + +\def\lisp{\begingroup + \nonfillstart + \def\Elisp{\endgroup\afterenvbreak}% + \tt + \rawbackslash % output the \ character from the 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} + +% 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. +% +\def\smalllispx{\begingroup + \nonfillstart + \def\Esmalllisp{\endgroup\afterenvbreak}% + % + % Smaller interline space and fonts for small examples. + \baselineskip 10pt + \indexfonts \tt + \rawbackslash % output the \ character from the current font + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \def\Edisplay{\endgroup\afterenvbreak}% + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \def\Eformat{\endgroup\afterenvbreak} + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \def\Eflushleft{\endgroup\afterenvbreak}% + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \def\Eflushright{\endgroup\afterenvbreak}% + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking 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} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\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 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #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\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\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 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\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 % +%% }% +%%} + +\def\defopvarparsebody #1#2#3#4#5 {\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 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\functionparens +\code{#1}% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #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}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% #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}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #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}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\code{#2} #3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% 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 +\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% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thischapter} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 Chapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +Section\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +Section\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 % +\else \ifnum \subsubsecno=0 % +Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +Section\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 + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\=\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% 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. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% 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. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% 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\setleading#1{% + \baselineskip = #1\relax + \normalbaselineskip = \baselineskip + \lineskip = \lineskipfactor\baselineskip + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% 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 + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% 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} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +%\hsize = 6.5in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 18pt plus 1pt +\setleading{15pt} +\advance\topskip by 1.2cm + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% 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}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + +% These values for secheadingskip and subsecheadingskip are +% experiments. RJC 7 Aug 1992 +\global\secheadingskip = 17pt plus 6pt minus 3pt +\global\subsecheadingskip = 14pt plus 6pt minus 3pt + +\global\lispnarrowing = 0.3in +\setleading{12pt} +\advance\topskip by -1cm +\global\parskip 3pt plus 1pt +\global\hsize = 5in +\global\vsize=7.5in +\global\tolerance=700 +\global\hfuzz=1pt +\global\contentsrightmargin=0pt + +\global\pagewidth=\hsize +\global\pageheight=\vsize + +\global\let\smalllisp=\smalllispx +\global\let\smallexample=\smalllispx +\global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% 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 @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +% \lvvmode is equivalent in function to \leavevmode. +% Using \leavevmode runs into trouble when written out to +% an index file due to the expansion of \leavevmode into ``\unhbox +% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our +% magic tricks with @. +\def\lvvmode{\vbox to 0pt{}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\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`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% 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. +% +@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 +% that, assuming it is called before the first `\' could plausibly occur. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} + +%% 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 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/lib/termcap/termcap.c b/lib/termcap/termcap.c new file mode 100644 index 0000000..3d6125a --- /dev/null +++ b/lib/termcap/termcap.c @@ -0,0 +1,716 @@ +/* Work-alike for termcap, plus extra features. + Copyright (C) 1985, 1986, 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; see the file COPYING. If not, write to +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)) +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#include <string.h> +#else +char *getenv (); +char *malloc (); +char *realloc (); +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _POSIX_VERSION +#include <fcntl.h> +#endif + +#endif /* not HAVE_CONFIG_H */ + +#ifndef NULL +#define NULL (char *) 0 +#endif + +/* BUFSIZE is the initial size allocated for the buffer + for reading the termcap file. + It is not a limit. + Make it large normally for speed. + Make it variable when debugging, so can exercise + increasing the space dynamically. */ + +#ifndef BUFSIZE +#ifdef DEBUG +#define BUFSIZE bufsize + +int bufsize = 128; +#else +#define BUFSIZE 2048 +#endif +#endif + +#ifndef emacs +static void +memory_out () +{ + write (2, "virtual memory exhausted\n", 25); + exit (1); +} + +static char * +xmalloc (size) + unsigned size; +{ + register char *tem = malloc (size); + + if (!tem) + memory_out (); + return tem; +} + +static char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *tem = realloc (ptr, size); + + if (!tem) + memory_out (); + return tem; +} +#endif /* not emacs */ + +/* Looking up capabilities in the entry already found. */ + +/* The pointer to the data made by tgetent is left here + for tgetnum, tgetflag and tgetstr to find. */ +static char *term_entry; + +static char *tgetst1 (); + +/* Search entry BP for capability CAP. + Return a pointer to the capability (in BP) if found, + 0 if not found. */ + +static char * +find_capability (bp, cap) + register char *bp, *cap; +{ + for (; *bp; bp++) + if (bp[0] == ':' + && bp[1] == cap[0] + && bp[2] == cap[1]) + return &bp[4]; + return NULL; +} + +int +tgetnum (cap) + char *cap; +{ + register char *ptr = find_capability (term_entry, cap); + if (!ptr || ptr[-1] != '#') + return -1; + return atoi (ptr); +} + +int +tgetflag (cap) + char *cap; +{ + register char *ptr = find_capability (term_entry, cap); + return ptr && ptr[-1] == ':'; +} + +/* Look up a string-valued capability CAP. + If AREA is non-null, it points to a pointer to a block in which + to store the string. That pointer is advanced over the space used. + If AREA is null, space is allocated with `malloc'. */ + +char * +tgetstr (cap, area) + char *cap; + char **area; +{ + register char *ptr = find_capability (term_entry, cap); + if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~')) + return NULL; + return tgetst1 (ptr, area); +} + +/* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted, + gives meaning of character following \, or a space if no special meaning. + Eight characters per line within the string. */ + +static char esctab[] + = " \007\010 \033\014 \ + \012 \ + \015 \011 \013 \ + "; + +/* PTR points to a string value inside a termcap entry. + Copy that value, processing \ and ^ abbreviations, + into the block that *AREA points to, + or to newly allocated storage if AREA is NULL. + Return the address to which we copied the value, + or NULL if PTR is NULL. */ + +static char * +tgetst1 (ptr, area) + char *ptr; + char **area; +{ + register char *p, *r; + register int c; + register int size; + char *ret; + register int c1; + + if (!ptr) + return NULL; + + /* `ret' gets address of where to store the string. */ + if (!area) + { + /* Compute size of block needed (may overestimate). */ + p = ptr; + while ((c = *p++) && c != ':' && c != '\n') + ; + ret = (char *) xmalloc (p - ptr + 1); + } + else + ret = *area; + + /* Copy the string value, stopping at null or colon. + Also process ^ and \ abbreviations. */ + p = ptr; + r = ret; + while ((c = *p++) && c != ':' && c != '\n') + { + if (c == '^') + c = *p++ & 037; + else if (c == '\\') + { + c = *p++; + if (c >= '0' && c <= '7') + { + c -= '0'; + size = 0; + + while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7') + { + c *= 8; + c += c1 - '0'; + p++; + } + } + else if (c >= 0100 && c < 0200) + { + c1 = esctab[(c & ~040) - 0100]; + if (c1 != ' ') + c = c1; + } + } + *r++ = c; + } + *r = '\0'; + /* Update *AREA. */ + if (area) + *area = r + 1; + return ret; +} + +/* Outputting a string with padding. */ + +short ospeed; +/* If OSPEED is 0, we use this as the actual baud rate. */ +int tputs_baud_rate; +char PC; + +/* Actual baud rate if positive; + - baud rate / 100 if negative. */ + +static short 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 +#endif /* not VMS */ + }; + +void +tputs (str, nlines, outfun) + register char *str; + int nlines; + register int (*outfun) (); +{ + register int padcount = 0; + register int speed; + +#ifdef emacs + extern baud_rate; + speed = baud_rate; +#else + if (ospeed == 0) + speed = tputs_baud_rate; + else + speed = speeds[ospeed]; +#endif + + if (!str) + return; + + while (*str >= '0' && *str <= '9') + { + padcount += *str++ - '0'; + padcount *= 10; + } + if (*str == '.') + { + str++; + padcount += *str++ - '0'; + } + if (*str == '*') + { + str++; + padcount *= nlines; + } + while (*str) + (*outfun) (*str++); + + /* padcount is now in units of tenths of msec. */ + padcount *= speeds[ospeed]; + padcount += 500; + padcount /= 1000; + if (speeds[ospeed] < 0) + padcount = -padcount; + else + { + padcount += 50; + padcount /= 100; + } + + while (padcount-- > 0) + (*outfun) (PC); +} + +/* Finding the termcap entry in the termcap data base. */ + +struct buffer + { + char *beg; + int size; + char *ptr; + int ateof; + int full; + }; + +/* Forward declarations of static functions. */ + +static int scan_file (); +static char *gobble_line (); +static int compare_contin (); +static int name_match (); + +#ifdef VMS + +#include <rmsdef.h> +#include <fab.h> +#include <nam.h> + +static int +valid_filename_p (fn) + char *fn; +{ + struct FAB fab = cc$rms_fab; + struct NAM nam = cc$rms_nam; + char esa[NAM$C_MAXRSS]; + + fab.fab$l_fna = fn; + fab.fab$b_fns = strlen(fn); + fab.fab$l_nam = &nam; + fab.fab$l_fop = FAB$M_NAM; + + nam.nam$l_esa = esa; + nam.nam$b_ess = sizeof esa; + + return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL; +} + +#else /* !VMS */ + +#define valid_filename_p(fn) (*(fn) == '/') + +#endif /* !VMS */ + +/* Find the termcap entry data for terminal type NAME + and store it in the block that BP points to. + Record its address for future use. + + If BP is null, space is dynamically allocated. + + Return -1 if there is some difficulty accessing the data base + of terminal types, + 0 if the data base is accessible but the type NAME is not defined + in it, and some other value otherwise. */ + +int +tgetent (bp, name) + char *bp, *name; +{ + register char *termcap_name; + register int fd; + struct buffer buf; + register char *bp1; + char *bp2; + char *term; + int malloc_size = 0; + register int c; + char *tcenv; /* TERMCAP value, if it contains :tc=. */ + char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */ + int filep; + + termcap_name = getenv ("TERMCAP"); + if (termcap_name && *termcap_name == '\0') + termcap_name = NULL; + + filep = termcap_name && valid_filename_p (termcap_name); + + /* If termcap_name is non-null and starts with / (in the un*x case, that is), + it is a file name to use instead of /etc/termcap. + If it is non-null and does not start with /, + it is the entry itself, but only if + the name the caller requested matches the TERM variable. */ + + if (termcap_name && !filep && !strcmp (name, getenv ("TERM"))) + { + indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0); + if (!indirect) + { + if (!bp) + bp = termcap_name; + else + strcpy (bp, termcap_name); + goto ret; + } + else + { /* It has tc=. Need to read /etc/termcap. */ + tcenv = termcap_name; + termcap_name = NULL; + } + } + + if (!termcap_name || !filep) +#ifdef VMS + termcap_name = "emacs_library:[etc]termcap.dat"; +#else + termcap_name = "/etc/termcap"; +#endif + + /* Here we know we must search a file and termcap_name has its name. */ + + fd = open (termcap_name, 0, 0); + if (fd < 0) + return -1; + + buf.size = BUFSIZE; + /* Add 1 to size to ensure room for terminating null. */ + buf.beg = (char *) xmalloc (buf.size + 1); + term = indirect ? indirect : name; + + if (!bp) + { + malloc_size = indirect ? strlen (tcenv) + 1 : buf.size; + bp = (char *) xmalloc (malloc_size); + } + bp1 = bp; + + if (indirect) + /* Copy the data from the environment variable. */ + { + strcpy (bp, tcenv); + bp1 += strlen (tcenv); + } + + while (term) + { + /* Scan the file, reading it via buf, till find start of main entry. */ + if (scan_file (term, fd, &buf) == 0) + { + close (fd); + free (buf.beg); + if (malloc_size) + free (bp); + return 0; + } + + /* Free old `term' if appropriate. */ + if (term != name) + free (term); + + /* If BP is malloc'd by us, make sure it is big enough. */ + if (malloc_size) + { + malloc_size = bp1 - bp + buf.size; + termcap_name = (char *) xrealloc (bp, malloc_size); + bp1 += termcap_name - bp; + bp = termcap_name; + } + + bp2 = bp1; + + /* Copy the line of the entry from buf into bp. */ + termcap_name = buf.ptr; + while ((*bp1++ = c = *termcap_name++) && c != '\n') + /* Drop out any \ newline sequence. */ + if (c == '\\' && *termcap_name == '\n') + { + bp1--; + termcap_name++; + } + *bp1 = '\0'; + + /* Does this entry refer to another terminal type's entry? + If something is found, copy it into heap and null-terminate it. */ + term = tgetst1 (find_capability (bp2, "tc"), (char **) 0); + } + + close (fd); + free (buf.beg); + + if (malloc_size) + bp = (char *) xrealloc (bp, bp1 - bp + 1); + + ret: + term_entry = bp; + if (malloc_size) + return (int) bp; + return 1; +} + +/* Given file open on FD and buffer BUFP, + scan the file from the beginning until a line is found + that starts the entry for terminal type STR. + Return 1 if successful, with that line in BUFP, + or 0 if no entry is found in the file. */ + +static int +scan_file (str, fd, bufp) + char *str; + int fd; + register struct buffer *bufp; +{ + register char *end; + + bufp->ptr = bufp->beg; + bufp->full = 0; + bufp->ateof = 0; + *bufp->ptr = '\0'; + + lseek (fd, 0L, 0); + + while (!bufp->ateof) + { + /* Read a line into the buffer. */ + end = NULL; + do + { + /* if it is continued, append another line to it, + until a non-continued line ends. */ + end = gobble_line (fd, bufp, end); + } + while (!bufp->ateof && end[-2] == '\\'); + + if (*bufp->ptr != '#' + && name_match (bufp->ptr, str)) + return 1; + + /* Discard the line just processed. */ + bufp->ptr = end; + } + return 0; +} + +/* Return nonzero if NAME is one of the names specified + by termcap entry LINE. */ + +static int +name_match (line, name) + char *line, *name; +{ + register char *tem; + + if (!compare_contin (line, name)) + return 1; + /* This line starts an entry. Is it the right one? */ + for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++) + if (*tem == '|' && !compare_contin (tem + 1, name)) + return 1; + + return 0; +} + +static int +compare_contin (str1, str2) + register char *str1, *str2; +{ + register int c1, c2; + while (1) + { + c1 = *str1++; + c2 = *str2++; + while (c1 == '\\' && *str1 == '\n') + { + str1++; + while ((c1 = *str1++) == ' ' || c1 == '\t'); + } + if (c2 == '\0') + { + /* End of type being looked up. */ + if (c1 == '|' || c1 == ':') + /* If end of name in data base, we win. */ + return 0; + else + return 1; + } + else if (c1 != c2) + return 1; + } +} + +/* Make sure that the buffer <- BUFP contains a full line + of the file open on FD, starting at the place BUFP->ptr + points to. Can read more of the file, discard stuff before + BUFP->ptr, or make the buffer bigger. + + Return the pointer to after the newline ending the line, + or to the end of the file, if there is no newline to end it. + + Can also merge on continuation lines. If APPEND_END is + non-null, it points past the newline of a line that is + continued; we add another line onto it and regard the whole + thing as one line. The caller decides when a line is continued. */ + +static char * +gobble_line (fd, bufp, append_end) + int fd; + register struct buffer *bufp; + char *append_end; +{ + register char *end; + register int nread; + register char *buf = bufp->beg; + register char *tem; + + if (!append_end) + append_end = bufp->ptr; + + while (1) + { + end = append_end; + while (*end && *end != '\n') end++; + if (*end) + break; + if (bufp->ateof) + return buf + bufp->full; + if (bufp->ptr == buf) + { + if (bufp->full == bufp->size) + { + bufp->size *= 2; + /* Add 1 to size to ensure room for terminating null. */ + tem = (char *) xrealloc (buf, bufp->size + 1); + bufp->ptr = (bufp->ptr - buf) + tem; + append_end = (append_end - buf) + tem; + bufp->beg = buf = tem; + } + } + else + { + append_end -= bufp->ptr - buf; + bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf); + bufp->ptr = buf; + } + if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full))) + bufp->ateof = 1; + bufp->full += nread; + buf[bufp->full] = '\0'; + } + return end + 1; +} + +#ifdef TEST + +#ifdef NULL +#undef NULL +#endif + +#include <stdio.h> + +main (argc, argv) + int argc; + char **argv; +{ + char *term; + char *buf; + + term = argv[1]; + printf ("TERM: %s\n", term); + + buf = (char *) tgetent (0, term); + if ((int) buf <= 0) + { + printf ("No entry.\n"); + return 0; + } + + printf ("Entry: %s\n", buf); + + tprint ("cm"); + tprint ("AL"); + + printf ("co: %d\n", tgetnum ("co")); + printf ("am: %d\n", tgetflag ("am")); +} + +tprint (cap) + char *cap; +{ + char *x = tgetstr (cap, 0); + register char *y; + + printf ("%s: ", cap); + if (x) + { + for (y = x; *y; y++) + if (*y <= ' ' || *y == 0177) + printf ("\\%0o", *y); + else + putchar (*y); + free (x); + } + else + printf ("none"); + putchar ('\n'); +} + +#endif /* TEST */ + diff --git a/lib/termcap/termcap.h b/lib/termcap/termcap.h new file mode 100644 index 0000000..e9d9361 --- /dev/null +++ b/lib/termcap/termcap.h @@ -0,0 +1,62 @@ +/* Declarations for termcap library. + Copyright (C) 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. */ + +#ifndef _TERMCAP_H +#define _TERMCAP_H 1 + +#if __STDC__ + +extern int tgetent (char *buffer, const char *termtype); + +extern int tgetnum (const char *name); +extern int tgetflag (const char *name); +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 char *tparam (const char *ctlstring, char *buffer, int size, ...); + +extern char *UP; +extern char *BC; + +extern char *tgoto (const char *cstring, int hpos, int vpos); + +#else /* not __STDC__ */ + +extern int tgetent (); + +extern int tgetnum (); +extern int tgetflag (); +extern char *tgetstr (); + +extern char PC; +extern short ospeed; + +extern void tputs (); + +extern char *tparam (); + +extern char *UP; +extern char *BC; + +extern char *tgoto (); + +#endif /* not __STDC__ */ + +#endif /* not _TERMCAP_H */ diff --git a/lib/termcap/tparam.c b/lib/termcap/tparam.c new file mode 100644 index 0000000..4badb65 --- /dev/null +++ b/lib/termcap/tparam.c @@ -0,0 +1,325 @@ +/* Merge parameters into a termcap entry string. + Copyright (C) 1985, 1987, 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; see the file COPYING. If not, write to +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)) +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#include <string.h> +#else +char *malloc (); +char *realloc (); +#endif + +#endif /* not HAVE_CONFIG_H */ + +#ifndef NULL +#define NULL (char *) 0 +#endif + +#ifndef emacs +static void +memory_out () +{ + write (2, "virtual memory exhausted\n", 25); + exit (1); +} + +static char * +xmalloc (size) + unsigned size; +{ + register char *tem = malloc (size); + + if (!tem) + memory_out (); + return tem; +} + +static char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *tem = realloc (ptr, size); + + if (!tem) + memory_out (); + return tem; +} +#endif /* not emacs */ + +/* Assuming STRING is the value of a termcap string entry + containing `%' constructs to expand parameters, + merge in parameter values and store result in block OUTSTRING points to. + LEN is the length of OUTSTRING. If more space is needed, + a block is allocated with `malloc'. + + The value returned is the address of the resulting string. + This may be OUTSTRING or may be the address of a block got with `malloc'. + In the latter case, the caller must free the block. + + The fourth and following args to tparam serve as the parameter values. */ + +static char *tparam1 (); + +/* VARARGS 2 */ +char * +tparam (string, outstring, len, arg0, arg1, arg2, arg3) + char *string; + char *outstring; + 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; +char *UP; + +static char tgoto_buf[50]; + +char * +tgoto (cm, hpos, vpos) + char *cm; + int hpos, vpos; +{ + int args[2]; + if (!cm) + return NULL; + args[0] = vpos; + args[1] = hpos; + return tparam1 (cm, tgoto_buf, 50, UP, BC, args); +} + +static char * +tparam1 (string, outstring, len, up, left, argp) + char *string; + char *outstring; + int len; + char *up, *left; + register int *argp; +{ + register int c; + register char *p = string; + register char *op = outstring; + char *outend; + int outlen = 0; + + register int tem; + int *old_argp = argp; + int doleft = 0; + int doup = 0; + + outend = outstring + len; + + while (1) + { + /* If the buffer might be too short, make it bigger. */ + if (op + 5 >= outend) + { + register char *new; + if (outlen == 0) + { + outlen = len + 40; + new = (char *) xmalloc (outlen); + outend += 40; + bcopy (outstring, new, op - outstring); + } + else + { + outend += outlen; + outlen *= 2; + new = (char *) xrealloc (outstring, outlen); + } + op += new - outstring; + outend += new - outstring; + outstring = new; + } + c = *p++; + if (!c) + break; + if (c == '%') + { + c = *p++; + tem = *argp; + switch (c) + { + case 'd': /* %d means output in decimal. */ + if (tem < 10) + goto onedigit; + if (tem < 100) + goto twodigit; + case '3': /* %3 means output in decimal, 3 digits. */ + if (tem > 999) + { + *op++ = tem / 1000 + '0'; + tem %= 1000; + } + *op++ = tem / 100 + '0'; + case '2': /* %2 means output in decimal, 2 digits. */ + twodigit: + tem %= 100; + *op++ = tem / 10 + '0'; + onedigit: + *op++ = tem % 10 + '0'; + argp++; + break; + + case 'C': + /* For c-100: print quotient of value by 96, if nonzero, + then do like %+. */ + if (tem >= 96) + { + *op++ = tem / 96; + tem %= 96; + } + case '+': /* %+x means add character code of char x. */ + tem += *p++; + case '.': /* %. means output as character. */ + if (left) + { + /* If want to forbid output of 0 and \n and \t, + and this is one of them, increment it. */ + while (tem == 0 || tem == '\n' || tem == '\t') + { + tem++; + if (argp == old_argp) + doup++, outend -= strlen (up); + else + doleft++, outend -= strlen (left); + } + } + *op++ = tem ? tem : 0200; + case 'f': /* %f means discard next arg. */ + argp++; + break; + + case 'b': /* %b means back up one arg (and re-use it). */ + argp--; + break; + + case 'r': /* %r means interchange following two args. */ + argp[0] = argp[1]; + argp[1] = tem; + old_argp++; + break; + + case '>': /* %>xy means if arg is > char code of x, */ + if (argp[0] > *p++) /* then add char code of y to the arg, */ + argp[0] += *p; /* and in any case don't output. */ + p++; /* Leave the arg to be output later. */ + break; + + case 'a': /* %a means arithmetic. */ + /* Next character says what operation. + Add or subtract either a constant or some other arg. */ + /* First following character is + to add or - to subtract + or = to assign. */ + /* Next following char is 'p' and an arg spec + (0100 plus position of that arg relative to this one) + or 'c' and a constant stored in a character. */ + tem = p[2] & 0177; + if (p[1] == 'p') + tem = argp[tem - 0100]; + if (p[0] == '-') + argp[0] -= tem; + else if (p[0] == '+') + argp[0] += tem; + else if (p[0] == '*') + argp[0] *= tem; + else if (p[0] == '/') + argp[0] /= tem; + else + argp[0] = tem; + + p += 3; + break; + + case 'i': /* %i means add one to arg, */ + argp[0] ++; /* and leave it to be output later. */ + argp[1] ++; /* Increment the following arg, too! */ + break; + + case '%': /* %% means output %; no arg. */ + goto ordinary; + + case 'n': /* %n means xor each of next two args with 140. */ + argp[0] ^= 0140; + argp[1] ^= 0140; + break; + + case 'm': /* %m means xor each of next two args with 177. */ + argp[0] ^= 0177; + argp[1] ^= 0177; + break; + + case 'B': /* %B means express arg as BCD char code. */ + argp[0] += 6 * (tem / 10); + break; + + case 'D': /* %D means weird Delta Data transformation. */ + argp[0] -= 2 * (tem % 16); + break; + } + } + else + /* Ordinary character in the argument string. */ + ordinary: + *op++ = c; + } + *op = 0; + while (doup-- > 0) + strcat (op, up); + while (doleft-- > 0) + strcat (op, left); + return outstring; +} + +#ifdef DEBUG + +main (argc, argv) + int argc; + char **argv; +{ + char buf[50]; + int args[3]; + args[0] = atoi (argv[2]); + args[1] = atoi (argv[3]); + args[2] = atoi (argv[4]); + tparam1 (argv[1], buf, "LEFT", "UP", args); + printf ("%s\n", buf); + return 0; +} + +#endif /* DEBUG */ diff --git a/lib/termcap/version.c b/lib/termcap/version.c new file mode 100644 index 0000000..51336db --- /dev/null +++ b/lib/termcap/version.c @@ -0,0 +1,2 @@ +/* Make the library identifiable with the RCS ident command. */ +static char *version_string = "\n$Version: GNU termcap 1.2 $\n"; diff --git a/lib/tilde/ChangeLog b/lib/tilde/ChangeLog new file mode 100644 index 0000000..986db67 --- /dev/null +++ b/lib/tilde/ChangeLog @@ -0,0 +1,6 @@ +Mon Jul 13 12:01:51 1992 Brian Fox (bfox@cubit) + + * tilde.c: (tilde_expand_word) If there is no variable $HOME, then + look up the user's home directory in the password database. + + diff --git a/lib/tilde/Makefile b/lib/tilde/Makefile new file mode 100644 index 0000000..50b4285 --- /dev/null +++ b/lib/tilde/Makefile @@ -0,0 +1,98 @@ +## -*- 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/doc/Makefile b/lib/tilde/doc/Makefile new file mode 100644 index 0000000..4e158bf --- /dev/null +++ b/lib/tilde/doc/Makefile @@ -0,0 +1,5 @@ +all: + cp tilde.texi tilde.info + +clean realclean maintainer-clean: + rm -f tilde.?? tilde.info diff --git a/lib/tilde/doc/tilde.texi b/lib/tilde/doc/tilde.texi new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tilde/doc/tilde.texi diff --git a/lib/tilde/memalloc.h b/lib/tilde/memalloc.h new file mode 100644 index 0000000..750d53d --- /dev/null +++ b/lib/tilde/memalloc.h @@ -0,0 +1,56 @@ +/* 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 <malloc.h> +# else /* !IBMESA */ +# include <alloca.h> +# 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 new file mode 100644 index 0000000..da75d95 --- /dev/null +++ b/lib/tilde/tilde.c @@ -0,0 +1,380 @@ +/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */ + +/* Copyright (C) 1988,1989 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_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "tilde.h" +#include <sys/types.h> +#include <pwd.h> + +#if defined (USG) && !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwuid (), *getpwnam (); +#endif /* USG && !defined (HAVE_GETPW_DECLS) */ + +#if !defined (savestring) +extern char *xmalloc (); +# ifndef strcpy +extern char *strcpy (); +# endif +#define savestring(x) 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 */ + +#if defined (TEST) || defined (STATIC_MALLOC) +static char *xmalloc (), *xrealloc (); +#else +extern char *xmalloc (), *xrealloc (); +#endif /* TEST || STATIC_MALLOC */ + +/* The default value of tilde_additional_prefixes. This is set to + whitespace preceding a tilde so that simple programs which do not + perform any word separation get desired behaviour. */ +static char *default_prefixes[] = + { " ~", "\t~", (char *)NULL }; + +/* The default value of tilde_additional_suffixes. This is set to + whitespace or newline so that simple programs which do not + perform any word separation get desired behaviour. */ +static char *default_suffixes[] = + { " ", "\n", (char *)NULL }; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +char **tilde_additional_prefixes = default_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +char **tilde_additional_suffixes = default_suffixes; + +/* Find the start of a tilde expansion in STRING, and return the index of + the tilde which starts the expansion. Place the length of the text + which identified this tilde starter in LEN, excluding the tilde itself. */ +static int +tilde_find_prefix (string, len) + char *string; + int *len; +{ + register int i, j, string_len; + register char **prefixes = tilde_additional_prefixes; + + string_len = strlen (string); + *len = 0; + + if (!*string || *string == '~') + return (0); + + if (prefixes) + { + for (i = 0; i < string_len; i++) + { + for (j = 0; prefixes[j]; j++) + { + if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0) + { + *len = strlen (prefixes[j]) - 1; + return (i + *len); + } + } + } + } + return (string_len); +} + +/* Find the end of a tilde expansion in STRING, and return the index of + the character which ends the tilde definition. */ +static int +tilde_find_suffix (string) + char *string; +{ + register int i, j, string_len; + register char **suffixes = tilde_additional_suffixes; + + string_len = strlen (string); + + for (i = 0; i < string_len; i++) + { + if (string[i] == '/' || !string[i]) + break; + + for (j = 0; suffixes && suffixes[j]; j++) + { + if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0) + return (i); + } + } + return (i); +} + +/* Return a new string which is the result of tilde expanding STRING. */ +char * +tilde_expand (string) + char *string; +{ + char *result, *tilde_expand_word (); + int result_size, result_index; + + result_size = result_index = 0; + result = (char *)NULL; + + /* Scan through STRING expanding tildes as we come to them. */ + while (1) + { + register int start, end; + char *tilde_word, *expansion; + int len; + + /* Make START point to the tilde which starts the expansion. */ + start = tilde_find_prefix (string, &len); + + /* Copy the skipped text into the result. */ + if ((result_index + start + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); + + strncpy (result + result_index, string, start); + result_index += start; + + /* Advance STRING to the starting tilde. */ + string += start; + + /* Make END be the index of one after the last character of the + username. */ + end = tilde_find_suffix (string); + + /* If both START and END are zero, we are all done. */ + if (!start && !end) + break; + + /* Expand the entire tilde word, and copy it into RESULT. */ + tilde_word = (char *)xmalloc (1 + end); + strncpy (tilde_word, string, end); + tilde_word[end] = '\0'; + string += end; + + expansion = tilde_expand_word (tilde_word); + free (tilde_word); + + len = strlen (expansion); + if ((result_index + len + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); + + strcpy (result + result_index, expansion); + result_index += len; + free (expansion); + } + + result[result_index] = '\0'; + + return (result); +} + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. */ +char * +tilde_expand_word (filename) + char *filename; +{ + char *dirname; + + dirname = filename ? savestring (filename) : (char *)NULL; + + if (dirname && *dirname == '~') + { + char *temp_name; + if (!dirname[1] || dirname[1] == '/') + { + /* Prepend $HOME to the rest of the string. */ + char *temp_home = (char *)getenv ("HOME"); + + /* 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; + } + + 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 + { + char *username; + struct passwd *user_entry; + int i; + + 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)) == 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) + { + 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; + } + } + /* 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); + } + } + return (dirname); +} + + +#if defined (TEST) +#undef NULL +#include <stdio.h> + +main (argc, argv) + int argc; + char **argv; +{ + char *result, line[512]; + int done = 0; + + while (!done) + { + printf ("~expand: "); + fflush (stdout); + + if (!gets (line)) + strcpy (line, "done"); + + if ((strcmp (line, "done") == 0) || + (strcmp (line, "quit") == 0) || + (strcmp (line, "exit") == 0)) + { + done = 1; + break; + } + + result = tilde_expand (line); + printf (" --> %s\n", result); + free (result); + } + exit (0); +} + +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 (); +} + +/* + * Local variables: + * compile-command: "gcc -g -DTEST -o tilde tilde.c" + * end: + */ +#endif /* TEST */ diff --git a/lib/tilde/tilde.h b/lib/tilde/tilde.h new file mode 100644 index 0000000..726d081 --- /dev/null +++ b/lib/tilde/tilde.h @@ -0,0 +1,38 @@ +/* tilde.h: Externally available variables and function in libtilde.a. */ + +#if !defined (__TILDE_H__) +# define __TILDE_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 */ + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern CPFunction *tilde_expansion_failure_hook; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +extern char **tilde_additional_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +extern char **tilde_additional_suffixes; + +/* Return a new string which is the result of tilde expanding STRING. */ +extern char *tilde_expand (); + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. */ +extern char *tilde_expand_word (); + +#endif /* __TILDE_H__ */ diff --git a/machines.h b/machines.h new file mode 100644 index 0000000..7fe1ff9 --- /dev/null +++ b/machines.h @@ -0,0 +1,2392 @@ +/* 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 <ronald@robobar.co.uk>). */ +# 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 <mbrennen@maverick.intecom.com>) */ +# 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 <machine/param.h> +# 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 <sys/param.h> +# 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 + <pwd.h> that cannot handle redefinitions in the + bash source + HAVE_RESOURCE - <sys/resource.h> 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 <sys/types.h> + 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<lib> 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 new file mode 100644 index 0000000..78f657d --- /dev/null +++ b/mailcheck.c @@ -0,0 +1,427 @@ +/* mailcheck.c -- The check is in the mail... */ + +/* 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 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 <stdio.h> +#include "bashtypes.h" +#include "posixstat.h" +#include <sys/param.h> +#include "bashansi.h" +#include "shell.h" +#include "maxpath.h" +#include "execute_cmd.h" +#include <tilde/tilde.h> + +#ifndef NOW +#define NOW ((time_t)time ((time_t *)0)) +#endif + +typedef struct { + char *name; + time_t access_time; + time_t mod_time; + long file_size; +} FILEINFO; + +/* The list of remembered mail files. */ +FILEINFO **mailfiles = (FILEINFO **)NULL; + +/* Number of mail files that we have. */ +int mailfiles_count = 0; + +/* The last known time that mail was checked. */ +int last_time_mail_checked = 0; + +/* 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; + + /* Skip leading whitespace in MAILCHECK. */ + if (temp) + { + while (whitespace (*temp)) + temp++; + + seconds = atoi (temp); + } + + /* Negative number, or non-numbers (such as empty string) cause no + checking to take place. */ + if (seconds < 0) + return (0); + + /* 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)); +} + +/* Okay, we have checked the mail. Perhaps I should make this function + go away. */ +void +reset_mail_timer () +{ + last_time_mail_checked = NOW; +} + +/* Locate a file in the list. Return index of + entry, or -1 if not found. */ +static int +find_mail_file (file) + char *file; +{ + register int i; + + for (i = 0; i < mailfiles_count; i++) + if (STREQ ((mailfiles[i])->name, file)) + return i; + + return -1; +} + +/* 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; +{ + struct stat finfo; + char *filename; + int i; + + filename = full_pathname (file); + i = find_mail_file (file); + if (i > -1) + { + if (stat (filename, &finfo) == 0) + { + mailfiles[i]->mod_time = finfo.st_mtime; + mailfiles[i]->access_time = finfo.st_atime; + mailfiles[i]->file_size = (long)finfo.st_size; + } + free (filename); + return i; + } + + i = mailfiles_count++; + mailfiles = (FILEINFO **)xrealloc + (mailfiles, mailfiles_count * sizeof (FILEINFO *)); + + 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; + } + return i; +} + +/* Reset the existing mail files access and modification times to zero. */ +void +reset_mail_files () +{ + register int i; + + for (i = 0; i < mailfiles_count; i++) + { + mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; + mailfiles[i]->file_size = 0L; + } +} + +/* Free the information that we have about the remembered mail files. */ +void +free_mail_files () +{ + register int i; + + for (i = 0; i < mailfiles_count; i++) + { + free (mailfiles[i]->name); + free (mailfiles[i]); + } + + if (mailfiles) + free (mailfiles); + + mailfiles_count = 0; + mailfiles = (FILEINFO **)NULL; +} + +/* 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; +{ + time_t time = (time_t)0; + struct stat finfo; + int i; + + i = find_mail_file (file); + if (i != -1) + time = mailfiles[i]->mod_time; + + if ((stat (file, &finfo) == 0) && (finfo.st_size > 0)) + return (time != finfo.st_mtime); + + return (0); +} + +/* Return non-zero if FILE's access date has changed. */ +static int +file_access_date_changed (file) + char *file; +{ + time_t time = (time_t)0; + struct stat finfo; + int i; + + i = find_mail_file (file); + if (i != -1) + time = mailfiles[i]->access_time; + + if ((stat (file, &finfo) == 0) && (finfo.st_size > 0)) + return (time != finfo.st_atime); + + return (0); +} + +/* Return non-zero if FILE's size has increased. */ +static int +file_has_grown (file) + char *file; +{ + long size = 0L; + struct stat finfo; + int i; + + i = find_mail_file (file); + if (i != -1) + 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. */ +static char * +parse_mailpath_spec (str) + char *str; +{ + char *s; + int pass_next; + + for (s = str, pass_next = 0; s && *s; s++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + if (*s == '\\') + { + pass_next++; + continue; + } + if (*s == '?' || *s == '%') + return s; + } + return ((char *)NULL); +} + +/* 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. */ +void +remember_mail_dates () +{ + char *mailpaths; + char *mailfile, *mp; + int i = 0; + + mailpaths = get_mailpaths (); + while (mailfile = extract_colon_unit (mailpaths, &i)) + { + mp = parse_mailpath_spec (mailfile); + if (mp && *mp) + *mp = '\0'; + add_mail_file (mailfile); + free (mailfile); + } + free (mailpaths); +} + +/* check_mail () is useful for more than just checking mail. Since it has + the paranoids dream ability of telling you when someone has read your + mail, it can just as easily be used to tell you when someones .profile + file has been read, thus letting one know when someone else has logged + in. Pretty good, huh? */ + +/* 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 + mail file has been accessed since the last time we remembered, then + the message "The mail in <mailfile> 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; + + 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))) + { + char *t; + int use_user_notification; + + if (!*current_mail_file) + { + free (current_mail_file); + continue; + } + + t = full_pathname (current_mail_file); + free (current_mail_file); + current_mail_file = t; + + use_user_notification = 0; + you_have_mail_message = "You have mail in $_"; + + mp = parse_mailpath_spec (current_mail_file); + if (mp && *mp) + { + *mp = '\0'; + you_have_mail_message = ++mp; + use_user_notification++; + } + + 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 + resets all the information. */ + file_is_bigger = file_has_grown (current_mail_file); + + i = add_mail_file (current_mail_file); + + if (i == -1) + continue; /* if this returns -1 , it is a bug */ + + /* If the user has just run a program which manipulates the + mail file, then don't bother explaining that the mail + file has been manipulated. Since some systems don't change + the access time to be equal to the modification time when + 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; + } + + /* 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 $_"; +#undef atime +#undef mtime + + if ((tlist = expand_string (you_have_mail_message, 1))) + { + char *tem = string_list (tlist); + printf ("%s\n", tem); + free (tem); + dispose_words (tlist); + } + else + printf ("\n"); + } + + if (find_variable ("MAIL_WARNING") && + file_access_date_changed (current_mail_file)) + { + add_mail_file (current_mail_file); + printf ("The mail in %s has been read!\n", current_mail_file); + } + + free (current_mail_file); + } + free (mailpaths); + + if (dollar_underscore) + { + bind_variable ("_", dollar_underscore); + free (dollar_underscore); + } + else + unbind_variable ("_"); +} diff --git a/make_cmd.c b/make_cmd.c new file mode 100644 index 0000000..85eb3d5 --- /dev/null +++ b/make_cmd.c @@ -0,0 +1,612 @@ +/* make_cmd.c -- + Functions for making instances of the various parser constructs. */ + +/* Copyright (C) 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 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 <stdio.h> +#include "bashtypes.h" +#include <sys/file.h> +#include "filecntl.h" +#include "bashansi.h" +#include "config.h" +#include "command.h" +#include "general.h" +#include "error.h" +#include "flags.h" +#include "make_cmd.h" +#include "subst.h" +#include "input.h" +#include "externs.h" + +#if defined (JOB_CONTROL) +#include "jobs.h" +#endif + +extern int line_number, current_command_line_count; +extern int disallow_filename_globbing; + +WORD_DESC * +make_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->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++); + } + return (temp); +} + +WORD_DESC * +make_word_from_token (token) + int token; +{ + char tokenizer[2]; + + tokenizer[0] = token; + tokenizer[1] = '\0'; + + return (make_word (tokenizer)); +} + +WORD_LIST * +make_word_list (word, link) + WORD_DESC *word; + WORD_LIST *link; +{ + WORD_LIST *temp; + + temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); + temp->word = word; + temp->next = link; + return (temp); +} + +WORD_LIST * +add_string_to_list (string, list) + char *string; + WORD_LIST *list; +{ + WORD_LIST *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; + SIMPLE_COM *pointer; +{ + COMMAND *temp; + + temp = (COMMAND *)xmalloc (sizeof (COMMAND)); + temp->type = type; + temp->value.Simple = pointer; + temp->value.Simple->flags = 0; + temp->flags = 0; + temp->redirects = (REDIRECT *)NULL; + return (temp); +} + +COMMAND * +command_connect (com1, com2, connector) + COMMAND *com1, *com2; + int connector; +{ + CONNECTION *temp; + + temp = (CONNECTION *)xmalloc (sizeof (CONNECTION)); + temp->connector = connector; + temp->first = com1; + temp->second = com2; + return (make_command (cm_connection, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_for_command (name, map_list, action) + WORD_DESC *name; + WORD_LIST *map_list; + COMMAND *action; +{ + FOR_COM *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)); +} + +#if defined (SELECT_COMMAND) +COMMAND * +make_select_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)); +} +#endif + +COMMAND * +make_group_command (command) + COMMAND *command; +{ + GROUP_COM *temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); + + temp->command = command; + return (make_command (cm_group, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_case_command (word, clauses) + WORD_DESC *word; + PATTERN_LIST *clauses; +{ + CASE_COM *temp; + + temp = (CASE_COM *)xmalloc (sizeof (CASE_COM)); + temp->flags = 0; + temp->word = word; + temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *); + return (make_command (cm_case, (SIMPLE_COM *)temp)); +} + +PATTERN_LIST * +make_pattern_list (patterns, action) + WORD_LIST *patterns; + COMMAND *action; +{ + PATTERN_LIST *temp; + + temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); + temp->patterns = REVERSE_LIST (patterns, WORD_LIST *); + temp->action = action; + temp->next = NULL; + return (temp); +} + +COMMAND * +make_if_command (test, true_case, false_case) + COMMAND *test, *true_case, *false_case; +{ + IF_COM *temp; + + temp = (IF_COM *)xmalloc (sizeof (IF_COM)); + temp->flags = 0; + temp->test = test; + temp->true_case = true_case; + temp->false_case = false_case; + return (make_command (cm_if, (SIMPLE_COM *)temp)); +} + +static COMMAND * +make_until_or_while (test, action, which) + COMMAND *test, *action; + enum command_type which; +{ + WHILE_COM *temp; + + temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); + temp->flags = 0; + temp->test = test; + temp->action = action; + return (make_command (which, (SIMPLE_COM *)temp)); +} + +COMMAND * +make_while_command (test, action) + COMMAND *test, *action; +{ + return (make_until_or_while (test, action, cm_while)); +} + +COMMAND * +make_until_command (test, action) + COMMAND *test, *action; +{ + return (make_until_or_while (test, action, cm_until)); +} + +COMMAND * +make_bare_simple_command () +{ + COMMAND *command; + SIMPLE_COM *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); +} + +/* Return a command which is the connection of the word or redirection + in ELEMENT, and the command * or NULL in COMMAND. */ +COMMAND * +make_simple_command (element, command) + ELEMENT element; + COMMAND *command; +{ + /* If we are starting from scratch, then make the initial command + structure. Also note that we have to fill in all the slots, since + 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)); + tw->word = element.word; + tw->next = command->value.Simple->words; + command->value.Simple->words = tw; + } + else + { + REDIRECT *r = element.redirect; + /* Due to the way <> is implemented, there may be more than a single + redirection in element.redirect. We just follow the chain as far + as it goes, and hook onto the end. */ + while (r->next) + r = r->next; + r->next = command->value.Simple->redirects; + command->value.Simple->redirects = element.redirect; + } + return (command); +} + +#define POSIX_HERE_DOCUMENTS +void +make_here_document (temp) + REDIRECT *temp; +{ + int kill_leading = 0; + + switch (temp->instruction) + { + /* 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: /* <<foo */ + { + 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; + } + } +} + +/* 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 * +make_redirection (source, instruction, dest_and_filename) + int source; + enum r_instruction instruction; + REDIRECTEE dest_and_filename; +{ + REDIRECT *temp = (REDIRECT *)xmalloc (sizeof (REDIRECT)); + + /* First do the common cases. */ + temp->redirector = source; + temp->redirectee = dest_and_filename; + temp->instruction = instruction; + temp->flags = 0; + temp->next = (REDIRECT *)NULL; + + switch (instruction) + { + + case r_output_direction: /* >foo */ + case r_output_force: /* >| foo */ + temp->flags = O_TRUNC | O_WRONLY | O_CREAT; + break; + + case r_input_direction: /* <foo */ + case r_inputa_direction: /* foo & makes this. */ + temp->flags = O_RDONLY; + break; + + case r_appending_to: /* >>foo */ + temp->flags = O_APPEND | O_WRONLY | O_CREAT; + break; + + case r_deblank_reading_until: /* <<-foo */ + case r_reading_until: /* << foo */ + break; + + 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; + + case r_input_output: + temp->flags = O_RDWR | O_CREAT; + break; + + default: + programming_error ("Redirection instruction from yyparse () '%d' is\n\ +out of range in make_redirection ().", instruction); + abort (); + break; + } + return (temp); +} + +COMMAND * +make_function_def (name, command) + WORD_DESC *name; + COMMAND *command; +{ + 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; + return (make_command (cm_function_def, (SIMPLE_COM *)temp)); +} + +/* Reverse the word list and redirection list in the simple command + has just been parsed. It seems simpler to do this here the one + time then by any other method that I can think of. */ +COMMAND * +clean_simple_command (command) + COMMAND *command; +{ + if (command->type != cm_simple) + { + programming_error + ("clean_simple_command () got a command with type %d.", command->type); + } + else + { + command->value.Simple->words = + REVERSE_LIST (command->value.Simple->words, WORD_LIST *); + 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 + the last command. This means that when the list is executed, all + the commands have stdin set to /dev/null when job control is not + active, instead of just the last. This is wrong, and needs fixing + up. This function takes the `&' and applies it to the last command + in the list. This is done only for lists connected by `;'; it makes + `;' bind `tighter' than `&'. */ +COMMAND * +connect_async_list (command, command2, connector) + COMMAND *command, *command2; + int connector; +{ + COMMAND *t, *t1, *t2; + + t1 = command; + t = command->value.Connection->second; + + if (!t || (command->flags & CMD_WANT_SUBSHELL) || + command->value.Connection->connector != ';') + { + t = command_connect (command, command2, connector); + return t; + } + + /* This is just defensive programming. The Yacc precedence rules + will generally hand this function a command where t points directly + to the command we want (e.g. given a ; b ; c ; d &, t1 will point + to the `a ; b ; c' list and t will be the `d'). We only want to do + this if the list is not being executed as a unit in the background + with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's + the only way to tell. */ + while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection && + t->value.Connection->connector == ';') + { + t1 = t; + t = t->value.Connection->second; + } + /* Now we have t pointing to the last command in the list, and + t1->value.Connection->second == t. */ + t2 = command_connect (t, command2, connector); + t1->value.Connection->second = t2; + return command; +} diff --git a/make_cmd.h b/make_cmd.h new file mode 100644 index 0000000..2118770 --- /dev/null +++ b/make_cmd.h @@ -0,0 +1,55 @@ +/* make_cmd.h -- Declarations of functions found in make_cmd.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 (_MAKE_CMD_H_) +#define _MAKE_CMD_H_ + +#include "stdc.h" + +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_word __P((char *)); +extern WORD_DESC *make_word_from_token __P((int)); + +extern COMMAND *make_command __P((enum command_type, SIMPLE_COM *)); +extern COMMAND *command_connect __P((COMMAND *, COMMAND *, int)); +extern COMMAND *make_for_command __P((WORD_DESC *, WORD_LIST *, COMMAND *)); +extern COMMAND *make_group_command __P((COMMAND *)); +extern COMMAND *make_case_command __P((WORD_DESC *, PATTERN_LIST *)); +extern PATTERN_LIST *make_pattern_list __P((WORD_LIST *, COMMAND *)); +extern COMMAND *make_if_command __P((COMMAND *, COMMAND *, COMMAND *)); +extern COMMAND *make_while_command __P((COMMAND *, COMMAND *)); +extern COMMAND *make_until_command __P((COMMAND *, COMMAND *)); +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 *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)); + +#endif /* !_MAKE_CMD_H */ diff --git a/maxpath.h b/maxpath.h new file mode 100644 index 0000000..6677309 --- /dev/null +++ b/maxpath.h @@ -0,0 +1,43 @@ +/* maxpath.h - Find out what this system thinks MAXPATHLEN is. */ + +/* 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 (_MAXPATH_H) +#define _MAXPATH_H + +#if !defined (MAXPATHLEN) && defined (HAVE_LIMITS_H) +# if !defined (BUILDING_MAKEFILE) +# include <limits.h> +# endif /* BUILDING_MAKEFILE */ +#endif /* !MAXPATHLEN && HAVE_LIMITS_H */ + +#if !defined (MAXPATHLEN) && defined (HAVE_SYS_PARAM) +# include <sys/param.h> +#endif /* !MAXPATHLEN && HAVE_SYS_PARAM */ + +#if !defined (MAXPATHLEN) && defined (PATH_MAX) +# define MAXPATHLEN PATH_MAX +#endif /* !MAXPATHLEN && PATH_MAX */ + +/* Yecch! Who cares about this gross concept in the first place? */ +#if !defined (MAXPATHLEN) +# define MAXPATHLEN 1024 +#endif /* MAXPATHLEN */ + +#endif /* _MAXPATH_H */ diff --git a/memalloc.h b/memalloc.h new file mode 100644 index 0000000..92c0648 --- /dev/null +++ b/memalloc.h @@ -0,0 +1,60 @@ +/* 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 <malloc.h> +# else /* !IBMESA */ +# include <alloca.h> +# endif /* !IBMESA */ +# else +# if defined (hpux_9) && defined (__STDC__) +extern void *alloca (); +# else +extern char *alloca (); +# endif +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/newversion.c b/newversion.c new file mode 100644 index 0000000..bdba480 --- /dev/null +++ b/newversion.c @@ -0,0 +1,281 @@ +/* Simple program to make new version numbers for the shell. + Big deal, but it was getting out of hand to do everything + in the makefile. */ + +/* Copyright (C) 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 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 <sys/types.h> +#include "posixstat.h" +#include <stdio.h> + +char *progname; +char *dir; + +FILE *must_open (); + +main (argc, argv) + int argc; + char **argv; +{ + FILE *file; + float distver = 0.0; + int buildver = 0, patchlevel = 0; + int dist = 0, build = 0, patch = 0; + int dist_inc = 0, build_inc = 0, patch_inc = 0; + int dot_dist_needs_making = 0; + int arg_index = 1; + struct stat sb; + + progname = argv[0]; + + while (arg_index < argc && argv[arg_index][0] == '-') + { + if (strcmp (argv[arg_index], "-dist") == 0) + { + dist++; + dist_inc++; + } + else if (strcmp (argv[arg_index], "-build") == 0) + { + build++; + build_inc++; + } + else if (strcmp (argv[arg_index], "-patch") == 0) + { + patch++; + patch_inc++; + } + else if (strcmp (argv[arg_index], "-dir") == 0) + { + dir = argv[++arg_index]; + if (dir == 0) + { + fprintf (stderr, "%s: `-dir' requires an argument\n", progname); + exit (1); + } + if (stat (dir, &sb) < 0) + { + fprintf (stderr, "%s: cannot stat %s\n", progname, dir); + exit (1); + } + if ((sb.st_mode & S_IFMT) != S_IFDIR) + { + fprintf (stderr, "%s: not a directory\n", progname); + exit (1); + } + } + else + { + fprintf (stderr, "%s: unknown option: %s\n", progname, argv[arg_index]); + fprintf (stderr, "usage: %s [-dist|-patch|-build] [-dir directory]\n", progname); + exit (1); + } + arg_index++; + } + + if (get_float_from_file (".distribution", &distver) == 0) + dot_dist_needs_making++; + + if (get_int_from_file (".patchlevel", &patchlevel) == 0) + { + patchlevel = 0; + patch_inc = 0; + } + + if (get_int_from_file (".build", &buildver) == 0) + buildver = 0; + + /* Setting distribution version. */ + if (dist && arg_index < argc) + if (sscanf (argv[arg_index], "%f", &distver) != 1) + { + fprintf (stderr, "%s: Bad input `%s'. Expected float value for -dist.\n", + progname, argv[arg_index]); + exit (1); + } + else + { + arg_index++; + dist_inc = 0; + } + + /* Setting patchlevel via argument. */ + if (patch && arg_index < argc) + if (sscanf (argv[arg_index], "%d", &patchlevel) != 1) + { + fprintf (stderr, "%s: Bad input `%s'. Expected int value for -patch.\n", + progname, argv[arg_index]); + exit (1); + } + else + { + arg_index++; + patch_inc = 0; + } + + if (build && arg_index < argc) + if (sscanf (argv[arg_index], "%d", &buildver) != 1) + { + fprintf (stderr, "%s: Bad input `%s'. Expected int value for -build.\n", + progname, argv[arg_index]); + exit (1); + } + else + { + arg_index++; + build_inc = 0; + } + + if (dot_dist_needs_making && !distver) + { + fprintf (stderr, "%s: There is no `.distribution' file to infer from.\n", progname); + exit (1); + } + + if (dist_inc) + distver = distver + 0.01; + + if (patch_inc) + patchlevel++; + + if (build_inc) + buildver++; + + file = must_open ("newversion.h", "w"); + + /* 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"); + + fprintf (file, "\n/* The distribution version number of this shell. */\n"); + fprintf (file, "#define DISTVERSION \"%.2f\"\n", distver); + + fprintf (file, "\n/* The patch level of this version of the shell. */\n"); + fprintf (file, "#define PATCHLEVEL %d\n", patchlevel); + + fprintf (file, "\n/* The last built version of this shell. */\n"); + fprintf (file, "#define BUILDVERSION %d\n", buildver); + + 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); + + fclose (file); + + file = must_open (".build", "w"); + fprintf (file, "%d\n", buildver); + fclose (file); + + /* Making a new distribution. */ + if (dist) + { + file = must_open (".distribution", "w"); + fprintf (file, "%.2f\n", distver); + fclose (file); + } + + /* Releasing a new patch level. */ + if (patch) + { + file = must_open (".patchlevel", "w"); + fprintf (file, "%d\n", patchlevel); + fclose (file); + } + + exit (0); +} + +char * +makename (fn) + char *fn; +{ + char *ret; + int dlen = 0; + + if (dir) + dlen = strlen (dir) + 1; + ret = (char *)malloc (dlen + strlen (fn) + 1); + if (ret == 0) + { + fprintf (stderr, "%s: malloc failed\n", progname); + exit (1); + } + if (dir) + sprintf (ret, "%s/%s", dir, fn); + else + strcpy (ret, fn); + + return ret; +} + +get_float_from_file (filename, var) + char *filename; + float *var; +{ + FILE *stream; + int result; + char *name; + + name = makename (filename); + stream = fopen (name, "r"); + free (name); + if (stream == (FILE *)NULL) + return (0); + result = fscanf (stream, "%f\n", var); + fclose (stream); + return (result == 1); +} + +get_int_from_file (filename, var) + char *filename; + int *var; +{ + FILE *stream; + int result; + char *name; + + name = makename (filename); + stream = fopen (name, "r"); + free (name); + if (stream == (FILE *)NULL) + return (0); + result = fscanf (stream, "%d\n", var); + fclose (stream); + return (result == 1); +} + +FILE * +must_open (name, mode) + char *name, *mode; +{ + FILE *temp = fopen (name, mode); + + if (!temp) + { + fprintf (stderr, "%s: Cannot open `%s' for mode `%s'.\n", + progname, name, mode); + fprintf + (stderr, + "Perhaps you don't have %s permission to the file or directory.\n", + (strcmp (mode, "w") == 0) ? "write" : "read"); + exit (3); + } + return (temp); +} diff --git a/nojobs.c b/nojobs.c new file mode 100644 index 0000000..e5e8d2c --- /dev/null +++ b/nojobs.c @@ -0,0 +1,644 @@ +/* The thing that makes children, remembers them, and contains wait loops. */ + +/* This file works under BSD, System V, minix, and Posix systems. */ + +/* Copyright (C) 1987, 1989, 1992 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 <stdio.h> +#include "bashtypes.h" +#include <signal.h> +#include <setjmp.h> +#include <errno.h> + +#include "config.h" +#include "command.h" +#include "general.h" +#include "filecntl.h" +#include "jobs.h" +#include "externs.h" +#include "error.h" + +#if defined (BUFFERED_INPUT) +# include "input.h" +#endif + +#if !defined (USG) && !defined (_POSIX_VERSION) +# include <sgtty.h> +#else +# if defined (_POSIX_VERSION) +# include <termios.h> +# else +# include <termio.h> +# if !defined (AIXRT) +# include <sys/ttold.h> +# endif /* !AIXRT */ +# endif /* !POSIX_VERSION */ +#endif /* USG && _POSIX_VERSION */ + +#if !defined (SIGABRT) +# define SIGABRT SIGIOT +#endif /* !SIGABRT */ + +#if defined (USG) || defined (_POSIX_VERSION) +# define killpg(pg, sig) kill(-(pg),(sig)) +#endif /* USG || _POSIX_VERSION */ + +#if defined (USG) +# define siginterrupt(sig, code) +#endif /* USG */ + +#if defined (_POSIX_VERSION) +# define WAITPID(pid, statusp, options) waitpid (pid, statusp, options) +#else +# define WAITPID(pid, statusp, options) wait (statusp) +#endif /* !_POSIX_VERSION */ + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +extern int interactive, interactive_shell, login_shell; +extern int subshell_environment; +extern int last_command_exit_value; +#if defined (_POSIX_VERSION) +extern sigset_t top_level_mask; +#endif + +pid_t last_made_pid = NO_PID; +pid_t last_asynchronous_pid = NO_PID; + +/* Call this when you start making children. */ +int already_making_children = 0; + +#if defined (_POSIX_VERSION) +static void reap_zombie_children (); +#endif + +struct proc_status { + pid_t pid; + int status; /* Exit status of PID or 128 + fatal signal number */ +}; + +static struct proc_status *pid_list = (struct proc_status *)NULL; +static int pid_list_size = 0; + +#define PROC_BAD -1 +#define PROC_STILL_ALIVE -2 + +/* Allocate new, or grow existing PID_LIST. */ +static void +alloc_pid_list () +{ + register int i; + int old = pid_list_size; + + pid_list_size += 10; + pid_list = (struct proc_status *) + xrealloc (pid_list, pid_list_size * sizeof (struct proc_status)); + + /* None of the newly allocated slots have process id's yet. */ + for (i = old; i < pid_list_size; i++) + pid_list[i].pid = NO_PID; +} + +/* Return the offset within the PID_LIST array of an empty slot. This can + create new slots if all of the existing slots are taken. */ +static int +find_proc_slot () +{ + register int i; + + for (i = 0; i < pid_list_size; i++) + if (pid_list[i].pid == NO_PID) + return (i); + + if (i == pid_list_size) + alloc_pid_list (); + + return (i); +} + +/* Return the offset within the PID_LIST array of a slot containing PID, + or the value NO_PID if the pid wasn't found. */ +static int +find_index_by_pid (pid) + pid_t pid; +{ + register int i; + + for (i = 0; i < pid_list_size; i++) + if (pid_list[i].pid == pid) + return (i); + + return (NO_PID); +} + +/* Return the status of PID as looked up in the PID_LIST array. A + return value of PROC_BAD indicates that PID wasn't found. */ +static int +find_status_by_pid (pid) + pid_t pid; +{ + int i; + + i = find_index_by_pid (pid); + if (i == NO_PID) + return (PROC_BAD); + return (pid_list[i].status); +} + +/* Give PID the status value STATUS in the PID_LIST array. */ +static void +set_pid_status (pid, status) + pid_t pid; + WAIT status; +{ + int slot; + + slot = find_index_by_pid (pid); + if (slot == NO_PID) + return; + + if (WIFSIGNALED (status)) + pid_list[slot].status = 128 + WTERMSIG (status); + else + pid_list[slot].status = WEXITSTATUS (status); +} + +static void +add_pid (pid) + pid_t pid; +{ + int slot; + + slot = find_proc_slot (); + pid_list[slot].pid = pid; + pid_list[slot].status = PROC_STILL_ALIVE; +} + +int +cleanup_dead_jobs () +{ + register int i; + +#if defined (_POSIX_VERSION) + reap_zombie_children (); +#endif + + for (i = 0; i < pid_list_size; i++) + if (pid_list[i].status != PROC_STILL_ALIVE) + pid_list[i].pid = NO_PID; +} + +/* Initialize the job control mechanism, and set up the tty stuff. */ +initialize_jobs () +{ + get_tty_state (); +} + +#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) +static SigHandler *old_winch; + +static sighandler +sigwinch_sighandler (sig) + int sig; +{ + struct winsize win; + +#if defined (USG) && !defined (_POSIX_VERSION) + 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 /* !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 */ + + /* 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 + } +} + +#if defined (_POSIX_VERSION) +/* Collect the status of all zombie children so that their system + resources can be deallocated. */ +static void +reap_zombie_children () +{ +#if defined (WNOHANG) + pid_t pid; + WAIT status; + + while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0) + set_pid_status (pid, status); +#endif /* WNOHANG */ +} +#endif /* _POSIX_VERSION */ + +/* Fork, handling errors. Returns the pid of the newly made child, or 0. + COMMAND is just for remembering the name of the command; we don't do + anything else with it. ASYNC_P says what to do with the tty. If + non-zero, then don't give it away. */ +pid_t +make_child (command, async_p) + char *command; + int async_p; +{ + pid_t pid; +#if defined (_POSIX_VERSION) + int retry = 1; +#endif /* _POSIX_VERSION */ + + /* Discard saved memory. */ + if (command) + free (command); + + start_pipeline (); + +#if defined (BUFFERED_INPUT) + /* If default_buffered_input is active, we are reading a script. If + the command is asynchronous, we have already duplicated /dev/null + as fd 0, but have not changed the buffered stream corresponding to + the old fd 0. We don't want to sync the stream in this case. */ + if (default_buffered_input != -1 && + (!async_p || default_buffered_input > 0)) + sync_buffered_stream (default_buffered_input); +#endif /* BUFFERED_INPUT */ + + /* Create the child, handle severe errors. */ +#if defined (_POSIX_VERSION) + retry_fork: +#endif /* _POSIX_VERSION */ + + if ((pid = fork ()) < 0) + { +#if defined (_POSIX_VERSION) + /* Posix systems with a non-blocking waitpid () system call available + get another chance after zombies are reaped. */ + if (errno == EAGAIN && retry) + { + reap_zombie_children (); + retry = 0; + goto retry_fork; + } +#endif /* _POSIX_VERSION */ + + internal_error ("fork: %s", strerror (errno)); + + throw_to_top_level (); + } + + if (pid == 0) + { +#if defined (BUFFERED_INPUT) + if (default_buffered_input > 0) + { + close_buffered_fd (default_buffered_input); + default_buffered_input = bash_input.location.buffered_fd = -1; + } +#endif /* BUFFERED_INPUT */ + +#if defined (_POSIX_VERSION) + /* 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 (); + } + +#if defined (SIGTSTP) + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); +#endif + } + else + { + /* In the parent. */ + + last_made_pid = pid; + + if (async_p) + last_asynchronous_pid = pid; + + add_pid (pid); + } + return (pid); +} + +/* Wait for a single pid (PID) and return its exit status. */ +wait_for_single_pid (pid) + pid_t pid; +{ + pid_t got_pid; + WAIT status; + int pstatus; + + pstatus = find_status_by_pid (pid); + + if (pstatus == PROC_BAD) + return (127); + + if (pstatus != PROC_STILL_ALIVE) + return (pstatus); + + siginterrupt (SIGINT, 1); + while ((got_pid = WAITPID (pid, &status, 0)) != pid) + { + if (got_pid < 0) + { + if (errno != EINTR && errno != ECHILD) + { + siginterrupt (SIGINT, 0); + file_error ("wait"); + } + break; + } + else if (got_pid > 0) + set_pid_status (got_pid, status); + } + + set_pid_status (got_pid, status); + siginterrupt (SIGINT, 0); + QUIT; + + if (WIFSIGNALED (status)) + return (128 + WTERMSIG (status)); + else + return (WEXITSTATUS (status)); +} + +/* Wait for all of the shell's children to exit. */ +void +wait_for_background_pids () +{ + pid_t got_pid; + WAIT status; + + /* If we aren't using job control, we let the kernel take care of the + bookkeeping for us. wait () will return -1 and set errno to ECHILD + when there are no more unwaited-for child processes on both + 4.2 BSD-based and System V-based systems. */ + + siginterrupt (SIGINT, 1); + + /* Wait for ECHILD */ + while ((got_pid = WAITPID (-1, &status, 0)) != -1) + set_pid_status (got_pid, status); + + if (errno != EINTR && errno != ECHILD) + { + siginterrupt (SIGINT, 0); + file_error("wait"); + } + + siginterrupt (SIGINT, 0); + QUIT; +} + +/* Handle SIGINT while we are waiting for children in a script to exit. + All interrupts are effectively ignored by the shell, but allowed to + kill a running job. */ +static sighandler +wait_sigint_handler (sig) + int sig; +{ +#if 0 + /* Run a trap handler if one has been defined. */ + maybe_call_trap_handler (sig); +#endif + +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* !VOID_SIGHANDLER */ +} + +/* Wait for pid (one of our children) to terminate. This is called only + by the execution code in execute_cmd.c. */ +int +wait_for (pid) + pid_t pid; +{ + int return_val, pstatus; + pid_t got_pid; + WAIT status; + SigHandler *old_sigint_handler; + + pstatus = find_status_by_pid (pid); + + if (pstatus == PROC_BAD) + return (0); + + if (pstatus != PROC_STILL_ALIVE) + return (pstatus); + + /* If we are running a script, ignore SIGINT while we're waiting for + a child to exit. The loop below does some of this, but not all. */ + if (!interactive_shell) + old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); + + while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */ + { + if (got_pid < 0 && errno == ECHILD) + { +#if !defined (_POSIX_VERSION) + status.w_termsig = status.w_retcode = 0; +#else + status = 0; +#endif /* _POSIX_VERSION */ + break; + } + else if (got_pid < 0 && errno != EINTR) + programming_error ("got errno %d while waiting for %d", errno, pid); + else if (got_pid > 0) + set_pid_status (got_pid, status); + } + + set_pid_status (got_pid, status); + +#if defined (_POSIX_VERSION) + if (got_pid >= 0) + reap_zombie_children (); +#endif /* _POSIX_VERSION */ + + if (!interactive_shell) + { + set_signal_handler (SIGINT, old_sigint_handler); + /* If the job exited because of SIGINT, make sure the shell acts as if + it had received one also. */ + if (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT)) + { + if (maybe_call_trap_handler (SIGINT) == 0) + (*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)) + { + fprintf (stderr, "%s", strsignal (WTERMSIG (status))); + if (WIFCORED (status)) + fprintf (stderr, " (core dumped)"); + fprintf (stderr, "\n"); + } + + if (interactive_shell && !subshell_environment) + { + if (WIFSIGNALED (status) || WIFSTOPPED (status)) + set_tty_state (); + else + get_tty_state (); + } + + return (return_val); +} + +/* Give PID SIGNAL. This determines what job the pid belongs to (if any). + If PID does belong to a job, and the job is stopped, then CONTinue the + job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, + then kill the process group associated with PID. */ +int +kill_pid (pid, signal, group) + pid_t pid; + int signal, group; +{ + int result; + + if (group) + result = killpg (pid, signal); + else + result = kill (pid, signal); + + return (result); +} + +#if defined (_POSIX_VERSION) +static struct termios shell_tty_info; +#else +# if defined (USG) +static struct termio shell_tty_info; +# else +static struct sgttyb shell_tty_info; +# endif /* USG */ +#endif /* _POSIX_VERSION */ + +static int got_tty_state = 0; + +/* Fill the contents of shell_tty_info with the current tty info. */ +get_tty_state () +{ + int tty = open ("/dev/tty", O_RDONLY); + if (tty != -1) + { +#if defined (_POSIX_VERSION) + tcgetattr (tty, &shell_tty_info); +#else +# if defined (USG) + ioctl (tty, TCGETA, &shell_tty_info); +# else + ioctl (tty, TIOCGETP, &shell_tty_info); +# endif +#endif + close (tty); + got_tty_state = 1; + } +} + +/* Make the current tty use the state in shell_tty_info. */ +set_tty_state () +{ + int tty = open ("/dev/tty", O_RDONLY); + if (tty != -1) + { + if (!got_tty_state) + { + close (tty); + return; + } +#if defined (_POSIX_VERSION) + tcsetattr (tty, TCSADRAIN, &shell_tty_info); +#else +# if defined (USG) + ioctl (tty, TCSETAW, &shell_tty_info); /* Wait for output, no flush */ +# else + ioctl (tty, TIOCSETN, &shell_tty_info); +# endif +#endif + close (tty); + } +} + +/* Give the terminal to PGRP. */ +give_terminal_to (pgrp) + pid_t pgrp; +{ +} + +/* Stop a pipeline. */ +stop_pipeline (async, ignore) + int async; + COMMAND *ignore; +{ + already_making_children = 0; +} + +void +start_pipeline () +{ + already_making_children = 1; +} + +/* Print descriptive information about the job with leader pid PID. */ +void +describe_pid (pid) + pid_t pid; +{ + fprintf (stderr, "%d\n", (int) pid); +} @@ -0,0 +1,3005 @@ +/* Yacc grammar for bash. */ + +/* Copyright (C) 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 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 LICENSE. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +%{ +#include <stdio.h> +#include "bashtypes.h" +#include <signal.h> +#include "bashansi.h" +#include "shell.h" +#include "flags.h" +#include "input.h" + +#if defined (READLINE) +# include <readline/readline.h> +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bashhist.h" +# include <readline/history.h> +#endif /* HISTORY */ + +#if defined (JOB_CONTROL) +# include "jobs.h" +#endif /* JOB_CONTROL */ + +#if defined (ALIAS) +# include "alias.h" +#endif /* ALIAS */ + +#if defined (PROMPT_STRING_DECODE) +#include <sys/param.h> +#include <time.h> +#include "maxpath.h" +#endif /* PROMPT_STRING_DECODE */ + +#define YYDEBUG 1 +extern int eof_encountered; +extern int no_line_editing; +extern int current_command_number; +extern int interactive, interactive_shell, login_shell; +extern int posixly_correct; +extern int last_command_exit_value; +extern int interrupt_immediately; +extern char *shell_name, *current_host_name; +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 + +/* **************************************************************** */ +/* */ +/* "Forward" declarations */ +/* */ +/* **************************************************************** */ + +/* 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 int reserved_word_acceptable (); +static int read_token (); + +static void report_syntax_error (); +static void handle_eof_input_unit (); +static void prompt_again (); +static void reset_readline_prompt (); +static void print_prompt (); + +/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ +char *ps1_prompt, *ps2_prompt; + +/* Handle on the current prompt string. Indirectly points through + ps1_ or ps2_prompt. */ +char **prompt_string_pointer = (char **)NULL; +char *current_prompt_string; + +/* 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; + +/* 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; + +/* 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) */ + +/* Either zero or EOF. */ +static int shell_input_line_terminator = 0; + +static REDIRECTEE redir; +%} + +%union { + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; +} + +/* Reserved words. Members of the first group are only recognized + 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 + +/* More general tokens. yylex () knows how to make these. */ +%token <word> WORD ASSIGNMENT_WORD +%token <number> NUMBER +%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND +%token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER +%token GREATER_BAR + +/* The types that the various syntactical units return. */ + +%type <command> inputunit command pipeline +%type <command> list list0 list1 simple_list simple_list1 +%type <command> simple_command shell_command_1 shell_command select_command +%type <command> group_command function_def if_command elif_clause subshell +%type <redirect> redirection redirections +%type <element> simple_command_element +%type <word_list> words pattern +%type <pattern> pattern_list case_clause_sequence case_clause_1 pattern_list_1 + +%start inputunit + +%left '&' ';' '\n' yacc_EOF +%left AND_AND OR_OR +%right '|' +%% + +inputunit: simple_list '\n' + { + /* Case of regular command. Discard the error + safety net,and return the command just parsed. */ + global_command = $1; + eof_encountered = 0; + discard_parser_constructs (0); + YYACCEPT; + } + | '\n' + { + /* Case of regular command, but not a very + interesting one. Return a NULL command. */ + global_command = (COMMAND *)NULL; + YYACCEPT; + } + | + error '\n' + { + /* Error during parsing. Return NULL command. */ + global_command = (COMMAND *)NULL; + eof_encountered = 0; + discard_parser_constructs (1); + if (interactive) + { + YYACCEPT; + } + else + { + YYABORT; + } + } + | yacc_EOF + { + /* Case of EOF seen by itself. Do ignoreeof or + not. */ + global_command = (COMMAND *)NULL; + handle_eof_input_unit (); + YYACCEPT; + } + ; + +words: + { $$ = (WORD_LIST *)NULL; } + | words WORD + { $$ = make_word_list ($2, $1); } + ; + +redirection: '>' WORD + { + redir.filename = $2; + $$ = make_redirection (1, r_output_direction, redir); + } + | '<' WORD + { + redir.filename = $2; + $$ = make_redirection (0, r_input_direction, redir); + } + | NUMBER '>' WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_output_direction, redir); + } + | NUMBER '<' WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_input_direction, redir); + } + | GREATER_GREATER WORD + { + redir.filename = $2; + $$ = make_redirection (1, r_appending_to, redir); + } + | NUMBER GREATER_GREATER WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_appending_to, redir); + } + | LESS_LESS WORD + { + redir.filename = $2; + $$ = make_redirection (0, r_reading_until, redir); + redir_stack[need_here_doc++] = $$; + } + | NUMBER LESS_LESS WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_reading_until, redir); + redir_stack[need_here_doc++] = $$; + } + | LESS_AND NUMBER + { + redir.dest = $2; + $$ = make_redirection (0, r_duplicating_input, redir); + } + | NUMBER LESS_AND NUMBER + { + redir.dest = $3; + $$ = make_redirection ($1, r_duplicating_input, redir); + } + | GREATER_AND NUMBER + { + redir.dest = $2; + $$ = make_redirection (1, r_duplicating_output, redir); + } + | NUMBER GREATER_AND NUMBER + { + redir.dest = $3; + $$ = make_redirection ($1, r_duplicating_output, redir); + } + | LESS_AND WORD + { + redir.filename = $2; + $$ = make_redirection (0, r_duplicating_input_word, redir); + } + | NUMBER LESS_AND WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_duplicating_input_word, redir); + } + | GREATER_AND WORD + { + redir.filename = $2; + $$ = make_redirection (1, r_duplicating_output_word, redir); + } + | NUMBER GREATER_AND WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_duplicating_output_word, redir); + } + | LESS_LESS_MINUS WORD + { + redir.filename = $2; + $$ = make_redirection + (0, r_deblank_reading_until, redir); + redir_stack[need_here_doc++] = $$; + } + | NUMBER LESS_LESS_MINUS WORD + { + redir.filename = $3; + $$ = make_redirection + ($1, r_deblank_reading_until, redir); + redir_stack[need_here_doc++] = $$; + } + | GREATER_AND '-' + { + redir.dest = 0L; + $$ = make_redirection (1, r_close_this, redir); + } + | NUMBER GREATER_AND '-' + { + redir.dest = 0L; + $$ = make_redirection ($1, r_close_this, redir); + } + | LESS_AND '-' + { + redir.dest = 0L; + $$ = make_redirection (0, r_close_this, redir); + } + | NUMBER LESS_AND '-' + { + redir.dest = 0L; + $$ = make_redirection ($1, r_close_this, redir); + } + | AND_GREATER WORD + { + redir.filename = $2; + $$ = make_redirection (1, r_err_and_out, redir); + } + | NUMBER LESS_GREATER WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_input_output, redir); + } + | 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; + } + } + | GREATER_BAR WORD + { + redir.filename = $2; + $$ = make_redirection (1, r_output_force, redir); + } + | NUMBER GREATER_BAR WORD + { + redir.filename = $3; + $$ = make_redirection ($1, r_output_force, redir); + } + ; + +simple_command_element: WORD + { $$.word = $1; $$.redirect = 0; } + | ASSIGNMENT_WORD + { $$.word = $1; $$.redirect = 0; } + | redirection + { $$.redirect = $1; $$.word = 0; } + ; + +redirections: redirection + { + $$ = $1; + } + | redirections redirection + { + register REDIRECT *t = $1; + + while (t->next) + t = t->next; + t->next = $2; + $$ = $1; + } + ; + +simple_command: simple_command_element + { $$ = make_simple_command ($1, (COMMAND *)NULL); } + | simple_command simple_command_element + { $$ = make_simple_command ($2, $1); } + ; + +command: simple_command + { $$ = clean_simple_command ($1); } + | shell_command + { $$ = $1; } + ; + +shell_command: shell_command_1 + { $$ = $1; } + | shell_command_1 redirections + { + if ($1->redirects) + { + register REDIRECT *t; + for (t = $1->redirects; t->next; t = t->next) + ; + t->next = $2; + } + else + $1->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 + { $$ = make_while_command ($2, $4); } + | UNTIL list DO list DONE + { $$ = make_until_command ($2, $4); } + | select_command + { $$ = $1; } + | if_command + { $$ = $1; } + | subshell + { $$ = $1; } + | group_command + { $$ = $1; } + | function_def + { $$ = $1; } + ; + +select_command: SELECT WORD newlines DO list DONE + { +#if defined (SELECT_COMMAND) + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5); +#endif + } + | SELECT WORD newlines '{' list '}' + { +#if defined (SELECT_COMMAND) + $$ = make_select_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5); +#endif + } + | SELECT WORD ';' newlines DO list DONE + { +#if defined (SELECT_COMMAND) + $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); +#endif + } + | SELECT WORD ';' newlines '{' 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 + { +#if defined (SELECT_COMMAND) + $$ = make_select_command ($2, (WORD_LIST *)reverse_list ($5), $9); +#endif + } + | SELECT WORD newlines IN words list_terminator newlines '{' 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); } + + | FUNCTION WORD '(' ')' newlines group_command + { $$ = make_function_def ($2, $6); } + + | 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 newlines group_command redirections + { $4->redirects = $5; $$ = make_function_def ($2, $4); } + ; + +subshell: '(' list ')' + { $2->flags |= CMD_WANT_SUBSHELL; $$ = $2; } + ; + +if_command: IF list THEN list FI + { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } + | IF list THEN list ELSE list FI + { $$ = make_if_command ($2, $4, $6); } + | IF list THEN list elif_clause FI + { $$ = make_if_command ($2, $4, $5); } + ; + + +group_command: '{' list '}' + { $$ = make_group_command ($2); } + ; + +elif_clause: ELIF list THEN list + { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } + | ELIF list THEN list ELSE list + { $$ = make_if_command ($2, $4, $6); } + | ELIF list THEN list elif_clause + { $$ = make_if_command ($2, $4, $5); } + ; + +case_clause_1: pattern_list_1 + | case_clause_sequence pattern_list_1 + { $2->next = $1; $$ = $2; } + ; + +pattern_list_1: newlines pattern ')' list + { $$ = make_pattern_list ($2, $4); } + | newlines pattern ')' newlines + { $$ = make_pattern_list ($2, (COMMAND *)NULL); } + | newlines '(' pattern ')' list + { $$ = make_pattern_list ($3, $5); } + | newlines '(' pattern ')' newlines + { $$ = make_pattern_list ($3, (COMMAND *)NULL); } + ; + +case_clause_sequence: pattern_list + | case_clause_sequence pattern_list + { $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 + { $$ = make_word_list ($3, $1); } + ; + +/* A list allows leading or trailing newlines and + newlines as operators (equivalent to semicolons). + It must end with a newline or semicolon. + Lists are used within commands such as if, for, while. */ + +list: newlines list0 + { + $$ = $2; + if (need_here_doc) + gather_here_documents (); + } + ; + +list0: list1 + | list1 '\n' newlines + | list1 '&' newlines + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); + else + $$ = command_connect ($1, (COMMAND *)NULL, '&'); + } + | list1 ';' newlines + + ; + +list1: list1 AND_AND newlines list1 + { $$ = command_connect ($1, $4, AND_AND); } + | list1 OR_OR newlines list1 + { $$ = command_connect ($1, $4, OR_OR); } + | list1 '&' newlines list1 + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, $4, '&'); + else + $$ = command_connect ($1, $4, '&'); + } + | list1 ';' newlines list1 + { $$ = command_connect ($1, $4, ';'); } + | list1 '\n' newlines list1 + { $$ = command_connect ($1, $4, ';'); } + | pipeline + { $$ = $1; } + | BANG pipeline + { + $2->flags |= CMD_INVERT_RETURN; + $$ = $2; + } + ; + +list_terminator:'\n' + | ';' + | yacc_EOF + ; + +newlines: + | newlines '\n' + ; + +/* A simple_list is a list that contains no significant newlines + and no leading or trailing newlines. Newlines are allowed + only following operators, where they are not significant. + + This is what an inputunit consists of. */ + +simple_list: simple_list1 + { + $$ = $1; + if (need_here_doc) + gather_here_documents (); + } + | simple_list1 '&' + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); + else + $$ = command_connect ($1, (COMMAND *)NULL, '&'); + if (need_here_doc) + gather_here_documents (); + } + | simple_list1 ';' + { + $$ = $1; + if (need_here_doc) + gather_here_documents (); + } + ; + +simple_list1: simple_list1 AND_AND newlines simple_list1 + { $$ = command_connect ($1, $4, AND_AND); } + | simple_list1 OR_OR newlines simple_list1 + { $$ = command_connect ($1, $4, OR_OR); } + | simple_list1 '&' simple_list1 + { + if ($1->type == cm_connection) + $$ = connect_async_list ($1, $3, '&'); + else + $$ = command_connect ($1, $3, '&'); + } + | simple_list1 ';' simple_list1 + { $$ = command_connect ($1, $3, ';'); } + | pipeline + { $$ = $1; } + | BANG pipeline + { + $2->flags |= CMD_INVERT_RETURN; + $$ = $2; + } + ; + +pipeline: + pipeline '|' newlines pipeline + { $$ = command_connect ($1, $4, '|'); } + | command + { $$ = $1; } + ; +%% + +/* Initial size to allocate for tokens, and the + amount to grow them by. */ +#define TOKEN_DEFAULT_GROW_SIZE 512 + +/* The token currently being read. */ +static int current_token = 0; + +/* The last read token, or NULL. read_token () uses this for context + checking. */ +static int last_read_token = 0; + +/* The token read prior to last_read_token. */ +static int token_before_that = 0; + +/* 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; + +/* Global var is non-zero when end of file has been reached. */ +int EOF_Reached = 0; + +/* 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 + installed function for getting the next character, makes UNGET the + installed function for un-getting a character, sets the type of stream + (either string or file) from TYPE, and makes LOCATION point to where + the input is coming from. */ + +/* Unconditionally returns end-of-file. */ +return_EOF () +{ + return (EOF); +} + +/* Variable containing the current get and unget functions. + See ./input.h for a clearer description. */ +BASH_INPUT bash_input; + +/* Set all of the fields in BASH_INPUT to NULL. */ +void +initialize_bash_input () +{ + bash_input.type = 0; + bash_input.name = (char *)NULL; + bash_input.location.file = (FILE *)NULL; + bash_input.location.string = (char *)NULL; + bash_input.getter = (Function *)NULL; + bash_input.ungetter = (Function *)NULL; +} + +/* Set the contents of the current bash input stream from + GET, UNGET, TYPE, NAME, and LOCATION. */ +void +init_yy_io (get, unget, type, name, location) + Function *get, *unget; + int type; + char *name; + INPUT_STREAM location; +{ + bash_input.type = type; + FREE (bash_input.name); + + if (name) + bash_input.name = savestring (name); + else + bash_input.name = (char *)NULL; + +#if defined (CRAY) + memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location)); +#else + bash_input.location = location; +#endif + bash_input.getter = get; + bash_input.ungetter = unget; +} + +/* Call this to get the next character of input. */ +yy_getc () +{ + return (*(bash_input.getter)) (); +} + +/* Call this to unget C. That is, to make C the next character + to be read. */ +yy_ungetc (c) + int c; +{ + return (*(bash_input.ungetter)) (c); +} + +#if defined (BUFFERED_INPUT) +int +input_file_descriptor () +{ + switch (bash_input.type) + { + case st_stream: + return (fileno (bash_input.location.file)); + case st_bstream: + return (bash_input.location.buffered_fd); + default: + return (fileno (stdin)); + } +} +#endif /* BUFFERED_INPUT */ + +/* **************************************************************** */ +/* */ +/* Let input be read from readline (). */ +/* */ +/* **************************************************************** */ + +#if defined (READLINE) +char *current_readline_prompt = (char *)NULL; +char *current_readline_line = (char *)NULL; +int current_readline_line_index = 0; + +static int +yy_readline_get () +{ + if (!current_readline_line) + { + SigHandler *old_sigint; + int line_len; + + if (!bash_readline_initialized) + initialize_readline (); + +#if defined (JOB_CONTROL) + if (job_control) + give_terminal_to (shell_pgrp); +#endif /* JOB_CONTROL */ + + if (signal_is_ignored (SIGINT) == 0) + { + old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); + interrupt_immediately++; + } + + if (!current_readline_prompt) + current_readline_line = readline (""); + else + current_readline_line = readline (current_readline_prompt); + + if (signal_is_ignored (SIGINT) == 0) + { + interrupt_immediately--; + set_signal_handler (SIGINT, old_sigint); + } + + /* Reset the prompt to whatever is in the decoded value of + prompt_string_pointer. */ + reset_readline_prompt (); + + current_readline_line_index = 0; + + if (!current_readline_line) + return (EOF); + + 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]) + { + free (current_readline_line); + current_readline_line = (char *)NULL; + return (yy_readline_get ()); + } + else + { + int c = (unsigned char)current_readline_line[current_readline_line_index++]; + return (c); + } +} + +static int +yy_readline_unget (c) +{ + if (current_readline_line_index && current_readline_line) + current_readline_line[--current_readline_line_index] = c; + return (c); +} + +void +with_input_from_stdin () +{ + INPUT_STREAM location; + + if (bash_input.type != st_stdin && stream_on_stack (st_stdin) == 0) + { + location.string = current_readline_line; + init_yy_io (yy_readline_get, yy_readline_unget, + st_stdin, "readline stdin", location); + } +} + +#else /* !READLINE */ + +void +with_input_from_stdin () +{ + with_input_from_stream (stdin, "stdin"); +} +#endif /* !READLINE */ + +/* **************************************************************** */ +/* */ +/* Let input come from STRING. STRING is zero terminated. */ +/* */ +/* **************************************************************** */ + +static int +yy_string_get () +{ + register unsigned char *string; + register int c; + + string = bash_input.location.string; + c = EOF; + + /* If the string doesn't exist, or is empty, EOF found. */ + if (string && *string) + { + c = *string++; + bash_input.location.string = string; + } + return (c); +} + +static int +yy_string_unget (c) + int c; +{ + *(--bash_input.location.string) = c; + return (c); +} + +void +with_input_from_string (string, name) + char *string; + char *name; +{ + INPUT_STREAM location; + + location.string = string; + + init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); +} + +/* **************************************************************** */ +/* */ +/* Let input come from STREAM. */ +/* */ +/* **************************************************************** */ + +static int +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 */ + return (result); +} + +static int +yy_stream_unget (c) + int c; +{ +#if defined (NO_READ_RESTART_ON_SIGNAL) + return (ungetc_with_restart (c, bash_input.location.file)); +#else + return (ungetc (c, bash_input.location.file)); +#endif +} + +void +with_input_from_stream (stream, name) + FILE *stream; + char *name; +{ + INPUT_STREAM location; + + location.file = stream; + init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location); +} + +typedef struct stream_saver { + struct stream_saver *next; + BASH_INPUT bash_input; + int line; +#if defined (BUFFERED_INPUT) + BUFFERED_STREAM *bstream; +#endif /* BUFFERED_INPUT */ +} STREAM_SAVER; + +/* The globally known line number. */ +int line_number = 0; + +STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; + +push_stream () +{ + STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); + + xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT)); + +#if defined (BUFFERED_INPUT) + saver->bstream = (BUFFERED_STREAM *)NULL; + /* If we have a buffered stream, clear out buffers[fd]. */ + if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) + { + saver->bstream = buffers[bash_input.location.buffered_fd]; + buffers[bash_input.location.buffered_fd] = (BUFFERED_STREAM *)NULL; + } +#endif /* BUFFERED_INPUT */ + + saver->line = line_number; + bash_input.name = (char *)NULL; + saver->next = stream_list; + stream_list = saver; + EOF_Reached = line_number = 0; +} + +pop_stream () +{ + int temp; + + if (!stream_list) + EOF_Reached = 1; + else + { + STREAM_SAVER *saver = stream_list; + + EOF_Reached = 0; + stream_list = stream_list->next; + + init_yy_io (saver->bash_input.getter, + saver->bash_input.ungetter, + saver->bash_input.type, + saver->bash_input.name, + saver->bash_input.location); + +#if defined (BUFFERED_INPUT) + /* If we have a buffered stream, restore buffers[fd]. */ + /* If the input file descriptor was changed while this was on the + save stack, update the buffered fd to the new file descriptor and + re-establish the buffer <-> bash_input fd correspondence. */ + if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) + { + if (bash_input_fd_changed) + { + bash_input_fd_changed = 0; + if (default_buffered_input >= 0) + { + bash_input.location.buffered_fd = default_buffered_input; + saver->bstream->b_fd = default_buffered_input; + } + } + buffers[bash_input.location.buffered_fd] = saver->bstream; + } +#endif /* BUFFERED_INPUT */ + + line_number = saver->line; + + FREE (saver->bash_input.name); + free (saver); + } +} + +/* Return 1 if a stream of type TYPE is saved on the stack. */ +int +stream_on_stack (type) + int 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: + * 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) +/* + * 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 + * implement alias expansion on a per-token basis. + */ + +typedef struct string_saver { + struct string_saver *next; + int expand_alias; /* Value to set expand_alias to when string is popped. */ + char *saved_line; + 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 + * the value of expand_next_token when the string is popped, so that the + * word after the alias in the original line is handled correctly when the + * alias expands to multiple words. TOKEN is the token that was expanded + * into S; it is saved and used to prevent infinite recursive expansion. + */ +static void +push_string (s, expand, token) + char *s; + int expand; + char *token; +{ + STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER)); + + temp->expand_alias = expand; + temp->saved_line = shell_input_line; + 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->next = pushed_string_list; + pushed_string_list = temp; + + save_expansion (token); + + shell_input_line = s; + shell_input_line_size = strlen (s); + shell_input_line_index = 0; + shell_input_line_terminator = '\0'; + expand_next_token = 0; +} + +/* + * Make the top of the pushed_string stack be the current shell input. + * Only called when there is something on the stack. Called from shell_getc + * when it thinks it has consumed the string generated by an alias expansion + * and needs to return to the original input line. + */ +static void +pop_string () +{ + STRING_SAVER *t; + + FREE (shell_input_line); + shell_input_line = pushed_string_list->saved_line; + 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; + pushed_string_list = pushed_string_list->next; + free((char *)t); +} + +static void +free_string_list () +{ + register STRING_SAVER *t = pushed_string_list, *t1; + + while (t) + { + t1 = t->next; + FREE (t->saved_line); + 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 \<newline> pairs. This is used by + read_secondary_line to read here documents. */ +static char * +read_a_line (remove_quoted_newline) + int remove_quoted_newline; +{ + static char *line_buffer = (char *)NULL; + static int buffer_size = 0; + int indx = 0, c, peekc, pass_next; + + pass_next = 0; + while (1) + { + c = yy_getc (); + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + if (c == 0) + continue; + + /* If there is no more input, then we return NULL. */ + if (c == EOF) + { + 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); + + /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a + here document with an unquoted delimiter. In this case, + the line will be expanded as if it were in double quotes. + We allow a backslash to escape the next character, but we + need to treat the backslash specially only if a backslash + quoting a backslash-newline pair appears in the line. */ + if (pass_next) + { + line_buffer[indx++] = c; + pass_next = 0; + } + else if (c == '\\' && remove_quoted_newline) + { + peekc = yy_getc (); + if (peekc == '\n') + continue; /* Make the unquoted \<newline> pair disappear. */ + else + { + yy_ungetc (peekc); + pass_next = 1; + line_buffer[indx++] = c; /* Preserve the backslash. */ + } + } + else + line_buffer[indx++] = c; + + if (c == '\n') + { + line_buffer[indx] = '\0'; + return (line_buffer); + } + } +} + +/* Return a line as in read_a_line (), but insure that the prompt is + the secondary prompt. This is used to read the lines of a here + document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove + newlines quoted with backslashes while reading the line. It is + non-zero unless the delimiter of the here document was quoted. */ +char * +read_secondary_line (remove_quoted_newline) + int remove_quoted_newline; +{ + prompt_string_pointer = &ps2_prompt; + prompt_again (); + return (read_a_line (remove_quoted_newline)); +} + + +/* **************************************************************** */ +/* */ +/* YYLEX () */ +/* */ +/* **************************************************************** */ + +/* Reserved words. These are only recognized as the first word of a + command. */ +STRING_INT_ALIST word_token_alist[] = { + { "if", IF }, + { "then", THEN }, + { "else", ELSE }, + { "elif", ELIF }, + { "fi", FI }, + { "case", CASE }, + { "esac", ESAC }, + { "for", FOR }, +#if defined (SELECT_COMMAND) + { "select", SELECT }, +#endif + { "while", WHILE }, + { "until", UNTIL }, + { "do", DO }, + { "done", DONE }, + { "in", IN }, + { "function", FUNCTION }, + { "{", '{' }, + { "}", '}' }, + { "!", BANG }, + { (char *)NULL, 0} +}; + +/* 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; +{ + int c; + + QUIT; + +#if defined (ALIAS) + /* If shell_input_line[shell_input_line_index] == 0, but there is + something on the pushed list of strings, then we don't want to go + off and get another line. We let the code down below handle it. */ + + if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && + (pushed_string_list == (STRING_SAVER *)NULL))) +#else /* !ALIAS */ + 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: + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + i = 0; + shell_input_line_terminator = 0; + +#if defined (JOB_CONTROL) + /* This can cause a problem when reading a command as the result + of a trap, when the trap is called from flush_child. This call + had better not cause jobs to disappear from the job table in + that case, or we will have big trouble. */ + notify_and_cleanup (); +#else /* !JOB_CONTROL */ + cleanup_dead_jobs (); +#endif /* !JOB_CONTROL */ + +#if defined (READLINE) + if (interactive && bash_input.type != st_string && no_line_editing) +#else + if (interactive && bash_input.type != st_string) +#endif + print_prompt (); + + if (bash_input.type == st_stream) + clearerr (stdin); + + while (c = yy_getc ()) + { + /* 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); + + if (c == EOF) + { + if (bash_input.type == st_stream) + clearerr (stdin); + + if (!i) + shell_input_line_terminator = EOF; + + shell_input_line[i] = '\0'; + break; + } + + shell_input_line[i++] = c; + + if (c == '\n') + { + shell_input_line[--i] = '\0'; + current_command_line_count++; + break; + } + } + shell_input_line_index = 0; + shell_input_line_len = i; /* == strlen (shell_input_line) */ + +#if defined (HISTORY) + if (interactive && shell_input_line && shell_input_line[0]) + { + char *expansions; + + expansions = pre_process_line (shell_input_line, 1, 1); + + free (shell_input_line); + shell_input_line = expansions; + shell_input_line_len = shell_input_line ? + strlen (shell_input_line) : + 0; + if (!shell_input_line_len) + current_command_line_count--; + + /* We have to force the xrealloc below because we don't know the + true allocated size of shell_input_line anymore. */ + shell_input_line_size = shell_input_line_len; + } +#endif /* HISTORY */ + + if (shell_input_line) + { + /* Lines that signify the end of the shell's input should not be + echoed. */ + if (echo_input_at_read && (shell_input_line[0] || + shell_input_line_terminator != EOF)) + fprintf (stderr, "%s\n", shell_input_line); + } + else + { + shell_input_line_size = 0; + prompt_string_pointer = ¤t_prompt_string; + prompt_again (); + goto restart_read; + } + + /* Add the newline to the end of this string, iff the string does + 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) + shell_input_line = xrealloc (shell_input_line, + 1 + (shell_input_line_size += 2)); + + shell_input_line[l] = '\n'; + shell_input_line[l + 1] = '\0'; + } + } + + c = shell_input_line[shell_input_line_index]; + + if (c) + shell_input_line_index++; + + if (c == '\\' && remove_quoted_newline && + shell_input_line[shell_input_line_index] == '\n') + { + prompt_again (); + goto restart_read_next_line; + } + +#if defined (ALIAS) + /* If C is NULL, we have reached the end of the current input string. If + pushed_string_list is non-empty, it's time to pop to the previous string + because we have fully consumed the result of the last alias expansion. + Do it transparently; just return the next character of the string popped + 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++; + } +#endif /* ALIAS */ + + if (!c && shell_input_line_terminator == EOF) + { + if (shell_input_line_index != 0) + return ('\n'); + else + return (EOF); + } + + return ((unsigned char)c); +} + +/* Put C back into the input for the shell. */ +static void +shell_ungetc (c) + int c; +{ + if (shell_input_line && shell_input_line_index) + shell_input_line[--shell_input_line_index] = c; +} + +/* Discard input until CHARACTER is seen. */ +static void +discard_until (character) + int character; +{ + int c; + + while ((c = shell_getc (0)) != EOF && c != 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) + char *command; +{ + Function *temp_last, *temp_this; + char *last_lastarg; + int temp_exit_value, temp_eof_encountered; + + temp_last = last_shell_builtin; + temp_this = this_shell_builtin; + temp_exit_value = last_command_exit_value; + temp_eof_encountered = eof_encountered; + last_lastarg = get_string_value ("_"); + if (last_lastarg) + last_lastarg = savestring (last_lastarg); + + parse_and_execute (savestring (command), "PROMPT_COMMAND", 0); + + last_shell_builtin = temp_last; + this_shell_builtin = temp_this; + last_command_exit_value = temp_exit_value; + eof_encountered = temp_eof_encountered; + + bind_variable ("_", last_lastarg); + FREE (last_lastarg); + + if (token_to_read == '\n') + token_to_read = 0; +} + +/* Command to read_token () explaining what we want it to do. */ +#define READ 0 +#define RESET 1 +#define prompt_is_ps1 \ + (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt) + +/* Function for yyparse to call. yylex keeps track of + the last two tokens read, and calls read_token. */ + +yylex () +{ + if (interactive && (!current_token || 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 + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ + if (prompt_is_ps1 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); + } + + /* Avoid printing a prompt if we're not going to read anything, e.g. + after resetting the parser with read_token (RESET). */ + if (token_to_read == 0 && interactive) + prompt_again (); + } + + 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; + +void +gather_here_documents () +{ + int r = 0; + while (need_here_doc) + { + make_here_document (redir_stack[r++]); + need_here_doc--; + } +} + +/* 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; + +#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) + +/* Check to see if TOKEN is a reserved word and return the token + value if it is. */ +#define CHECK_FOR_RESERVED_WORD(tok) \ + do { \ + if (!dollar_present && !quoted && \ + reserved_word_acceptable (last_read_token)) \ + { \ + int i; \ + 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)) \ + 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--; \ +\ + 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; +{ + 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. */ + + if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + { + FREE (token); + token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + } + + if (command == RESET) + { + delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_awaiting_satisfaction = 0; + in_case_pattern_list = 0; + +#if defined (ALIAS) + if (pushed_string_list) + { + free_string_list (); + pushed_string_list = (STRING_SAVER *)NULL; + } + + if (expanded_token_stack) + { + free_expansion_stack (); + expanded_token_stack = (EXPANSION_SAVER *)NULL; + } + + expand_next_token = 0; +#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'; + return ('\n'); + } + + if (token_to_read) + { + int rt = token_to_read; + token_to_read = 0; + return (rt); + } + +#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)); + + if (character == EOF) + { + EOF_Reached = 1; + return (yacc_EOF); + } + + if (character == '#' && (!interactive || interactive_comments)) + { + /* 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'); + } + + if (character == '\n') + { + /* If we're about to return an unquoted newline, we can go and collect + the text of any pending here document. */ + if (need_here_doc) + gather_here_documents (); + +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + + return (character); + } + + if (member (character, "()<>;&|")) + { +#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; +#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))) + { + switch (character) + { + /* 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); + else + { + shell_ungetc (peek_char); + return (LESS_LESS); + } + + case '>': + return (GREATER_GREATER); + + case ';': + in_case_pattern_list = 1; +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + return (SEMI_SEMI); + + case '&': + return (AND_AND); + + case '|': + return (OR_OR); + } + } + else + { + if (peek_char == '&') + { + switch (character) + { + case '<': return (LESS_AND); + case '>': return (GREATER_AND); + } + } + if (character == '<' && peek_char == '>') + return (LESS_GREATER); + if (character == '>' && peek_char == '|') + return (GREATER_BAR); + 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) + { + allow_open_brace = 1; +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + } + + if (in_case_pattern_list && (character == ')')) + in_case_pattern_list = 0; + +#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)) +#endif /* PROCESS_SUBSTITUTION */ + return (character); + } + + /* Hack <&- (close stdin) case. */ + if (character == '-') + { + switch (last_read_token) + { + case LESS_AND: + case 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; + + /* 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; + + /* 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; + + /* Non-zero means parsing a `${' construct. It is the count of + un-quoted `}' we need to see. */ + int dollar_brace_level = 0; + + /* A level variable for parsing '${ ... }' constructs inside of double + quotes. */ + int delimited_brace_level = 0; + + /* 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; + + /* Another level variable. This one is for dollar_parens inside of + double-quotes. */ + int delimited_paren_level = 0; + + /* The current delimiting character. */ + int cd; + + for (;;) + { + if (character == EOF) + goto got_token; + + if (pass_next_character) + { + pass_next_character = 0; + goto got_character; + } + + cd = current_delimiter (); + + 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 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; + } + } + + 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++; + + pass_next_character++; + goto got_character; + } + else if (peek_char == '[' && character == '$') + { + if (!delimiter_depth) + dollar_bracket_level++; + + pass_next_character++; + goto got_character; + } + /* This handles ${...} constructs. */ + else if (peek_char == '{' && character == '$') + { + if (!delimiter_depth) + dollar_brace_level++; + else + delimited_brace_level++; + + pass_next_character++; + goto got_character; + } + } + + /* 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 (!delimiter_depth && dollar_paren_level) + dollar_paren_level++; + } + + if (character == '[') + { + if (!delimiter_depth && dollar_bracket_level) + dollar_bracket_level++; + } + + if (character == '{' && !embedded_quoted_string) + { + if (delimiter_depth && delimited_brace_level) + delimited_brace_level++; + + if (!delimiter_depth && dollar_brace_level) + dollar_brace_level++; + } + + /* 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--; + + if (!delimiter_depth && dollar_paren_level) + { + dollar_paren_level--; + goto got_character; + } + } + + if (character == ']') + { + if (!delimiter_depth && dollar_bracket_level) + { + dollar_bracket_level--; + goto got_character; + } + } + + if (character == '}' && !embedded_quoted_string) + { + if (delimiter_depth && delimited_brace_level) + delimited_brace_level--; + + if (!delimiter_depth && dollar_brace_level) + { + dollar_brace_level--; + goto got_character; + } + } + } + + 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); + + quoted = 1; + goto got_character; + } + } + + if (all_digits) + all_digits = digit (character); + if (character == '$') + dollar_present = 1; + + got_character: + + if (character == CTLESC || character == CTLNUL) + token[token_index++] = CTLESC; + + token[token_index++] = character; + + 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 (); + + /* We want to remove quoted newlines (that is, a \<newline> 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_token: + + token[token_index] = '\0'; + + if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) && + character == EOF) + { + char reporter = '\0'; + + if (!delimiter_depth) + { + if (dollar_paren_level) + reporter = ')'; + else if (dollar_bracket_level) + reporter = ']'; + } + + if (!reporter) + reporter = current_delimiter (); + + report_error ("unexpected EOF while looking for `%c'", reporter); + return (-1); + } + + 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); + } + } + + /* 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); + } + + /* 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); + } + } + + /* Ditto for `{' in the FUNCTION case. */ + if (allow_open_brace) + { + allow_open_brace = 0; + if (token[0] == '{' && !token[1]) + { + open_brace_awaiting_satisfaction++; + return ('{'); + } + } + + if (posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + +#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 (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; + + if (expanded_token_stack && token_has_been_expanded (token)) + goto no_expansion; + + expanded = alias_expand_word (token); + if (expanded) + { + int len = strlen (expanded), expand_next; + + /* Erase the current token. */ + token_index = 0; + + expand_next = (expanded[len - 1] == ' ') || + (expanded[len - 1] == '\t'); + + 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 (!posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* 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 ('}'); + } + + 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); +} + +/* Return 1 if TOKEN is a token that after being read would allow + a reserved word to be seen, else 0. */ +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 == DO || + token == ELIF || + token == ELSE || + token == FI || + token == IF || + token == OR_OR || + token == SEMI_SEMI || + token == THEN || + token == UNTIL || + token == WHILE || + token == DONE || /* XXX these two are experimental */ + token == ESAC || + token == 0) + return (1); + else + return (0); +} + +/* Return the index of TOKEN in the alist of reserved words, or -1 if + TOKEN is not a shell reserved word. */ +int +find_reserved_word (token) + char *token; +{ + int i; + for (i = 0; word_token_alist[i].word != (char *)NULL; i++) + if (STREQ (token, word_token_alist[i].word)) + return i; + return -1; +} + +#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 + variable. */ +static void +reset_readline_prompt () +{ + if (prompt_string_pointer) + { + char *temp_prompt; + + temp_prompt = *prompt_string_pointer + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = xmalloc (1); + temp_prompt[0] = '\0'; + } + + FREE (current_readline_prompt); + + current_readline_prompt = temp_prompt; + } +} +#endif /* READLINE */ + +#if defined (HISTORY) +/* A list of tokens which can be followed by newlines, but not by + semi-colons. When concatenating multiple lines of history, the + 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, + 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. */ +char * +history_delimiting_chars () +{ + if (!delimiter_depth) + { + register int i; + + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); + } + return ("; "); + } + else + return ("\n"); +} +#endif /* HISTORY */ + +/* Issue a prompt, or prepare to issue a prompt when the next character + is read. */ +static void +prompt_again () +{ + char *temp_prompt; + + if (!interactive) /* XXX */ + return; + + ps1_prompt = get_string_value ("PS1"); + ps2_prompt = get_string_value ("PS2"); + + if (!prompt_string_pointer) + prompt_string_pointer = &ps1_prompt; + + temp_prompt = (*prompt_string_pointer) + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = xmalloc (1); + temp_prompt[0] = '\0'; + } + + current_prompt_string = *prompt_string_pointer; + prompt_string_pointer = &ps2_prompt; + +#if defined (READLINE) + if (!no_line_editing) + { + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } + else +#endif /* READLINE */ + { + FREE (current_decoded_prompt); + current_decoded_prompt = temp_prompt; + } +} + +static void +print_prompt () +{ + fprintf (stderr, "%s", current_decoded_prompt); + fflush (stderr); +} + +/* 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 + \n CRLF + \s the name of the shell + \w the current working directory + \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 + \<octal> character code in octal + \\ a backslash +*/ +#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; + +#if defined (PROMPT_STRING_DECODE) + + result = xmalloc (PROMPT_GROWTH); + result[0] = 0; + + while (c = *string++) + { + if (posixly_correct && c == '!') + { + if (*string == '!') + { + temp = savestring ("!"); + goto add_string; + } + else + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (history_number ()); +#endif /* HISTORY */ + string--; /* add_string increments string again. */ + goto add_string; + } + } + if (c == '\\') + { + c = *string; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char octal_string[4]; + int n; + + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; + + 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'; + } + + c = 0; + goto add_string; + } + + case 't': + case 'd': + /* Make the current time/date into a string. */ + { + time_t the_time = time (0); + char *ttemp = ctime (&the_time); + temp = savestring (ttemp); + + if (c == 't') + { + strcpy (temp, temp + 11); + temp[8] = '\0'; + } + else + temp[10] = '\0'; + + goto add_string; + } + + case 'n': + if (!no_line_editing) + temp = savestring ("\r\n"); + else + temp = savestring ("\n"); + goto add_string; + + case 's': + { + temp = base_pathname (shell_name); + temp = savestring (temp); + 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]; + + temp = get_string_value ("PWD"); + + if (!temp) + getwd (t_string); + 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); + } + else + temp = savestring (polite_directory_format (t_string)); + goto add_string; + } + + case 'u': + { + 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 '#': + { + temp = itos (current_command_number); + goto add_string; + } + + case '!': + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (history_number ()); +#endif /* HISTORY */ + goto add_string; + } + + case '$': + temp = savestring (geteuid () == 0 ? "#" : "$"); + goto add_string; + +#if defined (READLINE) + case '[': + case ']': + temp = xmalloc(3); + temp[0] = '\001'; + temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; + temp[2] = '\0'; + goto add_string; +#endif + + case '\\': + temp = savestring ("\\"); + goto add_string; + + default: + temp = savestring ("\\ "); + temp[1] = c; + + add_string: + if (c) + string++; + result = + sub_append_string (temp, result, &result_index, &result_size); + temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + result[result_index] = '\0'; + break; + } + } + else + { + while (3 + result_index > result_size) + result = xrealloc (result, result_size += PROMPT_GROWTH); + + result[result_index++] = c; + result[result_index] = '\0'; + } + } +#else /* !PROMPT_STRING_DECODE */ + result = savestring (string); +#endif /* !PROMPT_STRING_DECODE */ + + /* 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); + + return (result); +} + +/* Report a syntax error, and restart the parser. Call here for fatal + errors. */ +yyerror () +{ + report_syntax_error ((char *)NULL); + reset_parser (); +} + +/* Report a syntax error with line numbers, etc. + Call here for recoverable errors. If you have a message to print, + then place it in MESSAGE, otherwise pass NULL and this will figure + out an appropriate message for you. */ +static void +report_syntax_error (message) + char *message; +{ + 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); + } + + last_command_exit_value = EX_USAGE; + return; + } + + if (shell_input_line && *shell_input_line) + { + char *t = shell_input_line; + register int i = shell_input_line_index; + int token_end = 0; + + if (!t[i] && i) + i--; + + while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n')) + i--; + + if (i) + token_end = i + 1; + + while (i && !member (t[i], " \n\t;|&")) + i--; + + while (i != token_end && member (t[i], " \t\n")) + i++; + + if (token_end) + { + char *error_token; + error_token = xmalloc (1 + (token_end - i)); + strncpy (error_token, t + i, token_end - i); + error_token[token_end - i] = '\0'; + + 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'; + + report_error ("syntax error near unexpected token `%s'", etoken); + } + + if (!interactive) + { + 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'; + + report_error ("%s: line %d: `%s'", name, line_number, temp); + free (temp); + } + } + 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); + } + } + last_command_exit_value = EX_USAGE; +} + +/* ??? Needed function. ??? We have to be able to discard the constructs + created during parsing. In the case of error, we want to return + 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. */ +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. */ +int ignoreeof = 0; + +/* The number of times that we have encountered an EOF character without + another character intervening. When this gets above the limit, the + shell terminates. */ +int eof_encountered = 0; + +/* The limit for eof_encountered. */ +int eof_encountered_limit = 10; + +/* If we have EOF as the only input unit, this user wants to leave + the shell. If the shell is not interactive, then just leave. + Otherwise, if ignoreeof is set, and we haven't done this the + required number of times in a row, print a message. */ +static void +handle_eof_input_unit () +{ + if (interactive) + { + /* shell.c may use this to decide whether or not to write out the + history, among other things. We use it only for error reporting + in this file. */ + if (EOF_Reached) + EOF_Reached = 0; + + /* If the user wants to "ignore" eof, then let her do so, kind of. */ + if (ignoreeof) + { + if (eof_encountered < eof_encountered_limit) + { + fprintf (stderr, "Use \"%s\" to leave the shell.\n", + login_shell ? "logout" : "exit"); + eof_encountered++; + /* Reset the prompt string to be $PS1. */ + prompt_string_pointer = (char **)NULL; + prompt_again (); + last_read_token = current_token = '\n'; + return; + } + } + + /* In this case EOF should exit the shell. Do it now. */ + reset_parser (); + exit_builtin ((WORD_LIST *)NULL); + } + else + { + /* We don't write history files, etc., for non-interactive shells. */ + EOF_Reached = 1; + } +} diff --git a/parser-built b/parser-built new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/parser-built diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..247d78e --- /dev/null +++ b/parser.h @@ -0,0 +1,8 @@ +/* parser.h -- Everything you wanted to know about the parser, but were + afraid to ask. */ + +#if !defined (_PARSER_H) +# define _PARSER_H +# include "command.h" +# include "input.h" +#endif /* _PARSER_H */ diff --git a/portbash/README b/portbash/README new file mode 100644 index 0000000..93a9348 --- /dev/null +++ b/portbash/README @@ -0,0 +1 @@ +run sh mkdesc.sh for a first cut at a machines.h entry diff --git a/portbash/libc.sh b/portbash/libc.sh new file mode 100644 index 0000000..28429b3 --- /dev/null +++ b/portbash/libc.sh @@ -0,0 +1,172 @@ +#! /bin/sh + +CC=cc +export CC + +cat > x.c <<EOF +extern char *alloca(); + +main() +{ + char *s; + s = alloca(20); +} +EOF + +if ${CC} 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 <sys/types.h> +#include <sys/param.h> +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 <sys/types.h> + +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 <<EOF +#include <signal.h> + +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 <<EOF +#include <signal.h> + +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='<dirent.h>' +else + d='<sys/dir.h>' +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 new file mode 100644 index 0000000..77e8232 --- /dev/null +++ b/portbash/mkdesc.sh @@ -0,0 +1,11 @@ +#! /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 new file mode 100644 index 0000000..5198dd6 --- /dev/null +++ b/portbash/pgrp.c @@ -0,0 +1,48 @@ +/* + * If this system has a BSD-style getpgrp() call which takes a pid + * as an argument, output a -DBSD_GETPGRP. + */ +#include <stdio.h> +#include <sys/types.h> + +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 new file mode 100644 index 0000000..bcdb5ff --- /dev/null +++ b/portbash/signals.sh @@ -0,0 +1,64 @@ +#! /bin/sh +# +CC=cc +export CC + +cat > x.c <<EOF +#include <signal.h> + +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 <signal.h> +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 <signal.h> +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 <signal.h> +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 new file mode 100644 index 0000000..6a1be93 --- /dev/null +++ b/portbash/stdio.sh @@ -0,0 +1,87 @@ +#! /bin/sh +# +# test certain aspects of stdio +CC=cc +export CC + +cat > x.c << EOF +#include <stdio.h> +#include <varargs.h> + +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 <stdio.h> + +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 <stdio.h> +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 <stdio.h> + +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 new file mode 100644 index 0000000..99a686a --- /dev/null +++ b/portbash/strings.sh @@ -0,0 +1,87 @@ +#! /bin/sh +CC=cc +export CC + +if [ -f /usr/include/string.h ]; then + STRINGH='<string.h>' +elif [ -f /usr/include/strings.h ]; then + STRINGH='<strings.h>' +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 new file mode 100644 index 0000000..e89a742 --- /dev/null +++ b/portbash/syscalls.sh @@ -0,0 +1,80 @@ +#! /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/posixstat.h b/posixstat.h new file mode 100644 index 0000000..7d1cece --- /dev/null +++ b/posixstat.h @@ -0,0 +1,149 @@ +/* posixstat.h -- Posix stat(2) definitions for systems that + don't have them. */ + +/* 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 <sys/stat.h>. + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include <sys/stat.h> + +#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) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */ + +/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but + do not provide the S_IS* macros that Posix requires. */ + +#if defined (_S_IFMT) && !defined (S_IFMT) +#define S_IFMT _S_IFMT +#endif +#if defined (_S_IFIFO) && !defined (S_IFIFO) +#define S_IFIFO _S_IFIFO +#endif +#if defined (_S_IFCHR) && !defined (S_IFCHR) +#define S_IFCHR _S_IFCHR +#endif +#if defined (_S_IFDIR) && !defined (S_IFDIR) +#define S_IFDIR _S_IFDIR +#endif +#if defined (_S_IFBLK) && !defined (S_IFBLK) +#define S_IFBLK _S_IFBLK +#endif +#if defined (_S_IFREG) && !defined (S_IFREG) +#define S_IFREG _S_IFREG +#endif +#if defined (_S_IFLNK) && !defined (S_IFLNK) +#define S_IFLNK _S_IFLNK +#endif +#if defined (_S_IFSOCK) && !defined (S_IFSOCK) +#define S_IFSOCK _S_IFSOCK +#endif + +/* Test for each symbol individually and define the ones necessary (some + systems claiming Posix compatibility define some but not all). */ + +#if defined (S_IFBLK) && !defined (S_ISBLK) +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */ +#endif + +#if defined (S_IFCHR) && !defined (S_ISCHR) +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */ +#endif + +#if defined (S_IFDIR) && !defined (S_ISDIR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */ +#endif + +#if defined (S_IFREG) && !defined (S_ISREG) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */ +#endif + +#if defined (S_IFIFO) && !defined (S_ISFIFO) +#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */ +#endif + +#if defined (S_IFLNK) && !defined (S_ISLNK) +#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */ +#endif + +#if defined (S_IFSOCK) && !defined (S_ISSOCK) +#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */ +#endif + +/* + * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes + */ + +#if !defined (S_IRWXU) +# if !defined (S_IREAD) +# define S_IREAD 00400 +# define S_IWRITE 00200 +# define S_IEXEC 00100 +# endif /* S_IREAD */ + +# if !defined (S_IRUSR) +# define S_IRUSR S_IREAD /* read, owner */ +# define S_IWUSR S_IWRITE /* write, owner */ +# define S_IXUSR S_IEXEC /* execute, owner */ + +# define S_IRGRP (S_IREAD >> 3) /* read, group */ +# define S_IWGRP (S_IWRITE >> 3) /* write, group */ +# define S_IXGRP (S_IEXEC >> 3) /* execute, group */ + +# define S_IROTH (S_IREAD >> 6) /* read, other */ +# define S_IWOTH (S_IWRITE >> 6) /* write, other */ +# define S_IXOTH (S_IEXEC >> 6) /* execute, other */ +# endif /* !S_IRUSR */ + +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif /* !S_IRWXU */ + +/* These are non-standard, but are used in builtins.c$symbolic_umask() */ +#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) +#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) + +#endif /* _POSIXSTAT_H */ diff --git a/print_cmd.c b/print_cmd.c new file mode 100644 index 0000000..b70e8d4 --- /dev/null +++ b/print_cmd.c @@ -0,0 +1,827 @@ +/* print_command -- A way to make readable commands from a command tree. */ +/* Copyright (C) 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 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 <stdio.h> + +#if defined (HAVE_VARARGS_H) +# include <varargs.h> +#endif + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "shell.h" +#include "y.tab.h" +#include "stdc.h" +#include "builtins/common.h" + +#if defined (__GNUC__) || defined (ardent) +extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */ +#endif + +static int indentation = 0; +static int indentation_amount = 4; + +static void cprintf (), newline (), indent (), the_printed_command_resize (); +static void semicolon (); + +static void make_command_string_internal (); +static void command_print_word_list (); +static void print_case_clauses (); +static void print_redirection_list (); +static void print_redirection (); + +static void print_for_command (); +#if defined (SELECT_COMMAND) +static void print_select_command (); +#endif +static void print_group_command (); +static void print_case_command (); +static void print_while_command (); +static void print_until_command (); +static void print_until_or_while (); +static void print_if_command (); +static void print_function_def (); + +#define PRINTED_COMMAND_GROW_SIZE 1024 + +char *the_printed_command = (char *)NULL; +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; + +/* 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; + +/* Print COMMAND (a command tree) on standard output. */ +void +print_command (command) + COMMAND *command; +{ + command_string_index = 0; + printf ("%s", make_command_string (command)); +} + +/* Make a string which is the printed representation of the command + tree in COMMAND. We return this string. However, the string is + not consed, so you have to do that yourself if you want it to + remain around. */ +char * +make_command_string (command) + COMMAND *command; +{ + command_string_index = 0; + make_command_string_internal (command); + return (the_printed_command); +} + +/* The internal function. This is the real workhorse. */ +static void +make_command_string_internal (command) + COMMAND *command; +{ + if (!command) + cprintf (""); + else + { + if (skip_this_indent) + skip_this_indent--; + else + indent (indentation); + + if (command->flags & CMD_WANT_SUBSHELL) + cprintf ("( "); + + if (command->flags & CMD_INVERT_RETURN) + cprintf ("! "); + + switch (command->type) + { + case cm_for: + print_for_command (command->value.For); + break; + +#if defined (SELECT_COMMAND) + case cm_select: + print_select_command (command->value.Select); + break; +#endif + + case cm_case: + print_case_command (command->value.Case); + break; + + case cm_while: + print_while_command (command->value.While); + break; + + case cm_until: + print_until_command (command->value.While); + break; + + case cm_if: + print_if_command (command->value.If); + break; + + case cm_simple: + print_simple_command (command->value.Simple); + break; + + case cm_connection: + + skip_this_indent++; + make_command_string_internal (command->value.Connection->first); + + switch (command->value.Connection->connector) + { + case '&': + case '|': + { + char c = command->value.Connection->connector; + cprintf (" %c", c); + if (c != '&' || command->value.Connection->second) + { + cprintf (" "); + skip_this_indent++; + } + } + break; + + case AND_AND: + cprintf (" && "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case OR_OR: + cprintf (" || "); + if (command->value.Connection->second) + skip_this_indent++; + break; + + case ';': + cprintf (";"); + + if (inside_function_def) + cprintf ("\n"); + else + { + cprintf (" "); + if (command->value.Connection->second) + skip_this_indent++; + } + break; + + default: + cprintf ("print_command: bad connector `%d'", + command->value.Connection->connector); + break; + } + + make_command_string_internal (command->value.Connection->second); + break; + + case cm_function_def: + print_function_def (command->value.Function_def); + break; + + case cm_group: + print_group_command (command->value.Group); + break; + + default: + programming_error ("print_command: bad command type `%d'", command->type); + break; + } + + if (command->flags & CMD_WANT_SUBSHELL) + cprintf (" )"); + + if (command->redirects) + print_redirection_list (command->redirects); + } +} + +static void +_print_word_list (list, separator, pfunc) + WORD_LIST *list; + char *separator; + VFunction *pfunc; +{ + while (list) + { + (*pfunc) ("%s", list->word->word); + list = list->next; + if (list) + (*pfunc) ("%s", separator); + } +} + +void print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, (VFunction *)printf); +} + +static void +command_print_word_list (list, separator) + WORD_LIST *list; + char *separator; +{ + _print_word_list (list, separator, cprintf); +} + +static void +print_for_command (for_command) + FOR_COM *for_command; +{ + cprintf ("for %s in ", for_command->name->word); + command_print_word_list (for_command->map_list, " "); + cprintf (";"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (for_command->action); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} + +#if defined (SELECT_COMMAND) +static void +print_select_command (select_command) + SELECT_COM *select_command; +{ + cprintf ("select %s in ", select_command->name->word); + command_print_word_list (select_command->map_list, " "); + cprintf (";"); + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (select_command->action); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +} +#endif /* SELECT_COMMAND */ + +static void +print_group_command (group_command) + GROUP_COM *group_command; +{ + group_command_nesting++; + cprintf ("{ "); + + if (!inside_function_def) + skip_this_indent++; + else + { + /* This is a group command { ... } inside of a function + definition, and should be handled as a `normal' group + command, using the current indentation. */ + cprintf ("\n"); + indentation += indentation_amount; + } + + make_command_string_internal (group_command->command); + + cprintf ("\n"); + + if (group_command_nesting) + { + indentation -= indentation_amount; + indent (indentation); + if (!indentation) + cprintf (" "); + } + + cprintf ("}"); + group_command_nesting--; +} + +static void +print_case_command (case_command) + CASE_COM *case_command; +{ + cprintf ("case %s in ", case_command->word->word); + if (case_command->clauses) + print_case_clauses (case_command->clauses); + newline ("esac"); +} + +static void +print_case_clauses (clauses) + PATTERN_LIST *clauses; +{ + indentation += indentation_amount; + while (clauses) + { + newline (""); + command_print_word_list (clauses->patterns, " | "); + cprintf (")\n"); + indentation += indentation_amount; + make_command_string_internal (clauses->action); + indentation -= indentation_amount; + newline (";;"); + clauses = clauses->next; + } + indentation -= indentation_amount; +} + +static void +print_while_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "while"); +} + +static void +print_until_command (while_command) + WHILE_COM *while_command; +{ + print_until_or_while (while_command, "until"); +} + +static void +print_until_or_while (while_command, which) + WHILE_COM *while_command; + char *which; +{ + cprintf ("%s ", which); + skip_this_indent++; + make_command_string_internal (while_command->test); + semicolon (); + cprintf (" do\n"); /* was newline ("do\n"); */ + indentation += indentation_amount; + make_command_string_internal (while_command->action); + indentation -= indentation_amount; + semicolon (); + newline ("done"); +} + +static void +print_if_command (if_command) + IF_COM *if_command; +{ + cprintf ("if "); + skip_this_indent++; + make_command_string_internal (if_command->test); + semicolon (); + cprintf (" then\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->true_case); + indentation -= indentation_amount; + + if (if_command->false_case) + { + semicolon (); + newline ("else\n"); + indentation += indentation_amount; + make_command_string_internal (if_command->false_case); + indentation -= indentation_amount; + } + semicolon (); + newline ("fi"); +} + +void +print_simple_command (simple_command) + SIMPLE_COM *simple_command; +{ + command_print_word_list (simple_command->words, " "); + + if (simple_command->redirects) + { + cprintf (" "); + print_redirection_list (simple_command->redirects); + } +} + +static void +print_redirection_list (redirects) + REDIRECT *redirects; +{ + while (redirects) + { + print_redirection (redirects); + redirects = redirects->next; + if (redirects) + cprintf (" "); + } +} + +static void +print_redirection (redirect) + REDIRECT *redirect; +{ + int kill_leading = 0; + int redirector = redirect->redirector; + WORD_DESC *redirectee = redirect->redirectee.filename; + int redir_fd = redirect->redirectee.dest; + + switch (redirect->instruction) + { + case r_output_direction: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">%s", redirectee->word); + break; + + case r_input_direction: + if (redirector != 0) + cprintf ("%d", redirector); + cprintf ("<%s", redirectee->word); + break; + + case r_inputa_direction: /* Redirection created by the shell. */ + cprintf ("&"); + break; + + case r_appending_to: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">>%s", redirectee->word); + break; + + case r_deblank_reading_until: + kill_leading++; + /* ... */ + case r_reading_until: + if (redirector != 0) + cprintf ("%d", redirector); + /* If the here document delimiter is quoted, single-quote it. */ + if (redirect->redirectee.filename->quoted) + { + char *x; + x = single_quote (redirect->here_doc_eof); + cprintf ("<<%s%s\n", kill_leading? "-" : "", x); + free (x); + } + else + cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof); + cprintf ("%s%s", + redirect->redirectee.filename->word, redirect->here_doc_eof); + break; + + case r_duplicating_input: + cprintf ("%d<&%d", redirector, redir_fd); + break; + + case r_duplicating_output: + cprintf ("%d>&%d", redirector, redir_fd); + break; + + case r_duplicating_input_word: + cprintf ("%d<&%s", redirector, redirectee->word); + break; + + case r_duplicating_output_word: + cprintf ("%d>&%s", redirector, redirectee->word); + break; + + case r_close_this: + cprintf ("%d>&-", redirector); + break; + + case r_err_and_out: + cprintf (">&%s", redirectee->word); + break; + + case r_input_output: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf ("<>%s", redirectee->word); + break; + + case r_output_force: + if (redirector != 1) + cprintf ("%d", redirector); + cprintf (">|%s", redirectee->word); + break; + } +} + +static void +reset_locals () +{ + inside_function_def = 0; + indentation = 0; +} + +static void +print_function_def (func) + FUNCTION_DEF *func; +{ + cprintf ("function %s () \n", func->name->word); + add_unwind_protect (reset_locals, 0); + + indent (indentation); + cprintf ("{ \n"); + + 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); + + remove_unwind_protect (); + indentation -= indentation_amount; + inside_function_def--; + + newline ("}"); +} + +/* Return the string representation of the named function. + NAME is the name of the function. + COMMAND is the function body. It should be a GROUP_COM. + MULTI_LINE is non-zero to pretty-print, or zero for all on one line. + */ +char * +named_function_string (name, command, multi_line) + char *name; + COMMAND *command; + int multi_line; +{ + char *result; + int old_indent = indentation, old_amount = indentation_amount; + + command_string_index = 0; + + if (name && *name) + cprintf ("%s ", name); + + cprintf ("() "); + + if (!multi_line) + { + indentation = 1; + indentation_amount = 0; + } + else + { + cprintf ("\n"); + indentation += indentation_amount; + } + + inside_function_def++; + + if (multi_line) + cprintf ("{ \n"); + else + cprintf ("{ "); + + if (command->type == cm_group) + make_command_string_internal (command->value.Group->command); + else + make_command_string_internal (command); + + indentation = old_indent; + indentation_amount = old_amount; + inside_function_def--; + + newline ("}"); + + result = the_printed_command; + + if (!multi_line) + { +#if 0 + register int i; + for (i = 0; result[i]; i++) + if (result[i] == '\n') + { + strcpy (result + i, result + i + 1); + --i; + } +#else + if (result[2] == '\n') /* XXX -- experimental */ + strcpy (result + 2, result + 3); +#endif + } + + return (result); +} + +static void +newline (string) + char *string; +{ + cprintf ("\n"); + indent (indentation); + if (string && *string) + cprintf ("%s", string); +} + +static void +indent (amount) + int amount; +{ + while (amount-- > 0) + cprintf (" "); +} + +static void +semicolon () +{ + if (command_string_index > 0 && the_printed_command[command_string_index - 1] == '&') + return; + cprintf (";"); +} + +#if !defined (HAVE_VARARGS_H) +/* How to make the string. */ +static void +cprintf (format, arg1, arg2) + char *format, *arg1, *arg2; +{ + register char *s; + char char_arg[2], *argp, *args[2]; + int arg_len, c, arg_index; + + args[arg_index = 0] = arg1; + args[1] = arg2; + + arg_len = strlen (format); + the_printed_command_resize (arg_len + 1); + + char_arg[1] = '\0'; + s = format; + while (s && *s) + { + int free_argp = 0; + c = *s++; + if (c != '%' || !*s) + { + argp = s; + arg_len = 1; + } + else + { + c = *s++; + switch (c) + { + case '%': + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + break; + + case 's': + argp = (char *)args[arg_index++]; + arg_len = strlen (argp); + break; + + case 'd': + argp = itos (pointer_to_int (args[arg_index])); + arg_index++; + arg_len = strlen (argp); + free_argp = 1; + break; + + case 'c': + char_arg[0] = pointer_to_int (args[arg_index]); + arg_index++; + argp = char_arg; + arg_len = 1; + break; + + default: + programming_error ("cprintf: bad `%%' argument (%c)", c); + } + } + if (argp) + { + the_printed_command_resize (arg_len + 1); + FASTCOPY (argp, the_printed_command + command_string_index, arg_len); + command_string_index += arg_len; + if (free_argp) + free (argp); + } + } + + the_printed_command[command_string_index] = '\0'; +} + +#else /* We have support for varargs. */ + +/* How to make the string. */ +static void +cprintf (va_alist) + va_dcl +{ + register char *s; + char *control, char_arg[2], *argp; + int digit_arg, arg_len, c; + va_list args; + + va_start (args); + control = va_arg (args, char *); + + arg_len = strlen (control); + the_printed_command_resize (arg_len + 1); + + char_arg[1] = '\0'; + s = control; + while (s && *s) + { + int free_argp = 0; + c = *s++; + if (c != '%' || !*s) + { + argp = s - 1; + arg_len = 1; + } + else + { + c = *s++; + switch (c) + { + case '%': + char_arg[0] = c; + argp = char_arg; + arg_len = 1; + break; + + case 's': + argp = va_arg (args, char *); + arg_len = strlen (argp); + break; + + case 'd': + digit_arg = va_arg (args, int); + argp = itos (digit_arg); + arg_len = strlen (argp); + free_argp = 1; + break; + + case 'c': + char_arg[0] = va_arg (args, int); + argp = char_arg; + arg_len = 1; + break; + + default: + programming_error ("cprintf: bad `%%' argument (%c)", c); + } + } + + if (argp) + { + the_printed_command_resize (arg_len + 1); + FASTCOPY (argp, the_printed_command + command_string_index, arg_len); + command_string_index += arg_len; + if (free_argp) + free (argp); + } + } + + the_printed_command[command_string_index] = '\0'; +} +#endif /* HAVE_VARARGS_H */ + +/* Ensure that there is enough space to stuff LENGTH characters into + THE_PRINTED_COMMAND. */ +static void +the_printed_command_resize (length) + int length; +{ + if (!the_printed_command) + { + the_printed_command_size = length + 1; + the_printed_command = xmalloc (the_printed_command_size); + command_string_index = 0; + } + else if ((command_string_index + length) >= the_printed_command_size) + { + int new; + new = command_string_index + length + 1; + new = new + 2 * PRINTED_COMMAND_GROW_SIZE - 1; + new -= new % PRINTED_COMMAND_GROW_SIZE; + the_printed_command_size = new; + the_printed_command = xrealloc (the_printed_command, the_printed_command_size); + } +} @@ -0,0 +1,33 @@ +/* quit.h -- How to handle SIGINT gracefully. */ + +/* 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 (__QUIT_H__) +#define __QUIT_H__ + +/* Non-zero means SIGINT has already ocurred. */ +extern int interrupt_state; + +extern void throw_to_top_level (); + +/* Macro to call a great deal. SIGINT just sets above variable. When + 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__ */ @@ -0,0 +1 @@ +/bin/bash
\ No newline at end of file @@ -0,0 +1,1792 @@ +/* shell.c -- GNU's idea of the POSIX shell specification. + + This file is part of Bash, the Bourne Again SHell. Bash is free + software; no one can prevent you from reading the source code, or + giving it to someone else. This file is copyrighted under the GNU + General Public License, which can be found in the file called + COPYING. + + Copyright (C) 1988, 1991 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. + + Birthdate: + Sunday, January 10th, 1988. + Initial author: Brian Fox +*/ +#define INSTALL_DEBUG_MODE + +#include "bashtypes.h" +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <sys/file.h> +#include "filecntl.h" +#include <pwd.h> +#include "posixstat.h" +#include "bashansi.h" + +#if defined (HAVE_VARARGS_H) +#include <varargs.h> +#endif + +#include "shell.h" +#include "flags.h" + +#if defined (JOB_CONTROL) +#include "jobs.h" +#endif /* JOB_CONTROL */ + +#include "input.h" +#include "execute_cmd.h" + +#if defined (HISTORY) +# include "bashhist.h" +# include <readline/history.h> +#endif + +#include <tilde/tilde.h> + +#if defined (USG) && !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwuid (); +#endif /* USG && !HAVE_GETPW_DECLS */ + +extern int yydebug; +#if !defined (errno) +extern int errno; +#endif + +extern char *dist_version; +extern int patch_level, build_version; +extern int subshell_environment; /* Found in execute_cmd.c. */ +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 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; + +COMMAND *global_command = (COMMAND *)NULL; + +/* Non-zero after SIGINT. */ +int interrupt_state = 0; + +/* Information about the current user. */ +struct user_info current_user = +{ + -1, -1, -1, -1, (char *)NULL, (char *)NULL, (char *)NULL +}; + +/* The current host's name. */ +char *current_host_name = (char *)NULL; + +/* Non-zero means that this shell is a login shell. + Specifically: + 0 = not login shell. + 1 = login shell from getty (or equivalent fake out) + -1 = login shell from "-login" flag. + -2 = both from getty, and from flag. + */ +int login_shell = 0; + +/* Non-zero means that at this moment, the shell is interactive. In + general, this means that the shell is at this moment reading input + from the keyboard. */ +int interactive = 0; + +/* Non-zero means that the shell was started as an interactive shell. */ +int interactive_shell = 0; + +/* Tells what state the shell was in when it started: + 0 = non-interactive shell script + 1 = interactive + 2 = -c command + This is a superset of the information provided by interactive_shell. +*/ +int startup_state = 0; + +/* Special debugging helper. */ +int debugging_login_shell = 0; + +/* The environment that the shell passes to other commands. */ +char **shell_environment; + +/* Non-zero when we are executing a top-level command. */ +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; + +/* 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; + +/* 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. */ + +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. */ + +/* Some long-winded argument names. These are obviously new. */ +#define Int 1 +#define Charp 2 +struct { + char *name; + int type; + int *int_value; + char **char_value; +} long_args[] = { + { "debug", Int, &debugging, (char **)0x0 }, + { "norc", Int, &no_rc, (char **)0x0 }, + { "noprofile", Int, &no_profile, (char **)0x0 }, + { "rcfile", Charp, (int *)0x0, &bashrc_file }, + { "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 } +}; + +/* These are extern so execute_simple_command can set them, and then + 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; +int subshell_argc; +char **subshell_argv; +char **subshell_envp; + +#if defined (BUFFERED_INPUT) +/* The file descriptor from which the shell is reading input. */ +int default_buffered_input = -1; +#endif + +static int want_pending_command; +static char *local_pending_command; + +static int isnetconn (); +static void run_startup_files (); + +static void shell_initialize (); +static void shell_reinitialize (); +static void initialize_signals (); +static void initialize_terminating_signals (); + +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 */ + + /* 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 (); + + /* See whether or not we are running setuid or setgid. */ + privileged_mode = (current_user.uid != current_user.euid) || + (current_user.gid != current_user.egid); + + posixly_correct = (getenv ("POSIXLY_CORRECT") != (char *)NULL) || + (getenv ("POSIX_PEDANTIC") != (char *)NULL); + +#if defined (USE_GNU_MALLOC_LIBRARY) + mcheck (programming_error, (void (*) ())0); +#endif /* USE_GNU_MALLOC_LIBRARY */ + + if (setjmp (subshell_top_level)) + { + argc = subshell_argc; + argv = subshell_argv; + env = subshell_envp; + sourced_env = 0; + } + + /* 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; + default_input = stdin; +#if defined (BUFFERED_INPUT) + default_buffered_input = -1; +#endif + + /* Fix for the `infinite process creation' bug when running shell scripts + from startup files on System V. */ + login_shell = make_login_shell = 0; + + /* If this shell has already been run, then reinitialize it to a + vanilla state. */ + if (shell_initialized || shell_name) + { + /* Make sure that we do not infinitely recurse as a login shell. */ + if (*shell_name == '-') + shell_name++; + + shell_reinitialize (); + if (setjmp (top_level)) + 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 */ + + 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]) == '-') + { + 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++; + } + + /* If we're in a strict Posix.2 mode, turn on interactive comments. */ + if (posixly_correct) + interactive_comments = 1; + + /* If user supplied the "-login" flag, then set and invert LOGIN_SHELL. */ + if (make_login_shell) + { + login_shell++; + login_shell = -login_shell; + } + + /* 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; + } + + 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; + + default: + if (change_flag (arg_character, on_or_off) == FLAG_ERROR) + { + report_error ("%c%c: bad option", on_or_off, arg_character); + exit (1); + } + + } + } + /* Can't do just a simple increment anymore -- what about + "bash -abouo emacs ignoreeof -hP"? */ + arg_index = next_arg; + } + + /* Need to get the argument to a -c option processed in the + above loop. The next arg is a command to execute, and the + following args are $0...$n respectively. */ + if (want_pending_command) + { + local_pending_command = argv[arg_index]; + if (!local_pending_command) + { + report_error ("`-c' requires an argument"); + exit (1); + } + arg_index++; + } + 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 + the following conditions are met: + no -c command + no arguments remaining or the -s flag given + standard input is a terminal + standard output is a terminal + Refer to Posix.2, the description of the `sh' utility. */ + + if (forced_interactive || /* -i flag */ + (!local_pending_command && /* No -c command and ... */ + ((arg_index == argc) || /* no remaining args or... */ + 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; + } + 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 */ + } + +#define CLOSE_FDS_AT_LOGIN +#if defined (CLOSE_FDS_AT_LOGIN) + /* + * Some systems have the bad habit of starting login shells with lots of open + * file descriptors. For instance, most systems that have picked up the + * pre-4.0 Sun YP code leave a file descriptor open each time you call one + * of the getpw* functions, and it's set to be open across execs. That + * means one for login, one for xterm, one for shelltool, etc. + */ + if (login_shell && interactive_shell) + { + for (i = 3; i < 20; i++) + close (i); + } +#endif /* CLOSE_FDS_AT_LOGIN */ + + /* From here on in, the shell must be a normal functioning shell. + Variables from the environment are expected to be set, etc. */ + shell_initialize (); + + if (interactive_shell) + { + char *term = getenv ("TERM"); + no_line_editing |= term && (STREQ (term, "emacs")); + } + + 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++; + } + } + + arg_index = top_level_arg_index; + + /* Execute the start-up scripts. */ + + if (!interactive_shell) + { + makunbound ("PS1", shell_variables); + makunbound ("PS2", shell_variables); + interactive = 0; + } + else + { + change_flag ('i', FLAG_ON); + interactive = 1; + } + + if (!locally_skip_execution) + run_startup_files (); + +#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); +#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 defined (ONESHOT) + run_one_command (local_pending_command); + goto exit_shell; +#else /* ONESHOT */ + with_input_from_string (local_pending_command, "-c"); + goto read_and_execute; +#endif /* !ONESHOT */ + } + + /* Do the things that should be done only for interactive shells. */ + if (interactive_shell) + { + /* Set up for checking for presence of mail. */ + remember_mail_dates (); + reset_mail_timer (); + +#if defined (HISTORY) + /* Initialize the interactive history stuff. */ + if (!shell_initialized) + load_history (); +#endif /* HISTORY */ + + /* Initialize terminal state for interactive shells after the + .bash_profile and .bashrc are interpreted. */ + get_tty_state (); + } + + /* Get possible input filename. */ + if ((arg_index != argc) && !read_from_stdin) + { + int fd; + char *filename; + + free (dollar_vars[0]); + dollar_vars[0] = savestring (argv[arg_index]); + filename = savestring (argv[arg_index]); + + 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); + } + } + + arg_index++; + if (fd < 0) + { + file_error (filename); + exit (1); + } + + /* Only do this with file descriptors we can seek on. */ + if (lseek (fd, 0L, 1) != -1) + { + 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))) + { + report_error ("%s: cannot execute binary file", filename); + exit (EX_BINARY_FILE); + } + /* 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) + { + file_error (filename); + exit (127); + } + 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. */ + { + 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) + { + file_error (filename); + exit (127); + } + + SET_CLOSE_ON_EXEC (fd); + if (fileno (default_input) != fd) + SET_CLOSE_ON_EXEC (fileno (default_input)); + +#endif /* !BUFFERED_INPUT */ + + if (!interactive_shell || (!isatty (fd))) + { +#if defined (HISTORY) +# if defined (BANG_HISTORY) + history_expansion = 0; +# endif + remember_on_history = 0; +#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 (); +#endif /* JOB_CONTROL */ + + /* Always return the exit status of the last command to our parent. */ + exit (last_command_exit_value); +} + +#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); + } + + 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. + + If the executable file "/usr/gnu/src/bash/foo" contains: + + #!/usr/gnu/bin/bash + echo hello + + then: + + COMMAND EXECUTE BASHRC + -------------------------------- + bash -c foo NO + bash foo NO + foo NO + rsh machine ls YES (for rsh, which calls `bash -c') + rsh machine foo YES (for shell started by rsh) NO (for foo!) + 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); + } + + /* 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)) + { + char *env_file = (char *)NULL; + + if (!posixly_correct) + env_file = getenv ("BASH_ENV"); + if (!env_file) + env_file = getenv ("ENV"); + + if (env_file && *env_file) + { + WORD_LIST *list; + char *expanded_file_name; + + list = expand_string_unsplit (env_file, 1); + if (list) + { + expanded_file_name = string_list (list); + dispose_words (list); + + if (expanded_file_name && *expanded_file_name) + maybe_execute_file (expanded_file_name, 1); + + if (expanded_file_name) + free (expanded_file_name); + } + } + } +} + +#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. + 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. */ +maybe_make_restricted (name) + char *name; +{ + char *temp; + + temp = base_pathname (shell_name); + if (restricted || (STREQ (temp, "rbash"))) + { + set_var_read_only ("PATH"); + non_unsettable ("PATH"); + set_var_read_only ("SHELL"); + non_unsettable ("SHELL"); + 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; +{ + 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)); + + if (force_noninteractive) + { + old_interactive = interactive; + interactive = 0; + } + + 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); + + return (1); +} + +#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. */ +run_one_command (command) + char *command; +{ + int code; + + code = setjmp (top_level); + + if (code != NOT_JUMPED) + { +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + switch (code) + { + /* Some kind of throw to top_level has occured. */ + case FORCE_EOF: + return last_command_exit_value = 127; + case EXITPROG: + return last_command_exit_value; + case DISCARD: + return last_command_exit_value = 1; + default: + programming_error ("Bad jump %d", code); + } + } + return (parse_and_execute (savestring (command), "-c", -1)); +} +#endif /* ONESHOT */ + +reader_loop () +{ + int our_indirection_level; + COMMAND *current_command = (COMMAND *)NULL; + + our_indirection_level = ++indirection_level; + + while (!EOF_Reached) + { + 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: + /* 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); + } + } + + executing = 0; + dispose_used_env_vars (); + +#if (defined (Ultrix) && defined (mips)) || !defined (HAVE_ALLOCA) + /* Attempt to reclaim memory allocated with alloca (). */ + (void) alloca (0); +#endif + + if (read_command () == 0) + { + if (global_command) + { + current_command = global_command; + + current_command_number++; + + /* 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); + } + + 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) + EOF_Reached = EOF; + } + 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; + + indirection_string[0] = '\0'; + ps4 = get_string_value ("PS4"); + + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); + + ps4 = decode_prompt_string (ps4); + + 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]; + + indirection_string[i] = '\0'; + free (ps4); + return (indirection_string); +} + +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 */ +} + +parse_command () +{ + int r; + + 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) + { + char *command_to_execute; + + command_to_execute = get_string_value ("PROMPT_COMMAND"); + if (command_to_execute) + execute_prompt_command (command_to_execute); + } + + current_command_line_count = 0; + r = yyparse (); + + if (need_here_doc) + gather_here_documents (); + + return (r); +} + +read_command () +{ + SHELL_VAR *tmout_var = (SHELL_VAR *)NULL; + int tmout_len = 0, result; + SigHandler *old_alrm = (SigHandler *)NULL; + + prompt_string_pointer = &ps1_prompt; + global_command = (COMMAND *)NULL; + + /* Only do timeouts if interactive. */ + if (interactive) + { + 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); + } + } + } + + 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); +} + +/* Cause STREAM to buffer lines as opposed to characters or blocks. */ +static void +line_buffer_stream (stream) + FILE *stream; +{ + /* 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 */ +} + +/* Do whatever is necessary to initialize the shell. + Put new initializations in here. */ +static void +shell_initialize () +{ + /* Line buffer output for stderr and stdout. */ + line_buffer_stream (stderr); + line_buffer_stream (stdout); + + /* Sort the array of shell builtins so that the binary search in + find_shell_builtin () works correctly. */ + initialize_shell_builtins (); + + /* Initialize the trap signal handlers before installing our own + signal handlers. traps.c:restore_original_signals () is responsible + for restoring the original default signal handlers. That function + is called when we make a new child. */ + 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 + 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 (); + } + + /* Initialize our interface to the tilde expander. */ + tilde_initialize (); + + /* Initialize internal and environment variables. */ + initialize_shell_variables (shell_environment); + + /* Initialize filename hash tables. */ + initialize_filename_hashing (); + + /* Initialize the data structures for storing and running jobs. */ + initialize_jobs (); + + /* Initialize input streams to null. */ + initialize_bash_input (); +} + +/* Function called by main () when it appears that the shell has already + had some initialization performed. This is supposed to reset the world + back to a pristine state, as if we had been exec'ed. */ +static void +shell_reinitialize () +{ + /* The default shell prompts. */ + primary_prompt = PPROMPT; + secondary_prompt = SPROMPT; + + /* Things that get 1. */ + current_command_number = 1; + + /* We have decided that the ~/.bashrc file should not be executed + for the invocation of each shell script. If the variable $ENV + (or $BASH_ENV) is set, its value is used as the name of a file + to source. */ + no_rc = no_profile = 1; + + /* Things that get 0. */ + 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; + +#if defined (HISTORY) +# if defined (BANG_HISTORY) + history_expansion = 0; +# endif + remember_on_history = 0; +#endif /* HISTORY */ + +#if defined (RESTRICTED_SHELL) + restricted = 0; +#endif /* RESTRICTED_SHELL */ + + /* Ensure that the default startup file is used. (Except that we don't + execute this file for reinitialized shells). */ + bashrc_file = "~/.bashrc"; + + /* Delete all variables and functions. They will be reinitialized when + the environment is parsed. */ + + delete_all_variables (shell_variables); + delete_all_variables (shell_functions); + + /* 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 (); +#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 () +{ + 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++) + { + 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 /* !_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); + } +} + +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 <sys/socket.h> +#endif + +/* Is FD a socket or network connection? */ +static int +isnetconn (fd) + int fd; +{ +#if defined (USGr4) || defined (USGr4_2) + /* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */ + struct stat sb; + + if (fstat (fd, &sb) < 0) + return (0); + 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 */ +# if defined (S_ISSOCK) + struct stat sb; + + if (fstat (fd, &sb) < 0) + return (0); + return (S_ISSOCK (sb.st_mode)); +# else /* !S_ISSOCK */ + return (0); +# endif /* !S_ISSOCK */ +# endif /* !HAVE_SOCKETS */ +#endif /* !USGr4 && !USGr4_2 */ +} @@ -0,0 +1,107 @@ +/* shell.h -- The data structures used by the shell */ + +/* 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 "config.h" +#include "command.h" +#include "general.h" +#include "error.h" +#include "variables.h" +#include "quit.h" +#include "maxpath.h" +#include "unwind_prot.h" +#include "dispose_cmd.h" +#include "make_cmd.h" +#include "subst.h" +#include "externs.h" + +extern int EOF_Reached; + +#define NO_PIPE -1 +#define REDIRECT_BOTH -2 +#define IS_DESCRIPTOR -1 + +#define NO_VARIABLE -1 + +/* A bunch of stuff for flow of control using setjmp () and longjmp (). */ +#include <setjmp.h> +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 + +/* 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 + +/* 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_here_document "\\`$" + +/* Constants which specify how to handle backslashes and quoting in + expand_word_internal (). Q_DOUBLE_QUOTES means to use the function + slashify_in_quotes () to decide whether the backslash should be + retained. Q_HERE_DOCUMENT means slashify_in_here_document () to + decide whether to retain the backslash. Q_KEEP_BACKSLASH means + to unconditionally retain the backslash. */ +#define Q_DOUBLE_QUOTES 0x1 +#define Q_HERE_DOCUMENT 0x2 +#define Q_KEEP_BACKSLASH 0x4 + +extern char **shell_environment; +extern WORD_LIST *rest_of_args; + +/* Generalized global variables. */ +extern int executing, login_shell; + +/* Structure to pass around that holds a bitmap of file descriptors + to close, and the size of that structure. Used in execute_cmd.c. */ +struct fd_bitmap { + long size; + char *bitmap; +}; + +#define FD_BITMAP_SIZE 32 + +#define CTLESC '\001' +#define CTLNUL '\177' + +/* Information about the current user. */ +struct user_info { + int uid, euid; + int gid, egid; + char *user_name; + char *shell; /* shell from the password file */ + char *home_dir; +}; + +extern struct user_info current_user; diff --git a/siglist.c b/siglist.c new file mode 100644 index 0000000..7571cf0 --- /dev/null +++ b/siglist.c @@ -0,0 +1,219 @@ +/* siglist.c -- signal list for those machines that don't have one. */ + +/* Copyright (C) 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 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 <stdio.h> +#include <sys/types.h> +#include <signal.h> + +#include "siglist.h" + +#if !defined (NSIG) +# include "trap.h" +#endif + +char *sys_siglist[NSIG]; + +extern char *xmalloc (), *malloc (); + +void +initialize_siglist () +{ + register int i; + + for (i = 0; i < NSIG; i++) + sys_siglist[i] = (char *)0x0; + + sys_siglist[0] = "Bogus signal"; + +#if defined (SIGHUP) + sys_siglist[SIGHUP] = "Hangup"; +#endif + +#if defined (SIGINT) + sys_siglist[SIGINT] = "Interrupt"; +#endif + +#if defined (SIGQUIT) + sys_siglist[SIGQUIT] = "Quit"; +#endif + +#if defined (SIGILL) + sys_siglist[SIGILL] = "Illegal instruction"; +#endif + +#if defined (SIGTRAP) + sys_siglist[SIGTRAP] = "BPT trace/trap"; +#endif + +#if defined (SIGIOT) && !defined (SIGABRT) +#define SIGABRT SIGIOT +#endif + +#if defined (SIGABRT) + sys_siglist[SIGABRT] = "ABORT instruction"; +#endif + +#if defined (SIGEMT) + sys_siglist[SIGEMT] = "EMT instruction"; +#endif + +#if defined (SIGFPE) + sys_siglist[SIGFPE] = "Floating point exception"; +#endif + +#if defined (SIGKILL) + sys_siglist[SIGKILL] = "Killed"; +#endif + +#if defined (SIGBUS) + sys_siglist[SIGBUS] = "Bus error"; +#endif + +#if defined (SIGSEGV) + sys_siglist[SIGSEGV] = "Segmentation fault"; +#endif + +#if defined (SIGSYS) + sys_siglist[SIGSYS] = "Bad system call"; +#endif + +#if defined (SIGPIPE) + sys_siglist[SIGPIPE] = "Broken pipe"; +#endif + +#if defined (SIGALRM) + sys_siglist[SIGALRM] = "Alarm clock"; +#endif + +#if defined (SIGTERM) + sys_siglist[SIGTERM] = "Terminated"; +#endif + +#if defined (SIGURG) + sys_siglist[SIGURG] = "Urgent IO condition"; +#endif + +#if defined (SIGSTOP) + sys_siglist[SIGSTOP] = "Stopped (signal)"; +#endif + +#if defined (SIGTSTP) + sys_siglist[SIGTSTP] = "Stopped"; +#endif + +#if defined (SIGCONT) + sys_siglist[SIGCONT] = "Continue"; +#endif + +#if !defined (SIGCHLD) && defined (SIGCLD) +#define SIGCHLD SIGCLD +#endif + +#if defined (SIGCHLD) + sys_siglist[SIGCHLD] = "Child death or stop"; +#endif + +#if defined (SIGTTIN) + sys_siglist[SIGTTIN] = "Stopped (tty input)"; +#endif + +#if defined (SIGTTOU) + sys_siglist[SIGTTOU] = "Stopped (tty output)"; +#endif + +#if defined (SIGIO) + sys_siglist[SIGIO] = "I/O ready"; +#endif + +#if defined (SIGXCPU) + sys_siglist[SIGXCPU] = "CPU limit"; +#endif + +#if defined (SIGXFSZ) + sys_siglist[SIGXFSZ] = "File limit"; +#endif + +#if defined (SIGVTALRM) + sys_siglist[SIGVTALRM] = "Alarm (virtual)"; +#endif + +#if defined (SIGPROF) + sys_siglist[SIGPROF] = "Alarm (profile)"; +#endif + +#if defined (SIGWINCH) + sys_siglist[SIGWINCH] = "Window changed"; +#endif + +#if defined (SIGLOST) + sys_siglist[SIGLOST] = "Record lock"; +#endif + +#if defined (SIGUSR1) + sys_siglist[SIGUSR1] = "User signal 1"; +#endif + +#if defined (SIGUSR2) + sys_siglist[SIGUSR2] = "User signal 2"; +#endif + +#if defined (SIGMSG) + sys_siglist[SIGMSG] = "HFT input data pending"; +#endif + +#if defined (SIGPWR) + sys_siglist[SIGPWR] = "power failure imminent"; +#endif + +#if defined (SIGDANGER) + sys_siglist[SIGDANGER] = "system crash imminent"; +#endif + +#if defined (SIGMIGRATE) + sys_siglist[SIGMIGRATE] = "migrate process to another CPU"; +#endif + +#if defined (SIGPRE) + sys_siglist[SIGPRE] = "programming error"; +#endif + +#if defined (SIGGRANT) + sys_siglist[SIGGRANT] = "HFT monitor mode granted"; +#endif + +#if defined (SIGRETRACT) + sys_siglist[SIGRETRACT] = "HFT monitor mode retracted"; +#endif + +#if defined (SIGSOUND) + sys_siglist[SIGSOUND] = "HFT sound sequence has completed"; +#endif + + for (i = 0; i < NSIG; i++) + { + if (!sys_siglist[i]) + { + sys_siglist[i] = + (char *)xmalloc (10 + strlen ("Unknown Signal #")); + + sprintf (sys_siglist[i], "Unknown Signal #%d", i); + } + } +} diff --git a/siglist.h b/siglist.h new file mode 100644 index 0000000..b52d7ad --- /dev/null +++ b/siglist.h @@ -0,0 +1,40 @@ +/* siglist.h -- encapsulate various definitions for sys_siglist */ + +/* 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 (_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) +extern char *sys_siglist[]; +#endif /* !Solaris && !Linux && !__BSD_4_4__ && !Minix && !NetBSD && !FreeBSD && !BSD_OS */ + +#if !defined (strsignal) && !defined (Solaris) && !defined (NetBSD) +# define strsignal(sig) (char *)sys_siglist[sig] +#endif /* !strsignal && !Solaris && !NetBSD */ + +#endif /* _SIGLIST_H */ diff --git a/signames.c b/signames.c new file mode 100644 index 0000000..f5216d5 --- /dev/null +++ b/signames.c @@ -0,0 +1,297 @@ +/* signames.c -- Create and write `signames.h', which contains an array of + signal names. */ + +/* Copyright (C) 1992 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 <stdio.h> +#include <sys/types.h> +#include <signal.h> +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if !defined (NSIG) +# define NSIG 64 +#endif + +char *signal_names[2 * NSIG]; + +char *progname; + +initialize_signames () +{ + register int i; + + for (i = 1; i < sizeof(signal_names)/sizeof(signal_names[0]); i++) + signal_names[i] = (char *)NULL; + + /* `signal' 0 is what we do on exit. */ + signal_names[0] = "EXIT"; + + /* Place signal names which can be aliases for more common signal + names first. This allows (for example) SIGEMT to overwrite SIGGRANT. */ +#if defined (SIGGRANT) /* HFT monitor mode granted */ + signal_names[SIGGRANT] = "SIGGRANT"; +#endif + +#if defined (SIGRETRACT) /* HFT monitor mode retracted */ + signal_names[SIGRETRACT] = "SIGRETRACT"; +#endif + +#if defined (SIGHUP) /* hangup */ + signal_names[SIGHUP] = "SIGHUP"; +#endif + +#if defined (SIGINT) /* interrupt */ + signal_names[SIGINT] = "SIGINT"; +#endif + +#if defined (SIGQUIT) /* quit */ + signal_names[SIGQUIT] = "SIGQUIT"; +#endif + +#if defined (SIGILL) /* illegal instruction (not reset when caught) */ + signal_names[SIGILL] = "SIGILL"; +#endif + +#if defined (SIGTRAP) /* trace trap (not reset when caught) */ + signal_names[SIGTRAP] = "SIGTRAP"; +#endif + +#if defined (SIGABRT) /* Cause current process to dump core. */ + signal_names[SIGABRT] = "SIGABRT"; +#endif + +#if defined (SIGIOT) /* IOT instruction */ + signal_names[SIGIOT] = "SIGIOT"; +#endif + +#if defined (SIGEMT) /* EMT instruction */ + signal_names[SIGEMT] = "SIGEMT"; +#endif + +#if defined (SIGFPE) /* floating point exception */ + signal_names[SIGFPE] = "SIGFPE"; +#endif + +#if defined (SIGKILL) /* kill (cannot be caught or ignored) */ + signal_names[SIGKILL] = "SIGKILL"; +#endif + +#if defined (SIGBUS) /* bus error */ + signal_names[SIGBUS] = "SIGBUS"; +#endif + +#if defined (SIGSEGV) /* segmentation violation */ + signal_names[SIGSEGV] = "SIGSEGV"; +#endif + +#if defined (SIGSYS) /* bad argument to system call */ + signal_names[SIGSYS] = "SIGSYS"; +#endif + +#if defined (SIGPIPE) /* write on a pipe with no one to read it */ + signal_names[SIGPIPE] = "SIGPIPE"; +#endif + +#if defined (SIGALRM) /* alarm clock */ + signal_names[SIGALRM] = "SIGALRM"; +#endif + +#if defined (SIGTERM) /* software termination signal from kill */ + signal_names[SIGTERM] = "SIGTERM"; +#endif + +#if defined (SIGCLD) /* Like SIGCHLD. */ + signal_names[SIGCLD] = "SIGCLD"; +#endif + +#if defined (SIGPWR) /* Magic thing for some machines. */ + signal_names[SIGPWR] = "SIGPWR"; +#endif + +#if defined (SIGPOLL) /* For keyboard input? */ + signal_names[SIGPOLL] = "SIGPOLL"; +#endif + +#if defined (SIGURG) /* urgent condition on IO channel */ + signal_names[SIGURG] = "SIGURG"; +#endif + +#if defined (SIGSTOP) /* sendable stop signal not from tty */ + signal_names[SIGSTOP] = "SIGSTOP"; +#endif + +#if defined (SIGTSTP) /* stop signal from tty */ + signal_names[SIGTSTP] = "SIGTSTP"; +#endif + +#if defined (SIGCONT) /* continue a stopped process */ + signal_names[SIGCONT] = "SIGCONT"; +#endif + +#if defined (SIGCHLD) /* to parent on child stop or exit */ + signal_names[SIGCHLD] = "SIGCHLD"; +#endif + +#if defined (SIGTTIN) /* to readers pgrp upon background tty read */ + signal_names[SIGTTIN] = "SIGTTIN"; +#endif + +#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local<OSTOP) */ + signal_names[SIGTTOU] = "SIGTTOU"; +#endif + +#if defined (SIGIO) /* input/output possible signal */ + signal_names[SIGIO] = "SIGIO"; +#endif + +#if defined (SIGXCPU) /* exceeded CPU time limit */ + signal_names[SIGXCPU] = "SIGXCPU"; +#endif + +#if defined (SIGXFSZ) /* exceeded file size limit */ + signal_names[SIGXFSZ] = "SIGXFSZ"; +#endif + +#if defined (SIGVTALRM) /* virtual time alarm */ + signal_names[SIGVTALRM] = "SIGVTALRM"; +#endif + +#if defined (SIGPROF) /* profiling time alarm */ + signal_names[SIGPROF] = "SIGPROF"; +#endif + +#if defined (SIGWINCH) /* window changed */ + signal_names[SIGWINCH] = "SIGWINCH"; +#endif + +#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */ + signal_names[SIGLOST] = "SIGLOST"; +#endif + +#if defined (SIGUSR1) /* user defined signal 1 */ + signal_names[SIGUSR1] = "SIGUSR1"; +#endif + +#if defined (SIGUSR2) /* user defined signal 2 */ + signal_names[SIGUSR2] = "SIGUSR2"; +#endif + +#if defined (SIGMSG) /* HFT input data pending */ + signal_names[SIGMSG] = "SIGMSG"; +#endif + +#if defined (SIGPWR) /* power failure imminent (save your data) */ + signal_names[SIGPWR] = "SIGPWR"; +#endif + +#if defined (SIGDANGER) /* system crash imminent */ + signal_names[SIGDANGER] = "SIGDANGER"; +#endif + +#if defined (SIGMIGRATE) /* migrate process to another CPU */ + signal_names[SIGMIGRATE] = "SIGMIGRATE"; +#endif + +#if defined (SIGPRE) /* programming error */ + signal_names[SIGPRE] = "SIGPRE"; +#endif + +#if defined (SIGSOUND) /* HFT sound sequence has completed */ + signal_names[SIGSOUND] = "SIGSOUND"; +#endif + +#if defined (SIGWINDOW) + signal_names[SIGWINDOW] = "SIGWINDOW"; +#endif + +#if defined (SIGDIL) + signal_names[SIGDIL] = "SIGDIL"; +#endif + +#if defined (SIGSAK) /* Secure Attention Key */ + signal_names[SIGSAK] = "SIGSAK"; +#endif + + for (i = 0; i < NSIG; i++) + if (signal_names[i] == (char *)NULL) + { + signal_names[i] = (char *)malloc (18); + sprintf (signal_names[i], "SIGJUNK(%d)", i); + } +} + +write_signames (stream) + FILE *stream; +{ + register int i; + + fprintf (stream, "/* This file was automatically created by %s.\n", + progname); + fprintf (stream, " Do not edit. Edit signames.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++) + fprintf (stream, " \"%s\",\n", signal_names[i]); + + fprintf (stream, " (char *)0x0,\n"); + fprintf (stream, "};\n"); +} + +main (argc, argv) + int argc; + char **argv; +{ + char *stream_name; + FILE *stream; + + progname = argv[0]; + + 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); + } + + initialize_signames (); + write_signames (stream); + exit (0); +} @@ -0,0 +1,78 @@ +/* stdc.h -- macros to make source compile on both ANSI C and K&R C + compilers. */ + +/* 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 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 (__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) +# define __P(protos) protos +# endif +# define __STRING(x) #x + +# if !defined (__GNUC__) +# define inline +# endif + +#else /* !__STDC__ */ + +# if !defined (__P) +# define __P(protos) () +# endif +# define __STRING(x) "x" + +#if defined (__GNUC__) /* gcc with -traditional */ +# if !defined (const) +# define const __const +# endif +# if !defined (inline) +# define inline __inline +# endif +# if !defined (signed) +# define signed __signed +# endif +# if !defined (volatile) +# define volatile __volatile +# endif +#else /* !__GNUC__ */ +# if !defined (const) +# define const +# endif +# if !defined (inline) +# define inline +# endif +# if !defined (signed) +# define signed +# endif +# if !defined (volatile) +# define volatile +# endif +#endif /* !__GNUC__ */ + +#endif /* !__STDC__ */ + +#endif /* !__STDC_H__ */ @@ -0,0 +1,4867 @@ +/* subst.c -- The part of the shell that does parameter, command, and + globbing substitutions. */ + +/* 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. */ + +#include "bashtypes.h" +#include <stdio.h> +#include <pwd.h> +#include <signal.h> +#include <errno.h> +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "bashansi.h" +#include "posixstat.h" + +#include "shell.h" +#include "flags.h" +#include "jobs.h" +#include "execute_cmd.h" +#include "filecntl.h" + +#if defined (READLINE) +# include <readline/readline.h> +#else +# include <tilde/tilde.h> +#endif + +#if defined (HISTORY) +# include "bashhist.h" +# include <readline/history.h> +#endif + +#include <glob/fnmatch.h> +#include "builtins/getopt.h" + +/* The size that strings change by. */ +#define DEFAULT_ARRAY_SIZE 512 + +/* How to quote and determine the quoted state of the 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 posixly_correct; +extern int eof_encountered, eof_encountered_limit, ignoreeof; +extern char *this_command_name; +extern jmp_buf top_level; +#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 + +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_string_leave_quoted (); +static WORD_LIST *word_list_split (); +static char *quote_string (); +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 char *extract_delimited_string (); +static char *extract_dollar_brace_string (); + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Cons a new string from STRING starting at START and ending at END, + not including END. */ +char * +substring (string, start, end) + char *string; + int start, end; +{ + register int len = end - start; + register char *result = xmalloc (len + 1); + + strncpy (result, string + start, len); + result[len] = '\0'; + return (result); +} + +/* Conventions: + + A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. + The parser passes CTLNUL as CTLESC CTLNUL. */ + +/* The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. + This is necessary to make unquoted CTLESC and CTLNUL characters in the + data stream pass through properly. + Here we remove doubled CTLESC characters inside quoted strings before + quoting the entire string, so we do not double the number of CTLESC + characters. */ +static char * +remove_quoted_escapes (string) + char *string; +{ + register char *s; + + for (s = string; s && *s; s++) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) + strcpy (s, s + 1); /* XXX - should be memmove */ + } + return (string); +} + +/* Quote escape characters in string s, but no other characters. This is + used to protect CTLESC and CTLNUL in variable values from the rest of + the word expansion process after the variable is expanded. */ +static char * +quote_escapes (string) + char *string; +{ + register char *s, *t; + char *result; + + result = xmalloc ((strlen (string) * 2) + 1); + for (s = string, t = result; s && *s; ) + { + if (*s == CTLESC || *s == CTLNUL) + *t++ = CTLESC; + *t++ = *s++; + } + *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; +{ + 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); + } + + for (i = *sindex; (c = string[i]); i++) + { + if (c == CTLESC) + { + i++; + continue; + } + + if (MEMBER (c, charlist)) + break; + } + + temp = xmalloc (1 + (i - *sindex)); + strncpy (temp, string + (*sindex), i - (*sindex)); + temp[i - (*sindex)] = '\0'; + *sindex = i; + + return (temp); +} + +/* 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. */ +static char * +string_extract (string, sindex, charlist) + char *string, *charlist; + int *sindex; +{ + register int c, i = *sindex; + char *temp; + + while (c = string[i]) + { + if (c == '\\') + if (string[i + 1]) + i++; + else + break; + else + if (MEMBER (c, charlist)) + break; + i++; + } + temp = xmalloc (1 + (i - *sindex)); + strncpy (temp, string + (*sindex), i - (*sindex)); + temp[i - (*sindex)] = '\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) + char *string; +{ + register int i, j; + register char *temp; + + temp = xmalloc (1 + strlen (string)); + + 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 + +/* 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); + + pass_character = delimiter = delimited_nesting_level = 0; + + nesting_level = 1; + + for (i = *sindex; c = string[i]; i++) + { + if (pass_character) + { + pass_character = 0; + continue; + } + + if (c == CTLESC) + { + pass_character++; + continue; + } + + if (c == '\\') + { + if ((delimiter == '"') && + (member (string[i + 1], slashify_in_quotes))) + { + pass_character++; + continue; + } + } + + if (!delimiter || delimiter == '"') + { + 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; + } + + if (STREQN (string + i, closer, len_closer)) + { + i += len_closer - 1; + + if (delimiter && delimited_nesting_level) + delimited_nesting_level--; + + if (!delimiter) + { + nesting_level--; + if (nesting_level == 0) + break; + } + } + } + + if (delimiter) + { + if (c == delimiter || delimiter == '\\') + delimiter = 0; + continue; + } + else + { + if (c == '"' || c == '\'' || c == '\\') + delimiter = c; + } + } + + l = i - *sindex; + result = xmalloc (1 + l); + strncpy (result, string + *sindex, l); + result[l] = '\0'; + *sindex = i; + + if (!c && (delimiter || nesting_level)) + { + report_error ("bad substitution: no `%s' in %s", closer, string); + free (result); + longjmp (top_level, DISCARD); + } + return (result); +} + +/* 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 */ +static char * +extract_dollar_brace_string (string, sindex) + char *string; + int *sindex; +{ + register int i, c, l; + int pass_character, nesting_level; + int delimiter, delimited_nesting_level; + char *result; + + pass_character = delimiter = delimited_nesting_level = 0; + + nesting_level = 1; + + for (i = *sindex; c = string[i]; i++) + { + if (pass_character) + { + pass_character = 0; + continue; + } + + if (c == CTLESC) + { + pass_character++; + continue; + } + + /* Backslashes quote the next character. */ + if (c == '\\') + { + if ((delimiter == '"') && + (member (string[i + 1], slashify_in_quotes))) + { + pass_character++; + continue; + } + } + + if (!delimiter || delimiter == '"') + { + 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; + } + } + } + + if (delimiter) + { + if (c == delimiter || delimiter == '\\') + delimiter = 0; + continue; + } + else + { + if (c == '"' || c == '\'' || c == '\\') + delimiter = c; + } + } + + l = i - *sindex; + result = xmalloc (1 + l); + strncpy (result, string + *sindex, l); + result[l] = '\0'; + *sindex = i; + + if (!c && (delimiter || nesting_level)) + { + report_error ("bad substitution: no ending `}' in %s", string); + free (result); + longjmp (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. */ +static char * +string_extract_double_quoted (string, sindex) + char *string; + int *sindex; +{ + register int c, j, i; + char *temp; /* The new string we return. */ + int pass_next, backquote; /* State variables for the machine. */ + + pass_next = backquote = 0; + temp = xmalloc (1 + strlen (string) - *sindex); + + for (j = 0, i = *sindex; c = string[i]; i++) + { + /* Process a character that was quoted by a backslash. */ + if (pass_next) + { + /* Posix.2 sez: + + ``The backslash shall retain its special meaning as an escape + character only when followed by one of the characters: + $ ` " \ <newline>''. + + We handle the double quotes here. expand_word_internal handles + the rest. */ + if (c != '"') + temp[j++] = '\\'; + temp[j++] = c; + pass_next = 0; + continue; + } + + /* 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_next++; + 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 (c == '`') + backquote = 0; + temp[j++] = c; + continue; + } + + if (c == '`') + { + temp[j++] = c; + backquote++; + 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] == '{'))) + { + register int t; + int si; + char *ret; + + 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]; + + i = si; + temp[j++] = string[i]; + free (ret); + continue; + } + + /* An unescaped double quote serves to terminate the string. */ + if (c == '"') + break; + + /* Add the character to the quoted string we're accumulating. */ + temp[j++] = c; + } + temp[j] = '\0'; + + /* Point to after the closing quote. */ + if (c) + i++; + *sindex = i; + + return (temp); +} + +/* 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) + char *string; + int *sindex; +{ + register int i = *sindex; + char *temp; + + while (string[i] && string[i] != '\'') + i++; + + temp = xmalloc (1 + i - *sindex); + strncpy (temp, string + *sindex, i - *sindex); + temp[i - *sindex] = '\0'; + + if (string[i]) + i++; + *sindex = i; + + return (temp); +} + +/* 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. */ +int +char_is_quoted (string, eindex) + char *string; + int eindex; +{ + int i, pass_next, quoted; + char *temp; + + for (i = pass_next = quoted = 0; i <= eindex; i++) + { + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + 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] == '\\') + { + 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; + + olen = strlen (openstr); + for (i = pass_next = openc = 0; i <= eindex; i++) + { + if (pass_next) + { + pass_next = 0; + if (i >= eindex) /* XXX was if (i >= eindex - 1) */ + return 0; + continue; + } + else if (STREQN (string + i, openstr, olen)) + { + 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] == '"') + { + i++; + temp = string_extract_double_quoted (string, &i); + free (temp); + if (i > eindex) + return 0; + } + else if (string[i] == '\\') + { + pass_next = 1; + continue; + } + } + return (openc); +} +#endif /* READLINE */ + +/* Extract the name of the variable to bind to from the assignment string. */ +char * +assignment_name (string) + char *string; +{ + int offset = assignment (string); + char *temp; + + if (!offset) + return (char *)NULL; + temp = xmalloc (offset + 1); + strncpy (temp, string, offset); + temp[offset] = '\0'; + return (temp); +} + +/* 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. */ +static char * +string_list_internal (list, sep) + WORD_LIST *list; + char *sep; +{ + register WORD_LIST *t; + char *result, *r; + int word_len, sep_len, result_size; + + if (!list) + return ((char *)NULL); + + /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ + sep_len = STRLEN (sep); + result_size = 0; + + for (t = list; t; t = t->next) + { + if (t != list) + result_size += sep_len; + result_size += strlen (t->word->word); + } + + r = result = xmalloc (result_size + 1); + + for (t = list; t; t = t->next) + { + if (t != list && sep_len) + { + FASTCOPY (sep, r, sep_len); + r += sep_len; + } + + word_len = strlen (t->word->word); + FASTCOPY (t->word->word, r, word_len); + r += word_len; + } + + *r = '\0'; + return (result); +} + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +char * +string_list (list) + WORD_LIST *list; +{ + return (string_list_internal (list, " ")); +} + +/* Return a single string of all the words present in LIST, obeying the + quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the + expansion [of $*] appears within a double quoted string, it expands + to a single field with the value of each parameter separated by the + first character of the IFS variable, or by a <space> if IFS is unset." */ +char * +string_list_dollar_star (list) + WORD_LIST *list; +{ + char *ifs = get_string_value ("IFS"); + char sep[2]; + + if (!ifs) + sep[0] = ' '; + else if (!*ifs) + sep[0] = '\0'; + else + sep[0] = *ifs; + + sep[1] = '\0'; + + return (string_list_internal (list, sep)); +} + +/* Return the list of words present in STRING. Separate the string into + words at any of the characters found in SEPARATORS. If QUOTED is + non-zero then word in the list will have its quoted flag set, otherwise + the quoted flag is left as make_word () deemed fit. + + This obeys the P1003.2 word splitting semantics. If `separators' is + exactly <space><tab><newline>, then the splitting algorithm is that of + the Bourne shell, which treats any sequence of characters from `separators' + as a delimiter. If IFS is unset, which results in `separators' being set + to "", no splitting occurs. If separators has some other value, the + following rules are applied (`IFS white space' means zero or more + occurrences of <space>, <tab>, or <newline>, as long as those characters + are in `separators'): + + 1) IFS white space is ignored at the start and the end of the + string. + 2) Each occurrence of a character in `separators' that is not + IFS white space, along with any adjacent occurrences of + IFS white space delimits a field. + 3) Any nonzero-length sequence of IFS white space delimits a field. + */ + +/* 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. */ +/* +#define remove_quoted_nulls(string) \ + do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0) +*/ +static void +remove_quoted_nulls (string) + char *string; +{ + char *nstr, *s, *p; + + nstr = savestring (string); + nstr[0] = '\0'; + for (p = nstr, s = string; *s; s++) + { + if (*s == CTLESC) + { + *p++ = *s++; /* CTLESC */ + if (*s == 0) + break; + *p++ = *s; /* quoted char */ + continue; + } + if (*s == CTLNUL) + continue; + *p++ = *s; + } + *p = '\0'; + strcpy (string, nstr); + free (nstr); +} + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +void +word_list_remove_quoted_nulls (list) + WORD_LIST *list; +{ + register WORD_LIST *t; + + t = list; + + while (t) + { + remove_quoted_nulls (t->word->word); + t = t->next; + } +} + +/* This performs word splitting and quoted null character removal on + STRING. */ + +#define issep(c) (member ((c), separators)) + +WORD_LIST * +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; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + sh_style_split = + separators && *separators && (STREQ (separators, " \t\n")); + + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in IFS. Do not do this if + STRING is quoted or if there are no separator characters. */ + if (!quoted || !separators || !*separators) + { + for (s = string; *s && spctabnl (*s) && issep (*s); s++); + + if (!*s) + return ((WORD_LIST *)NULL); + + string = s; + } + + /* OK, now STRING points to a word that does not begin with white space. + The splitting algorithm is: + 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]) + { + current_word = string_extract_verbatim (string, &sindex, separators); + if (!current_word) + break; + + /* If we have a quoted empty string, add a quoted null argument. We + want to preserve the quoted null character iff this is a quoted + empty string; otherwise the quoted null characters are removed + below. */ + if (QUOTED_NULL (current_word)) + { + WORD_DESC *t = make_word (" "); + t->quoted++; + free (t->word); + t->word = make_quoted_char ('\0'); + result = make_word_list (t, result); + } + else if (strlen (current_word)) + { + /* 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 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; + } + + free (current_word); + + /* Move past the current separator character. */ + if (string[sindex]) + sindex++; + + /* Now skip sequences of space, tab, or newline characters if they are + in the list of separators. */ + while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex])) + sindex++; + + } + return (REVERSE_LIST (result, WORD_LIST *)); +} + +/* Parse a single word from STRING, using SEPARATORS to separate fields. + ENDPTR is set to the first character after the word. This is used by + the `read' builtin. + XXX - this function is very similar to list_string; they should be + combined - XXX */ +char * +get_word_from_string (stringp, separators, endptr) + char **stringp, *separators, **endptr; +{ + register char *s; + char *current_word; + int sindex, sh_style_split; + + if (!stringp || !*stringp || !**stringp) + return ((char *)NULL); + + s = *stringp; + + sh_style_split = + separators && *separators && (STREQ (separators, " \t\n")); + + /* Remove sequences of whitespace at the beginning of STRING, as + long as those characters appear in IFS. */ + if (sh_style_split || !separators || !*separators) + { + for (; *s && spctabnl (*s) && issep (*s); s++); + + /* If the string is nothing but whitespace, update it and return. */ + if (!*s) + { + *stringp = s; + if (endptr) + *endptr = s; + return ((char *)NULL); + } + } + + /* OK, S points to a word that does not begin with white space. + 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); + + /* Set ENDPTR to the first character after the end of the word. */ + if (endptr) + *endptr = s + sindex; + + /* Move past the current separator character. */ + if (s[sindex]) + sindex++; + + /* Now skip sequences of space, tab, or newline characters if they are + in the list of separators. */ + while (s[sindex] && spctabnl (s[sindex]) && issep (s[sindex])) + sindex++; + + /* Update STRING to point to the next field. */ + *stringp = s + sindex; + return (current_word); +} + +/* Remove IFS white space at the end of STRING. Start at the end + of the string and walk backwards until the beginning of the string + or we find a character that's not IFS white space and not CTLESC. + Only let CTLESC escape a white space character if SAW_ESCAPE is + non-zero. */ +char * +strip_trailing_ifs_whitespace (string, separators, saw_escape) + char *string, *separators; + int saw_escape; +{ + char *s; + + s = string + STRLEN (string) - 1; + while (s > string && ((spctabnl (*s) && issep (*s)) || + (saw_escape && *s == CTLESC && spctabnl (s[1])))) + s--; + *++s = '\0'; + return string; +} + +#if defined (PROCESS_SUBSTITUTION) +#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC) +#else +#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC) +#endif + +/* If there are any characters in STRING that require full expansion, + then call FUNC to expand STRING; otherwise just perform quote + removal if necessary. This returns a new string. */ +static char * +maybe_expand_string (string, quoted, func) + char *string; + int quoted; + WORD_LIST *(*func)(); +{ + WORD_LIST *list; + int i, saw_quote; + char *ret; + + for (i = saw_quote = 0; string[i]; i++) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + } + + if (string[i]) + { + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + } + else if (saw_quote && !quoted) + ret = string_quote_removal (string, quoted); + else + ret = savestring (string); + return ret; +} + +/* 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 + expansion on the right-hand side. Perform tilde expansion in any + case. Do not perform word splitting on the result of expansion. */ +static int +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; + + if (name[offset] == '=') + { + char *temp; + + name[offset] = 0; + temp = name + offset + 1; + + if (expand && temp[0]) + { + if (strchr (temp, '~') && unquoted_member ('~', temp)) + temp = tilde_expand (temp); + else + temp = savestring (temp); + + value = maybe_expand_string (temp, 0, expand_string_unsplit); + free (temp); + } + else + value = savestring (temp); + } + + if (value == 0) + value = savestring (""); + + entry = bind_variable (name, value); + + if (echo_command_at_execute) + fprintf (stderr, "%s%s=%s\n", indirection_level_string (), 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); +} + +/* Perform the assignment statement in STRING, and expand the + right side by doing command and parameter expansion. */ +do_assignment (string) + char *string; +{ + return do_assignment_internal (string, 1); +} + +/* 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. */ +do_assignment_no_expand (string) + char *string; +{ + return do_assignment_internal (string, 0); +} + +/* Most of the substitutions must be done in parallel. In order + to avoid using tons of unclear goto's, I have some functions + for manipulating malloc'ed strings. They all take INDX, a + pointer to an integer which is the offset into the string + where manipulation is taking place. They also take SIZE, a + pointer to an integer which is the current length of the + character array for this 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. + Returns TARGET in case the location has changed. */ +inline char * +sub_append_string (source, target, indx, size) + char *source, *target; + int *indx, *size; +{ + if (source) + { + int srclen, n; + + srclen = strlen (source); + if (srclen >= (int)(*size - *indx)) + { + n = srclen + *indx; + n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); + target = xrealloc (target, (*size = n)); + } + + FASTCOPY (source, target + *indx, srclen); + *indx += srclen; + target[*indx] = '\0'; + + free (source); + } + return (target); +} + +/* Append the textual representation of NUMBER to TARGET. + INDX and SIZE are as in SUB_APPEND_STRING. */ +char * +sub_append_number (number, target, indx, size) + int number, *indx, *size; + char *target; +{ + char *temp; + + temp = itos (number); + return (sub_append_string (temp, target, indx, size)); +} + +/* 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; + 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); + + while (args) + { + list = make_word_list (make_word (args->word->word), list); + args = args->next; + } + return (REVERSE_LIST (list, WORD_LIST *)); +} + +/* 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. */ +char * +string_rest_of_args (dollar_star) + int dollar_star; +{ + register WORD_LIST *list = list_rest_of_args (); + char *string; + + string = dollar_star ? string_list_dollar_star (list) : string_list (list); + dispose_words (list); + return (string); +} + +/*************************************************** + * * + * Functions to Expand a String * + * * + ***************************************************/ +/* Call expand_word_internal to expand W and handle error returns. + A convenience function for functions that don't want to handle + any errors or free any memory before aborting. */ +static WORD_LIST * +call_expand_word_internal (w, q, c, e) + WORD_DESC *w; + int q, *c, *e; +{ + WORD_LIST *result; + + result = expand_word_internal (w, q, c, e); + if (result == &expand_word_error) + longjmp (top_level, DISCARD); + else if (result == &expand_word_fatal) + longjmp (top_level, FORCE_EOF); + else + return (result); +} + +/* Perform parameter expansion, command substitution, and arithmetic + expansion on STRING, as if it were a word. Leave the result quoted. */ +static WORD_LIST * +expand_string_internal (string, quoted) + char *string; + int quoted; +{ + WORD_DESC td; + WORD_LIST *tresult; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + bzero (&td, sizeof (td)); + td.word = string; + tresult = call_expand_word_internal (&td, quoted, (int *)NULL, (int *)NULL); + return (tresult); +} + +/* 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 + remove_quoted_nulls () is in here because word splitting normally + takes care of quote removal. */ +WORD_LIST * +expand_string_unsplit (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *value; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + value = expand_string_internal (string, quoted); + if (value) + { + if (value->word) + remove_quoted_nulls (value->word->word); + dequote_list (value); + } + 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 + things like ${1+"$@"}. This does parameter expansion, command + subsitution, arithmetic expansion, and word splitting. */ +static WORD_LIST * +expand_string_leave_quoted (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *tlist; + WORD_LIST *tresult; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + tlist = expand_string_internal (string, quoted); + + if (tlist) + { + tresult = word_list_split (tlist); + dispose_words (tlist); + return (tresult); + } + return ((WORD_LIST *)NULL); +} + +/* 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 + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +WORD_LIST * +expand_string (string, quoted) + char *string; + int quoted; +{ + WORD_LIST *result; + + if (!string || !*string) + return ((WORD_LIST *)NULL); + + result = expand_string_leave_quoted (string, quoted); + + if (result) + dequote_list (result); + return (result); +} + +/*************************************************** + * * + * Functions to handle quoting chars * + * * + ***************************************************/ + +/* 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 +dequote_list (list) + register WORD_LIST *list; +{ + register char *s; + + while (list) + { + s = dequote_string (list->word->word); + free (list->word->word); + list->word->word = s; + list = list->next; + } +} + +static char * +make_quoted_char (c) + int c; +{ + char *temp; + + temp = xmalloc (3); + if (c == 0) + { + temp[0] = CTLNUL; + temp[1] = '\0'; + } + else + { + temp[0] = CTLESC; + temp[1] = c; + temp[2] = '\0'; + } + return (temp); +} + +/* Quote STRING. Return a new string. */ +static char * +quote_string (string) + char *string; +{ + char *result; + + if (!*string) + { + result = xmalloc (2); + result[0] = CTLNUL; + result[1] = '\0'; + } + else + { + register char *t; + + result = xmalloc ((strlen (string) * 2) + 1); + + for (t = result; string && *string; ) + { + *t++ = CTLESC; + *t++ = *string++; + } + *t = '\0'; + } + return (result); +} + +/* De-quoted quoted characters in STRING. */ +char * +dequote_string (string) + char *string; +{ + register char *t; + char *result; + + result = xmalloc (strlen (string) + 1); + + if (QUOTED_NULL (string)) + { + result[0] = '\0'; + return (result); + } + + /* If no character in the string can be quoted, don't bother examining + each character. Just return a copy of the string passed to us. */ + if (strchr (string, CTLESC) == NULL) /* XXX */ + { /* XXX */ + strcpy (result, string); /* XXX */ + return (result); /* XXX */ + } + + for (t = result; string && *string; string++) + { + if (*string == CTLESC) + { + string++; + + if (!*string) + break; + } + + *t++ = *string; + } + + *t = '\0'; + return (result); +} + +/* Quote the entire WORD_LIST list. */ +static void +quote_list (list) + WORD_LIST *list; +{ + register WORD_LIST *w; + + for (w = list; w; w = w->next) + { + char *t = w->word->word; + w->word->word = quote_string (t); + free (t); + w->word->quoted = 1; + } +} + +/* **************************************************************** */ +/* */ +/* Functions for Removing Patterns */ +/* */ +/* **************************************************************** */ + +/* Remove the portion of PARAM matched by PATTERN according to OP, where OP + can have one of 4 values: + RP_LONG_LEFT remove longest matching portion at start of PARAM + RP_SHORT_LEFT remove shortest matching portion at start of PARAM + RP_LONG_RIGHT remove longest matching portion at end of PARAM + RP_SHORT_RIGHT remove shortest matching portion at end of PARAM +*/ + +#define RP_LONG_LEFT 1 +#define RP_SHORT_LEFT 2 +#define RP_LONG_RIGHT 3 +#define RP_SHORT_RIGHT 4 + +static char * +remove_pattern (param, pattern, op) + char *param, *pattern; + int op; +{ + register int len = param ? strlen (param) : 0; + register char *end = param + len; + register char *p, *ret, c; + + if (pattern == NULL || *pattern == '\0') /* minor optimization */ + return (savestring (param)); + + if (param == NULL || *param == '\0') + return (param); + + switch (op) + { + case RP_LONG_LEFT: /* remove longest match at start */ + for (p = end; p >= param; p--) + { + c = *p; *p = '\0'; + if (fnmatch (pattern, param, 0) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + } + break; + + case RP_SHORT_LEFT: /* remove shortest match at start */ + for (p = param; p <= end; p++) + { + c = *p; *p = '\0'; + if (fnmatch (pattern, param, 0) != FNM_NOMATCH) + { + *p = c; + return (savestring (p)); + } + *p = c; + } + 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 */ +} + +/******************************************* + * * + * Functions to expand WORD_DESCs * + * * + *******************************************/ + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ + +WORD_LIST * +expand_word (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result, *tresult; + + 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); +} + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +WORD_LIST * +expand_word_no_split (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_LIST *result; + + result = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL); + if (result) + dequote_list (result); + return (result); +} + +/* Perform shell expansions on WORD, but do not perform word splitting or + quote removal on the result. */ +WORD_LIST * +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 the value of a positional parameter. This handles values > 10. */ +char * +get_dollar_var_value (ind) + int ind; +{ + char *temp; + + if (ind < 10) + { + if (dollar_vars[ind]) + temp = savestring (dollar_vars[ind]); + else + temp = (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; + } + return (temp); +} + +#if defined (PROCESS_SUBSTITUTION) + +/* **************************************************************** */ +/* */ +/* Hacking Process Substitution */ +/* */ +/* **************************************************************** */ + +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 + +static char **fifo_list = (char **)NULL; +static int nfifo = 0; +static int fifo_list_size = 0; + +static void +add_fifo_list (pathname) + char *pathname; +{ + if (nfifo >= fifo_list_size - 1) + { + fifo_list_size += FIFO_INCR; + fifo_list = (char **)xrealloc (fifo_list, + fifo_list_size * sizeof (char *)); + } + + fifo_list[nfifo++] = savestring (pathname); +} + +void +unlink_fifo_list () +{ + if (!nfifo) + return; + + while (nfifo--) + { + unlink (fifo_list[nfifo]); + free (fifo_list[nfifo]); + fifo_list[nfifo] = (char *)NULL; + } + nfifo = 0; +} + +static char * +make_named_pipe () +{ + char *tname; + + tname = mktemp (savestring ("/tmp/sh-np-XXXXXX")); + if (mkfifo (tname, 0600) < 0) + { + free (tname); + return ((char *)NULL); + } + + add_fifo_list (tname); + 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 + has open to children. NFDS is a count of the number of bits currently + 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 totfds; /* The highest possible number of open files. */ + +static void +add_fifo_list (fd) + int fd; +{ + if (!dev_fd_list || fd >= totfds) + { + int ofds; + + ofds = totfds; + totfds = getdtablesize (); + if (totfds < 0 || totfds > 256) + totfds = 256; + if (fd > totfds) + totfds = fd + 2; + + dev_fd_list = xrealloc (dev_fd_list, totfds); + bzero (dev_fd_list + ofds, totfds - ofds); + } + + dev_fd_list[fd] = 1; + nfds++; +} + +void +unlink_fifo_list () +{ + register int i; + + if (!nfds) + return; + + for (i = 0; nfds && i < totfds; i++) + if (dev_fd_list[i]) + { + close (i); + dev_fd_list[i] = 0; + nfds--; + } + + nfds = 0; +} + +#if defined (NOTDEF) +print_dev_fd_list () +{ + register int i; + + fprintf (stderr, "pid %d: dev_fd_list:", getpid ()); + fflush (stderr); + + for (i = 0; i < totfds; i++) + { + if (dev_fd_list[i]) + fprintf (stderr, " %d", i); + } + fprintf (stderr, "\n"); +} +#endif /* NOTDEF */ + +static char * +make_dev_fd_filename (fd) + int fd; +{ + char *ret; + + ret = xmalloc (16 * sizeof (char)); + sprintf (ret, "/dev/fd/%d", fd); + add_fifo_list (fd); + return (ret); +} + +#endif /* HAVE_DEV_FD */ + +/* Return a filename that will open a connection to the process defined by + executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return + a filename in /dev/fd corresponding to a descriptor that is one of the + ends of the pipe. If not defined, we use named pipes on systems that have + them. Systems without /dev/fd and named pipes are out of luck. + + OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or + use the read end of the pipe and dup that file descriptor to fd 0 in + the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for + writing or use the write end of the pipe in the child, and dup that + file descriptor to fd 1 in the child. The parent does the opposite. */ + +static char * +process_substitute (string, open_for_read_in_child) + char *string; + int open_for_read_in_child; +{ + char *pathname; + int fd, result; + pid_t old_pid, pid; +#if defined (HAVE_DEV_FD) + int parent_pipe_fd, child_pipe_fd; + int fildes[2]; +#endif /* HAVE_DEV_FD */ +#if defined (JOB_CONTROL) + pid_t old_pipeline_pgrp; +#endif + + if (!string || !*string) + return ((char *)NULL); + +#if !defined (HAVE_DEV_FD) + pathname = make_named_pipe (); +#else /* HAVE_DEV_FD */ + if (pipe (fildes) < 0) + { + internal_error ("can't make pipes for process substitution: %s", + strerror (errno)); + return ((char *)NULL); + } + /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of + the pipe in the parent, otherwise the read end. */ + parent_pipe_fd = fildes[open_for_read_in_child]; + child_pipe_fd = fildes[1 - open_for_read_in_child]; + pathname = make_dev_fd_filename (parent_pipe_fd); +#endif /* HAVE_DEV_FD */ + + if (!pathname) + { + internal_error ("cannot make pipe for process subsitution: %s", + strerror (errno)); + return ((char *)NULL); + } + + old_pid = last_made_pid; + +#if defined (JOB_CONTROL) + old_pipeline_pgrp = pipeline_pgrp; + pipeline_pgrp = shell_pgrp; + cleanup_the_pipeline (); + pid = make_child ((char *)NULL, 1); + if (pid == 0) + { + /* Cancel traps, in trap.c. */ + restore_original_signals (); + setup_async_signals (); + subshell_environment++; + } + 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 */ + + if (pid < 0) + { + internal_error ("cannot make a child for process substitution: %s", + strerror (errno)); + free (pathname); +#if defined (HAVE_DEV_FD) + close (parent_pipe_fd); + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ + return ((char *)NULL); + } + + if (pid > 0) + { + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + +#if defined (HAVE_DEV_FD) + close (child_pipe_fd); +#endif /* HAVE_DEV_FD */ + + return (pathname); + } + + set_sigint_handler (); + +#if defined (JOB_CONTROL) + set_job_control (0); +#endif /* JOB_CONTROL */ + +#if !defined (HAVE_DEV_FD) + /* Open the named pipe in the child. */ + fd = open (pathname, open_for_read_in_child ? O_RDONLY : 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)); + exit (127); + } +#else /* HAVE_DEV_FD */ + fd = child_pipe_fd; +#endif /* HAVE_DEV_FD */ + + 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)); + exit (127); + } + + close (fd); + + /* Need to close any files that this process has open to pipes inherited + from its parent. */ + if (current_fds_to_close) + { + close_fd_bitmap (current_fds_to_close); + current_fds_to_close = (struct fd_bitmap *)NULL; + } + +#if defined (HAVE_DEV_FD) + /* Make sure we close the parent's end of the pipe and clear the slot + in the fd list so it is not closed later, if reallocated by, for + instance, pipe(2). */ + close (parent_pipe_fd); + dev_fd_list[parent_pipe_fd] = 0; +#endif /* HAVE_DEV_FD */ + + result = parse_and_execute (string, "process substitution", 0); + +#if !defined (HAVE_DEV_FD) + /* Make sure we close the named pipe in the child before we exit. */ + close (open_for_read_in_child ? 0 : 1); +#endif /* !HAVE_DEV_FD */ + + exit (result); + /*NOTREACHED*/ +} +#endif /* PROCESS_SUBSTITUTION */ + +/* Perform command substitution on STRING. This returns a string, + possibly quoted. */ +static char * +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; + + istring_index = istring_size = 0; + + /* Don't fork () if there is no need to. In the case of no command to + run, just return NULL. */ + if (!string || !*string || (string[0] == '\n' && !string[1])) + return ((char *)NULL); + + /* Pipe the output of executing STRING into the current shell. */ + if (pipe (fildes) < 0) + { + internal_error ("Can't 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); + + if (pid == 0) + /* Reset the signal handlers in the child, but don't free the + trap strings. */ + reset_signal_handlers (); +#endif /* !JOB_CONTROL */ + + if (pid < 0) + { + internal_error ("Can't make a child for command substitution: %s", + strerror (errno)); + error_exit: + + FREE (istring); + close (fildes[0]); + close (fildes[1]); + return ((char *)NULL); + } + + if (pid == 0) + { + set_sigint_handler (); /* XXX */ +#if defined (JOB_CONTROL) + set_job_control (0); +#endif + if (dup2 (fildes[1], 1) < 0) + { + internal_error + ("command_substitute: cannot duplicate pipe as fd 1: %s", + strerror (errno)); + exit (EXECUTION_FAILURE); + } + + /* If standard output is closed in the parent shell + (such as after `exec >&-'), file descriptor 1 will be + the lowest available file descriptor, and end up in + fildes[0]. This can happen for stdin and stderr as well, + but stdout is more important -- it will cause no output + to be generated from this command. */ + if ((fildes[1] != fileno (stdin)) && + (fildes[1] != fileno (stdout)) && + (fildes[1] != fileno (stderr))) + close (fildes[1]); + + if ((fildes[0] != fileno (stdin)) && + (fildes[0] != fileno (stdout)) && + (fildes[0] != fileno (stderr))) + close (fildes[0]); + + /* The currently executing shell is not interactive. */ + interactive = 0; + + /* Command substitution does not inherit the -e flag. */ + exit_immediately_on_error = 0; + + remove_quoted_escapes (string); + + /* Give command substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp (top_level); + + if (result == EXITPROG) + exit (last_command_exit_value); + else if (result) + exit (EXECUTION_FAILURE); + else + exit (parse_and_execute (string, "command substitution", -1)); + } + else + { + FILE *istream; + + istream = fdopen (fildes[0], "r"); + +#if defined (JOB_CONTROL) && defined (PGRP_PIPE) + close_pgrp_pipe (); +#endif /* JOB_CONTROL && PGRP_PIPE */ + + close (fildes[1]); + + if (!istream) + { + internal_error ("Can't reopen pipe to command substitution (fd %d): %s", + fildes[0], strerror (errno)); + goto error_exit; + } + + /* Read the output of the command through the pipe. */ + while (1) + { +#if defined (NO_READ_RESTART_ON_SIGNAL) + c = getc_with_restart (istream); +#else + c = getc (istream); +#endif /* !NO_READ_RESTART_ON_SIGNAL */ + + 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); + } + + if (quoted || c == CTLESC || c == CTLNUL) + istring[istring_index++] = CTLESC; + + istring[istring_index++] = c; + istring[istring_index] = '\0'; + } + + fclose (istream); + close (fildes[0]); + + last_command_exit_value = wait_for (pid); + last_command_subst_pid = pid; + last_made_pid = old_pid; + +#if defined (JOB_CONTROL) + /* If last_command_exit_value > 128, then the substituted command + was terminated by a signal. If that signal was SIGINT, then send + SIGINT to ourselves. This will break out of loops, for instance. */ + if (last_command_exit_value == (128 + SIGINT)) + kill (getpid (), SIGINT); + + /* wait_for gives the terminal back to shell_pgrp. If some other + process group should have it, give it away to that group here. */ + if (interactive && pipeline_pgrp != (pid_t)0) + give_terminal_to (pipeline_pgrp); +#endif /* JOB_CONTROL */ + + /* If we read no output, just return now and save ourselves some + trouble. */ + if (istring_index == 0) + goto error_exit; + + /* Strip trailing newlines from the output of the command. */ + if (quoted) + { + while (istring_index > 0) + { + if (istring[istring_index - 1] == '\n') + { + --istring_index; + + /* If the newline was quoted, remove the quoting char. */ + if (istring[istring_index - 1] == CTLESC) + --istring_index; + } + else + break; + } + istring[istring_index] = '\0'; + } + else + strip_trailing (istring, 1); + + return (istring); + } +} + +/******************************************************** + * * + * Utility functions for parameter expansion * + * * + ********************************************************/ + +/* 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) + char *value, *temp; + int c; +{ + int pattern_specifier; + WORD_LIST *l; + char *pattern, *t, *tword; + + if (c == '#') + { + if (*value == '#') + { + value++; + pattern_specifier = RP_LONG_LEFT; + } + else + pattern_specifier = RP_SHORT_LEFT; + } + else /* c == '%' */ + { + if (*value == '%') + { + value++; + pattern_specifier = RP_LONG_RIGHT; + } + else + pattern_specifier = 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 (strchr (value, '~')) + tword = tilde_expand (value); + else + tword = savestring (value); + + /* 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); + + if (pattern) + { + tword = quote_string_for_globbing (pattern, 1); + free (pattern); + pattern = tword; + } + + t = remove_pattern (temp, pattern, pattern_specifier); + + FREE (pattern); + return (t); +} + +static int +valid_brace_expansion_word (name, var_is_special) + char *name; + int var_is_special; +{ + if (digit (*name) && all_digits (name)) + return 1; + else if (var_is_special) + return 1; + 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 + the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that + NAME was found inside of a double-quoted expression. */ +static char * +parameter_brace_expand_word (name, var_is_special, quoted) + char *name; + int var_is_special, quoted; +{ + char *temp = (char *)NULL; + + /* Handle multiple digit arguments, as in ${11}. */ + if (digit (*name)) + { + int 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'; + strcpy (tt + 1, name); + l = expand_string_leave_quoted (tt, quoted); + free (tt); + temp = string_list (l); + dispose_words (l); + } + else + { + SHELL_VAR *var = find_variable (name); + + if (var && !invisible_p (var) && (temp = value_cell (var))) + temp = quoted && temp && *temp ? quote_string (temp) + : quote_escapes (temp); + } + 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 "=". */ +static char * +parameter_brace_expand_rhs (name, value, c, quoted) + char *name, *value; + int c, quoted; +{ + WORD_LIST *l; + char *t, *t1, *temp; + int i, lquote, hasdol; + + if (value[0] == '~' || + (strchr (value, '~') && unquoted_substring ("=~", value))) + temp = tilde_expand (value); + else + temp = savestring (value); + + /* This is a hack. A better fix is coming later. */ + lquote = 0; + if (*temp == '"' && temp[strlen (temp) - 1] == '"') + { + i = 1; + t = string_extract_double_quoted (temp, &i); /* XXX */ + 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; + 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) + { + temp = string_list (l); + dispose_words (l); + } + else if (lquote) + { + temp = xmalloc (2); + temp[0] = CTLNUL; + temp[1] = '\0'; + } + else + temp = (char *)NULL; + + if (c == '-' || c == '+') + return (temp); + + /* c == '=' */ + if (temp) + t = savestring (temp); + else + t = savestring (""); + t1 = dequote_string (t); + free (t); + bind_variable (name, t1); + free (t1); + return (temp); +} + +/* Deal with the right hand side of a ${name:?value} expansion in the case + that NAME is null or not set. If VALUE is non-null it is expanded and + used as the error message to print, otherwise a standard message is + printed. */ +static void +parameter_brace_expand_error (name, value) + char *name, *value; +{ + 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); + dispose_words (l); + } + else + report_error ("%s: parameter null or not set", name); + + /* Free the data we have allocated during this expansion, since we + are about to longjmp out. */ + free (name); + FREE (value); +} + +/* Return 1 if NAME is something for which parameter_brace_expand_length is + OK to do. */ +static int +valid_length_expression (name) + char *name; +{ + return (!name[1] || /* ${#} */ + ((name[1] == '@' || name[1] == '*') && !name[2]) || /* ${#@}, ${#*} */ + (digit (name[1]) && all_digits (name + 1)) || /* ${#11} */ + legal_identifier (name + 1)); /* ${#PS1} */ +} + +/* Handle the parameter brace expansion that requires us to return the + length of a parameter. */ +static int +parameter_brace_expand_length (name) + char *name; +{ + char *t; + int number = 0; + + if (name[1] == '\0') /* ${#} */ + { + WORD_LIST *l = list_rest_of_args (); + number = list_length (l); + dispose_words (l); + } + else if (name[1] != '*' && name[1] != '@') + { + number = 0; + + if (digit (name[1])) /* ${#1} */ + { + if (t = get_dollar_var_value (atoi (name + 1))) + { + number = strlen (t); + free (t); + } + } + 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); + + FREE (t); + } + } + 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); + } +#endif /* KSH_INCOMPATIBLE */ + } + return (number); +} + +/* Make a word list which is the parameter and variable expansion, + command substitution, arithmetic substitution, and quote removed + expansion of WORD. Return a pointer to a WORD_LIST which is the + 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. + 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. + EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, + else zero. + + This only does word splitting in the case of $@ expansion. In that + case, we split on ' '. */ + +/* Values for the local variable quoted_state. */ +#define UNQUOTED 0 +#define PARTIALLY_QUOTED 1 +#define WHOLLY_QUOTED 2 + +static WORD_LIST * +expand_word_internal (word, quoted, contains_dollar_at, expanded_something) + WORD_DESC *word; + int quoted; + int *contains_dollar_at; + int *expanded_something; +{ + /* The thing that we finally output. */ + WORD_LIST *result = (WORD_LIST *)NULL; + + /* The intermediate string that we build while expanding. */ + char *istring = xmalloc (DEFAULT_ARRAY_SIZE); + + /* The current size of the above object. */ + int istring_size = DEFAULT_ARRAY_SIZE; + + /* Index into ISTRING. */ + int istring_index = 0; + + /* Temporary string storage. */ + char *temp = (char *)NULL; + + /* The text of WORD. */ + register char *string = word->word; + + /* The index into STRING. */ + int sindex = 0; + + /* This gets 1 if we see a $@ while quoted. */ + int quoted_dollar_at = 0; + + /* 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; + + 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'; + + if (!string) goto final_exit; + + if (contains_dollar_at) + *contains_dollar_at = 0; + + /* Begin the expansion. */ + + for (;;) + { + c = string[sindex]; + + /* Case on toplevel character. */ + switch (c) + { + case '\0': + goto finished_with_string; + + case CTLESC: + temp = xmalloc (3); + temp[0] = CTLESC; + temp[1] = c = string[++sindex]; + temp[2] = '\0'; + + if (string[sindex]) + sindex++; + + goto add_string; + +#if defined (PROCESS_SUBSTITUTION) + /* Process substitution. */ + case '<': + case '>': + { + char *temp1; + int old_index; + + if (string[++sindex] != '(' || quoted || posixly_correct) + { + sindex--; + goto add_character; + } + else + old_index = ++sindex; /* skip past both '<' and '(' */ + + temp1 = extract_process_subst + (string, (c == '<') ? "<(" : ">(", &old_index); + sindex = old_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 == '>')); + + FREE (temp1); + + goto dollar_add_string; + } +#endif /* PROCESS_SUBSTITUTION */ + + /* See about breaking this into a separate function: + char * + param_expand (string, sindex, quoted, expanded_something, + contains_dollar_at, quoted_dollar_at) + char *string; + int *sindex, quoted, *expanded_something, *contains_dollar_at; + int *quoted_dollar_at; + */ + case '$': + + if (expanded_something) + *expanded_something = 1; + + c = string[++sindex]; + + /* Do simple cases first. Switch on what follows '$'. */ + switch (c) + { + /* $0 .. $9? */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + temp = dollar_vars[digit_value (c)]; + if (unbound_vars_is_error && temp == (char *)NULL) + { + report_error ("$%c: unbound variable", c); + free (string); + free (istring); + last_command_exit_value = 1; + return (&expand_word_error); + } + if (temp) + temp = savestring (temp); + goto dollar_add_string; + + /* $$ -- pid of the invoking shell. */ + case '$': + number = dollar_dollar_pid; + + add_number: + temp = itos (number); + dollar_add_string: + if (string[sindex]) sindex++; + + /* Add TEMP to ISTRING. */ + add_string: + istring = sub_append_string + (temp, istring, &istring_index, &istring_size); + temp = (char *)NULL; + break; + + /* $# -- number of positional parameters. */ + case '#': + { + WORD_LIST *list = list_rest_of_args (); + number = list_length (list); + dispose_words (list); + goto add_number; + } + + /* $? -- return value of the last synchronous command. */ + case '?': + number = last_command_exit_value; + goto add_number; + + /* $- -- flags supplied to the shell on invocation or + by `set'. */ + case '-': + temp = which_set_flags (); + goto dollar_add_string; + + /* $! -- Pid of the last asynchronous command. */ + case '!': + number = (int)last_asynchronous_pid; + + /* If no asynchronous pids have been created, echo nothing. */ + if (number == (int)NO_PID) + { + if (string[sindex]) + sindex++; + if (expanded_something) + *expanded_something = 0; + break; + } + goto add_number; + + /* The only difference between this and $@ is when the + arg is quoted. */ + case '*': /* `$*' */ + temp = string_rest_of_args (quoted); + + if (quoted && temp && *temp == '\0' /* && istring_index > 0 */) + { + free (temp); + temp = (char *)NULL; + } + + /* In the case of a quoted string, quote the entire arg-list. + "$1 $2 $3". */ + if (quoted && temp) + { + char *james_brown = temp; + temp = quote_string (temp); + free (james_brown); + } + goto dollar_add_string; + + /* When we have "$@" what we want is "$1" "$2" "$3" ... This + means that we have to turn quoting off after we split into + 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; + } + + /* ${[#]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 '{' */ + /* break; */ + + /* Do command or arithmetic substitution. */ + 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; + + l = expand_string (t, 1); + t = string_list (l); + dispose_words (l); + } + + /* No error messages. */ + this_command_name = (char *)NULL; + + number = evalexp (t); + free (temp); + free (t); + + goto add_number; + } + + goto handle_command_substitution; + } + + /* Do straight arithmetic substitution. */ + case '[': + /* We have to extract the contents of this + arithmetic substitution. */ + { + char *t; + int old_index = ++sindex; + WORD_LIST *l; + + temp = extract_arithmetic_subst (string, &old_index); + sindex = old_index; + + /* 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 (t); + free (t); + free (temp); + + 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; + + 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; + } + } + break; /* End case '$': */ + + case '`': /* Backquoted command substitution. */ + { + sindex++; + + if (expanded_something) + *expanded_something = 1; + + temp = string_extract (string, &sindex, "`"); + de_backslash (temp); + + handle_command_substitution: + command_subst_result = command_substitute (temp, quoted); + + FREE (temp); + + temp = command_subst_result; + + if (string[sindex]) + sindex++; + + goto add_string; + } + + case '\\': + if (string[sindex + 1] == '\n') + { + sindex += 2; + continue; + } + else + { + char *slashify_chars = ""; + + c = string[++sindex]; + + if (quoted == Q_HERE_DOCUMENT) + slashify_chars = slashify_in_here_document; + else if (quoted == Q_DOUBLE_QUOTES) + slashify_chars = slashify_in_quotes; + + if (quoted && !member (c, slashify_chars)) + { + temp = xmalloc (3); + temp[0] = '\\'; temp[1] = c; temp[2] = '\0'; + if (c) + sindex++; + 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; + } + } + + case '"': + if (quoted) + goto add_character; + sindex++; + { + WORD_LIST *tresult = (WORD_LIST *)NULL; + + t_index = sindex; + temp = string_extract_double_quoted (string, &sindex); + + /* 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; + + 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; + } + + /* 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; + + /* 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; + + add_quoted_string: + + 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; */ + + 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; + + break; + } + + default: + + /* This is the fix for " $@ " */ + if (quoted) + { + temp = make_quoted_char (c); + if (string[sindex]) + sindex++; + goto 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); + } + istring[istring_index++] = c; + istring[istring_index] = '\0'; + + /* Next character. */ + sindex++; + } + } + +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) + { + if (istring_size < 2) + istring = xrealloc (istring, istring_size += 2); + istring[0] = CTLNUL; + istring[1] = '\0'; + } + + /* 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) + { + 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; + } + } + else if (word->assignment) + { + 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); + } + 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"; + } + + /* 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; + } + } + + free (istring); + result = (WORD_LIST *) + list_append (REVERSE_LIST (result, WORD_LIST *), temp_list); + } + else + result = (WORD_LIST *)NULL; + + return (result); +} + +/* **************************************************************** */ +/* */ +/* Functions for Quote Removal */ +/* */ +/* **************************************************************** */ + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes. */ +char * +string_quote_removal (string, quoted) + char *string; + int quoted; +{ + char *r, *result_string, *temp, *temp1; + 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];) + { + switch (c) + { + case '\\': + c = string[++sindex]; + if ((quoted || dquote) && !member (c, slashify_in_quotes)) + *r++ = '\\'; + + default: + *r++ = c; + sindex++; + break; + + case '\'': + if (quoted || dquote) + { + *r++ = c; + sindex++; + } + else + { + tindex = ++sindex; + temp = string_extract_single_quoted (string, &tindex); + sindex = tindex; + + if (temp) + { + strcpy (r, temp); + r += strlen (r); + free (temp); + } + } + break; + + case '"': + dquote = 1 - dquote; + sindex++; + break; + } + } + *r = '\0'; + return (result_string); +} + +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +WORD_DESC * +word_quote_removal (word, quoted) + WORD_DESC *word; + int quoted; +{ + WORD_DESC *w; + char *t; + + t = string_quote_removal (word->word, quoted); + w = make_word (t); + return (w); +} + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +WORD_LIST * +word_list_quote_removal (list, quoted) + WORD_LIST *list; + int quoted; +{ + WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult; + + t = list; + while (t) + { + 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); +} + +/* Return 1 if CHARACTER appears in an unquoted portion of + STRING. Return 0 otherwise. */ +static int +unquoted_member (character, string) + int character; + char *string; +{ + int sindex, tindex, c; + char *temp; + + sindex = 0; + + while (c = string[sindex]) + { + if (c == character) + return (1); + + switch (c) + { + case '\\': + sindex++; + if (string[sindex]) + sindex++; + break; + + case '"': + case '\'': + + tindex = ++sindex; + if (c == '"') + temp = string_extract_double_quoted (string, &tindex); + else + temp = string_extract_single_quoted (string, &tindex); + sindex = tindex; + + FREE (temp); + break; + + default: + sindex++; + break; + } + } + return (0); +} + +/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ +static int +unquoted_substring (substr, string) + char *substr, *string; +{ + int sindex, tindex, c, sublen; + char *temp; + + if (!substr || !*substr) + return (0); + + sublen = strlen (substr); + sindex = 0; + + while (c = string[sindex]) + { + if (STREQN (string + sindex, substr, sublen)) + return (1); + + switch (c) + { + case '\\': + sindex++; + + if (string[sindex]) + sindex++; + break; + + case '"': + case '\'': + + tindex = ++sindex; + + if (c == '"') + temp = string_extract_double_quoted (string, &tindex); + else + temp = string_extract_single_quoted (string, &tindex); + sindex = tindex; + + FREE (temp); + + break; + + default: + sindex++; + break; + } + } + return (0); +} + +/******************************************* + * * + * Functions to perform word splitting * + * * + *******************************************/ + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +WORD_LIST * +word_split (w) + WORD_DESC *w; +{ + WORD_LIST *result; + + if (w) + { + SHELL_VAR *ifs = find_variable ("IFS"); + char *ifs_chars; + + /* If IFS is unset, it defaults to " \t\n". */ + if (ifs) + ifs_chars = value_cell (ifs); + else + ifs_chars = " \t\n"; + + if (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); + } + else + result = (WORD_LIST *)NULL; + return (result); +} + +/* Perform word splitting on LIST and return the RESULT. It is possible + to return (WORD_LIST *)NULL. */ +static WORD_LIST * +word_list_split (list) + WORD_LIST *list; +{ + WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult; + + t = list; + while (t) + { + tresult = word_split (t->word); + result = (WORD_LIST *) list_append (result, tresult); + t = t->next; + } + return (result); +} + +/************************************************** + * * + * Functions to expand an entire WORD_LIST * + * * + **************************************************/ + +static WORD_LIST *varlist = (WORD_LIST *)NULL; + +/* Separate out any initial variable assignments from TLIST. If set -k has + been executed, remove all assignment statements from TLIST. Initial + variable assignments and other environment assignments are placed + on VARLIST. */ +static WORD_LIST * +separate_out_assignments (tlist) + WORD_LIST *tlist; +{ + register WORD_LIST *vp, *lp; + + if (!tlist) + return ((WORD_LIST *)NULL); + + varlist = (WORD_LIST *)NULL; + vp = lp = tlist; + + /* Separate out variable assignments at the start of the command. + Loop invariant: vp->next == lp + Loop postcondition: + lp = list of words left after assignment statements skipped + tlist = original list of words + */ + while (lp && lp->word->assignment) + { + vp = lp; + lp = lp->next; + } + + /* If lp != tlist, we have some initial assignment statements. */ + /* We make VARLIST point to the list of assignment words and + TLIST point to the remaining words. */ + if (lp != tlist) + { + varlist = tlist; + /* ASSERT(vp->next == lp); */ + vp->next = (WORD_LIST *)NULL; /* terminate variable list */ + tlist = lp; /* remainder of word list */ + } + + /* vp == end of variable list */ + /* tlist == remainder of original word list without variable assignments */ + if (!tlist) + /* All the words in tlist were assignment statements */ + return ((WORD_LIST *)NULL); + + /* ASSERT(tlist != NULL); */ + /* ASSERT(tlist->word->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. */ + if (place_keywords_in_env) + { + WORD_LIST *tp; /* tp == running pointer into tlist */ + + tp = tlist; + lp = tlist->next; + + /* Loop Invariant: tp->next == lp */ + /* Loop postcondition: tlist == word list without assignment statements */ + while (lp) + { + if (lp->word->assignment) + { + /* Found an assignment statement, add this word to end of + varlist (vp). */ + if (!varlist) + varlist = vp = lp; + else + { + vp->next = lp; + vp = lp; + } + + /* Remove the word pointed to by LP from TLIST. */ + tp->next = lp->next; + /* ASSERT(vp == lp); */ + lp->next = (WORD_LIST *)NULL; + lp = tp->next; + } + else + { + tp = lp; + lp = lp->next; + } + } + } + return (tlist); +} + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ + +WORD_LIST * +expand_words (list) + WORD_LIST *list; +{ + return (expand_words_internal (list, 1)); +} + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +WORD_LIST * +expand_words_no_vars (list) + WORD_LIST *list; +{ + return (expand_words_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 (). + 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. */ +static WORD_LIST * +expand_words_internal (list, do_vars) + WORD_LIST *list; + int do_vars; +{ + register WORD_LIST *tlist, *new_list = (WORD_LIST *)NULL; + WORD_LIST *orig_list; + + if (!list) + return ((WORD_LIST *)NULL); + + tlist = copy_word_list (list); + + if (do_vars) + { + tlist = separate_out_assignments (tlist); + if (!tlist) + { + 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); + dispose_words (varlist); + varlist = (WORD_LIST *)NULL; + } + return ((WORD_LIST *)NULL); + } + } + + /* Begin expanding the words that remain. The expansions take place on + things that aren't really variable assignments. */ + +#if defined (BRACE_EXPANSION) + /* Do brace expansion on this word if there are any brace characters + in the string. */ + if (!no_brace_expansion) + { + register char **expansions; + WORD_LIST *braces = (WORD_LIST *)NULL, *disposables = (WORD_LIST *)NULL; + int eindex; + + while (tlist) + { + WORD_LIST *next; + + next = tlist->next; + + /* Only do brace expansion if the word has a brace character. If + not, just add the word list element to BRACES and continue. In + the common case, at least when running shell scripts, this will + degenerate to a bunch of calls to `strchr', and then what is + basically a reversal of TLIST into BRACES, which is corrected + by a call to reverse_list () on BRACES when the end of TLIST + is reached. */ + if (strchr (tlist->word->word, '{')) + { + expansions = brace_expand (tlist->word->word); + + for (eindex = 0; expansions[eindex]; eindex++) + { + braces = make_word_list (make_word (expansions[eindex]), + braces); + free (expansions[eindex]); + } + free (expansions); + + /* Add TLIST to the list of words to be freed after brace + expansion has been performed. */ + tlist->next = disposables; + disposables = tlist; + } + else + { + tlist->next = braces; + braces = tlist; + } + + tlist = next; + } + + dispose_words (disposables); + tlist = REVERSE_LIST (braces, WORD_LIST *); + } +#endif /* BRACE_EXPANSION */ + + orig_list = tlist; + + /* We do tilde expansion all the time. This is what 1003.2 says. */ + while (tlist) + { + register char *current_word; + WORD_LIST *expanded, *t, *reversed, *next; + int expanded_something = 0; + + current_word = 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))) + { + char *tt; + + tt = tlist->word->word; + tlist->word->word = tilde_expand (tt); + free (tt); + } + + expanded = expand_word_internal + (tlist->word, 0, (int *)NULL, &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); + else + longjmp (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) + { + t = word_list_split (expanded); + dispose_words (expanded); + } + else + { + /* If no parameter expansion, command substitution, process + substitution, or arithmetic substitution took place, then + do not do word splitting. We still have to remove quoted + null characters from the result. */ + word_list_remove_quoted_nulls (expanded); + t = 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; + } + + 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; + + orig_list = disposables = (WORD_LIST *)NULL; + tlist = new_list; + + /* orig_list == output list, despite the name. */ + if (!disallow_filename_globbing) + { + while (tlist) + { + /* For each word, either globbing is attempted or the word is + added to orig_list. If globbing succeeds, the results are + added to orig_list and the word (tlist) is added to the list + of disposable words. If globbing fails and failed glob + expansions are left unchanged (the shell default), the + original word is added to orig_list. If globbing fails and + failed glob expansions are removed, the original word is + added to the list of disposable words. orig_list ends up + 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 && + unquoted_glob_pattern_p (tlist->word->word)) + { + temp_list = 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)) + { + temp_list = (char **) xmalloc (sizeof (char *)); + temp_list[0] = (char *)NULL; + } + + /* Dequote the current word in case we have to use it. */ + if (!temp_list[0]) + { + register char *t = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = t; + } + + /* 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); + + if (glob_list) + { + orig_list = (WORD_LIST *)list_append + (glob_list, orig_list); + tlist->next = disposables; + disposables = 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; + } + } + else + { + /* Dequote the string. */ + register char *t = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = t; + tlist->next = orig_list; + orig_list = tlist; + } + + free_array (temp_list); + temp_list = (char **)NULL; + + tlist = next; + } + + if (disposables) + dispose_words (disposables); + + new_list = REVERSE_LIST (orig_list, WORD_LIST *); + } + else + { + /* Dequote the words, because we're not performing globbing. */ + register WORD_LIST *wl = new_list; + register char *wp; + while (wl) + { + wp = dequote_string (wl->word->word); + free (wl->word->word); + wl->word->word = wp; + wl = wl->next; + } + } + } + + if (do_vars) + { + register WORD_LIST *lp; + Function *assign_func; + + /* If the remainder of the words expand to nothing, Posix.2 requires + that the variable and environment assignments affect the shell's + 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) + { + 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); +} + +/* 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); + + return (results); +#endif /* !USE_POSIX_GLOB_LIBRARY */ +} + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + 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 { + char *name; + VFunction *function; +} special_vars[] = { + { "PATH", sv_path }, + { "MAIL", sv_mail }, + { "MAILPATH", sv_mail }, + { "MAILCHECK", sv_mail }, + + { "POSIXLY_CORRECT", sv_strict_posix }, + { "POSIX_PEDANTIC", sv_strict_posix }, + /* 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 }, +#endif /* READLINE */ + + /* Variables which only do something special when HISTORY is defined. */ +#if defined (HISTORY) + { "HISTSIZE", sv_histsize }, + { "HISTFILESIZE", sv_histfilesize }, + { "command_oriented_history", sv_command_oriented_history }, +# if defined (BANG_HISTORY) + { "histchars", sv_histchars }, +# endif + { "history_control", sv_history_control }, + { "HISTCONTROL", sv_history_control }, +#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 } +}; + +/* 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. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + int i = 0; + + while (special_vars[i].name) + { + 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); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +#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 + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && !no_line_editing) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostname_completion_file (name) + char *name; +{ + hostname_list_initialized = 0; +} +#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 + the history. Otherwise, if there is NO value for this variable, + unstifle the history. */ +void +sv_histsize (name) + char *name; +{ + char *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 (); + } + } + else + unstifle_history (); +} + +/* What to do if the HISTFILESIZE variable changes. */ +void +sv_histfilesize (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; + } + } +} + +/* What to do after the HISTORY_CONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp = get_string_value (name); + + history_control = 0; + + if (temp && *temp) + { + if (strcmp (temp, "ignorespace") == 0) + history_control = 1; + else if (strcmp (temp, "ignoredups") == 0) + history_control = 2; + else if (strcmp (temp, "ignoreboth") == 0) + 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) +/* Setting/unsetting of the history expansion character. */ + +void +sv_histchars (name) + char *name; +{ + char *temp = get_string_value (name); + + if (temp) + { + history_expansion_char = *temp; + if (temp[0] && temp[1]) + { + history_subst_char = temp[1]; + if (temp[2]) + history_comment_char = temp[2]; + } + } + else + { + history_expansion_char = '!'; + history_subst_char = '^'; + history_comment_char = '#'; + } +} +# endif /* BANG_HISTORY */ +#endif /* HISTORY */ + +void +sv_allow_null_glob_expansion (name) + char *name; +{ + SET_INT_VAR (name, allow_null_glob_expansion); +} + +/* If the variable exists, then the value of it can be the number + of times we actually ignore the EOF. The default is small, + (smaller than csh, anyway). */ +void +sv_ignoreeof (name) + char *name; +{ + SHELL_VAR *tmp_var; + char *temp; + int new_limit; + + eof_encountered = 0; + + tmp_var = find_variable (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); +} + +#if defined (GETOPTS_BUILTIN) +void +sv_optind (name) + char *name; +{ + char *tt = get_string_value ("OPTIND"); + int s = 0; + + if (tt && *tt) + { + s = atoi (tt); + + /* According to POSIX, setting OPTIND=1 resets the internal state + of getopt (). */ + if (s < 0 || s == 1) + s = 0; + } + getopts_reset (s); +} + +void +sv_opterr (name) + char *name; +{ + char *tt = get_string_value ("OPTERR"); + int s = 1; + + if (tt && *tt) + s = atoi (tt); + sh_opterr = s; +} +#endif /* GETOPTS_BUILTIN */ + +void +sv_strict_posix (name) + char *name; +{ + SET_INT_VAR (name, posixly_correct); + if (posixly_correct) + interactive_comments = 1; +#if defined (READLINE) + posix_readline_initialize (posixly_correct); +#endif /* READLINE */ +} @@ -0,0 +1,181 @@ +/* subst.h -- Names of externally visible functions in subst.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 (_SUBST_H_) +#define _SUBST_H_ + +#include "stdc.h" + +/* Cons a new string from STRING starting at START and ending at END, + not including END. */ +extern char *substring __P((char *, int, int)); + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +extern char * de_backslash __P((char *)); + +/* Replace instances of \! in a string with !. */ +extern void unquote_bang __P((char *)); + +/* 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 ")". */ +extern char *extract_command_subst __P((char *, int *)); + +/* 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 "]". */ +extern char *extract_arithmetic_subst __P((char *, int *)); + +#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 ")". */ +extern char *extract_process_subst __P((char *, char *, int *)); +#endif /* PROCESS_SUBSTITUTION */ + +/* Extract the name of the variable to bind to from the assignment string. */ +extern char *assignment_name __P((char *)); + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +extern char *string_list __P((WORD_LIST *)); + +/* Return a single string of all the words present in LIST, obeying the + quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the + expansion [of $*] appears within a double quoted string, it expands + to a single field with the value of each parameter separated by the + first character of the IFS variable, or by a <space> if IFS is unset." */ +extern char *string_list_dollar_star __P((WORD_LIST *)); + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +extern void word_list_remove_quoted_nulls __P((WORD_LIST *)); + +/* This performs word splitting and quoted null character removal on + STRING. */ +extern WORD_LIST *list_string __P((char *, char *, int)); + +extern char *get_word_from_string __P((char **, char *, char **)); +extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); + +/* 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 + expansion on the right-hand side. Perform tilde expansion in any + case. Do not perform word splitting on the result of expansion. */ +extern int do_assignment __P((char *)); +extern int do_assignment_no_expand __P((char *)); + +/* 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. + Returns TARGET in case the location has changed. */ +extern char *sub_append_string __P((char *, char *, int *, int *)); + +/* Append the textual representation of NUMBER to TARGET. + INDEX and SIZE are as in SUB_APPEND_STRING. */ +extern char *sub_append_number __P((int, char *, int *, int *)); + +/* Return the word list that corresponds to `$*'. */ +extern WORD_LIST *list_rest_of_args __P((void)); + +/* 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. */ +extern char *string_rest_of_args __P((int)); + +/* 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 + remove_quoted_nulls () is in here because word splitting normally + takes care of quote removal. */ +extern WORD_LIST *expand_string_unsplit __P((char *, int)); + +/* 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 + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +extern WORD_LIST *expand_string __P((char *, int)); + +/* De-quoted quoted characters in STRING. */ +extern char *dequote_string __P((char *)); + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ +extern WORD_LIST *expand_word __P((WORD_DESC *, int)); + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +extern WORD_LIST *expand_word_no_split __P((WORD_DESC *, int)); +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)); + +/* 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)); + +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +extern WORD_DESC *word_quote_removal __P((WORD_DESC *, int)); + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +extern WORD_LIST *word_list_quote_removal __P((WORD_LIST *, int)); + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +extern WORD_LIST *word_split __P((WORD_DESC *)); + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ +extern WORD_LIST *expand_words __P((WORD_LIST *)); + +/* Same as expand_words (), but doesn't hack variable or environment + 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 *)); + +#endif /* !_SUBST_H_ */ diff --git a/support/PORTING b/support/PORTING new file mode 100644 index 0000000..1869472 --- /dev/null +++ b/support/PORTING @@ -0,0 +1,22 @@ +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 <sys/wait.h> 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 new file mode 100644 index 0000000..bd36b7e --- /dev/null +++ b/support/SYMLINKS @@ -0,0 +1,23 @@ +# +# symlink map for bash source tree +# +# 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/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 +# +posixstat.h lib/posixheaders/posixstat.h +ansi_stdlib.h lib/posixheaders/ansi_stdlib.h +stdc.h lib/posixheaders/stdc.h +memalloc.h lib/posixheaders/memalloc.h +filecntl.h lib/posixheaders/filecntl.h diff --git a/support/bash.xbm b/support/bash.xbm new file mode 100644 index 0000000..5c32613 --- /dev/null +++ b/support/bash.xbm @@ -0,0 +1,59 @@ +From: Simon Marshall <sm2@sequent.cc.hull.ac.uk> +Date: Wed, 8 May 91 17:15:58 +0100 +To: bug-bash@ai.mit.edu +Subject: X bitmap for bash + + Since other GNU software comes with its very own X bitmap, I + thought it was about time bash had one too & here it is! To use, + stick the stuff after my signature in a file <path>/bash.xbm. If + using a twm window manager, insert the lines: + +IconDirectory "<path>" +Icons { + "<xterm title>" "bash.xbm" +} + in your ~/.twmrc file. The <xterm title> can be a prefix, so if + you have titles "bash@machine", the prefix "bash" will do. I'm not + familiar enough with other window managers, but they should be + similar. + + If you like it, you're welcome to it... + + Simon. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#define bash_width 64 +#define bash_height 48 +static char bash_bits[] = { + 0x00, 0x60, 0x06, 0x30, 0x04, 0x00, 0x00, 0x00, 0x60, 0x98, 0x01, 0x40, + 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0xa0, 0x80, 0x80, 0xff, 0x00, 0x00, + 0x06, 0x00, 0x1c, 0x03, 0xe1, 0x5f, 0x03, 0x00, 0x02, 0x00, 0x22, 0x0c, + 0x5d, 0xf4, 0x0e, 0x00, 0xe1, 0x02, 0x09, 0x19, 0x17, 0x91, 0x3d, 0x00, + 0xf8, 0x87, 0x40, 0x90, 0x88, 0x88, 0x6e, 0x00, 0x8e, 0x9b, 0x04, 0x62, + 0x22, 0x22, 0xd6, 0x00, 0x02, 0xee, 0x4c, 0x68, 0x44, 0x44, 0x6c, 0x01, + 0x02, 0xf8, 0xa1, 0x4a, 0x11, 0x11, 0xb1, 0x02, 0x05, 0xa0, 0x22, 0xe0, + 0x88, 0x88, 0x68, 0x03, 0x42, 0x50, 0x5d, 0x40, 0x22, 0x22, 0xa2, 0x05, + 0x11, 0x81, 0x00, 0x44, 0x44, 0x44, 0x44, 0x07, 0x02, 0x20, 0x84, 0x60, + 0x11, 0x11, 0xd1, 0x0d, 0x02, 0x0a, 0x02, 0xc0, 0x88, 0x88, 0x48, 0x0b, + 0x44, 0x40, 0x00, 0x42, 0x22, 0x22, 0xa2, 0x1d, 0x24, 0x08, 0x02, 0x64, + 0x44, 0x44, 0xc4, 0x1a, 0x08, 0x00, 0x20, 0x20, 0x11, 0x11, 0x91, 0x15, + 0x88, 0x00, 0x00, 0xe1, 0xff, 0xff, 0xff, 0x1a, 0x10, 0x08, 0x22, 0x10, + 0x00, 0x00, 0xc0, 0x15, 0x31, 0x40, 0x00, 0xf2, 0x03, 0xc0, 0xc1, 0x1a, + 0x41, 0x24, 0x48, 0x6c, 0x06, 0x80, 0xc1, 0x15, 0x82, 0x01, 0x00, 0x66, + 0x06, 0x80, 0xc1, 0x1a, 0x04, 0x22, 0x12, 0x67, 0x06, 0x80, 0xc1, 0x15, + 0x0a, 0x04, 0xe0, 0x66, 0xe6, 0xb8, 0xc7, 0x1a, 0x09, 0xf0, 0x17, 0xee, + 0xb3, 0xa5, 0xcf, 0x15, 0x30, 0x00, 0x00, 0x6e, 0x86, 0x8d, 0xcd, 0x1a, + 0x00, 0x01, 0x80, 0x67, 0xe6, 0xbd, 0xcd, 0x15, 0x00, 0x46, 0x40, 0x66, + 0xb6, 0xb1, 0xcd, 0x1a, 0x00, 0x38, 0x3c, 0x66, 0xb6, 0xa5, 0xcd, 0x15, + 0x00, 0x00, 0x02, 0xf6, 0xe3, 0x9d, 0xdd, 0x1a, 0x00, 0x04, 0x60, 0x06, + 0x00, 0x00, 0xc0, 0x15, 0x00, 0x04, 0x40, 0xfe, 0xff, 0xff, 0xff, 0x1a, + 0x00, 0x02, 0x80, 0x12, 0x11, 0x11, 0x91, 0x15, 0x00, 0x00, 0x00, 0x8a, + 0x88, 0x88, 0x88, 0x1a, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0xa2, 0x15, + 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0xc4, 0x9a, 0x00, 0x00, 0x00, 0x12, + 0x11, 0x11, 0x91, 0xb5, 0x00, 0x00, 0x10, 0x8a, 0x88, 0x88, 0x88, 0xba, + 0x00, 0x00, 0x10, 0x22, 0x22, 0x22, 0xa2, 0xd5, 0x00, 0x00, 0x30, 0xc6, + 0x44, 0x44, 0xcc, 0xdf, 0x00, 0x20, 0x39, 0x96, 0x15, 0x51, 0x99, 0xf5, + 0x80, 0xf2, 0x56, 0x8b, 0x9a, 0xea, 0x9b, 0xff, 0xc1, 0xad, 0x5e, 0xaf, + 0xbb, 0xfa, 0xba, 0xdf, 0x22, 0x9b, 0xae, 0xd7, 0x54, 0x5d, 0xd7, 0xbf, + 0x3b, 0x32, 0xce, 0xff, 0xff, 0xff, 0xff, 0xab, 0xae, 0x2b, 0x59, 0xaf, + 0xd4, 0xae, 0x2e, 0xc3, 0xdd, 0x43, 0xa9, 0xd1, 0xba, 0xae, 0x2c, 0xcd}; diff --git a/support/bashbug.sh b/support/bashbug.sh new file mode 100644 index 0000000..fb5600b --- /dev/null +++ b/support/bashbug.sh @@ -0,0 +1,84 @@ +#!/bin/sh - +# +# bashbug - create a bug report and mail it 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 +export PATH + +TEMP=/tmp/bashbug.$$ + +BUGADDR=${1-bug-bash@prep.ai.mit.edu} + +: ${EDITOR=emacs} + +trap 'rm -f $TEMP $TEMP.x; exit 1' 1 2 3 13 15 +trap 'rm -f $TEMP $TEMP.x' 0 + +UN= +if (uname) >/dev/null 2>&1; then + UN=`uname -a` +fi + +if [ -f /usr/lib/sendmail ] ; then + RMAIL="/usr/lib/sendmail" +elif [ -f /usr/sbin/sendmail ] ; then + RMAIL="/usr/sbin/sendmail" +else + RMAIL=rmail +fi + +cat > $TEMP <<EOF +From: ${USER} +To: ${BUGADDR} +Subject: [50 character or so descriptive subject here (for reference)] + +Configuration Information [Automatically generated, do not change]: +Machine: $MACHINE +OS: $OS +Compiler: $CC +Compilation CFLAGS: $CFLAGS +uname output: $UN + +Bash Version: $RELEASE +Patch Level: $PATCHLEVEL + +Description: + [Detailed description of the problem, suggestion, or complaint.] + +Repeat-By: + [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.] +EOF + +chmod u+w $TEMP +cp $TEMP $TEMP.x + +if $EDITOR $TEMP +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 + } +fi + +exit 0 diff --git a/support/cat-s b/support/cat-s new file mode 100644 index 0000000..87ba163 --- /dev/null +++ b/support/cat-s @@ -0,0 +1,16 @@ +# 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 new file mode 100755 index 0000000..89e0752 --- /dev/null +++ b/support/clone-bash @@ -0,0 +1,95 @@ +#! /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/cppmagic b/support/cppmagic new file mode 100755 index 0000000..b0a951c --- /dev/null +++ b/support/cppmagic @@ -0,0 +1,51 @@ +#!/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 new file mode 100755 index 0000000..b82ca4d --- /dev/null +++ b/support/fixlinks @@ -0,0 +1,61 @@ +#! /bin/sh +# +# fixlinks - make symlinks in the bash source tree so that there is +# exactly one version of any given source file. +# +# + +SRCDIR=. +while [ $# -gt 0 ]; do + case "$1" in + -s) shift; SRCDIR=$1 ;; + -u) unfix=yes ;; + -*) echo "$0: $1: bad option" 1>&2 + echo "$0: usage: $0 [-u] [-s srcdir] [linkmap]" 1>&2 + exit 1;; + *) break ;; + esac + shift +done + +if [ ! -d $SRCDIR/builtins ]; then + echo "$0: must be run with valid -s argument or from source directory" 1>&2 + exit 1 +fi + +if [ $# -eq 0 ]; then + linkfile=$SRCDIR/support/SYMLINKS +else + linkfile=$1 +fi + +if [ ! -f "$linkfile" ]; then + echo "$0: symlink map file \`$linkfile' does not exist" + exit 1 +fi + +rm -f /tmp/z +if (ln -s /dev/null /tmp/z) >/dev/null 2>&1; then + LN="ln -s" +else + LN=ln +fi + +while read name target +do + case "$name" in + \#*) continue;; + esac + + rm -f $name + case "$unfix" in + yes) dirname=`expr "$name" ':' '^\(.*\)/[^/]*'` + [ -z "$dirname" ] && dirname=. + cp $dirname/$target $name + echo $target copied to $name ;; + *) $LN $target $name ; echo "$name -> $target" ;; + esac + +done < $linkfile + +exit 0 diff --git a/support/getcppsyms.c b/support/getcppsyms.c new file mode 100644 index 0000000..eb4c72d --- /dev/null +++ b/support/getcppsyms.c @@ -0,0 +1,428 @@ +/* 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 <stdio.h> +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/inpath b/support/inpath new file mode 100755 index 0000000..95f28bc --- /dev/null +++ b/support/inpath @@ -0,0 +1,19 @@ +#! /bin/sh +# +# Search $PATH for a file the same name as $1; return TRUE if found. +# + +command=$1 +[ -n "$command" ] || exit 1 + +set `echo $PATH | sed 's/^:/.:/ + s/::/:.:/g + s/:$/:./ + s/:/ /g'` + +while [ $# -ne 0 ] ; do + [ -f $1/$command ] && exit 0 # test -x not universal + shift +done + +exit 1 diff --git a/support/install.sh b/support/install.sh new file mode 100755 index 0000000..ea88212 --- /dev/null +++ b/support/install.sh @@ -0,0 +1,235 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/support/mkdirs b/support/mkdirs new file mode 100755 index 0000000..52228d1 --- /dev/null +++ b/support/mkdirs @@ -0,0 +1,29 @@ +#! /bin/sh +# +# mkdirs - a work-alike for `mkdir -p' +# +# Chet Ramey +# chet@po.cwru.edu + +for dir +do + + [ -d "$dir" ] && continue + + tomake=$dir + while [ "$dir" ]; do + # dir=${dir%/*} + # dir=`expr "$dir" ':' '^\(/.*\)/[^/]*'` + dir=`expr "$dir" ':' '^\(.*\)/[^/]*'` + tomake="$dir $tomake" + done + + for d in $tomake + do + [ -d $d ] && continue + echo mkdir $d + mkdir $d + done +done + +exit 0 diff --git a/support/mklinks b/support/mklinks new file mode 100755 index 0000000..612aa99 --- /dev/null +++ b/support/mklinks @@ -0,0 +1,41 @@ + +# 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 new file mode 100755 index 0000000..00b7403 --- /dev/null +++ b/support/mkmachtype @@ -0,0 +1,279 @@ +#!/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 <unistd.h> + 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 <<EOF +main() +{ +#if defined (sony) +#if defined (MIPSEB) +#else + printf("m68k-sony-newsos\n"); exit(0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf("arm-acorn-riscix"); exit (0); +#endif + +#if defined(hp300) && !defined(hpux) + printf("m68k-hp-bsd\n"); exit(0); +#endif + +#if defined(NeXT) + printf("m68k-next-bsd\n"); 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__) || (defined(__bsdi__) && defined(__i386__)) + 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_) + printf("i386-sequent-ptx\n"); exit(0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/support/mksysdefs b/support/mksysdefs new file mode 100755 index 0000000..37b188e --- /dev/null +++ b/support/mksysdefs @@ -0,0 +1,497 @@ +#!/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/support/printenv b/support/printenv new file mode 100755 index 0000000..8aebd43 --- /dev/null +++ b/support/printenv @@ -0,0 +1,11 @@ +#! /bin/sh - + +if [ $# -eq 0 ]; then + env + exit +elif eval [ "\${$1-unset}" = "unset" ]; then + exit 1 +else + eval echo \$$1 + exit 0 +fi diff --git a/support/recho.c b/support/recho.c new file mode 100644 index 0000000..b9dc00b --- /dev/null +++ b/support/recho.c @@ -0,0 +1,32 @@ +#include <stdio.h> + +main(argc, argv) +int argc; +char **argv; +{ + register int i; + + for (i = 1; i < argc; i++) { + printf("argv[%d] = <", i); + strprint(argv[i]); + printf(">\n"); + } +} + +strprint(str) +char *str; +{ + register char *s; + int c; + + for (s = str; s && *s; s++) { + if (*s < ' ') { + putchar('^'); + putchar(*s+64); + } else if (*s == 127) { + putchar('^'); + putchar('?'); + } else + putchar(*s); + } +} diff --git a/support/srcdir b/support/srcdir new file mode 100755 index 0000000..9d8ccd7 --- /dev/null +++ b/support/srcdir @@ -0,0 +1,13 @@ +#! /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 new file mode 100755 index 0000000..12281e5 --- /dev/null +++ b/support/texi2dvi @@ -0,0 +1,263 @@ +#!/bin/sh +# texi2dvi -- smartly produce DVI files from texinfo sources +# +# Copyright (C) 1992, 1993 Free Software Foundation. +# +# 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, 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. +# +# 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 +# + +# 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. +# +# 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` + +usage="Usage: ${progname} {-D} {-h} [file1] {file2} {...} + {--debug} {--help} + + Options in braces are optional. Those in brackets are required. +" + +if test $# -eq 0 ; then + echo "${usage}" 1>&2; + exit 1 +fi + +backup_extension=".bak" +texindex="texindex" +tex="tex" +bq="\`" # To prevent hairy quoting and escaping later. +eq="'" +orig_pwd="`pwd`" + +if test "z${TEXINDEX}" != "z" ; then + texindex="${TEXINDEX}" +fi + +if test "z${TEX}" != "z" ; then + tex="${TEX}" +fi + +# Save this so we can construct a new TEXINPUTS path for each file to be +# processed. +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 + ;; + 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 + +test "z${debug}" = "zt" && set -x + +# Texify files +for command_line_filename in ${1+"$@"} ; do + # Roughly equivalent to `dirname ...`, but more portable + directory="`echo ${command_line_filename} | sed 's/\/[^\/]*$//'`" + filename_texi="`basename ${command_line_filename}`" + # Strip off the last extension part (probably .texinfo or .texi) + filename_noext="`echo ${filename_texi} | sed 's/\.[^.]*$//'`" + + # If directory and file are the same, then it's probably because there's + # no pathname component. Set dirname to `.', the current directory. + if test "z${directory}" = "z${command_line_filename}" ; then + directory="." + fi + + # 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 `.'. + TEXINPUTS=".:${directory}:${TEXINPUTS_orig}" + + # "Unset" variables that might have values from previous iterations and + # which won't be completely reset later. + definite_index_files="" + + # See if file exists here. If it doesn't we're in trouble since, even + # though the user may be able to reenter a valid filename at the tex + # prompt (assuming they're attending the terminal), this script won't be + # 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; + fi + + # Find all files having root filename with a two-letter extension, + # determine whether they're really index files, and save them. Foo.aux + # is actually the cross-references file, but we need to keep track of + # 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 test ! -s "${this_file}" ; then + continue; + fi + + # Examine first character of file. If it's not a backslash or + # single quote, then it's definitely not an index or xref file. + first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`" + if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then + definite_index_files="${definite_index_files} ${this_file}" + fi + done + orig_index_files="${definite_index_files}" + orig_index_files_sans_aux="`echo ${definite_index_files} \ + | sed 's/'${filename_noext}'\.aux//; + s/^[ ]*//;s/[ ]*$//;'`" + + # Now save copies of original index files so we have some means of + # comparison later. + for index_file_to_save in ${orig_index_files} ; do + cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}" + done + + # Run texindex on current index files. If they already exist, and + # after running TeX a first time the index files don't change, then + # there's no reason to run TeX again. But we won't know that if the + # index files are out of date or nonexistent. + if test "${orig_index_files_sans_aux}" ; then + ${texindex} ${orig_index_files_sans_aux} + fi + + if ${tex} ${command_line_filename} ; then # TeX run first time + definite_index_files="" + # Get list of new index files + 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 test ! -s ${this_file} ; then + continue; + fi + + # Examine first character of file. If it's not a backslash or + # single quote, then it's definitely not an index or xref file. + first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`" + if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then + definite_index_files="${definite_index_files} ${this_file}" + fi + done + new_index_files="${definite_index_files}" + new_index_files_sans_aux="`echo ${definite_index_files} \ + | sed 's/'${filename_noext}'\.aux//; + s/^[ ]*//;s/[ ]*$//;'`" + + # If old and new list don't at least have the same file list, then one + # 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. + index_files_changed_p="" + for this_file in ${new_index_files} ; do + # 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. + index_files_changed_p=t + break + fi + done + fi + + # If index files have changed since TeX has been run, or if the aux + # file wasn't present originally, run texindex and TeX again. + if test "${index_files_changed_p}" ; then + retval=0 + if test "${new_index_files_sans_aux}" ; then + ${texindex} ${new_index_files_sans_aux} + retval=$? + fi + if test ${retval} -eq 0 ; then + ${tex} "${command_line_filename}" + fi + fi + fi + + # Generate list of files to delete, then call rm once with the entire + # 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}" + done + if test "${file_list}" ; then + rm -f ${file_list} + fi +done + +# +# eof +# @@ -0,0 +1,1132 @@ +/* GNU test program (ksb and mjb) */ + +/* Modified to run with the GNU shell Apr 25, 1988 by bfox. */ + +/* Copyright (C) 1987, 1988, 1989, 1990, 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 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. */ + +/* Define STANDALONE to get the /bin/test version. Otherwise, you get + the shell builtin version. */ +/* #define STANDALONE */ + +#include <stdio.h> +#include "bashtypes.h" + +#if !defined (STANDALONE) +# if !defined (_POSIX_VERSION) +# include <sys/file.h> +# endif /* !_POSIX_VERSION */ +# include "posixstat.h" +# include "filecntl.h" +# include "shell.h" +#else /* STANDALONE */ +# include "system.h" +# if !defined (S_IXUGO) +# define S_IXUGO 0111 +# endif +# if defined (HAVE_UNISTD_H) +# include <unistd.h> +# endif /* HAVE_UNISTD_H */ +# define whitespace(c) (((c) == ' ') || ((c) == '\t')) +# define digit(c) ((c) >= '0' && (c) <= '9') +# define digit_value(c) ((c) - '0') +#endif /* STANDALONE */ + +#if !defined (STRLEN) +# define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) +#endif + +#include <errno.h> +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#if !defined (STREQ) +# define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0) +#endif /* !STREQ */ + +#if !defined (member) +# define member(c, s) (int)((c) ? (char *)strchr ((s), (c)) : 0) +#endif /* !member */ + +/* Make gid_t and uid_t mean something for non-posix systems. */ +#if !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 */ + +#if !defined (R_OK) +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 +#endif /* R_OK */ + +/* 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). */ +#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; +# define test_exit(val) \ + do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) +#endif /* STANDALONE */ + +#if defined (AFS) + /* We have to use access(2) for machines running AFS, because it's + not a Unix file system. This may produce incorrect answers for + non-AFS files. I hate AFS. */ +# define EACCESS(path, mode) access(path, mode) +#else +# define EACCESS(path, mode) eaccess(path, mode) +#endif /* AFS */ + +static int pos; /* The offset of the current argument in ARGV. */ +static int argc; /* The number of arguments present in ARGV. */ +static char **argv; /* The argument list. */ +static int noeval; + +static int isint (); +static int unop (); +static int binop (); +static int unary_operator (); +static int binary_operator (); +static int two_arguments (); +static int three_arguments (); +static int posixtest (); + +static int expr (); +static int term (); +static int and (); +static int or (); + +static void +test_syntax_error (format, arg) + char *format, *arg; +{ +#if !defined (STANDALONE) + extern int interactive_shell; + extern char *get_name_for_error (); + if (!interactive_shell) + fprintf (stderr, "%s: ", get_name_for_error ()); +#endif + fprintf (stderr, "%s: ", argv[0]); + fprintf (stderr, format, arg); + fflush (stderr); + test_exit (SHELL_BOOLEAN (FALSE)); +} + +/* A wrapper for stat () which disallows pathnames that are empty strings + and handles /dev/fd emulation on systems that don't have it. */ +static int +test_stat (path, finfo) + char *path; + struct stat *finfo; +{ + if (*path == '\0') + { + errno = ENOENT; + return (-1); + } +#if !defined (HAVE_DEV_FD) + if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0) + { + int fd; + if (isint (path + 8, &fd)) + return (fstat (fd, finfo)); + else + { + errno = EBADF; + return (-1); + } + } +#endif /* !HAVE_DEV_FD */ + return (stat (path, finfo)); +} + +/* Do the same thing access(2) does, but use the effective uid and gid, + and don't make the mistake of telling root that any file is + executable. */ +static int +eaccess (path, mode) + char *path; + int mode; +{ + struct stat st; + static int euid = -1; + + if (test_stat (path, &st) < 0) + return (-1); + + if (euid == -1) +#if defined (SHELL) + euid = current_user.euid; +#else + euid = geteuid (); +#endif + + if (euid == 0) + { + /* Root can read or write any file. */ + if (mode != X_OK) + return (0); + + /* Root can execute any file that has any one of the execute + bits set. */ + if (st.st_mode & S_IXUGO) + return (0); + } + + if (st.st_uid == euid) /* owner */ + mode <<= 6; + else if (group_member (st.st_gid)) + mode <<= 3; + + if (st.st_mode & mode) + return (0); + + return (-1); +} + +#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; +#endif /* HAVE_GETGROUPS */ + +#if !defined (NOGROUP) +# define NOGROUP (GID_T) -1 +#endif + +/* Return non-zero if GID is one that we have in our groups list. */ +int +group_member (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 */ + + 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) + { + 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); + } + + /* In case of error, the user loses. */ + 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); + } +#endif /* HAVE_GETGROUPS */ + + return (0); +} + +/* 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 +beyond () +{ + test_syntax_error ("argument expected\n", (char *)NULL); +} + +/* Syntax error for when an integer argument was expected, but + something else was found. */ +static void +integer_expected_error (pch) + char *pch; +{ + test_syntax_error ("integer expression expected %s\n", pch); +} + +/* 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. */ +static int +isint (string, result) + register 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) + { + value *= sign; + *result = value; + } + + 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); +} + +/* + * 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 ] + * '-'('z'|'n') string + * string + * string ('!='|'=') string + * <int> '-'(eq|ne|le|lt|ge|gt) <int> + * file '-'(nt|ot|ef) file + * '(' <expr> ')' + * int ::= + * '-l' string + * positive and negative integers + */ +static int +term () +{ + int value; + + if (pos >= argc) + beyond (); + + /* Deal with leading "not"'s. */ + if ('!' == argv[pos][0] && '\000' == argv[pos][1]) + { + value = FALSE; + while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) + { + advance (1); + value ^= (TRUE); + } + + return (value ^ (term ())); + } + + /* A paren-bracketed argument. */ + if (argv[pos][0] == '(' && !argv[pos][1]) + { + advance (1); + value = expr (); + if (argv[pos] == 0) + test_syntax_error ("`)' expected\n"); + else if (argv[pos][0] != ')' || argv[pos][1]) + test_syntax_error ("`)' expected, found %s\n", argv[pos]); + advance (0); + return (TRUE == (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])))) + value = binary_operator (); + + /* Might be a switch type argument */ + else if ('-' == argv[pos][0] && 0 == argv[pos][2]) + { + if (unop (argv[pos][1])) + value = unary_operator (); + else + test_syntax_error ("%s: unary operator expected\n", argv[pos]); + } + else + { + value = (argv[pos][0] != '\0'); + advance (0); + } + + return (value); +} + +static int +binary_operator () +{ + 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; + + if (argv[pos][0] == '-' && argv[pos][1] == 'l' && !argv[pos][2]) + { + l_is_l = 1; + op = pos + 2; + + /* 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]); + + advance (0); + } + else + { + l_is_l = 0; + op = pos + 1; + } + + if ((op < argc - 2) && + (argv[op + 1][0] == '-' && argv[op + 1][1] == 'l' && !argv[op + 1][2])) + { + r_is_l = 1; + advance (0); + } + else + r_is_l = 0; + + if (argv[op][0] == '-') + { + /* check for eq, nt, and stuff */ + switch (argv[op][1]) + { + 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; + } + test_syntax_error ("%s: unknown binary operator", argv[op]); + } + + if (argv[op][0] == '=' && !argv[op][1]) + { + value = (argv[pos][0] == argv[pos+2][0]) && + (strcmp (argv[pos], argv[pos + 2]) == 0); + pos += 3; + return (TRUE == value); + } + + if (argv[op][0] == '!' && argv[op][1] == '=' && !argv[op][2]) + { + value = (argv[pos][0] != argv[pos + 2][0]) || + (strcmp (argv[pos], argv[pos + 2]) != 0); + pos += 3; + return (TRUE == value); + } + return (FALSE); +} + +static int +unary_operator () +{ + long r, value; + struct stat stat_buf; + + switch (argv[pos][1]) + { + default: + return (FALSE); + + /* All of the following unary operators use unary_advance (), which + checks to make sure that there is an argument, and then advances + pos right past it. This means that pos - 1 is the location of the + argument. */ + + case 'a': /* file exists in the file system? */ + case 'e': + unary_advance (); + value = -1 != test_stat (argv[pos - 1], &stat_buf); + return (TRUE == value); + + case 'r': /* file is readable? */ + unary_advance (); + value = -1 != EACCESS (argv[pos - 1], R_OK); + return (TRUE == value); + + case 'w': /* File is writeable? */ + unary_advance (); + value = -1 != EACCESS (argv[pos - 1], W_OK); + return (TRUE == value); + + case 'x': /* File is executable? */ + unary_advance (); + value = -1 != EACCESS (argv[pos - 1], X_OK); + return (TRUE == value); + + 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 */ + + 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)); + + 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. */ +#if defined (S_IFMT) + return (TRUE == ((S_ISREG (stat_buf.st_mode)) || + (0 == (stat_buf.st_mode & S_IFMT)))); +#else + return (TRUE == (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))); + + 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)); + + 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 */ + + 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))); + + 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))); + + 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 */ + + case 'L': /* Same as -h */ + /*FALLTHROUGH*/ + + case 'h': /* File is a symbolic link? */ + unary_advance (); +#ifndef S_ISLNK + 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 */ + + 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))); + + 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))); + + 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))); +#endif + + 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 (TRUE == (isatty (1))); + + case 'n': /* True if arg has some length. */ + unary_advance (); + return (TRUE == (argv[pos - 1][0] != 0)); + + case 'z': /* True if arg has no length. */ + unary_advance (); + return (TRUE == (argv[pos - 1][0] == '\0')); + } +} + +/* + * and: + * term + * term '-a' and + */ +static int +and () +{ + int value; + + value = term (); + while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) + { + advance (0); + value = TRUTH_AND (value, and ()); + } + return (TRUE == value); +} + +/* + * or: + * and + * and '-o' or + */ +static int +or () +{ + int value; + + value = and (); + + while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) + { + advance (0); + value = TRUTH_OR (value, or ()); + } + + return (TRUE == value); +} + +/* + * expr: + * or + */ +static int +expr () +{ + if (pos >= argc) + beyond (); + + return (FALSE ^ (or ())); /* Same with this. */ +} + +/* Return TRUE if S is one of the test command's binary operators. */ +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"))); +} + +/* Return non-zero if OP is one of the test command's unary operators. */ +static int +unop (op) + int op; +{ + return (member (op, "abcdefgkLhprsStuwxOGnz")); +} + +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 (unop (argv[pos][1])) + value = unary_operator (); + else + test_syntax_error ("%s: unary operator expected\n", argv[pos]); + } + else + test_syntax_error ("%s: unary operator expected\n", argv[pos]); + + return (value); +} + +static int +three_arguments () +{ + int value; + + if (argv[pos][0] == '!' && !argv[pos][1]) + { + advance (1); + value = !two_arguments (); + } + else if (binop (argv[pos+1])) + { + value = binary_operator (); + 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]); + return (value); +} + +/* This is an implementation of a Posix.2 proposal by David Korn. */ +static int +posixtest () +{ + int value; + + switch (argc - 1) /* one extra passed in */ + { + case 0: + value = FALSE; + pos = argc; + break; + + case 1: + value = argv[1][0] != '\0'; + pos = argc; + break; + + case 2: + value = two_arguments (); + pos = argc; + break; + + case 3: + value = three_arguments (); + break; + + case 4: + if (STREQ (argv[pos], "!")) + { + advance (1); + value = !three_arguments (); + break; + } + /* FALLTHROUGH */ + case 5: + default: + value = expr (); + } + + return (value); +} + +/* + * [: + * '[' expr ']' + * test: + * test expr + */ +int +#if defined (STANDALONE) +main (margc, margv) +#else +test_command (margc, margv) +#endif /* STANDALONE */ + int margc; + char **margv; +{ + int value; + +#if !defined (STANDALONE) + int code; + + code = setjmp (test_exit_buf); + + if (code) + return (test_error_return); +#endif /* STANDALONE */ + + argv = margv; + + if (margv[0] && margv[0][0] == '[' && !margv[0][1]) + { + --margc; + + if (margc < 2) + test_exit (SHELL_BOOLEAN (FALSE)); + + if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1])) + test_syntax_error ("missing `]'\n", (char *)NULL); + } + + argc = margc; + pos = 1; + + if (pos >= argc) + test_exit (SHELL_BOOLEAN (FALSE)); + + noeval = 0; + value = posixtest (); + + if (pos != argc) + test_syntax_error ("too many arguments\n", (char *)NULL); + + test_exit (SHELL_BOOLEAN (value)); +} diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..a1a081b --- /dev/null +++ b/tests/README @@ -0,0 +1 @@ +Type `sh run-all'. diff --git a/tests/dollar-at.sh b/tests/dollar-at.sh new file mode 100755 index 0000000..c3004d5 --- /dev/null +++ b/tests/dollar-at.sh @@ -0,0 +1 @@ +recho "$@" diff --git a/tests/dollar-star.sh b/tests/dollar-star.sh new file mode 100755 index 0000000..982f04c --- /dev/null +++ b/tests/dollar-star.sh @@ -0,0 +1 @@ +recho "$*" diff --git a/tests/dollar.right b/tests/dollar.right new file mode 100644 index 0000000..4d9b746 --- /dev/null +++ b/tests/dollar.right @@ -0,0 +1,3 @@ +argv[1] = <a b> +argv[1] = <a> +argv[2] = <b> diff --git a/tests/exp-tests b/tests/exp-tests new file mode 100644 index 0000000..d45b702 --- /dev/null +++ b/tests/exp-tests @@ -0,0 +1,326 @@ +# +# A suite of tests for bash word expansions +# +# This tests parameter and variable expansion, with an empahsis on +# proper quoting behavior. +# +# Chet Ramey + +# +# If you comment out the body of this function, you can do a diff against +# `expansion-tests.right' to see if the shell is behaving correctly +# +expect() +{ + echo expect "$@" +} + +# Test the substitution quoting characters (CTLESC and CTLNUL) in different +# combinations + +expect "<^A>" +recho `echo ''` +expect "<^A>" +recho `echo ""` +expect "<^B>" +recho `echo ''` +expect "<^B>" +recho `echo ""` +expect "<^A>" +recho `echo ` +expect "<^B>" +recho `echo ` + +# Test null strings without variable expansion +expect "<abcdefgh>" +recho abcd""efgh +expect "<abcdefgh>" +recho abcd''efgh +expect "<abcdefgh>" +recho ""abcdefgh +expect "<abcdefgh>" +recho ''abcdefgh +expect "<abcd>" +recho abcd"" +expect "<abcd>" +recho abcd'' + +# Test the quirky behavior of $@ in "" +expect nothing +recho "$@" +expect "< >" +recho " $@" +expect "<-->" +recho "-${@}-" + +# Test null strings with variable expansion that fails +expect '<>' +recho $xxx"" +expect '<>' +recho ""$xxx +expect '<>' +recho $xxx'' +expect '<>' +recho ''$xxx +expect '<>' +recho $xxx""$yyy +expect '<>' +recho $xxx''$yyy + +# Test null strings with variable expansion that succeeds +xxx=abc +yyy=def + +expect '<abc>' +recho $xxx"" +expect '<abc>' +recho ""$xxx +expect '<abc>' +recho $xxx'' +expect '<abc>' +recho ''$xxx +expect '<abcdef>' +recho $xxx""$yyy +expect '<abcdef>' +recho $xxx''$yyy + +unset xxx yyy + +# Test the unquoted special quoting characters +expect "<^A>" +recho +expect "<^B>" +recho +expect "<^A>" +recho "" +expect "<^B>" +recho "" +expect "<^A>" +recho '' +expect "<^B>" +recho '' + +# Test expansion of a variable that is unset +expect nothing +recho $xxx +expect '<>' +recho "$xxx" + +expect nothing +recho "$xxx${@}" + +# Test empty string expansion +expect '<>' +recho "" +expect '<>' +recho '' + +# Test command substitution with (disabled) history substitution +expect '<Hello World!>' +# set +H +recho "`echo \"Hello world!\"`" + +# Test some shell special characters +expect '<`>' +recho "\`" +expect '<">' +recho "\"" +expect '<\^A>' +recho "\" + +expect '<\$>' +recho "\\$" + +expect '<\\>' +recho "\\\\" + +# This should give argv[1] = a argv[2] = b +expect '<a> <b>' +FOO=`echo 'a b' | tr ' ' '\012'` +recho $FOO + +# This should give argv[1] = ^A argv[2] = ^B +expect '<^A> <^B>' +FOO=`echo ' ' | tr ' ' '\012'` +recho $FOO + +# Test quoted and unquoted globbing characters +expect '<**>' +recho "*"* + +expect '<\.\./*/>' +recho "\.\./*/" + +# Test patterns that come up when the shell quotes funny character +# combinations +expect '<^A^B^A^B>' +recho '' +expect '<^A^A>' +recho '' +expect '<^A^B>' +recho '' +expect '<^A^A^B>' +recho '' + +# More tests of "$@" +expect '< abc> <def> <ghi> <jkl >' +set abc def ghi jkl +recho " $@ " + +expect '<--abc> <def> <ghi> <jkl-->' +set abc def ghi jkl +recho "--$@--" + +expect '< >' +recho " " +expect '< - >' +recho " - " + +# Test combinations of different types of quoting in a fully-quoted string +# (so the WHOLLY_QUOTED tests fail and it doesn't get set) +expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>' +recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" + +# Test the various Posix parameter expansions + +expect '<foo bar>' +recho "${x:-$(echo "foo bar")}" +expect '<foo> <bar>' +recho ${x:-$(echo "foo bar")} + +unset X +expect '<abc>' +recho ${X:=abc} +expect '<abc>' +recho $X + +set a b c +expect '<posix>' +recho ${3:+posix} + +POSIX=/usr/posix +expect '<10>' +recho ${#POSIX} + +# remove shortest trailing match +x=file.c +expect '<file.o>' +recho ${x%.c}.o + +# remove longest trailing match +x=posix/src/std +expect '<posix>' +recho ${x%%/*} + +# remove shortest leading pattern +x=$HOME/src/cmd +expect '</src/cmd>' +recho ${x#$HOME} + +# remove longest leading pattern +x=/one/two/three +expect '<three>' +recho ${x##*/} + +# Command substitution and the quirky differences between `` and $() + +expect '<\$x>' +recho '\$x' + +expect '<$x>' +recho `echo '\$x'` + +expect '<\$x>' +recho $(echo '\$x') + +# The difference between $* "$*" and "$@" + +set "abc" "def ghi" "jkl" + +expect '<abc> <def> <ghi> <jkl>' +recho $* + +expect '<abc def ghi jkl>' +recho "$*" + +OIFS="$IFS" +IFS=":$IFS" + +# The special behavior of "$*", using the first character of $IFS as separator +expect '<abc:def ghi:jkl>' +recho "$*" + +IFS="$OIFS" + +expect '<abc> <def ghi> <jkl>' +recho "$@" + +expect '<xxabc> <def ghi> <jklyy>' +recho "xx$@yy" + +expect '<abc> <def ghi> <jklabc> <def ghi> <jkl>' +recho "$@$@" + +foo=abc +bar=def + +expect '<abcdef>' +recho "$foo""$bar" + +unset foo +set $foo bar '' xyz "$foo" abc + +expect '<bar> <> <xyz> <> <abc>' +recho "$@" + +# More tests of quoting and deferred evaluation + +foo=10 x=foo +y='$'$x +expect '<$foo>' +recho $y +eval y='$'$x +expect '<10>' +recho $y + +# case statements + +NL=' +' +x='ab +cd' + +expect '<newline expected>' +case "$x" in +*$NL*) recho "newline expected" ;; +esac + +expect '<got it>' +case \? in +*"?"*) recho "got it" ;; +esac + +expect '<got it>' +case \? in +*\?*) recho "got it" ;; +esac + +set one two three four five +expect '<one> <three> <five>' +recho $1 $3 ${5} $8 ${9} +expect '<5> <5>' +recho $# ${#} + +expect '<42>' +recho $((28 + 14)) +expect '<26>' +recho $[ 13 * 2 ] + +expect '<\>' +recho `echo \\\\` + +expect '<~>' +recho '~' + +expect nothing +recho $! diff --git a/tests/exp.right b/tests/exp.right new file mode 100644 index 0000000..f34e88a --- /dev/null +++ b/tests/exp.right @@ -0,0 +1,113 @@ +argv[1] = <^A> +argv[1] = <^A> +argv[1] = <^B> +argv[1] = <^B> +argv[1] = <^A> +argv[1] = <^B> +argv[1] = <abcdefgh> +argv[1] = <abcdefgh> +argv[1] = <abcdefgh> +argv[1] = <abcdefgh> +argv[1] = <abcd> +argv[1] = <abcd> +argv[1] = < > +argv[1] = <--> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <abcdef> +argv[1] = <abcdef> +argv[1] = <^A> +argv[1] = <^B> +argv[1] = <^A> +argv[1] = <^B> +argv[1] = <^A> +argv[1] = <^B> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <Hello world!> +argv[1] = <`> +argv[1] = <"> +argv[1] = <\^A> +argv[1] = <\$> +argv[1] = <\\> +argv[1] = <a> +argv[2] = <b> +argv[1] = <^A> +argv[2] = <^B> +argv[1] = <**> +argv[1] = <\.\./*/> +argv[1] = <^A^B^A^B> +argv[1] = <^A^A> +argv[1] = <^A^B> +argv[1] = <^A^A^B> +argv[1] = < abc> +argv[2] = <def> +argv[3] = <ghi> +argv[4] = <jkl > +argv[1] = <--abc> +argv[2] = <def> +argv[3] = <ghi> +argv[4] = <jkl--> +argv[1] = < > +argv[1] = < - > +argv[1] = </^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/> +argv[1] = <foo bar> +argv[1] = <foo> +argv[2] = <bar> +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <posix> +argv[1] = <10> +argv[1] = <file.o> +argv[1] = <posix> +argv[1] = </src/cmd> +argv[1] = <three> +argv[1] = <\$x> +argv[1] = <$x> +argv[1] = <\$x> +argv[1] = <abc> +argv[2] = <def> +argv[3] = <ghi> +argv[4] = <jkl> +argv[1] = <abc def ghi jkl> +argv[1] = <abc:def ghi:jkl> +argv[1] = <abc> +argv[2] = <def ghi> +argv[3] = <jkl> +argv[1] = <xxabc> +argv[2] = <def ghi> +argv[3] = <jklyy> +argv[1] = <abc> +argv[2] = <def ghi> +argv[3] = <jklabc> +argv[4] = <def ghi> +argv[5] = <jkl> +argv[1] = <abcdef> +argv[1] = <bar> +argv[2] = <> +argv[3] = <xyz> +argv[4] = <> +argv[5] = <abc> +argv[1] = <$foo> +argv[1] = <10> +argv[1] = <newline expected> +argv[1] = <got it> +argv[1] = <got it> +argv[1] = <one> +argv[2] = <three> +argv[3] = <five> +argv[1] = <5> +argv[2] = <5> +argv[1] = <42> +argv[1] = <26> +argv[1] = <\> +argv[1] = <~> diff --git a/tests/glob-test b/tests/glob-test new file mode 100644 index 0000000..e8c1c70 --- /dev/null +++ b/tests/glob-test @@ -0,0 +1,179 @@ +# +# test the shell globbing +# +expect() +{ + echo expect "$@" +} + +TESTDIR=/tmp/glob-test +rm -rf $TESTDIR +mkdir $TESTDIR +builtin cd $TESTDIR + +touch a b c d abc abd abe bb bcd ca cb dd de +mkdir bdir + +# see if `regular' globbing works right +expect '<a> <abc> <abd> <abe> <X*>' +recho a* X* + +expect '<a> <abc> <abd> <abe>' +recho \a* + +# see if null glob expansion works +allow_null_glob_expansion= + +expect '<a> <abc> <abd> <abe>' +recho a* X* + +unset allow_null_glob_expansion + +# see if the code that expands directories only works +expect '<bdir/>' +recho b*/ + +# Test quoted and unquoted globbing characters +expect '<*>' +recho \* + +expect '<a*>' +recho 'a*' + +expect '<a*>' +recho a\* + +expect '<c> <ca> <cb> <a*> <*q*>' +recho c* a\* *q* + +expect '<**>' +recho "*"* + +expect '<**>' +recho \** + +expect '<\.\./*/>' +recho "\.\./*/" + +expect '<s/\..*//>' +recho 's/\..*//' + +# Pattern from Larry Wall's Configure that caused bash to blow up +expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>' +recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" + +# Make sure character classes work properly + +expect '<abc> <abd> <abe> <bb> <cb>' +recho [a-c]b* + +expect '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>' +recho [a-y]*[^c] + +expect '<abd> <abe>' +recho a*[^c] + +touch a-b aXb +expect '<a-b> <aXb>' +recho a[X-]b + +touch .x .y +expect '<d> <dd> <de>' +recho [^a-c]* + +# Make sure that filenames with embedded globbing characters are handled +# properly +mkdir a\*b +> a\*b/ooo + +expect '<a*b/ooo>' +recho a\*b/* + +expect '<a*b/ooo>' +recho a\*?/* + +expect '<no match>' +cmd='echo !7' +case "$cmd" in +*\\!*) echo match ;; +*) echo no match ;; +esac + +expect '<not there>' +file='r.*' +case $file in +*.\*) echo not there ;; +*) echo there ;; +esac + +# examples from the Posix.2 spec (d11.2, p. 243) +expect '<abc>' +recho a[b]c + +expect '<abc>' +recho a["b"]c + +expect '<abc>' +recho a[\b]c + +expect '<abc>' +recho a?c + +expect '<match>' +case abc in +a"b"c) echo match + ;; +*) echo BAD + ;; +esac + +expect '<match>' +case abc in +a*c) echo match + ;; +*) echo BAD + ;; +esac + +expect '<ok>' +case abc in +"a?c") echo bad + ;; +*) echo ok + ;; +esac + +expect '<ok>' +case abc in +a\*c) echo bad + ;; +*) echo ok + ;; +esac + +expect '<ok>' +case abc in +a\[b]c) echo bad + ;; +*) echo ok + ;; +esac + +expect '<ok>' +case "$nosuchvar" in +"") echo ok ;; +*) echo bad ;; +esac + +# This is very odd, but sh and ksh seem to agree +expect '<ok>' +case abc in +a["\b"]c) echo ok + ;; +*) echo bad + ;; +esac + +builtin cd / +rm -rf $TESTDIR +exit 0 diff --git a/tests/glob.right b/tests/glob.right new file mode 100644 index 0000000..4f2acbb --- /dev/null +++ b/tests/glob.right @@ -0,0 +1,63 @@ +argv[1] = <a> +argv[2] = <abc> +argv[3] = <abd> +argv[4] = <abe> +argv[5] = <X*> +argv[1] = <a> +argv[2] = <abc> +argv[3] = <abd> +argv[4] = <abe> +argv[1] = <a> +argv[2] = <abc> +argv[3] = <abd> +argv[4] = <abe> +argv[1] = <bdir/> +argv[1] = <*> +argv[1] = <a*> +argv[1] = <a*> +argv[1] = <c> +argv[2] = <ca> +argv[3] = <cb> +argv[4] = <a*> +argv[5] = <*q*> +argv[1] = <**> +argv[1] = <**> +argv[1] = <\.\./*/> +argv[1] = <s/\..*//> +argv[1] = </^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/> +argv[1] = <abc> +argv[2] = <abd> +argv[3] = <abe> +argv[4] = <bb> +argv[5] = <cb> +argv[1] = <abd> +argv[2] = <abe> +argv[3] = <bb> +argv[4] = <bcd> +argv[5] = <bdir> +argv[6] = <ca> +argv[7] = <cb> +argv[8] = <dd> +argv[9] = <de> +argv[1] = <abd> +argv[2] = <abe> +argv[1] = <a-b> +argv[2] = <aXb> +argv[1] = <d> +argv[2] = <dd> +argv[3] = <de> +argv[1] = <a*b/ooo> +argv[1] = <a*b/ooo> +no match +not there +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <abc> +argv[1] = <abc> +match +match +ok +ok +ok +ok +ok diff --git a/tests/ifs-test-1.sh b/tests/ifs-test-1.sh new file mode 100644 index 0000000..a153ce9 --- /dev/null +++ b/tests/ifs-test-1.sh @@ -0,0 +1,5 @@ +OIFS="$IFS" +IFS=":$IFS" +eval foo="a:b:c" +IFS="$OIFS" +echo $foo diff --git a/tests/ifs-test-2.sh b/tests/ifs-test-2.sh new file mode 100644 index 0000000..3249f1b --- /dev/null +++ b/tests/ifs-test-2.sh @@ -0,0 +1,9 @@ +OIFS=$IFS +IFS=":$IFS" +foo=$(echo a:b:c) +IFS=$OIFS + +for i in $foo +do + echo $i +done diff --git a/tests/ifs-test-3.sh b/tests/ifs-test-3.sh new file mode 100644 index 0000000..4693792 --- /dev/null +++ b/tests/ifs-test-3.sh @@ -0,0 +1,9 @@ +OIFS=$IFS +IFS=":$IFS" +foo=`echo a:b:c` +IFS=$OIFS + +for i in $foo +do + echo $i +done diff --git a/tests/ifs.1.right b/tests/ifs.1.right new file mode 100644 index 0000000..af0abb2 --- /dev/null +++ b/tests/ifs.1.right @@ -0,0 +1 @@ +a:b:c diff --git a/tests/ifs.2.right b/tests/ifs.2.right new file mode 100644 index 0000000..af0abb2 --- /dev/null +++ b/tests/ifs.2.right @@ -0,0 +1 @@ +a:b:c diff --git a/tests/ifs.3.right b/tests/ifs.3.right new file mode 100644 index 0000000..af0abb2 --- /dev/null +++ b/tests/ifs.3.right @@ -0,0 +1 @@ +a:b:c diff --git a/tests/input-line.sh b/tests/input-line.sh new file mode 100644 index 0000000..086d7e3 --- /dev/null +++ b/tests/input-line.sh @@ -0,0 +1,4 @@ +echo before calling input-line.sub +../bash ./input-line.sub +this line for input-line.sub +echo finished with input-line.sub diff --git a/tests/input-line.sub b/tests/input-line.sub new file mode 100644 index 0000000..7bc8df2 --- /dev/null +++ b/tests/input-line.sub @@ -0,0 +1,2 @@ +read line +echo line read by $0 was \`$line\' diff --git a/tests/input.right b/tests/input.right new file mode 100644 index 0000000..8733feb --- /dev/null +++ b/tests/input.right @@ -0,0 +1,3 @@ +before calling input-line.sub +line read by ./input-line.sub was `this line for input-line.sub' +finished with input-line.sub diff --git a/tests/minus-e b/tests/minus-e new file mode 100644 index 0000000..be67ec5 --- /dev/null +++ b/tests/minus-e @@ -0,0 +1,6 @@ +set -e +if set +e +then + false +fi +echo hi diff --git a/tests/minus-e.right b/tests/minus-e.right new file mode 100644 index 0000000..45b983b --- /dev/null +++ b/tests/minus-e.right @@ -0,0 +1 @@ +hi diff --git a/tests/misc/chld-trap.sh b/tests/misc/chld-trap.sh new file mode 100755 index 0000000..89b342d --- /dev/null +++ b/tests/misc/chld-trap.sh @@ -0,0 +1,14 @@ +#! /bin/sh +# +# show that setting a trap on SIGCHLD is not disastrous. +# + +trap 'echo caught a child death' SIGCHLD + +sleep 5 & +sleep 5 & +sleep 5 & + +wait + +exit 0 diff --git a/tests/misc/dot-test-1.sh b/tests/misc/dot-test-1.sh new file mode 100644 index 0000000..eab465e --- /dev/null +++ b/tests/misc/dot-test-1.sh @@ -0,0 +1,3 @@ +echo this is $0 +. ./dot-test-1.sub +echo after . dot-test-1.sub diff --git a/tests/misc/dot-test-1.sub b/tests/misc/dot-test-1.sub new file mode 100644 index 0000000..58df5f4 --- /dev/null +++ b/tests/misc/dot-test-1.sub @@ -0,0 +1 @@ +echo this is dot-test-1.sub diff --git a/tests/misc/gotest b/tests/misc/gotest new file mode 100644 index 0000000..df0a342 --- /dev/null +++ b/tests/misc/gotest @@ -0,0 +1,26 @@ +aflag= +bflag= + +while getopts ab: name +do + case $name in + a) aflag=1 ;; + b) bflag=1 + bval=$OPTARG;; + ?) echo Usage: $0 [-a] [-b value] args + exit 2;; + esac + +done + +if [ ! -z "$aflag" ] ; then echo -a specified ; fi +if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi + +if [ "$OPTIND" -gt 1 ] +then + shift $(( $OPTIND - 1 )) +fi + +echo remaining args: "$*" + +exit 0 diff --git a/tests/misc/perf-script b/tests/misc/perf-script new file mode 100644 index 0000000..e1172a9 --- /dev/null +++ b/tests/misc/perf-script @@ -0,0 +1,81 @@ +#!/bin/bash + +typeset -i m2 m1 M n2 n1 N m n +typeset -i MM=5 NN=5 + +case $# in + 0) : + ;; + 1) MM=$1; NN=$1 + ;; + 2) MM=$1; NN=$2 + ;; + *) echo 1>&2 "Usage: $0 [m [n]]" + ;; +esac + +EMPTYLINE=: # echo +echo 'a = { ' # mathematica + +let "M=1" # for (M=1; M<=MM; M++) +while let "M <= MM"; do + let "N=1" # for (N=1; N<=NN; N++) + while let "N <= NN"; do + + let "m1 = M - 1" + let "m2 = M + 1" + let "n1 = N - 1" + let "n2 = N + 1" + + + echo -n '{ ' # math + let "m=1" # for(m=1; m<=MM; m++) + while let "m <= MM"; do + let "n=1" # for(n=1; n<=NN; n++) + while let "n <= NN"; do + + let "x = (m-m1)*(m-M)*(m-m2)" + let "y = (n-n1)*(n-N)*(n-n2)" + + if let "(x*x + (n-N)*(n-N)) * ((m-M)*(m-M) + y*y)"; then + echo -n "0," + else # neighbour + echo -n "1," + fi + + let "n=n+1" + done + echo -n " "; let "m=m+1" # ". " + done + echo '},' + + + let "N=N+1" + $EMPTYLINE + done + $EMPTYLINE + let "M=M+1" +done + +echo '}' + + + +echo -n 'o = { ' +let "m=1" +while let "m <= MM"; do + let "n=1" + while let "n <= NN"; do + echo -n "1," + let "n=n+1" + done + let "m=m+1" +done +echo " }" + + +echo 'x = LinearSolve[a,o] ' + +exit 0 + + diff --git a/tests/misc/redir.t1.sh b/tests/misc/redir.t1.sh new file mode 100644 index 0000000..0ea00f9 --- /dev/null +++ b/tests/misc/redir.t1.sh @@ -0,0 +1,26 @@ +read line1 + +echo read line1 \"$line1\" + +exec 4</etc/passwd + +exec 5<&0 +exec 0<&4 + +read line2 + +echo read line2 \"$line2\" + +exec 0<&5 + +read line3 + +echo read line3 \"$line3\" + +exec 0<&4 + +read line4 + +echo read line4 \"$line4\" + +exec 4<&- diff --git a/tests/misc/redir.t2.sh b/tests/misc/redir.t2.sh new file mode 100644 index 0000000..44b2624 --- /dev/null +++ b/tests/misc/redir.t2.sh @@ -0,0 +1,17 @@ +read line1 + +echo read line 1 \"$line1\" + +exec 4<&0 + +exec 0</dev/tty + +read line2 + +echo line read from tty = \"$line2\" + +exec 0<&4 + +read line3 + +echo read line 3 \"$line3\" diff --git a/tests/misc/redir.t3.sh b/tests/misc/redir.t3.sh new file mode 100755 index 0000000..9fd42c7 --- /dev/null +++ b/tests/misc/redir.t3.sh @@ -0,0 +1,8 @@ +# +# Test the effect of input buffering on the shell's input +# +echo this is redir.t3.sh + +exec 0< redir.t3.sub + +echo after exec in redir.t3.sh diff --git a/tests/misc/redir.t3.sub b/tests/misc/redir.t3.sub new file mode 100644 index 0000000..b32fbaa --- /dev/null +++ b/tests/misc/redir.t3.sub @@ -0,0 +1 @@ +echo this is redir-test-3.sub diff --git a/tests/misc/redir.t4.sh b/tests/misc/redir.t4.sh new file mode 100644 index 0000000..861acdd --- /dev/null +++ b/tests/misc/redir.t4.sh @@ -0,0 +1,12 @@ +echo "Point 1" +exec 3</etc/passwd +exec 4>a +exec 5>b +echo "Point 2" +echo to a 1>&4 +echo to b 1>&5 +exec 11</etc/printcap +echo "Point 3" +echo to a 1>&4 +echo to b 1>&5 +exit 0 diff --git a/tests/misc/run.r1.sh b/tests/misc/run.r1.sh new file mode 100755 index 0000000..bf22fe3 --- /dev/null +++ b/tests/misc/run.r1.sh @@ -0,0 +1 @@ +../../bash redir.t1.sh diff --git a/tests/misc/run.r2.sh b/tests/misc/run.r2.sh new file mode 100755 index 0000000..3b24701 --- /dev/null +++ b/tests/misc/run.r2.sh @@ -0,0 +1 @@ +../../bash ./redir.t2.sh < /etc/passwd diff --git a/tests/misc/run.r3.sh b/tests/misc/run.r3.sh new file mode 100755 index 0000000..b413674 --- /dev/null +++ b/tests/misc/run.r3.sh @@ -0,0 +1,3 @@ +# +# the `after exec in ...' should not be echoed +../../bash < redir.t3.sh diff --git a/tests/misc/sigint.t1.sh b/tests/misc/sigint.t1.sh new file mode 100755 index 0000000..7b74c30 --- /dev/null +++ b/tests/misc/sigint.t1.sh @@ -0,0 +1,9 @@ +echo before trap +trap 'echo caught sigint' 2 +echo after trap + +for i in 1 2 3 +do + echo $i + sleep 5 +done diff --git a/tests/misc/sigint.t2.sh b/tests/misc/sigint.t2.sh new file mode 100755 index 0000000..69eaf56 --- /dev/null +++ b/tests/misc/sigint.t2.sh @@ -0,0 +1,7 @@ +echo before loop + +for i in 1 2 3 +do + echo $i + sleep 5 +done diff --git a/tests/misc/sigint.t3.sh b/tests/misc/sigint.t3.sh new file mode 100755 index 0000000..2627fe6 --- /dev/null +++ b/tests/misc/sigint.t3.sh @@ -0,0 +1,11 @@ +sleep 5 & +sleep 5 & +sleep 5 & + +echo wait 1 +wait + +echo wait 2 +wait + +exit diff --git a/tests/misc/sigint.t4.sh b/tests/misc/sigint.t4.sh new file mode 100755 index 0000000..587dd26 --- /dev/null +++ b/tests/misc/sigint.t4.sh @@ -0,0 +1,13 @@ +trap 'echo sigint' 2 + +sleep 5 & +sleep 5 & +sleep 5 & + +echo wait 1 +wait + +echo wait 2 +wait + +exit diff --git a/tests/misc/test-minus-e.1 b/tests/misc/test-minus-e.1 new file mode 100644 index 0000000..03d7ecf --- /dev/null +++ b/tests/misc/test-minus-e.1 @@ -0,0 +1,12 @@ +touch .file +while set -e ; test -r .file ; do + echo -n "stop loop? " + read reply + case "$reply" in + y*) rm .file non-dash-file ;; + esac + set +e +done + + + diff --git a/tests/misc/test-minus-e.2 b/tests/misc/test-minus-e.2 new file mode 100644 index 0000000..ad6a0c8 --- /dev/null +++ b/tests/misc/test-minus-e.2 @@ -0,0 +1,14 @@ +touch .file +set -e +while set +e ; test -r .file ; do + echo -n "stop loop? [yes to quit] " + read reply + if [ "$reply" = yes ] ; then + rm .file non-dash-file + fi + set -e +done +rm -f .file + + + diff --git a/tests/new-exp.right b/tests/new-exp.right new file mode 100644 index 0000000..07e2e9c --- /dev/null +++ b/tests/new-exp.right @@ -0,0 +1,33 @@ +argv[1] = <foo bar> +argv[1] = <foo> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +./new-exp.tests: ${HOME:`echo }`}: bad substitution +./new-exp.tests: ${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}: bad substitution +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = </usr/homes/chet> +argv[1] = <*@> +argv[1] = <@*> +argv[1] = <)> +argv[1] = <")"> +argv[1] = <-abcd> +argv[2] = <-> +argv[1] = <-abcd> +argv[2] = <-> +argv[1] = <-abcd-> +argv[1] = <a b c d e> +bar foo +bar foo +bar foo +bar foo +bar foo +./new-exp.tests: ABX: unbound variable +./new-exp.tests: $6: cannot assign in this way + +./new-exp.tests: ABXD: parameter unset diff --git a/tests/new-exp.tests b/tests/new-exp.tests new file mode 100644 index 0000000..f19ecf6 --- /dev/null +++ b/tests/new-exp.tests @@ -0,0 +1,95 @@ +expect() +{ + echo expect "$@" +} + +HOME=/usr/homes/chet # to make the check against new-exp.right work +expect '<foo bar>' +recho "${undef-"foo bar"}" # should be foo bar +expect '<foo>' +recho "${und="foo"}" # should be foo + +expect "<$HOME>" +recho ${HOME-"}"} +expect "<$HOME>" +recho "${HOME-'}'}" +expect "<$HOME>" +recho "${HOME-"}"}" + +expect $0: '${HOME:`echo }`}: bad substitution' +recho "${HOME:`echo }`}" # should be an error -- bad substitution + +expect $0: '${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}: bad substitution' +x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} # memory leak + +expect "<$HOME>" +recho ${HOME} +expect "<$HOME>" +recho ${HOME:-`echo }`} +expect "<$HOME>" +recho ${HOME:-`echo "}"`} +expect "<$HOME>" +recho "${HOME:-`echo "}"`}" +expect "<$HOME>" +recho "$(echo "${HOME}")" +expect "<$HOME>" +recho "$(echo "$(echo ${HOME})")" +expect "<$HOME>" +recho "$(echo "$(echo "${HOME}")")" + +P=*@* +expect '<*@>' +recho "${P%"*"}" # should be *@ +expect '<@*>' +recho "${P#\*}" # should be @* + +expect '<)>' +recho "$(echo ")")" # should be ) +expect '<")">' +recho "$(echo "\")\"")" # should be ")" + +foo='abcd ' +expect '<-abcd> <->' +recho -${foo}- # should be -abcd - +expect '<-abcd> <->' +recho -${foo% *}- # should be -abcd - +expect '<-abcd->' +recho -${foo%% *}- # should be -abcd- + +set a b c d e +expect '<a b c d e>' +IFS="" +recho "$@" +IFS=' +' + +foo=bar +expect '<bar foo>' +echo -n $foo' ' ; echo foo + +expect '<bar foo>' +echo -n $foo" " ; echo foo + +expect '<bar foo>' +echo -n "$foo " ; echo foo + +expect '<bar foo>' +echo -e "$foo\c " ; echo foo + +expect '<bar foo>' +echo -e $foo"\c " ; echo foo + +set -u +expect $0: ABX: unbound variable +recho ${ABX} +set +u + +expect $0: '$6: cannot assign in this way' +recho ${6="arg6"} + +expect a newline +echo $abmcde + +# this must be last! +expect $0: 'ABXD: parameter unset' +recho ${ABXD:?"parameter unset"} diff --git a/tests/prec.right b/tests/prec.right new file mode 100644 index 0000000..e6af552 --- /dev/null +++ b/tests/prec.right @@ -0,0 +1,28 @@ +`Say' echos its argument. Its return value is of no interest. +`Truth' echos its argument and returns a TRUE result. +`False' echos its argument and returns a FALSE result. + + Truth 1 && Truth 2 || Say 3 output=12 +( Truth 1 && Truth 2 ) || Say 3 output=12 + + Truth 1 && False 2 || Say 3 output=123 +( Truth 1 && False 2 ) || Say 3 output=123 + + False 1 && Truth 2 || Say 3 output=13 +( False 1 && Truth 2 ) || Say 3 output=13 + + False 1 && False 2 || Say 3 output=13 +( False 1 && False 2 ) || Say 3 output=13 + +Truth 1 || Truth 2 && Say 3 output=13 +Truth 1 || ( Truth 2 && Say 3 ) output=1 + +Truth 1 || False 2 && Say 3 output=13 +Truth 1 || ( False 2 && Say 3 ) output=1 + +False 1 || Truth 2 && Say 3 output=123 +False 1 || ( Truth 2 && Say 3 ) output=123 + +False 1 || False 2 && Say 3 output=12 +False 1 || ( False 2 && Say 3 ) output=12 + diff --git a/tests/precedence b/tests/precedence new file mode 100755 index 0000000..9bbdb97 --- /dev/null +++ b/tests/precedence @@ -0,0 +1,75 @@ +# @(#)precedence_test 1.0 91/07/24 Maarten Litmaath +# test of relative precedences for `&&' and `||' operators + +echo "\`Say' echos its argument. Its return value is of no interest." +case `echo -n` in + '') Say () { echo -n "$*" ; } ;; + *) Say () { echo "$*\c" ; } ;; +esac + +echo "\`Truth' echos its argument and returns a TRUE result." +Truth () { + Say $1; + return 0; +} + +echo "\`False' echos its argument and returns a FALSE result." +False () { + Say $1; + return 1; +} + +echo "" + +cmd1='$open $test1 && $test2 $close || $test3' +cmd2='$test1 || $open $test2 && $test3 $close' + +grouping_sh= +grouping_C='( )' + +test3='Say 3' + +for i in 1 2 +do + eval proto=\$cmd$i + + for test1 in 'Truth 1' 'False 1' + do + for test2 in 'Truth 2' 'False 2' + do + for precedence in sh C + do + eval set x \$grouping_$precedence + shift + open=${1-' '} + close=${2-' '} + eval cmd=\""$proto"\" + Say "$cmd output=" + output=`eval "$cmd"` + Say "$output" + read correct || { echo 'Input fubar. Abort.' >&2; exit 1; } + test "X$output" = "X$correct" || echo " correct=$correct" + echo '' + done + + echo '' + done + done +done << EOF +12 +12 +123 +123 +13 +13 +13 +13 +13 +1 +13 +1 +123 +123 +12 +12 +EOF diff --git a/tests/run-all b/tests/run-all new file mode 100755 index 0000000..7add688 --- /dev/null +++ b/tests/run-all @@ -0,0 +1,17 @@ +#! /bin/sh + +PATH=.:$PATH # just to get the right version of printenv +export PATH +unset ENV + +echo Any output from any test indicates an anomaly worth investigating +for x in run-* +do + case $x in + $0) ;; + *.orig|*~) ;; + *) echo $x ; sh $x ;; + esac +done + +exit 0 diff --git a/tests/run-dollars b/tests/run-dollars new file mode 100755 index 0000000..00ad7f1 --- /dev/null +++ b/tests/run-dollars @@ -0,0 +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 diff --git a/tests/run-exp-tests b/tests/run-exp-tests new file mode 100755 index 0000000..b95f603 --- /dev/null +++ b/tests/run-exp-tests @@ -0,0 +1,2 @@ +../bash ./exp-tests | grep -v '^expect' > xx +diff xx exp.right && rm -f xx diff --git a/tests/run-glob-test b/tests/run-glob-test new file mode 100755 index 0000000..1e598dc --- /dev/null +++ b/tests/run-glob-test @@ -0,0 +1,4 @@ +PATH=$PATH:`pwd` +export PATH +../bash ./glob-test | grep -v '^expect' > xx +diff xx glob.right && rm -f xx diff --git a/tests/run-ifs-tests b/tests/run-ifs-tests new file mode 100755 index 0000000..1f9c8c0 --- /dev/null +++ b/tests/run-ifs-tests @@ -0,0 +1,13 @@ +# +# show that IFS is only applied to the result of expansions +# +../bash ifs-test-1.sh > xx +diff xx ./ifs.1.right + +../bash ifs-test-2.sh > xx +diff xx ./ifs.2.right + +../bash ifs-test-3.sh > xx +diff xx ./ifs.3.right + +rm -f xx diff --git a/tests/run-input-test b/tests/run-input-test new file mode 100755 index 0000000..25d63a0 --- /dev/null +++ b/tests/run-input-test @@ -0,0 +1,2 @@ +../bash < ./input-line.sh > xx +diff xx input.right && rm -f xx diff --git a/tests/run-minus-e b/tests/run-minus-e new file mode 100755 index 0000000..51d3229 --- /dev/null +++ b/tests/run-minus-e @@ -0,0 +1,2 @@ +../bash ./minus-e > xx +diff xx minus-e.right && rm -f xx diff --git a/tests/run-new-exp b/tests/run-new-exp new file mode 100755 index 0000000..ef57d32 --- /dev/null +++ b/tests/run-new-exp @@ -0,0 +1,2 @@ +../bash ./new-exp.tests 2>&1 | grep -v '^expect' > xx +diff xx new-exp.right && rm -f xx diff --git a/tests/run-precedence b/tests/run-precedence new file mode 100755 index 0000000..9303e87 --- /dev/null +++ b/tests/run-precedence @@ -0,0 +1,2 @@ +../bash ./precedence > xx +diff xx prec.right && rm -f xx diff --git a/tests/run-set-e-test b/tests/run-set-e-test new file mode 100755 index 0000000..1afef16 --- /dev/null +++ b/tests/run-set-e-test @@ -0,0 +1,2 @@ +../bash ./set-e-test > xx +diff xx set-e.right && rm -f xx diff --git a/tests/run-strip b/tests/run-strip new file mode 100755 index 0000000..8c97f6f --- /dev/null +++ b/tests/run-strip @@ -0,0 +1,2 @@ +../bash ./strip.tests > xx +diff xx strip.right && rm -f xx diff --git a/tests/run-varenv b/tests/run-varenv new file mode 100755 index 0000000..04aece9 --- /dev/null +++ b/tests/run-varenv @@ -0,0 +1,2 @@ +../bash ./varenv.sh | grep -v '^expect' > xx +diff xx varenv.right && rm -f xx diff --git a/tests/set-e-test b/tests/set-e-test new file mode 100644 index 0000000..ce3feb0 --- /dev/null +++ b/tests/set-e-test @@ -0,0 +1,16 @@ +if : ; then + set -e + N=95 + while :; do + # expr returns 1 if expression is null or 0 + set +e + N_MOD_100=`expr $N % 100` + set -e + echo $N_MOD_100 + N=`expr $N + 1` + if [ $N -eq 110 ]; then + break + fi + done + set +e +fi diff --git a/tests/set-e.right b/tests/set-e.right new file mode 100644 index 0000000..92cb7af --- /dev/null +++ b/tests/set-e.right @@ -0,0 +1,15 @@ +95 +96 +97 +98 +99 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/tests/strip.right b/tests/strip.right new file mode 100644 index 0000000..dfab897 --- /dev/null +++ b/tests/strip.right @@ -0,0 +1,12 @@ +'' +' ab ' +' ' +'' +'' +'' +'ababababababab' +'ababababababab ' +'ababababababab ' +'abababa +bababab ' +'' diff --git a/tests/strip.tests b/tests/strip.tests new file mode 100644 index 0000000..b669b52 --- /dev/null +++ b/tests/strip.tests @@ -0,0 +1,22 @@ +v=`echo "" ; echo "" ; echo ""` +echo "'$v'" +v=`echo -n " ab "` +echo "'$v'" +v=`echo -n " "` +echo "'$v'" +v=`echo -n ""` +echo "'$v'" +v=`echo ""` +echo "'$v'" +v=`echo` +echo "'$v'" +v=`echo ababababababab` +echo "'$v'" +v=`echo "ababababababab "` +echo "'$v'" +v=`echo -n "ababababababab "` +echo "'$v'" +v=`echo -ne "abababa\nbababab "` +echo "'$v'" +v="`echo -e '\n\n\n\n'`" +echo "'$v'" diff --git a/tests/tilde-tests b/tests/tilde-tests new file mode 100644 index 0000000..a510751 --- /dev/null +++ b/tests/tilde-tests @@ -0,0 +1,16 @@ +HOME=/usr/xyz +set -v +echo ~chet +echo ~ch\et +echo ~chet/"foo" +echo "~chet"/"foo" +echo \~chet/"foo" +echo \~chet/bar +echo ~\chet/bar +echo ~chet""/bar +echo ":~chet/" +echo abcd~chet +echo "SHELL=~/bash" +echo SHELL=~/bash +echo abcd:~chet +echo PATH=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin diff --git a/tests/tilde.right b/tests/tilde.right new file mode 100644 index 0000000..2920187 --- /dev/null +++ b/tests/tilde.right @@ -0,0 +1,14 @@ +/usr/homes/chet +~chet +/usr/homes/chet/foo +~chet/foo +~chet/foo +~chet/bar +~chet/bar +~chet/bar +:~chet/ +abcd~chet +SHELL=~/bash +SHELL=/usr/xyz/bash +abcd:~chet +PATH=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin diff --git a/tests/varenv.right b/tests/varenv.right new file mode 100644 index 0000000..74ce5d3 --- /dev/null +++ b/tests/varenv.right @@ -0,0 +1,14 @@ +3 4 +5 6 7 8 9 +7 8 9 +/usr/chet +/usr/chet +/usr/chet +/a/b/c +/usr/chet +/usr/chet 7 +/a/b/c 9 /a/b/c +/a/b/c 9 /a/b/c +/a/b/c /a/b/c +1 2 +1 1 diff --git a/tests/varenv.sh b/tests/varenv.sh new file mode 100644 index 0000000..d6bd4e5 --- /dev/null +++ b/tests/varenv.sh @@ -0,0 +1,94 @@ +# +# varenv.sh +# +# Test the behavior of the shell with respect to variable and environment +# assignments +# +expect() +{ + echo expect "$@" +} + +a=1 +b=2 +c=3 +d=4 +e=5 +f=6 g=7 h=8 + +a=3 b=4 $CHMOD $MODE $FN + +# This should echo "3 4" according to Posix.2 +expect "3 4" +echo $a $b + +set -k + +# Assignment statements made when no words are left affect the shell's +# environment +a=5 b=6 $CHMOD c=7 $MODE d=8 $FN e=9 + +expect "5 6 7 8 9" +echo $a $b $c $d $e + +$CHMOD f=7 $MODE g=8 $FN h=9 +expect "7 8 9" +echo $f $g $h + +set +k + +# The temporary environment does not affect variable expansion, only the +# environment given to the command + +export HOME=/usr/chet +expect $HOME +echo $HOME + +expect $HOME +HOME=/a/b/c /bin/echo $HOME + +expect $HOME +echo $HOME + +# This should echo /a/b/c +expect /a/b/c +HOME=/a/b/c printenv HOME + +set -k + +# This should echo $HOME 9, NOT /a/b/c 9 + +expect "$HOME" +HOME=/a/b/c /bin/echo $HOME c=9 +expect "$HOME 7" +echo $HOME $c + +# I claim the next two echo calls should give identical output. +# ksh agrees, the System V.3 sh does not + +expect "/a/b/c 9 /a/b/c" +HOME=/a/b/c $ECHO a=$HOME c=9 +echo $HOME $c $a + +expect "/a/b/c 9 /a/b/c" +HOME=/a/b/c a=$HOME c=9 +echo $HOME $c $a +set +k + +# How do assignment statements affect subsequent assignments on the same +# line? +expect "/a/b/c /a/b/c" +HOME=/a/b/c a=$HOME +echo $HOME $a + +# The system V.3 sh does this wrong; the last echo should output "1 1", +# but the system V.3 sh has it output "2 2". Posix.2 says the assignment +# statements are processed left-to-right. bash and ksh output the right +# thing +c=1 +d=2 +expect "1 2" +echo $c $d +d=$c c=$d +expect "1 1" +echo $c $d @@ -0,0 +1,672 @@ +/* trap.c -- Not the trap command, but useful functions for manipulating + those objects. The trap command is in builtins/trap.def. */ + +/* 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. */ + +#include <stdio.h> + +#include "bashtypes.h" +#include "trap.h" + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#include "shell.h" +#include "signames.h" + +/* Flags which describe the current handling state of a signal. */ +#define SIG_INHERITED 0x0 /* Value inherited from parent. */ +#define SIG_TRAPPED 0x1 /* Currently trapped. */ +#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. */ + +/* An array of such flags, one for each signal, describing what the + shell will do with a signal. */ +static int sigmodes[NSIG]; + +static void change_signal (), restore_signal (); + +/* Variables used here but defined in other files. */ +extern int interactive_shell, interactive; +extern int interrupt_immediately; +extern int last_command_exit_value; + +/* The list of things to do originally, before we started trapping. */ +SigHandler *original_signals[NSIG]; + +/* For each signal, a slot for a string, which is a command to be + executed when that signal is recieved. The slot can also contain + 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]; + +/* A bitmap of signals received for which we have trap handlers. */ +int pending_traps[NSIG]; + +/* A value which can never be the target of a trap handler. */ +#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps + +void +initialize_traps () +{ + register int i; + + trap_list[0] = (char *)NULL; + sigmodes[0] = SIG_INHERITED; /* On EXIT trap handler. */ + + for (i = 1; i < NSIG; i++) + { + pending_traps[i] = 0; + trap_list[i] = (char *)DEFAULT_SIG; + sigmodes[i] = SIG_INHERITED; + original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; + } + + /* Show which signals are treated specially by the shell. */ +#if defined (SIGCHLD) + original_signals[SIGCHLD] = (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL); + set_signal_handler (SIGCHLD, original_signals[SIGCHLD]); + sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); +#endif /* SIGCHLD */ + + original_signals[SIGINT] = + (SigHandler *) set_signal_handler (SIGINT, SIG_DFL); + set_signal_handler (SIGINT, original_signals[SIGINT]); + sigmodes[SIGINT] |= SIG_SPECIAL; + + original_signals[SIGQUIT] = + (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL); + set_signal_handler (SIGQUIT, original_signals[SIGQUIT]); + sigmodes[SIGQUIT] |= SIG_SPECIAL; + + if (interactive) + { + original_signals[SIGTERM] = (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL); + set_signal_handler (SIGTERM, original_signals[SIGTERM]); + sigmodes[SIGTERM] |= SIG_SPECIAL; + } +} + +/* Return the print name of this signal. */ +char * +signal_name (sig) + int sig; +{ + if (sig >= NSIG || sig < 0) + return ("bad signal number"); + else + return (signal_names[sig]); +} + +/* Turn a string into a signal number, or a number into + a signal number. If STRING is "2", "SIGINT", or "INT", + then (int)2 is returned. Return NO_SIG if STRING doesn't + contain a valid signal descriptor. */ +int +decode_signal (string) + char *string; +{ + int sig; + + if (sscanf (string, "%d", &sig) == 1) + { + if (sig < NSIG && sig >= 0) + return (sig); + else + return (NO_SIG); + } + + for (sig = 0; sig < NSIG; sig++) + if (STREQ (string, signal_names[sig]) || + STREQ (string, &(signal_names[sig])[3])) + return (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 + +void +run_pending_traps () +{ + register int sig; + int old_exit_value; + + if (catch_flag == 0) /* simple optimization */ + return; + + catch_flag = 0; + + /* Preserve $? when running trap. */ + old_exit_value = last_command_exit_value; + + for (sig = 1; sig < NSIG; sig++) + { + /* XXX this could be made into a counter by using + while (pending_traps[sig]--) instead of the if statement. */ + if (pending_traps[sig]) + { +#if defined (_POSIX_VERSION) + sigset_t set, oset; + + sigemptyset (&set); + sigemptyset (&oset); + + sigaddset (&set, sig); + sigprocmask (SIG_BLOCK, &set, &oset); +#else +# if defined (HAVE_BSD_SIGNALS) + int oldmask = sigblock (sigmask (sig)); +# endif +#endif /* POSIX_VERSION */ + + if (sig == SIGINT) + { + run_interrupt_trap (); + interrupt_state = 0; + } + else + parse_and_execute (savestring (trap_list[sig]), "trap", 0); + + pending_traps[sig] = 0; + +#if defined (_POSIX_VERSION) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +#else +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (oldmask); +# endif +#endif /* POSIX_VERSION */ + } + } + + last_command_exit_value = old_exit_value; +} + +sighandler +trap_handler (sig) + int sig; +{ + if ((sig >= NSIG) || + (trap_list[sig] == (char *)DEFAULT_SIG) || + (trap_list[sig] == (char *)IGNORE_SIG)) + programming_error ("trap_handler: Bad signal %d", sig); + else + { +#if defined (USG) && !defined (HAVE_BSD_SIGNALS) && !defined (_POSIX_VERSION) + set_signal_handler (sig, trap_handler); +#endif /* USG && !HAVE_BSD_SIGNALS && !_POSIX_VERSION */ + + catch_flag = 1; + pending_traps[sig]++; + + if (interrupt_immediately) + run_pending_traps (); + } +#if !defined (VOID_SIGHANDLER) + return (0); +#endif /* VOID_SIGHANDLER */ +} + +#if defined (JOB_CONTROL) && defined (SIGCHLD) +/* Make COMMAND_STRING be executed when SIGCHLD is caught. */ +void +set_sigchld_trap (command_string) + char *command_string; +{ + void set_signal (); + + set_signal (SIGCHLD, command_string); +} + +/* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current + SIGCHLD trap handler is DEFAULT_SIG. */ +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) + char *command; +{ + void set_signal (); + + set_signal (SIGINT, command); +} + +/* Reset the SIGINT handler so that subshells that are doing `shellsy' + things, like waiting for command substitution or executing commands + in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ +SigHandler * +set_sigint_handler () +{ + if (sigmodes[SIGINT] & SIG_HARD_IGNORE) + return ((SigHandler *)SIG_IGN); + + else if (sigmodes[SIGINT] & SIG_IGNORED) + return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); + + else if (sigmodes[SIGINT] & SIG_TRAPPED) + return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); + + /* The signal is not trapped, so set the handler to the shell's special + interrupt handler. */ + else if (interactive) /* XXX - was interactive_shell */ + return (set_signal_handler (SIGINT, sigint_sighandler)); + else + return (set_signal_handler (SIGINT, termination_unwind_protect)); +} + +/* Set SIG to call STRING as a command. */ +void +set_signal (sig, string) + int sig; + char *string; +{ + /* 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) + return; + + /* Make sure we have original_signals[sig] if the signal has not yet + been trapped. */ + if ((sigmodes[sig] & SIG_TRAPPED) == 0) + { + /* If we aren't sure of the original value, check it. */ + if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) + { + original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); + set_signal_handler (sig, original_signals[sig]); + } + + /* Signals ignored on entry to the shell cannot be trapped or reset. */ + if (original_signals[sig] == SIG_IGN) + { + sigmodes[sig] |= SIG_HARD_IGNORE; + return; + } + } + + /* Only change the system signal handler if SIG_NO_TRAP is not set. + The trap command string is changed in either case. The shell signal + handlers for SIGINT and SIGCHLD run the user specified traps in an + environment in which it is safe to do so. */ + if ((sigmodes[sig] & SIG_NO_TRAP) == 0) + { + set_signal_handler (sig, SIG_IGN); + change_signal (sig, savestring (string)); + set_signal_handler (sig, trap_handler); + } + else + change_signal (sig, savestring (string)); +} + +static void +free_trap_command (sig) + int sig; +{ + if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && + (trap_list[sig] != (char *)IGNORE_SIG) && + (trap_list[sig] != (char *)DEFAULT_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 +change_signal (sig, value) + int sig; + char *value; +{ + free_trap_command (sig); + trap_list[sig] = value; + + sigmodes[sig] |= SIG_TRAPPED; + if (value == (char *)IGNORE_SIG) + sigmodes[sig] |= SIG_IGNORED; + else + sigmodes[sig] &= ~SIG_IGNORED; + if (sigmodes[sig] & SIG_INPROGRESS) + sigmodes[sig] |= SIG_CHANGED; +} + +#define GET_ORIGINAL_SIGNAL(sig) \ + if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ + get_original_signal (sig) + +static void +get_original_signal (sig) + int sig; +{ + /* If we aren't sure the of the original value, then get it. */ + if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) + { + original_signals[sig] = + (SigHandler *) set_signal_handler (sig, SIG_DFL); + set_signal_handler (sig, original_signals[sig]); + + /* Signals ignored on entry to the shell cannot be trapped. */ + if (original_signals[sig] == SIG_IGN) + sigmodes[sig] |= SIG_HARD_IGNORE; + } +} + +/* Restore the default action for SIG; i.e., the action the shell + would have taken before you used the trap command. This is called + from trap_builtin (), which takes care to restore the handlers for + the signals the shell treats specially. */ +void +restore_default_signal (sig) + int sig; +{ + if (sig == 0) + { + free_trap_command (sig); + trap_list[sig] = (char *)NULL; + sigmodes[sig] &= ~SIG_TRAPPED; + return; + } + + GET_ORIGINAL_SIGNAL (sig); + + /* A signal ignored on entry to the shell cannot be trapped or reset, but + no error is reported when attempting to do so. Thanks Posix.2. */ + if (sigmodes[sig] & SIG_HARD_IGNORE) + return; + + /* If we aren't trapping this signal, don't bother doing anything else. */ + if (!(sigmodes[sig] & SIG_TRAPPED)) + return; + + /* Only change the signal handler for SIG if it allows it. */ + if (!(sigmodes[sig] & SIG_NO_TRAP)) + set_signal_handler (sig, original_signals[sig]); + + /* Change the trap command in either case. */ + change_signal (sig, (char *)DEFAULT_SIG); + + /* Mark the signal as no longer trapped. */ + sigmodes[sig] &= ~SIG_TRAPPED; +} + +/* Make this signal be ignored. */ +void +ignore_signal (sig) + int sig; +{ + 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. */ + 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)) + return; + + /* Only change the signal handler for SIG if it allows it. */ + if (!(sigmodes[sig] & SIG_NO_TRAP)) + set_signal_handler (sig, SIG_IGN); + + /* Change the trap command in either case. */ + change_signal (sig, (char *)IGNORE_SIG); +} + +/* Handle the calling of "trap 0". The only sticky situation is when + the command to be executed includes an "exit". This is why we have + to provide our own place for top_level to jump to. */ +int +run_exit_trap () +{ + int 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) + { + char *trap_command; + int code; + + trap_command= savestring (trap_list[0]); + sigmodes[0] &= ~SIG_TRAPPED; + sigmodes[0] |= SIG_INPROGRESS; + + code = setjmp (top_level); + + if (code == 0) + parse_and_execute (trap_command, "trap", 0); + else if (code == EXITPROG) + return (last_command_exit_value); + else + return (old_exit_value); + } + + return (old_exit_value); +} + +/* Set the handler signal SIG to the original and free any trap + command associated with it. */ +static void +restore_signal (sig) + int sig; +{ + set_signal_handler (sig, original_signals[sig]); + change_signal (sig, (char *)DEFAULT_SIG); + sigmodes[sig] &= ~SIG_TRAPPED; +} + +/* Free all the allocated strings in the list of traps and reset the trap + values to the default. */ +void +free_trap_strings () +{ + register int i; + + for (i = 0; i < NSIG; i++) + { + free_trap_command (i); + trap_list[i] = (char *)DEFAULT_SIG; + sigmodes[i] &= ~SIG_TRAPPED; + } +} + +/* Reset the handler for SIG to the original value. */ +static void +reset_signal (sig) + int 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 () +{ + 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); + } + } +} + +/* 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 () +{ + register int i; + + reset_terminating_signals (); /* in shell.c */ + + 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) + restore_signal (i); + else if (sigmodes[i] & SIG_TRAPPED) + { + if (trap_list[i] == (char *)IGNORE_SIG) + set_signal_handler (i, SIG_IGN); + else + restore_signal (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 () +{ + 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; + + if (sigmodes[SIGINT] & SIG_CHANGED) + { + free (saved_command); + sigmodes[SIGINT] &= ~SIG_CHANGED; + } + } +} + +/* If a trap handler exists for signal SIG, then call it; otherwise just + return failure. */ +int +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)) + { + switch (sig) + { + case SIGINT: + run_interrupt_trap (); + break; + case 0: + run_exit_trap (); + break; + default: + trap_handler (sig); + break; + } + return (1); + } + else + return (0); +} + +int +signal_is_trapped (sig) + int sig; +{ + return (sigmodes[sig] & SIG_TRAPPED); +} + +int +signal_is_special (sig) + int sig; +{ + return (sigmodes[sig] & SIG_SPECIAL); +} + +int +signal_is_ignored (sig) + int sig; +{ + return (sigmodes[sig] & SIG_IGNORED); +} + +void +set_signal_ignored (sig) + int sig; +{ + sigmodes[sig] |= SIG_HARD_IGNORE; + original_signals[sig] = SIG_IGN; +} @@ -0,0 +1,65 @@ +/* trap.h -- data structures used in the trap mechanism. */ + +/* 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 (__TRAP_H__) +#define __TRAP_H__ + +#include "stdc.h" + +#if !defined (SIG_DFL) +#include <sys/types.h> +#include <signal.h> +#endif /* SIG_DFL */ + +#if !defined (NSIG) +#define NSIG 64 +#endif /* !NSIG */ + +#define NO_SIG -1 +#define DEFAULT_SIG SIG_DFL +#define IGNORE_SIG SIG_IGN + +#define signal_object_p(x) (decode_signal (x) != NO_SIG) + +extern char *trap_list[NSIG]; + +/* 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_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 free_trap_strings __P((void)); +extern void reset_signal_handlers __P((void)); +extern void restore_original_signals __P((void)); + +extern char *signal_name __P((int)); + +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)); + +#endif /* __TRAP_H__ */ diff --git a/unwind_prot.c b/unwind_prot.c new file mode 100644 index 0000000..d9399d7 --- /dev/null +++ b/unwind_prot.c @@ -0,0 +1,272 @@ +/* I can't stand it anymore! Please can't we just write the + whole Unix system in lisp or something? */ + +/* 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 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. */ + +/* **************************************************************** */ +/* */ +/* Unwind Protection Scheme for Bash */ +/* */ +/* **************************************************************** */ +#include "bashtypes.h" +#include <signal.h> +#include "config.h" +#include "command.h" +#include "general.h" +#include "unwind_prot.h" +#include "quit.h" + +/* If CLEANUP is null, then ARG contains a tag to throw back to. */ +typedef struct _uwp { + struct _uwp *next; + Function *cleanup; + char *arg; +} UNWIND_ELT; + +static void + unwind_frame_discard_internal (), unwind_frame_run_internal (), + add_unwind_protect_internal (), remove_unwind_protect_internal (), + run_unwind_protects_internal (), without_interrupts (); + +static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL; + +extern int interrupt_immediately; + +/* Run a function without interrupts. This relies on the fact that the + FUNCTION cannot change the value of interrupt_immediately. (I.e., does + not call QUIT (). */ +static void +without_interrupts (function, arg1, arg2) + VFunction *function; + char *arg1, *arg2; +{ + int old_interrupt_immediately; + + old_interrupt_immediately = interrupt_immediately; + interrupt_immediately = 0; + + (*function)(arg1, arg2); + + interrupt_immediately = old_interrupt_immediately; +} + +/* Start the beginning of a region. */ +void +begin_unwind_frame (tag) + char *tag; +{ + add_unwind_protect ((Function *)NULL, tag); +} + +/* Discard the unwind protects back to TAG. */ +void +discard_unwind_frame (tag) + char *tag; +{ + if (unwind_protect_list) + without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL); +} + +/* Run the unwind protects back to TAG. */ +void +run_unwind_frame (tag) + char *tag; +{ + if (unwind_protect_list) + without_interrupts (unwind_frame_run_internal, tag, (char *)NULL); +} + +/* Add the function CLEANUP with ARG to the list of unwindable things. */ +void +add_unwind_protect (cleanup, arg) + Function *cleanup; + char *arg; +{ + without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg); +} + +/* Remove the top unwind protect from the list. */ +void +remove_unwind_protect () +{ + if (unwind_protect_list) + without_interrupts + (remove_unwind_protect_internal, (char *)NULL, (char *)NULL); +} + +/* Run the list of cleanup functions in unwind_protect_list. */ +void +run_unwind_protects () +{ + if (unwind_protect_list) + without_interrupts + (run_unwind_protects_internal, (char *)NULL, (char *)NULL); +} + +/* **************************************************************** */ +/* */ +/* The Actual Functions */ +/* */ +/* **************************************************************** */ + +static void +add_unwind_protect_internal (cleanup, arg) + Function *cleanup; + char *arg; +{ + UNWIND_ELT *elt; + + elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT)); + elt->cleanup = cleanup; + elt->arg = arg; + elt->next = unwind_protect_list; + unwind_protect_list = elt; +} + +static void +remove_unwind_protect_internal () +{ + UNWIND_ELT *elt = unwind_protect_list; + + if (elt) + { + unwind_protect_list = unwind_protect_list->next; + free (elt); + } +} + +static void +run_unwind_protects_internal () +{ + UNWIND_ELT *t, *elt = unwind_protect_list; + + while (elt) + { + /* This function can be run at strange times, like when unwinding + the entire world of unwind protects. Thus, we may come across + an element which is simply a label for a catch frame. Don't call + the non-existant function. */ + if (elt->cleanup) + (*(elt->cleanup)) (elt->arg); + + t = elt; + elt = elt->next; + free (t); + } + unwind_protect_list = elt; +} + +static void +unwind_frame_discard_internal (tag) + char *tag; +{ + UNWIND_ELT *elt; + + while (elt = unwind_protect_list) + { + unwind_protect_list = unwind_protect_list->next; + if (!elt->cleanup && (STREQ (elt->arg, tag))) + { + free (elt); + break; + } + else + free (elt); + } +} + +static void +unwind_frame_run_internal (tag) + char *tag; +{ + UNWIND_ELT *elt; + + while (elt = unwind_protect_list) + { + unwind_protect_list = elt->next; + + /* If tag, then compare. */ + if (!elt->cleanup) + { + if (STREQ (elt->arg, tag)) + { + free (elt); + break; + } + free (elt); + continue; + } + else + { + (*(elt->cleanup)) (elt->arg); + free (elt); + } + } +} + +/* Structure describing a saved variable and the value to restore it to. */ +typedef struct { + int *variable; + char *desired_setting; + int size; +} SAVED_VAR; + +/* Restore the value of a variable, based on the contents of SV. If + sv->size is greater than sizeof (int), sv->desired_setting points to + a block of memory SIZE bytes long holding the value, rather than the + value itself. This block of memory is copied back into the variable. */ +static void +restore_variable (sv) + SAVED_VAR *sv; +{ + if (sv->size > sizeof (int)) + { + bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size); + free (sv->desired_setting); + } + else + *(sv->variable) = (int)sv->desired_setting; + + free (sv); +} + +/* Save the value of a variable so it will be restored when unwind-protects + are run. VAR is a pointer to the variable. VALUE is the value to be + saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what + can be saved in an int, memory will be allocated and the value saved + into that using bcopy (). */ +void +unwind_protect_var (var, value, size) + int *var; + char *value; + int size; +{ + SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR)); + + s->variable = var; + if (size > sizeof (int)) + { + s->desired_setting = (char *)xmalloc (size); + bcopy (value, (char *)s->desired_setting, size); + } + else + s->desired_setting = value; + s->size = size; + add_unwind_protect ((Function *)restore_variable, (char *)s); +} diff --git a/unwind_prot.h b/unwind_prot.h new file mode 100644 index 0000000..e013631 --- /dev/null +++ b/unwind_prot.h @@ -0,0 +1,47 @@ +/* unwind_prot.h - Macros and functions for hacking unwind protection. */ + +/* 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 (_UNWIND_PROT_H) +#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 (); + +/* 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)) + +/* How to protect a pointer to a string. */ +#define unwind_protect_string(X) \ + unwind_protect_var ((int *)&(X), (X), sizeof (char *)) + +/* How to protect any old pointer. */ +#define unwind_protect_pointer(X) unwind_protect_string (X) + +/* 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)) + +#endif /* _UNWIND_PROT_H */ diff --git a/variables.c b/variables.c new file mode 100644 index 0000000..2c911c2 --- /dev/null +++ b/variables.c @@ -0,0 +1,1804 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* 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 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 <stdio.h> +#include "bashtypes.h" +#include "posixstat.h" +#include <ctype.h> +#include <pwd.h> + +#include "bashansi.h" +#include "shell.h" +#include "hash.h" +#include "flags.h" +#include "execute_cmd.h" + +#include "builtins/common.h" +#include <tilde/tilde.h> + +/* 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 char *shell_name; +extern char *primary_prompt, *secondary_prompt; +extern Function *this_shell_builtin; +extern time_t shell_start_time; + +/* The list of shell variables that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_variables = (HASH_TABLE *)NULL; + +/* The list of shell functions that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; + +/* The current variable context. This is really a count of how deep into + executing functions we are. */ +int variable_context = 0; + +/* The array of shell assignments which are made only in the environment + for a single command. */ +char **temporary_env = (char **)NULL; + +/* The array of shell assignments which are in the environment for the + execution of a shell function. */ +char **function_env = (char **)NULL; + +/* The array of shell assignments which are made only in the environment + for the execution of a shell builtin command which may cause more than + one command to be executed (e.g., "source"). */ +char **builtin_env = (char **)NULL; + +/* Some funky variables which are known about specially. Here is where + "$*", "$1", and all the cruft is kept. */ +char *dollar_vars[10]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; + +/* The value of $$. */ +int dollar_dollar_pid; + +/* An array which is passed to commands as their environment. It is + manufactured from the overlap of the initial environment and the + shell variables that are marked for export. */ +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; + +static char *have_local_variables; /* XXX */ +static int local_variable_stack_size = 0; /* XXX */ + +/* Some forward declarations. */ +static void initialize_dynamic_variables (); +static void sbrand (); /* set bash random number generator. */ +static int qsort_var_comp (); + +/* Make VAR be auto-exported. VAR is a pointer to a SHELL_VAR. */ +#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) + char **env; +{ + char *name, *string, *current_dir; + int c, char_index; + int string_index = 0; + SHELL_VAR *temp_var; + + if (!shell_variables) + shell_variables = make_hash_table (0); + + if (!shell_functions) + shell_functions = make_hash_table (0); + + while (string = env[string_index++]) + { + int string_length; + + char_index = 0; + + string_length = strlen (string); + name = xmalloc (1 + string_length); + + while ((c = *string++) && c != '=') + name[char_index++] = c; + + name[char_index] = '\0'; + + /* If exported function, define it now. */ + if (!privileged_mode && STREQN ("() {", string, 4)) + { + SHELL_VAR *f; + char *eval_string; + + eval_string = xmalloc (3 + string_length + strlen (name)); + sprintf (eval_string, "%s %s", name, string); + + parse_and_execute (eval_string, name, 0); + + if (name[char_index - 1] == ')') + name[char_index - 2] = '\0'; + + if (f = find_function (name)) + { + f->attributes |= (att_exported | att_imported); + array_needs_making = 1; + } + else + report_error ("error importing function definition for `%s'", name); + } + else + { + SHELL_VAR *v; + + v = bind_variable (name, string); + v->attributes |= (att_exported | att_imported); + array_needs_making = 1; + } + free (name); + } + + /* 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, + 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); + else + { + current_dir = get_working_directory ("shell-init"); + if (current_dir) + { + bind_variable ("PWD", current_dir); + free (current_dir); + } + } + + /* Remember this pid. */ + dollar_dollar_pid = (int)getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); + set_auto_export (temp_var); + + temp_var = set_if_not ("TERM", "dumb"); + set_auto_export (temp_var); + + if (interactive_shell) + { + set_if_not ("PS1", primary_prompt); + set_if_not ("PS2", secondary_prompt); + } + set_if_not ("PS4", "+ "); + +#if defined (INSECURITY) + set_if_not ("IFS", " \t\n"); +#else + bind_variable ("IFS", " \t\n"); +#endif /* INSECURITY */ + + /* Magic machine types. Pretty convenient. */ + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + set_auto_export (temp_var); + temp_var = set_if_not ("OSTYPE", OSTYPE); + set_auto_export (temp_var); + + /* Default MAILCHECK for interactive shells. */ + if (interactive_shell) + set_if_not ("MAILCHECK", "60"); + + /* Do some things with shell level. */ + temp_var = set_if_not ("SHLVL", "0"); + set_auto_export (temp_var); + 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); + } + +#if defined (GETOPTS_BUILTIN) + /* Initialize the `getopts' stuff. */ + bind_variable ("OPTIND", "1"); + bind_variable ("OPTERR", "1"); +#endif /* GETOPTS_BUILTIN */ + + /* 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); + 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); + } + + /* Make a variable called BASH_VERSION which contains the version info. */ + bind_variable ("BASH_VERSION", shell_version_string ()); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + 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"); + + set_if_not ("HISTFILE", name); + free (name); + + set_if_not ("HISTSIZE", "500"); + sv_histsize ("HISTSIZE"); + } +#endif /* HISTORY */ + + /* Seed the random number generator. */ + sbrand (dollar_dollar_pid); + + /* 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"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + +#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"); + } +#endif /* HISTORY */ + + /* 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 +adjust_shell_level (change) + int change; +{ + char *new_level, *old_SHLVL; + int old_level; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL) + old_level = atoi (old_SHLVL); + else + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + new_level = itos (shell_level); + bind_variable ("SHLVL", new_level); + 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; +{ + register int i; + + if (!non_unsettable_vars) + { + non_unsettable_vars = (char **)xmalloc (1 * sizeof (char *)); + non_unsettable_vars[0] = (char *)NULL; + } + + for (i = 0; non_unsettable_vars[i]; i++) + if (STREQ (non_unsettable_vars[i], name)) + return; + + 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; +} + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v = find_variable (name); + + if (!v) + v = bind_variable (name, value); + return (v); +} + +/* Map FUNCTION over the variables in VARIABLES. Return an array of the + variables that satisfy FUNCTION. Satisfy means that FUNCTION returns + a non-zero value for. A NULL value for FUNCTION means to use all + variables. */ +SHELL_VAR ** +map_over (function, var_hash_table) + Function *function; + HASH_TABLE* var_hash_table; +{ + register int i; + register BUCKET_CONTENTS *tlist; + SHELL_VAR *var, **list = (SHELL_VAR **)NULL; + int list_index = 0, list_size = 0; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + tlist = get_hash_bucket (i, var_hash_table); + + while (tlist) + { + var = (SHELL_VAR *)tlist->data; + + if (!function || (*function) (var)) + { + if (list_index + 1 >= list_size) + list = (SHELL_VAR **) + xrealloc (list, (list_size += 20) * sizeof (SHELL_VAR *)); + + list[list_index++] = var; + list[list_index] = (SHELL_VAR *)NULL; + } + tlist = tlist->next; + } + } + return (list); +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, array_len ((char **)array), sizeof (SHELL_VAR *), qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Create a NULL terminated array of all the shell variables in TABLE. */ +static SHELL_VAR ** +all_vars (table) + HASH_TABLE *table; +{ + SHELL_VAR **list; + + list = map_over ((Function *)NULL, table); + if (list) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (all_vars (shell_variables)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (all_vars (shell_functions)); +} + +/* Print VARS to stdout in such a way that they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (!invisible_p (var)) + print_assignment (var); +} + +#if defined (NOTDEF) +/* Print LIST (a linked list of shell variables) to stdout + by printing the names, without the values. Used to support the + `set +' command. */ +print_vars_no_values (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (!invisible_p (var)) + printf ("%s\n", var->name); +} +#endif + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (function_p (var) && var->value) + { + printf ("%s=", var->name); + print_var_function (var); + printf ("\n"); + } + else if (var->value) + { + printf ("%s=", var->name); + print_var_value (var); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. */ +void +print_var_value (var) + SHELL_VAR *var; +{ + if (var->value) + printf ("%s", var->value); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + if (function_p (var) && var->value) + printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1)); +} + +/* **************************************************************** */ +/* */ +/* 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 + localized as possible. */ + +/* 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 SHELL_VAR * +assign_seconds (self, value) + SHELL_VAR *self; + char *value; +{ + seconds_value_assigned = atol (value); + shell_start_time = NOW; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + + time_since_start = NOW - shell_start_time; + p = itos((int) seconds_value_assigned + time_since_start); + + FREE (var->value); + + var->attributes |= att_integer; + var->value = p; + return (var); +} + +/* The random number seed. You can change this by setting RANDOM. */ +static unsigned long rseed = 1; + +/* A linear congruential random number generator based on the ANSI + C standard. A more complicated one is overkill. */ + +/* Returns a pseudo-random number between 0 and 32767. */ +static int +brand () +{ + rseed = rseed * 1103515245 + 12345; + return ((unsigned int)(rseed / 65536) % 32768); +} + +/* Set the random number generator seed to SEED. */ +static void +sbrand (seed) + int seed; +{ + rseed = seed; +} + +static SHELL_VAR * +assign_random (self, value) + SHELL_VAR *self; + char *value; +{ + int s = atoi (value); + + sbrand (s); + return (self); +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = brand (); + p = itos ((int)rv); + + FREE (var->value); + + var->attributes |= att_integer; + var->value = p; + return (var); +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (line_number); + FREE (var->value); + var->value = p; + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (history_number ()); + FREE (var->value); + var->value = p; + return (var); +} +#endif + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + v = bind_variable ("SECONDS", (char *)NULL); + v->dynamic_value = get_seconds; + v->assign_func = assign_seconds; + + v = bind_variable ("RANDOM", (char *)NULL); + v->dynamic_value = get_random; + v->assign_func = assign_random; + + v = bind_variable ("LINENO", (char *)NULL); + v->dynamic_value = get_lineno; + v->assign_func = (DYNAMIC_FUNC *)NULL; + +#if defined (HISTORY) + v = bind_variable ("HISTCMD", (char *)NULL); + v->dynamic_value = get_histcmd; + v->assign_func = (DYNAMIC_FUNC *)NULL; +#endif +} + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ +SHELL_VAR * +var_lookup (name, hashed_vars) + char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = find_hash_item (name, hashed_vars); + + if (bucket) + return ((SHELL_VAR *)bucket->data); + else + return ((SHELL_VAR *)NULL); +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. */ +SHELL_VAR * +find_variable_internal (name, search_tempenv) + char *name; + int search_tempenv; +{ + SHELL_VAR *var = (SHELL_VAR *)NULL; + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + to get the `exported' value of $foo. This happens if we are executing + a function or builtin, or if we are looking up a variable in a + "subshell environment". */ + if ((search_tempenv || subshell_environment) && + (temporary_env || builtin_env || function_env)) + var = find_tempenv_variable (name); + + if (!var) + var = var_lookup (name, shell_variables); + + if (!var) + return ((SHELL_VAR *)NULL); + + if (var->dynamic_value) + return ((*(var->dynamic_value)) (var)); + else + return (var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + char *name; +{ + return (find_variable_internal + (name, (variable_context || this_shell_builtin || builtin_env))); +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + char *name; +{ + return (var_lookup (name, shell_functions)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist, or only has a function as a value. Don't cons a new + string. */ +char * +get_string_value (var_name) + char *var_name; +{ + SHELL_VAR *var = find_variable (var_name); + + if (!var) + return (char *)NULL; + else + return (var->value); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name) + char *name; +{ + SHELL_VAR *new_var, *old_var; + BUCKET_CONTENTS *elt; + + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_var && old_var->context == variable_context) + return (old_var); + + elt = remove_hash_item (name, shell_variables); + if (elt) + { + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + } + else + old_var = (SHELL_VAR *)NULL; + + /* If a variable does not already exist with this name, then + just make a new one. */ + if (!old_var) + { + new_var = bind_variable (name, ""); + } + else + { + new_var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + new_var->name = savestring (name); + new_var->value = savestring (""); + + 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->prev_context = old_var; + elt = add_hash_item (savestring (name), shell_variables); + elt->data = (char *)new_var; + } + + new_var->context = variable_context; + + /* XXX */ + if (local_variable_stack_size <= variable_context) + { + 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); + bzero ((char *)have_local_variables + old_size, + local_variable_stack_size - old_size); + } + have_local_variables[variable_context] = 1; /* XXX */ + + return (new_var); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. */ +SHELL_VAR * +bind_variable (name, value) + char *name, *value; +{ + SHELL_VAR *entry = var_lookup (name, shell_variables); + BUCKET_CONTENTS *elt; + + if (!entry) + { + /* Make a new entry for this variable. Then do the binding. */ + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->attributes = 0; + entry->name = savestring (name); + + if (value) + { + if (*value) + entry->value = savestring (value); + else + { + entry->value = xmalloc (1); + entry->value[0] = '\0'; + } + } + else + entry->value = (char *)NULL; + + 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; + } + else if (entry->assign_func) + return ((*(entry->assign_func)) (entry, value)); + else + { + if (readonly_p (entry)) + { + report_error ("%s: read-only 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; + + 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); + } + 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; + } + } + + if (mark_modified_vars) + entry->attributes |= att_exported; + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Dispose of the information attached to VAR. */ +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (!var) + return; + + if (function_p (var)) + dispose_command ((COMMAND *)var->value); + else if (var->value) + free (var->value); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the variable referenced by NAME. */ +unbind_variable (name) + char *name; +{ + SHELL_VAR *var = find_variable (name); + + if (!var) + return (-1); + + if (var->value) + { + free (var->value); + var->value = (char *)NULL; + } + + makunbound (name, shell_variables); + + return (0); +} + +/* Make the variable associated with NAME go away. HASH_LIST is the + 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. */ +makunbound (name, hash_list) + char *name; + HASH_TABLE *hash_list; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var, *new_var; + char *t; + + elt = remove_hash_item (name, hash_list); + + if (!elt) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + new_var = old_var->prev_context; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + if (new_var) + { + /* Has to be a variable, functions don't have previous contexts. */ + BUCKET_CONTENTS *new_elt; + + new_elt = add_hash_item (savestring (new_var->name), hash_list); + new_elt->data = (char *)new_var; + + if (exported_p (new_var)) + set_var_auto_export (new_var->name); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + return (0); +} + +/* Remove the variable with NAME if it is a local variable in the + current context. */ +kill_local_variable (name) + char *name; +{ + SHELL_VAR *temp = find_variable (name); + + if (temp && (temp->context == variable_context)) + { + makunbound (name, shell_variables); + return (0); + } + return (-1); +} + +/* Get rid of all of the variables in the current context. */ +int +variable_in_context (var) + SHELL_VAR *var; +{ + return (var && var->context == variable_context); +} + +void +kill_all_local_variables () +{ + register int i, pass; + register SHELL_VAR *var, **list; + HASH_TABLE *varlist; + + /* XXX */ + if (!have_local_variables || have_local_variables[variable_context] == 0) + return; + + for (pass = 0; pass < 2; pass++) + { + varlist = pass ? shell_functions : shell_variables; + + list = map_over (variable_in_context, varlist); + + if (list) + { + for (i = 0; var = list[i]; i++) + makunbound (var->name, varlist); + + free (list); + } + } + + have_local_variables[variable_context] = 0; /* XXX */ +} + +/* 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; + } +} + +static SHELL_VAR * +new_shell_variable (name) + char *name; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + bzero ((char *)var, sizeof (SHELL_VAR)); + var->name = savestring (name); + return (var); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + char *name; + COMMAND *value; +{ + SHELL_VAR *entry = find_function (name); + + if (!entry) + { + BUCKET_CONTENTS *elt; + + elt = add_hash_item (savestring (name), shell_functions); + + elt->data = (char *)new_shell_variable (name); + entry = (SHELL_VAR *)elt->data; + entry->dynamic_value = (DYNAMIC_FUNC *)NULL; + entry->assign_func = (DYNAMIC_FUNC *)NULL; + + /* Functions are always made at the top level. This allows a + function to define another function (like autoload). */ + entry->context = 0; + } + + 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->attributes |= att_function; + + if (mark_modified_vars) + entry->attributes |= att_exported; + + entry->attributes &= ~att_invisible; /* Just to be sure */ + + array_needs_making = 1; + + return (entry); +} + +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + 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); + else + copy->value = (char *)NULL; + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->context = var->context; + + /* Don't bother copying previous contexts along with this variable. */ + copy->prev_context = (SHELL_VAR *)NULL; + } + return (copy); +} + +/* Make the variable associated with NAME be read-only. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry = find_variable (name); + + if (!entry) + { + entry = bind_variable (name, ""); + if (!no_invisible_vars) + entry->attributes |= att_invisible; + } + entry->attributes |= att_readonly; +} + +/* Make the function associated with NAME be read-only. + If NAME does not exist, we just punt, like auto_export code below. */ +void +set_func_read_only (name) + char *name; +{ + SHELL_VAR *entry = find_function (name); + + if (entry) + entry->attributes |= att_readonly; +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +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; + } + + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + char *name; +{ + SHELL_VAR *entry = find_function (name); + + if (entry) + { + entry->attributes |= att_exported; + array_needs_making = 1; + } +} + +/* Returns non-zero if STRING is an assignment statement. The returned value + is the index of the `=' sign. */ +assignment (string) + char *string; +{ + register int c, indx = 0; + + c = string[indx]; + + if (!isletter (c) && c != '_') + return (0); + + while (c = string[indx]) + { + /* The following is safe. Note that '=' at the start of a word + is not an assignment statement. */ + if (c == '=') + return (indx); + + if (!isletter (c) && !digit (c) && c != '_') + return (0); + + indx++; + } + return (0); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (!invisible_p (var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + SHELL_VAR **list; + + list = map_over (visible_var, shell_variables); + + if (list) + sort_variables (list); + + return (list); +} + +SHELL_VAR ** +all_visible_functions () +{ + SHELL_VAR **list; + + list = map_over (visible_var, shell_functions); + + if (list) + sort_variables (list); + + return (list); +} + +/* Return non-zero if the variable VAR is visible and exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (!invisible_p (var) && exported_p (var)); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +char ** +make_var_array (hashed_vars) + HASH_TABLE *hashed_vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list = (char **)NULL; + SHELL_VAR **vars; + + vars = map_over (visible_and_exported, hashed_vars); + + if (!vars) + return (char **)NULL; + + list = (char **)xmalloc ((1 + array_len ((char **)vars)) * sizeof (char *)); + + 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); + else + value = value_cell (var); + + if (value) + { + int name_len = strlen (var->name); + int value_len = strlen (value); + char *p; + + 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++; + } + } + + free (vars); + list[list_index] = (char *)NULL; + return (list); +} + +/* Add STRING to the array of foo=bar strings that we already + have to add to the environment. */ +assign_in_env (string) + char *string; +{ + int size; + + int offset = assignment (string); + char *name = savestring (string); + char *temp, *value = (char *)NULL; + int nlen, vlen; + + if (name[offset] == '=') + { + WORD_LIST *list; + + name[offset] = 0; + temp = name + offset + 1; + temp = tilde_expand (temp); + + list = expand_string_unsplit (temp, 0); + value = string_list (list); + + if (list) + dispose_words (list); + + free (temp); + } + + if (!value) + value = savestring (""); + + nlen = strlen (name); + vlen = strlen (value); + temp = xmalloc (2 + nlen + vlen); + strcpy (temp, name); + temp[nlen] = '='; + strcpy (temp + nlen + 1, value); + free (name); + free (value); + + if (!temporary_env) + { + temporary_env = (char **)xmalloc (sizeof (char *)); + temporary_env [0] = (char *)NULL; + } + + size = array_len (temporary_env); + temporary_env = (char **) + xrealloc (temporary_env, (size + 2) * (sizeof (char *))); + + 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, + so we do too. */ + fprintf (stderr, "%s%s\n", indirection_level_string (), temp); + fflush (stderr); + } + + return 1; +} + +/* Search for NAME in ARRAY, an array of strings in the same format as the + environment array (i.e, name=value). If NAME is present, make a new + variable and return it. Otherwise, return NULL. */ +static SHELL_VAR * +find_name_in_env_array (name, array) + char *name; + char **array; +{ + register int i, l = strlen (name); + + if (!array) + return ((SHELL_VAR *)NULL); + + for (i = 0; array[i]; i++) + { + if (STREQN (array[i], name, l) && array[i][l] == '=') + { + SHELL_VAR *temp; + + temp = new_shell_variable (name); + + if (array[i][l + 1]) + temp->value = savestring (&array[i][l + 1]); + else + temp->value = (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; + + return (temp); + } + } + return ((SHELL_VAR *)NULL); +} + +/* Find a variable in the temporary environment that is named NAME. + The temporary environment can be either the environment provided + to a simple command, or the environment provided to a shell function. + We only search the function environment if we are currently executing + a shell function body (variable_context > 0). Return a consed variable, + or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + char *name; +{ + SHELL_VAR *var = (SHELL_VAR *)NULL; + + if (temporary_env) + var = find_name_in_env_array (name, temporary_env); + + /* We don't check this_shell_builtin because the command that needs the + value from builtin_env may be a disk command run inside a script run + with `.' and a temporary env. */ + if (!var && builtin_env) + var = find_name_in_env_array (name, builtin_env); + + if (!var && variable_context && function_env) + var = find_name_in_env_array (name, function_env); + + return (var); +} + +/* Free the storage allocated to the string array pointed to by ARRAYP, and + make that variable have a null pointer as a value. */ +static void +dispose_temporary_vars (arrayp) + char ***arrayp; +{ + if (!*arrayp) + return; + + free_array (*arrayp); + *arrayp = (char **)NULL; + array_needs_making = 1; +} + +/* Free the storage used in the variable array for temporary + environment variables. */ +void +dispose_used_env_vars () +{ + dispose_temporary_vars (&temporary_env); +} + +/* Free the storage used for temporary environment variables given to + commands when executing inside of a function body. */ +void +dispose_function_env () +{ + dispose_temporary_vars (&function_env); +} + +/* Free the storage used for temporary environment variables given to + commands when executing a builtin command such as "source". */ +void +dispose_builtin_env () +{ + dispose_temporary_vars (&builtin_env); +} + +/* 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); +} + +#define ISFUNC(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')')) + +/* Add ASSIGN to ARRAY, or supercede a previous assignment in the + array with the same left-hand side. Return the new array. */ +char ** +add_or_supercede (assign, array) + char *assign; + register char **array; +{ + register int i; + int equal_offset = assignment (assign); + + if (!equal_offset) + return (array); + + /* If this is a function, then only supercede the function definition. + We do this by including the `=(' in the comparison. */ + if (assign[equal_offset + 1] == '(') + equal_offset++; + + for (i = 0; array && array[i]; i++) + { + if (STREQN (assign, array[i], equal_offset + 1)) + { + free (array[i]); + array[i] = savestring (assign); + return (array); + } + } + array = (char **)xrealloc (array, ((2 + i) * sizeof (char *))); + array[i++] = savestring (assign); + array[i] = (char *)NULL; + return (array); +} + +/* Make the environment array for the command about to be executed. If the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. */ +void +maybe_make_export_env () +{ + register int i; + register char **temp_array; + + if (array_needs_making) + { + 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); + free_array (temp_array); + + temp_array = make_var_array (shell_functions); + for (i = 0; temp_array && temp_array[i]; i++) + export_env = add_or_supercede (temp_array[i], export_env); + free_array (temp_array); + + if (function_env) + for (i = 0; function_env[i]; i++) + export_env = add_or_supercede (function_env[i], export_env); + + if (temporary_env) + for (i = 0; temporary_env[i]; i++) + export_env = add_or_supercede (temporary_env[i], export_env); + + /* If we changed the array, then sort it alphabetically. */ + if (temporary_env || function_env) + sort_char_array (export_env); + + array_needs_making = 0; + } +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + char *dummy; + + dummy = xmalloc (4 + strlen (command_name)); + + /* These three statements replace a call to sprintf */ + dummy[0] = '_'; + dummy[1] = '='; + strcpy (dummy + 2, command_name); + export_env = add_or_supercede (dummy, export_env); + free (dummy); +} + +/* 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 (NeXT) && !defined (HPOSF1) +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 */ +{ + SHELL_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 = strlen (name); + + /* 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; environ[i]; i++) + { + if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) + return (environ[i] + len + 1); + } + } + + return ((char *)NULL); +} +#endif /* !NeXT && !HPOSF1 */ diff --git a/variables.h b/variables.h new file mode 100644 index 0000000..8f4ef3e --- /dev/null +++ b/variables.h @@ -0,0 +1,108 @@ +/* variables.h -- data structures for shell variables. */ + +#if !defined (_VARIABLES_H_) +#define _VARIABLES_H_ + +#include "stdc.h" + +/* Shell variables and functions are stored in hash tables. */ +#include "hash.h" + +/* What a shell variable looks like. */ + +typedef struct variable *DYNAMIC_FUNC (); + +typedef struct variable { + char *name; /* Symbol that the user types. */ + char *value; /* Value that is returned. */ + DYNAMIC_FUNC *dynamic_value; /* Function called to return a `dynamic' + value for a variable, like $SECONDS + or $RANDOM. */ + DYNAMIC_FUNC *assign_func; /* Function called when this `special + variable' is assigned a value in + bind_variable. */ + int attributes; /* export, readonly, array, invisible... */ + int context; /* Which context this variable belongs to. */ + struct variable *prev_context; /* Value from previous context or NULL. */ +} SHELL_VAR; + +/* 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 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 function_p(var) ((((var)->attributes) & (att_function))) +#define integer_p(var) ((((var)->attributes) & (att_integer))) +#define imported_p(var) ((((var)->attributes) & (att_imported))) + +#define value_cell(var) ((var)->value) +#define function_cell(var) (COMMAND *)((var)->value) + +/* Stuff for hacking variables. */ +extern int variable_context; +extern HASH_TABLE *shell_variables, *shell_functions; +extern char *dollar_vars[]; +extern char **export_env; +extern char **non_unsettable_vars; + +extern void initialize_shell_variables __P((char **)); + +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 *)); +extern SHELL_VAR **map_over __P((Function *, HASH_TABLE *)); +extern SHELL_VAR **all_shell_variables __P((void)); +extern SHELL_VAR **all_shell_functions __P((void)); +extern SHELL_VAR **all_visible_variables __P((void)); +extern SHELL_VAR **all_visible_functions __P((void)); + +extern char **make_var_array __P((HASH_TABLE *)); +extern char **add_or_supercede __P((char *, char **)); + +extern char *get_string_value __P((char *)); + +extern int assignment __P((char *)); +extern int variable_in_context __P((SHELL_VAR *)); +extern int assign_in_env __P((char *)); +extern int unbind_variable __P((char *)); +extern int makunbound __P((char *, HASH_TABLE *)); +extern int kill_local_variable __P((char *)); +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_function_env __P((void)); +extern void dispose_builtin_env __P((void)); +extern void dispose_used_env_vars __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 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_function __P((SHELL_VAR *)); + +#endif /* !_VARIABLES_H_ */ diff --git a/version.c b/version.c new file mode 100644 index 0000000..8ba1db7 --- /dev/null +++ b/version.c @@ -0,0 +1,26 @@ +/* version.c -- distribution and version numbers. */ + +/* Copyright (C) 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 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 "version.h" + +char *dist_version = DISTVERSION; +int patch_level = PATCHLEVEL; +int build_version = BUILDVERSION; +char *sccs_version = SCCSVERSION; diff --git a/vprint.c b/vprint.c new file mode 100644 index 0000000..9907936 --- /dev/null +++ b/vprint.c @@ -0,0 +1,80 @@ +/* vprint.c -- v[fs]printf() for 4.[23] BSD systems. */ + +/* 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 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 <stdio.h> + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *)0) +# else +# define NULL 0x0 +# endif /* __STDC__ */ +#endif /* !NULL */ + +/* + * Beware! Don't trust the value returned by either of these functions; it + * seems that pre-4.3-tahoe implementations of _doprnt () return the first + * argument, i.e. a char *. + */ +#include <varargs.h> + +int +vfprintf (iop, fmt, ap) + FILE *iop; + char *fmt; + va_list ap; +{ + int len; + char localbuf[BUFSIZ]; + + if (iop->_flag & _IONBF) + { + iop->_flag &= ~_IONBF; + iop->_ptr = iop->_base = localbuf; + len = _doprnt (fmt, ap, iop); + (void) fflush (iop); + iop->_flag |= _IONBF; + iop->_base = NULL; + iop->_bufsiz = 0; + iop->_cnt = 0; + } + else + len = _doprnt (fmt, ap, iop); + return (ferror (iop) ? EOF : len); +} + +/* + * Ditto for vsprintf + */ +int +vsprintf (str, fmt, ap) + char *str, *fmt; + va_list ap; +{ + FILE f; + int len; + + f._flag = _IOWRT|_IOSTRG; + f._ptr = str; + f._cnt = 32767; + len = _doprnt (fmt, ap, &f); + *f._ptr = 0; + return (len); +} @@ -0,0 +1,4205 @@ + +/* A Bison parser, made from ./parse.y + by GNU Bison version 1.25 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define IF 258 +#define THEN 259 +#define ELSE 260 +#define ELIF 261 +#define FI 262 +#define CASE 263 +#define ESAC 264 +#define FOR 265 +#define SELECT 266 +#define WHILE 267 +#define UNTIL 268 +#define DO 269 +#define DONE 270 +#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 + +#line 21 "./parse.y" + +#include <stdio.h> +#include "bashtypes.h" +#include <signal.h> +#include "bashansi.h" +#include "shell.h" +#include "flags.h" +#include "input.h" + +#if defined (READLINE) +# include <readline/readline.h> +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bashhist.h" +# include <readline/history.h> +#endif /* HISTORY */ + +#if defined (JOB_CONTROL) +# include "jobs.h" +#endif /* JOB_CONTROL */ + +#if defined (ALIAS) +# include "alias.h" +#endif /* ALIAS */ + +#if defined (PROMPT_STRING_DECODE) +#include <sys/param.h> +#include <time.h> +#include "maxpath.h" +#endif /* PROMPT_STRING_DECODE */ + +#define YYDEBUG 1 +extern int eof_encountered; +extern int no_line_editing; +extern int current_command_number; +extern int interactive, interactive_shell, login_shell; +extern int posixly_correct; +extern int last_command_exit_value; +extern int interrupt_immediately; +extern char *shell_name, *current_host_name; +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 + +/* **************************************************************** */ +/* */ +/* "Forward" declarations */ +/* */ +/* **************************************************************** */ + +/* 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 int reserved_word_acceptable (); +static int read_token (); + +static void report_syntax_error (); +static void handle_eof_input_unit (); +static void prompt_again (); +static void reset_readline_prompt (); +static void print_prompt (); + +/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ +char *ps1_prompt, *ps2_prompt; + +/* Handle on the current prompt string. Indirectly points through + ps1_ or ps2_prompt. */ +char **prompt_string_pointer = (char **)NULL; +char *current_prompt_string; + +/* 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; + +/* 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; + +/* 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) */ + +/* Either zero or EOF. */ +static int shell_input_line_terminator = 0; + +static REDIRECTEE redir; + +#line 122 "./parse.y" +typedef union { + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; +} YYSTYPE; +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 258 +#define YYFLAG -32768 +#define YYNTBASE 45 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 288 ? yytranslate[x] : 73) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, + 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, 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, 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, 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, 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 +}; + +#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 +}; + +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 +}; + +#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 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +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 +}; +#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 +}; + +static const short yyr2[] = { 0, + 2, 1, 2, 1, 0, 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 +}; + +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 +}; + +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 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, +-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 +}; + +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 +}; + + +#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 +}; + +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 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/local/lib/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 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. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include <alloca.h> +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#include <malloc.h> +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include <malloc.h> + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 196 "/usr/local/lib/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 164 "./parse.y" +{ + /* Case of regular command. Discard the error + safety net,and return the command just parsed. */ + global_command = yyvsp[-1].command; + eof_encountered = 0; + discard_parser_constructs (0); + YYACCEPT; + ; + break;} +case 2: +#line 173 "./parse.y" +{ + /* Case of regular command, but not a very + interesting one. Return a NULL command. */ + global_command = (COMMAND *)NULL; + YYACCEPT; + ; + break;} +case 3: +#line 181 "./parse.y" +{ + /* Error during parsing. Return NULL command. */ + global_command = (COMMAND *)NULL; + eof_encountered = 0; + discard_parser_constructs (1); + if (interactive) + { + YYACCEPT; + } + else + { + YYABORT; + } + ; + break;} +case 4: +#line 196 "./parse.y" +{ + /* Case of EOF seen by itself. Do ignoreeof or + not. */ + global_command = (COMMAND *)NULL; + handle_eof_input_unit (); + YYACCEPT; + ; + break;} +case 5: +#line 206 "./parse.y" +{ yyval.word_list = (WORD_LIST *)NULL; ; + break;} +case 6: +#line 208 "./parse.y" +{ yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-1].word_list); ; + break;} +case 7: +#line 212 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (1, r_output_direction, redir); + ; + break;} +case 8: +#line 217 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (0, r_input_direction, redir); + ; + break;} +case 9: +#line 222 "./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" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (yyvsp[-2].number, r_input_direction, redir); + ; + break;} +case 11: +#line 232 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (1, r_appending_to, redir); + ; + break;} +case 12: +#line 237 "./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" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (0, r_reading_until, redir); + redir_stack[need_here_doc++] = yyval.redirect; + ; + break;} +case 14: +#line 248 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (yyvsp[-2].number, r_reading_until, redir); + redir_stack[need_here_doc++] = yyval.redirect; + ; + break;} +case 15: +#line 254 "./parse.y" +{ + redir.dest = yyvsp[0].number; + yyval.redirect = make_redirection (0, r_duplicating_input, redir); + ; + break;} +case 16: +#line 259 "./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" +{ + redir.dest = yyvsp[0].number; + yyval.redirect = make_redirection (1, r_duplicating_output, redir); + ; + break;} +case 18: +#line 269 "./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" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (0, r_duplicating_input_word, redir); + ; + break;} +case 20: +#line 279 "./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" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (1, r_duplicating_output_word, redir); + ; + break;} +case 22: +#line 289 "./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" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection + (0, r_deblank_reading_until, redir); + redir_stack[need_here_doc++] = yyval.redirect; + ; + break;} +case 24: +#line 301 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection + (yyvsp[-2].number, r_deblank_reading_until, redir); + redir_stack[need_here_doc++] = yyval.redirect; + ; + break;} +case 25: +#line 308 "./parse.y" +{ + redir.dest = 0L; + yyval.redirect = make_redirection (1, r_close_this, redir); + ; + break;} +case 26: +#line 313 "./parse.y" +{ + redir.dest = 0L; + yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); + ; + break;} +case 27: +#line 318 "./parse.y" +{ + redir.dest = 0L; + yyval.redirect = make_redirection (0, r_close_this, redir); + ; + break;} +case 28: +#line 323 "./parse.y" +{ + redir.dest = 0L; + yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); + ; + break;} +case 29: +#line 328 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (1, r_err_and_out, redir); + ; + break;} +case 30: +#line 333 "./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" +{ + 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; + } + ; + break;} +case 32: +#line 354 "./parse.y" +{ + redir.filename = yyvsp[0].word; + yyval.redirect = make_redirection (1, r_output_force, redir); + ; + break;} +case 33: +#line 359 "./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" +{ yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; + break;} +case 35: +#line 368 "./parse.y" +{ yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; + break;} +case 36: +#line 370 "./parse.y" +{ yyval.element.redirect = yyvsp[0].redirect; yyval.element.word = 0; ; + break;} +case 37: +#line 374 "./parse.y" +{ + yyval.redirect = yyvsp[0].redirect; + ; + break;} +case 38: +#line 378 "./parse.y" +{ + register REDIRECT *t = yyvsp[-1].redirect; + + while (t->next) + t = t->next; + t->next = yyvsp[0].redirect; + yyval.redirect = yyvsp[-1].redirect; + ; + break;} +case 39: +#line 389 "./parse.y" +{ yyval.command = make_simple_command (yyvsp[0].element, (COMMAND *)NULL); ; + break;} +case 40: +#line 391 "./parse.y" +{ yyval.command = make_simple_command (yyvsp[0].element, yyvsp[-1].command); ; + break;} +case 41: +#line 395 "./parse.y" +{ yyval.command = clean_simple_command (yyvsp[0].command); ; + break;} +case 42: +#line 397 "./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" +{ + if (yyvsp[-1].command->redirects) + { + register REDIRECT *t; + for (t = yyvsp[-1].command->redirects; t->next; t = t->next) + ; + t->next = yyvsp[0].redirect; + } + else + yyvsp[-1].command->redirects = yyvsp[0].redirect; + yyval.command = yyvsp[-1].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); ; + 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); ; + 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); ; + 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); ; + 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); ; + 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); ; + break;} +case 51: +#line 431 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; + break;} +case 52: +#line 433 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; + break;} +case 53: +#line 435 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; + break;} +case 54: +#line 437 "./parse.y" +{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; + break;} +case 55: +#line 439 "./parse.y" +{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; + break;} +case 56: +#line 441 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +case 57: +#line 443 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +case 58: +#line 445 "./parse.y" +{ yyval.command = yyvsp[0].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" +{ +#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" +{ +#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" +{ +#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" +{ +#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" +{ +#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" +{ +#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 67: +#line 491 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; + 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); ; + break;} +case 69: +#line 497 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; + 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); ; + 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" +{ yyvsp[-1].command->flags |= CMD_WANT_SUBSHELL; yyval.command = yyvsp[-1].command; ; + break;} +case 74: +#line 514 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, (COMMAND *)NULL); ; + break;} +case 75: +#line 516 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-5].command, yyvsp[-3].command, yyvsp[-1].command); ; + break;} +case 76: +#line 518 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[-1].command); ; + break;} +case 77: +#line 523 "./parse.y" +{ yyval.command = make_group_command (yyvsp[-1].command); ; + break;} +case 78: +#line 527 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-2].command, yyvsp[0].command, (COMMAND *)NULL); ; + break;} +case 79: +#line 529 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[0].command); ; + break;} +case 80: +#line 531 "./parse.y" +{ yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, yyvsp[0].command); ; + break;} +case 82: +#line 536 "./parse.y" +{ yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; + break;} +case 83: +#line 540 "./parse.y" +{ yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; + break;} +case 84: +#line 542 "./parse.y" +{ yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; + break;} +case 85: +#line 544 "./parse.y" +{ yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; + break;} +case 86: +#line 546 "./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); ; + break;} +case 93: +#line 565 "./parse.y" +{ yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; + break;} +case 94: +#line 567 "./parse.y" +{ yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-2].word_list); ; + break;} +case 95: +#line 576 "./parse.y" +{ + yyval.command = yyvsp[0].command; + if (need_here_doc) + gather_here_documents (); + ; + break;} +case 98: +#line 586 "./parse.y" +{ + if (yyvsp[-2].command->type == cm_connection) + yyval.command = connect_async_list (yyvsp[-2].command, (COMMAND *)NULL, '&'); + else + yyval.command = command_connect (yyvsp[-2].command, (COMMAND *)NULL, '&'); + ; + break;} +case 100: +#line 597 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; + break;} +case 101: +#line 599 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; + break;} +case 102: +#line 601 "./parse.y" +{ + if (yyvsp[-3].command->type == cm_connection) + yyval.command = connect_async_list (yyvsp[-3].command, yyvsp[0].command, '&'); + else + yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '&'); + ; + break;} +case 103: +#line 608 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; + break;} +case 104: +#line 610 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; + break;} +case 105: +#line 612 "./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" +{ + yyval.command = yyvsp[0].command; + if (need_here_doc) + gather_here_documents (); + ; + break;} +case 113: +#line 642 "./parse.y" +{ + if (yyvsp[-1].command->type == cm_connection) + yyval.command = connect_async_list (yyvsp[-1].command, (COMMAND *)NULL, '&'); + else + yyval.command = command_connect (yyvsp[-1].command, (COMMAND *)NULL, '&'); + if (need_here_doc) + gather_here_documents (); + ; + break;} +case 114: +#line 651 "./parse.y" +{ + yyval.command = yyvsp[-1].command; + if (need_here_doc) + gather_here_documents (); + ; + break;} +case 115: +#line 659 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; + break;} +case 116: +#line 661 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; + break;} +case 117: +#line 663 "./parse.y" +{ + if (yyvsp[-2].command->type == cm_connection) + yyval.command = connect_async_list (yyvsp[-2].command, yyvsp[0].command, '&'); + else + yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, '&'); + ; + break;} +case 118: +#line 670 "./parse.y" +{ yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, ';'); ; + break;} +case 119: +#line 672 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +case 120: +#line 674 "./parse.y" +{ + yyvsp[0].command->flags |= CMD_INVERT_RETURN; + yyval.command = yyvsp[0].command; + ; + break;} +case 121: +#line 682 "./parse.y" +{ yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '|'); ; + break;} +case 122: +#line 684 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 498 "/usr/local/lib/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 686 "./parse.y" + + +/* Initial size to allocate for tokens, and the + amount to grow them by. */ +#define TOKEN_DEFAULT_GROW_SIZE 512 + +/* The token currently being read. */ +static int current_token = 0; + +/* The last read token, or NULL. read_token () uses this for context + checking. */ +static int last_read_token = 0; + +/* The token read prior to last_read_token. */ +static int token_before_that = 0; + +/* 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; + +/* Global var is non-zero when end of file has been reached. */ +int EOF_Reached = 0; + +/* 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 + installed function for getting the next character, makes UNGET the + installed function for un-getting a character, sets the type of stream + (either string or file) from TYPE, and makes LOCATION point to where + the input is coming from. */ + +/* Unconditionally returns end-of-file. */ +return_EOF () +{ + return (EOF); +} + +/* Variable containing the current get and unget functions. + See ./input.h for a clearer description. */ +BASH_INPUT bash_input; + +/* Set all of the fields in BASH_INPUT to NULL. */ +void +initialize_bash_input () +{ + bash_input.type = 0; + bash_input.name = (char *)NULL; + bash_input.location.file = (FILE *)NULL; + bash_input.location.string = (char *)NULL; + bash_input.getter = (Function *)NULL; + bash_input.ungetter = (Function *)NULL; +} + +/* Set the contents of the current bash input stream from + GET, UNGET, TYPE, NAME, and LOCATION. */ +void +init_yy_io (get, unget, type, name, location) + Function *get, *unget; + int type; + char *name; + INPUT_STREAM location; +{ + bash_input.type = type; + FREE (bash_input.name); + + if (name) + bash_input.name = savestring (name); + else + bash_input.name = (char *)NULL; + +#if defined (CRAY) + memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location)); +#else + bash_input.location = location; +#endif + bash_input.getter = get; + bash_input.ungetter = unget; +} + +/* Call this to get the next character of input. */ +yy_getc () +{ + return (*(bash_input.getter)) (); +} + +/* Call this to unget C. That is, to make C the next character + to be read. */ +yy_ungetc (c) + int c; +{ + return (*(bash_input.ungetter)) (c); +} + +#if defined (BUFFERED_INPUT) +int +input_file_descriptor () +{ + switch (bash_input.type) + { + case st_stream: + return (fileno (bash_input.location.file)); + case st_bstream: + return (bash_input.location.buffered_fd); + default: + return (fileno (stdin)); + } +} +#endif /* BUFFERED_INPUT */ + +/* **************************************************************** */ +/* */ +/* Let input be read from readline (). */ +/* */ +/* **************************************************************** */ + +#if defined (READLINE) +char *current_readline_prompt = (char *)NULL; +char *current_readline_line = (char *)NULL; +int current_readline_line_index = 0; + +static int +yy_readline_get () +{ + if (!current_readline_line) + { + SigHandler *old_sigint; + int line_len; + + if (!bash_readline_initialized) + initialize_readline (); + +#if defined (JOB_CONTROL) + if (job_control) + give_terminal_to (shell_pgrp); +#endif /* JOB_CONTROL */ + + if (signal_is_ignored (SIGINT) == 0) + { + old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); + interrupt_immediately++; + } + + if (!current_readline_prompt) + current_readline_line = readline (""); + else + current_readline_line = readline (current_readline_prompt); + + if (signal_is_ignored (SIGINT) == 0) + { + interrupt_immediately--; + set_signal_handler (SIGINT, old_sigint); + } + + /* Reset the prompt to whatever is in the decoded value of + prompt_string_pointer. */ + reset_readline_prompt (); + + current_readline_line_index = 0; + + if (!current_readline_line) + return (EOF); + + 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]) + { + free (current_readline_line); + current_readline_line = (char *)NULL; + return (yy_readline_get ()); + } + else + { + int c = (unsigned char)current_readline_line[current_readline_line_index++]; + return (c); + } +} + +static int +yy_readline_unget (c) +{ + if (current_readline_line_index && current_readline_line) + current_readline_line[--current_readline_line_index] = c; + return (c); +} + +void +with_input_from_stdin () +{ + INPUT_STREAM location; + + if (bash_input.type != st_stdin && stream_on_stack (st_stdin) == 0) + { + location.string = current_readline_line; + init_yy_io (yy_readline_get, yy_readline_unget, + st_stdin, "readline stdin", location); + } +} + +#else /* !READLINE */ + +void +with_input_from_stdin () +{ + with_input_from_stream (stdin, "stdin"); +} +#endif /* !READLINE */ + +/* **************************************************************** */ +/* */ +/* Let input come from STRING. STRING is zero terminated. */ +/* */ +/* **************************************************************** */ + +static int +yy_string_get () +{ + register unsigned char *string; + register int c; + + string = bash_input.location.string; + c = EOF; + + /* If the string doesn't exist, or is empty, EOF found. */ + if (string && *string) + { + c = *string++; + bash_input.location.string = string; + } + return (c); +} + +static int +yy_string_unget (c) + int c; +{ + *(--bash_input.location.string) = c; + return (c); +} + +void +with_input_from_string (string, name) + char *string; + char *name; +{ + INPUT_STREAM location; + + location.string = string; + + init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); +} + +/* **************************************************************** */ +/* */ +/* Let input come from STREAM. */ +/* */ +/* **************************************************************** */ + +static int +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 */ + return (result); +} + +static int +yy_stream_unget (c) + int c; +{ +#if defined (NO_READ_RESTART_ON_SIGNAL) + return (ungetc_with_restart (c, bash_input.location.file)); +#else + return (ungetc (c, bash_input.location.file)); +#endif +} + +void +with_input_from_stream (stream, name) + FILE *stream; + char *name; +{ + INPUT_STREAM location; + + location.file = stream; + init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location); +} + +typedef struct stream_saver { + struct stream_saver *next; + BASH_INPUT bash_input; + int line; +#if defined (BUFFERED_INPUT) + BUFFERED_STREAM *bstream; +#endif /* BUFFERED_INPUT */ +} STREAM_SAVER; + +/* The globally known line number. */ +int line_number = 0; + +STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; + +push_stream () +{ + STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); + + xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT)); + +#if defined (BUFFERED_INPUT) + saver->bstream = (BUFFERED_STREAM *)NULL; + /* If we have a buffered stream, clear out buffers[fd]. */ + if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) + { + saver->bstream = buffers[bash_input.location.buffered_fd]; + buffers[bash_input.location.buffered_fd] = (BUFFERED_STREAM *)NULL; + } +#endif /* BUFFERED_INPUT */ + + saver->line = line_number; + bash_input.name = (char *)NULL; + saver->next = stream_list; + stream_list = saver; + EOF_Reached = line_number = 0; +} + +pop_stream () +{ + int temp; + + if (!stream_list) + EOF_Reached = 1; + else + { + STREAM_SAVER *saver = stream_list; + + EOF_Reached = 0; + stream_list = stream_list->next; + + init_yy_io (saver->bash_input.getter, + saver->bash_input.ungetter, + saver->bash_input.type, + saver->bash_input.name, + saver->bash_input.location); + +#if defined (BUFFERED_INPUT) + /* If we have a buffered stream, restore buffers[fd]. */ + /* If the input file descriptor was changed while this was on the + save stack, update the buffered fd to the new file descriptor and + re-establish the buffer <-> bash_input fd correspondence. */ + if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) + { + if (bash_input_fd_changed) + { + bash_input_fd_changed = 0; + if (default_buffered_input >= 0) + { + bash_input.location.buffered_fd = default_buffered_input; + saver->bstream->b_fd = default_buffered_input; + } + } + buffers[bash_input.location.buffered_fd] = saver->bstream; + } +#endif /* BUFFERED_INPUT */ + + line_number = saver->line; + + FREE (saver->bash_input.name); + free (saver); + } +} + +/* Return 1 if a stream of type TYPE is saved on the stack. */ +int +stream_on_stack (type) + int 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: + * 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) +/* + * 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 + * implement alias expansion on a per-token basis. + */ + +typedef struct string_saver { + struct string_saver *next; + int expand_alias; /* Value to set expand_alias to when string is popped. */ + char *saved_line; + 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 + * the value of expand_next_token when the string is popped, so that the + * word after the alias in the original line is handled correctly when the + * alias expands to multiple words. TOKEN is the token that was expanded + * into S; it is saved and used to prevent infinite recursive expansion. + */ +static void +push_string (s, expand, token) + char *s; + int expand; + char *token; +{ + STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER)); + + temp->expand_alias = expand; + temp->saved_line = shell_input_line; + 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->next = pushed_string_list; + pushed_string_list = temp; + + save_expansion (token); + + shell_input_line = s; + shell_input_line_size = strlen (s); + shell_input_line_index = 0; + shell_input_line_terminator = '\0'; + expand_next_token = 0; +} + +/* + * Make the top of the pushed_string stack be the current shell input. + * Only called when there is something on the stack. Called from shell_getc + * when it thinks it has consumed the string generated by an alias expansion + * and needs to return to the original input line. + */ +static void +pop_string () +{ + STRING_SAVER *t; + + FREE (shell_input_line); + shell_input_line = pushed_string_list->saved_line; + 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; + pushed_string_list = pushed_string_list->next; + free((char *)t); +} + +static void +free_string_list () +{ + register STRING_SAVER *t = pushed_string_list, *t1; + + while (t) + { + t1 = t->next; + FREE (t->saved_line); + 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 \<newline> pairs. This is used by + read_secondary_line to read here documents. */ +static char * +read_a_line (remove_quoted_newline) + int remove_quoted_newline; +{ + static char *line_buffer = (char *)NULL; + static int buffer_size = 0; + int indx = 0, c, peekc, pass_next; + + pass_next = 0; + while (1) + { + c = yy_getc (); + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + if (c == 0) + continue; + + /* If there is no more input, then we return NULL. */ + if (c == EOF) + { + 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); + + /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a + here document with an unquoted delimiter. In this case, + the line will be expanded as if it were in double quotes. + We allow a backslash to escape the next character, but we + need to treat the backslash specially only if a backslash + quoting a backslash-newline pair appears in the line. */ + if (pass_next) + { + line_buffer[indx++] = c; + pass_next = 0; + } + else if (c == '\\' && remove_quoted_newline) + { + peekc = yy_getc (); + if (peekc == '\n') + continue; /* Make the unquoted \<newline> pair disappear. */ + else + { + yy_ungetc (peekc); + pass_next = 1; + line_buffer[indx++] = c; /* Preserve the backslash. */ + } + } + else + line_buffer[indx++] = c; + + if (c == '\n') + { + line_buffer[indx] = '\0'; + return (line_buffer); + } + } +} + +/* Return a line as in read_a_line (), but insure that the prompt is + the secondary prompt. This is used to read the lines of a here + document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove + newlines quoted with backslashes while reading the line. It is + non-zero unless the delimiter of the here document was quoted. */ +char * +read_secondary_line (remove_quoted_newline) + int remove_quoted_newline; +{ + prompt_string_pointer = &ps2_prompt; + prompt_again (); + return (read_a_line (remove_quoted_newline)); +} + + +/* **************************************************************** */ +/* */ +/* YYLEX () */ +/* */ +/* **************************************************************** */ + +/* Reserved words. These are only recognized as the first word of a + command. */ +STRING_INT_ALIST word_token_alist[] = { + { "if", IF }, + { "then", THEN }, + { "else", ELSE }, + { "elif", ELIF }, + { "fi", FI }, + { "case", CASE }, + { "esac", ESAC }, + { "for", FOR }, +#if defined (SELECT_COMMAND) + { "select", SELECT }, +#endif + { "while", WHILE }, + { "until", UNTIL }, + { "do", DO }, + { "done", DONE }, + { "in", IN }, + { "function", FUNCTION }, + { "{", '{' }, + { "}", '}' }, + { "!", BANG }, + { (char *)NULL, 0} +}; + +/* 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; +{ + int c; + + QUIT; + +#if defined (ALIAS) + /* If shell_input_line[shell_input_line_index] == 0, but there is + something on the pushed list of strings, then we don't want to go + off and get another line. We let the code down below handle it. */ + + if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && + (pushed_string_list == (STRING_SAVER *)NULL))) +#else /* !ALIAS */ + 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: + + /* Allow immediate exit if interrupted during input. */ + QUIT; + + i = 0; + shell_input_line_terminator = 0; + +#if defined (JOB_CONTROL) + /* This can cause a problem when reading a command as the result + of a trap, when the trap is called from flush_child. This call + had better not cause jobs to disappear from the job table in + that case, or we will have big trouble. */ + notify_and_cleanup (); +#else /* !JOB_CONTROL */ + cleanup_dead_jobs (); +#endif /* !JOB_CONTROL */ + +#if defined (READLINE) + if (interactive && bash_input.type != st_string && no_line_editing) +#else + if (interactive && bash_input.type != st_string) +#endif + print_prompt (); + + if (bash_input.type == st_stream) + clearerr (stdin); + + while (c = yy_getc ()) + { + /* 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); + + if (c == EOF) + { + if (bash_input.type == st_stream) + clearerr (stdin); + + if (!i) + shell_input_line_terminator = EOF; + + shell_input_line[i] = '\0'; + break; + } + + shell_input_line[i++] = c; + + if (c == '\n') + { + shell_input_line[--i] = '\0'; + current_command_line_count++; + break; + } + } + shell_input_line_index = 0; + shell_input_line_len = i; /* == strlen (shell_input_line) */ + +#if defined (HISTORY) + if (interactive && shell_input_line && shell_input_line[0]) + { + char *expansions; + + expansions = pre_process_line (shell_input_line, 1, 1); + + free (shell_input_line); + shell_input_line = expansions; + shell_input_line_len = shell_input_line ? + strlen (shell_input_line) : + 0; + if (!shell_input_line_len) + current_command_line_count--; + + /* We have to force the xrealloc below because we don't know the + true allocated size of shell_input_line anymore. */ + shell_input_line_size = shell_input_line_len; + } +#endif /* HISTORY */ + + if (shell_input_line) + { + /* Lines that signify the end of the shell's input should not be + echoed. */ + if (echo_input_at_read && (shell_input_line[0] || + shell_input_line_terminator != EOF)) + fprintf (stderr, "%s\n", shell_input_line); + } + else + { + shell_input_line_size = 0; + prompt_string_pointer = ¤t_prompt_string; + prompt_again (); + goto restart_read; + } + + /* Add the newline to the end of this string, iff the string does + 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) + shell_input_line = xrealloc (shell_input_line, + 1 + (shell_input_line_size += 2)); + + shell_input_line[l] = '\n'; + shell_input_line[l + 1] = '\0'; + } + } + + c = shell_input_line[shell_input_line_index]; + + if (c) + shell_input_line_index++; + + if (c == '\\' && remove_quoted_newline && + shell_input_line[shell_input_line_index] == '\n') + { + prompt_again (); + goto restart_read_next_line; + } + +#if defined (ALIAS) + /* If C is NULL, we have reached the end of the current input string. If + pushed_string_list is non-empty, it's time to pop to the previous string + because we have fully consumed the result of the last alias expansion. + Do it transparently; just return the next character of the string popped + 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++; + } +#endif /* ALIAS */ + + if (!c && shell_input_line_terminator == EOF) + { + if (shell_input_line_index != 0) + return ('\n'); + else + return (EOF); + } + + return ((unsigned char)c); +} + +/* Put C back into the input for the shell. */ +static void +shell_ungetc (c) + int c; +{ + if (shell_input_line && shell_input_line_index) + shell_input_line[--shell_input_line_index] = c; +} + +/* Discard input until CHARACTER is seen. */ +static void +discard_until (character) + int character; +{ + int c; + + while ((c = shell_getc (0)) != EOF && c != 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) + char *command; +{ + Function *temp_last, *temp_this; + char *last_lastarg; + int temp_exit_value, temp_eof_encountered; + + temp_last = last_shell_builtin; + temp_this = this_shell_builtin; + temp_exit_value = last_command_exit_value; + temp_eof_encountered = eof_encountered; + last_lastarg = get_string_value ("_"); + if (last_lastarg) + last_lastarg = savestring (last_lastarg); + + parse_and_execute (savestring (command), "PROMPT_COMMAND", 0); + + last_shell_builtin = temp_last; + this_shell_builtin = temp_this; + last_command_exit_value = temp_exit_value; + eof_encountered = temp_eof_encountered; + + bind_variable ("_", last_lastarg); + FREE (last_lastarg); + + if (token_to_read == '\n') + token_to_read = 0; +} + +/* Command to read_token () explaining what we want it to do. */ +#define READ 0 +#define RESET 1 +#define prompt_is_ps1 \ + (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt) + +/* Function for yyparse to call. yylex keeps track of + the last two tokens read, and calls read_token. */ + +yylex () +{ + if (interactive && (!current_token || 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 + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ + if (prompt_is_ps1 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); + } + + /* Avoid printing a prompt if we're not going to read anything, e.g. + after resetting the parser with read_token (RESET). */ + if (token_to_read == 0 && interactive) + prompt_again (); + } + + 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; + +void +gather_here_documents () +{ + int r = 0; + while (need_here_doc) + { + make_here_document (redir_stack[r++]); + need_here_doc--; + } +} + +/* 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; + +#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) + +/* Check to see if TOKEN is a reserved word and return the token + value if it is. */ +#define CHECK_FOR_RESERVED_WORD(tok) \ + do { \ + if (!dollar_present && !quoted && \ + reserved_word_acceptable (last_read_token)) \ + { \ + int i; \ + 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)) \ + 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--; \ +\ + 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; +{ + 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. */ + + if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + { + FREE (token); + token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + } + + if (command == RESET) + { + delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_awaiting_satisfaction = 0; + in_case_pattern_list = 0; + +#if defined (ALIAS) + if (pushed_string_list) + { + free_string_list (); + pushed_string_list = (STRING_SAVER *)NULL; + } + + if (expanded_token_stack) + { + free_expansion_stack (); + expanded_token_stack = (EXPANSION_SAVER *)NULL; + } + + expand_next_token = 0; +#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'; + return ('\n'); + } + + if (token_to_read) + { + int rt = token_to_read; + token_to_read = 0; + return (rt); + } + +#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)); + + if (character == EOF) + { + EOF_Reached = 1; + return (yacc_EOF); + } + + if (character == '#' && (!interactive || interactive_comments)) + { + /* 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'); + } + + if (character == '\n') + { + /* If we're about to return an unquoted newline, we can go and collect + the text of any pending here document. */ + if (need_here_doc) + gather_here_documents (); + +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + + return (character); + } + + if (member (character, "()<>;&|")) + { +#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; +#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))) + { + switch (character) + { + /* 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); + else + { + shell_ungetc (peek_char); + return (LESS_LESS); + } + + case '>': + return (GREATER_GREATER); + + case ';': + in_case_pattern_list = 1; +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + return (SEMI_SEMI); + + case '&': + return (AND_AND); + + case '|': + return (OR_OR); + } + } + else + { + if (peek_char == '&') + { + switch (character) + { + case '<': return (LESS_AND); + case '>': return (GREATER_AND); + } + } + if (character == '<' && peek_char == '>') + return (LESS_GREATER); + if (character == '>' && peek_char == '|') + return (GREATER_BAR); + 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) + { + allow_open_brace = 1; +#if defined (ALIAS) + expand_next_token = 0; +#endif /* ALIAS */ + } + + if (in_case_pattern_list && (character == ')')) + in_case_pattern_list = 0; + +#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)) +#endif /* PROCESS_SUBSTITUTION */ + return (character); + } + + /* Hack <&- (close stdin) case. */ + if (character == '-') + { + switch (last_read_token) + { + case LESS_AND: + case 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; + + /* 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; + + /* 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; + + /* Non-zero means parsing a `${' construct. It is the count of + un-quoted `}' we need to see. */ + int dollar_brace_level = 0; + + /* A level variable for parsing '${ ... }' constructs inside of double + quotes. */ + int delimited_brace_level = 0; + + /* 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; + + /* Another level variable. This one is for dollar_parens inside of + double-quotes. */ + int delimited_paren_level = 0; + + /* The current delimiting character. */ + int cd; + + for (;;) + { + if (character == EOF) + goto got_token; + + if (pass_next_character) + { + pass_next_character = 0; + goto got_character; + } + + cd = current_delimiter (); + + 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 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; + } + } + + 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++; + + pass_next_character++; + goto got_character; + } + else if (peek_char == '[' && character == '$') + { + if (!delimiter_depth) + dollar_bracket_level++; + + pass_next_character++; + goto got_character; + } + /* This handles ${...} constructs. */ + else if (peek_char == '{' && character == '$') + { + if (!delimiter_depth) + dollar_brace_level++; + else + delimited_brace_level++; + + pass_next_character++; + goto got_character; + } + } + + /* 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 (!delimiter_depth && dollar_paren_level) + dollar_paren_level++; + } + + if (character == '[') + { + if (!delimiter_depth && dollar_bracket_level) + dollar_bracket_level++; + } + + if (character == '{' && !embedded_quoted_string) + { + if (delimiter_depth && delimited_brace_level) + delimited_brace_level++; + + if (!delimiter_depth && dollar_brace_level) + dollar_brace_level++; + } + + /* 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--; + + if (!delimiter_depth && dollar_paren_level) + { + dollar_paren_level--; + goto got_character; + } + } + + if (character == ']') + { + if (!delimiter_depth && dollar_bracket_level) + { + dollar_bracket_level--; + goto got_character; + } + } + + if (character == '}' && !embedded_quoted_string) + { + if (delimiter_depth && delimited_brace_level) + delimited_brace_level--; + + if (!delimiter_depth && dollar_brace_level) + { + dollar_brace_level--; + goto got_character; + } + } + } + + 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); + + quoted = 1; + goto got_character; + } + } + + if (all_digits) + all_digits = digit (character); + if (character == '$') + dollar_present = 1; + + got_character: + + if (character == CTLESC || character == CTLNUL) + token[token_index++] = CTLESC; + + token[token_index++] = character; + + 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 (); + + /* We want to remove quoted newlines (that is, a \<newline> 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_token: + + token[token_index] = '\0'; + + if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) && + character == EOF) + { + char reporter = '\0'; + + if (!delimiter_depth) + { + if (dollar_paren_level) + reporter = ')'; + else if (dollar_bracket_level) + reporter = ']'; + } + + if (!reporter) + reporter = current_delimiter (); + + report_error ("unexpected EOF while looking for `%c'", reporter); + return (-1); + } + + 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); + } + } + + /* 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); + } + + /* 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); + } + } + + /* Ditto for `{' in the FUNCTION case. */ + if (allow_open_brace) + { + allow_open_brace = 0; + if (token[0] == '{' && !token[1]) + { + open_brace_awaiting_satisfaction++; + return ('{'); + } + } + + if (posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + +#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 (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; + + if (expanded_token_stack && token_has_been_expanded (token)) + goto no_expansion; + + expanded = alias_expand_word (token); + if (expanded) + { + int len = strlen (expanded), expand_next; + + /* Erase the current token. */ + token_index = 0; + + expand_next = (expanded[len - 1] == ' ') || + (expanded[len - 1] == '\t'); + + 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 (!posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* 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 ('}'); + } + + 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); +} + +/* Return 1 if TOKEN is a token that after being read would allow + a reserved word to be seen, else 0. */ +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 == DO || + token == ELIF || + token == ELSE || + token == FI || + token == IF || + token == OR_OR || + token == SEMI_SEMI || + token == THEN || + token == UNTIL || + token == WHILE || + token == DONE || /* XXX these two are experimental */ + token == ESAC || + token == 0) + return (1); + else + return (0); +} + +/* Return the index of TOKEN in the alist of reserved words, or -1 if + TOKEN is not a shell reserved word. */ +int +find_reserved_word (token) + char *token; +{ + int i; + for (i = 0; word_token_alist[i].word != (char *)NULL; i++) + if (STREQ (token, word_token_alist[i].word)) + return i; + return -1; +} + +#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 + variable. */ +static void +reset_readline_prompt () +{ + if (prompt_string_pointer) + { + char *temp_prompt; + + temp_prompt = *prompt_string_pointer + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = xmalloc (1); + temp_prompt[0] = '\0'; + } + + FREE (current_readline_prompt); + + current_readline_prompt = temp_prompt; + } +} +#endif /* READLINE */ + +#if defined (HISTORY) +/* A list of tokens which can be followed by newlines, but not by + semi-colons. When concatenating multiple lines of history, the + 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, + 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. */ +char * +history_delimiting_chars () +{ + if (!delimiter_depth) + { + register int i; + + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); + } + return ("; "); + } + else + return ("\n"); +} +#endif /* HISTORY */ + +/* Issue a prompt, or prepare to issue a prompt when the next character + is read. */ +static void +prompt_again () +{ + char *temp_prompt; + + if (!interactive) /* XXX */ + return; + + ps1_prompt = get_string_value ("PS1"); + ps2_prompt = get_string_value ("PS2"); + + if (!prompt_string_pointer) + prompt_string_pointer = &ps1_prompt; + + temp_prompt = (*prompt_string_pointer) + ? decode_prompt_string (*prompt_string_pointer) + : (char *)NULL; + + if (temp_prompt == 0) + { + temp_prompt = xmalloc (1); + temp_prompt[0] = '\0'; + } + + current_prompt_string = *prompt_string_pointer; + prompt_string_pointer = &ps2_prompt; + +#if defined (READLINE) + if (!no_line_editing) + { + FREE (current_readline_prompt); + current_readline_prompt = temp_prompt; + } + else +#endif /* READLINE */ + { + FREE (current_decoded_prompt); + current_decoded_prompt = temp_prompt; + } +} + +static void +print_prompt () +{ + fprintf (stderr, "%s", current_decoded_prompt); + fflush (stderr); +} + +/* 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 + \n CRLF + \s the name of the shell + \w the current working directory + \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 + \<octal> character code in octal + \\ a backslash +*/ +#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; + +#if defined (PROMPT_STRING_DECODE) + + result = xmalloc (PROMPT_GROWTH); + result[0] = 0; + + while (c = *string++) + { + if (posixly_correct && c == '!') + { + if (*string == '!') + { + temp = savestring ("!"); + goto add_string; + } + else + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (history_number ()); +#endif /* HISTORY */ + string--; /* add_string increments string again. */ + goto add_string; + } + } + if (c == '\\') + { + c = *string; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char octal_string[4]; + int n; + + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; + + 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'; + } + + c = 0; + goto add_string; + } + + case 't': + case 'd': + /* Make the current time/date into a string. */ + { + time_t the_time = time (0); + char *ttemp = ctime (&the_time); + temp = savestring (ttemp); + + if (c == 't') + { + strcpy (temp, temp + 11); + temp[8] = '\0'; + } + else + temp[10] = '\0'; + + goto add_string; + } + + case 'n': + if (!no_line_editing) + temp = savestring ("\r\n"); + else + temp = savestring ("\n"); + goto add_string; + + case 's': + { + temp = base_pathname (shell_name); + temp = savestring (temp); + 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]; + + temp = get_string_value ("PWD"); + + if (!temp) + getwd (t_string); + 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); + } + else + temp = savestring (polite_directory_format (t_string)); + goto add_string; + } + + case 'u': + { + 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 '#': + { + temp = itos (current_command_number); + goto add_string; + } + + case '!': + { +#if !defined (HISTORY) + temp = savestring ("1"); +#else /* HISTORY */ + temp = itos (history_number ()); +#endif /* HISTORY */ + goto add_string; + } + + case '$': + temp = savestring (geteuid () == 0 ? "#" : "$"); + goto add_string; + +#if defined (READLINE) + case '[': + case ']': + temp = xmalloc(3); + temp[0] = '\001'; + temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; + temp[2] = '\0'; + goto add_string; +#endif + + case '\\': + temp = savestring ("\\"); + goto add_string; + + default: + temp = savestring ("\\ "); + temp[1] = c; + + add_string: + if (c) + string++; + result = + sub_append_string (temp, result, &result_index, &result_size); + temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + result[result_index] = '\0'; + break; + } + } + else + { + while (3 + result_index > result_size) + result = xrealloc (result, result_size += PROMPT_GROWTH); + + result[result_index++] = c; + result[result_index] = '\0'; + } + } +#else /* !PROMPT_STRING_DECODE */ + result = savestring (string); +#endif /* !PROMPT_STRING_DECODE */ + + /* 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); + + return (result); +} + +/* Report a syntax error, and restart the parser. Call here for fatal + errors. */ +yyerror () +{ + report_syntax_error ((char *)NULL); + reset_parser (); +} + +/* Report a syntax error with line numbers, etc. + Call here for recoverable errors. If you have a message to print, + then place it in MESSAGE, otherwise pass NULL and this will figure + out an appropriate message for you. */ +static void +report_syntax_error (message) + char *message; +{ + 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); + } + + last_command_exit_value = EX_USAGE; + return; + } + + if (shell_input_line && *shell_input_line) + { + char *t = shell_input_line; + register int i = shell_input_line_index; + int token_end = 0; + + if (!t[i] && i) + i--; + + while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n')) + i--; + + if (i) + token_end = i + 1; + + while (i && !member (t[i], " \n\t;|&")) + i--; + + while (i != token_end && member (t[i], " \t\n")) + i++; + + if (token_end) + { + char *error_token; + error_token = xmalloc (1 + (token_end - i)); + strncpy (error_token, t + i, token_end - i); + error_token[token_end - i] = '\0'; + + 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'; + + report_error ("syntax error near unexpected token `%s'", etoken); + } + + if (!interactive) + { + 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'; + + report_error ("%s: line %d: `%s'", name, line_number, temp); + free (temp); + } + } + 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); + } + } + last_command_exit_value = EX_USAGE; +} + +/* ??? Needed function. ??? We have to be able to discard the constructs + created during parsing. In the case of error, we want to return + 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. */ +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. */ +int ignoreeof = 0; + +/* The number of times that we have encountered an EOF character without + another character intervening. When this gets above the limit, the + shell terminates. */ +int eof_encountered = 0; + +/* The limit for eof_encountered. */ +int eof_encountered_limit = 10; + +/* If we have EOF as the only input unit, this user wants to leave + the shell. If the shell is not interactive, then just leave. + Otherwise, if ignoreeof is set, and we haven't done this the + required number of times in a row, print a message. */ +static void +handle_eof_input_unit () +{ + if (interactive) + { + /* shell.c may use this to decide whether or not to write out the + history, among other things. We use it only for error reporting + in this file. */ + if (EOF_Reached) + EOF_Reached = 0; + + /* If the user wants to "ignore" eof, then let her do so, kind of. */ + if (ignoreeof) + { + if (eof_encountered < eof_encountered_limit) + { + fprintf (stderr, "Use \"%s\" to leave the shell.\n", + login_shell ? "logout" : "exit"); + eof_encountered++; + /* Reset the prompt string to be $PS1. */ + prompt_string_pointer = (char **)NULL; + prompt_again (); + last_read_token = current_token = '\n'; + return; + } + } + + /* In this case EOF should exit the shell. Do it now. */ + reset_parser (); + exit_builtin ((WORD_LIST *)NULL); + } + else + { + /* We don't write history files, etc., for non-interactive shells. */ + EOF_Reached = 1; + } +} @@ -0,0 +1,43 @@ +typedef union { + WORD_DESC *word; /* the word that we read. */ + int number; /* the number that we read. */ + WORD_LIST *word_list; + COMMAND *command; + REDIRECT *redirect; + ELEMENT element; + PATTERN_LIST *pattern; +} YYSTYPE; +#define IF 258 +#define THEN 259 +#define ELSE 260 +#define ELIF 261 +#define FI 262 +#define CASE 263 +#define ESAC 264 +#define FOR 265 +#define SELECT 266 +#define WHILE 267 +#define UNTIL 268 +#define DO 269 +#define DONE 270 +#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 + + +extern YYSTYPE yylval; |