From 726f63884db0132f01745f1fb4465e6621088ccf Mon Sep 17 00:00:00 2001 From: Jari Aalto Date: Mon, 26 Aug 1996 18:22:31 +0000 Subject: [PATCH] Imported from ../bash-1.14.7.tar.gz. --- .distribution | 1 + .patchlevel | 1 + COPYING | 257 ++ CWRU/PLATFORMS | 18 + CWRU/POSIX.NOTES | 63 + CWRU/README | 26 + CWRU/changelog | 786 +++++ CWRU/misc/aux-mach-desc | 20 + CWRU/misc/bison | 7 + CWRU/misc/open-files.c | 16 + CWRU/misc/pid.c | 7 + CWRU/misc/sigs.c | 27 + CWRU/misc/sigstat.c | 206 ++ CWRU/sh-redir-hack | 15 + INSTALL | 212 ++ MANIFEST | 421 +++ Makefile | 115 + NEWS | 10 + README | 52 + RELEASE | 269 ++ alias.c | 535 ++++ alias.h | 75 + ansi_stdlib.h | 41 + bashansi.h | 36 + bashhist.c | 390 +++ bashhist.h | 42 + bashline.c | 1797 ++++++++++++ bashtypes.h | 34 + bracecomp.c | 166 ++ braces.c | 371 +++ builtins.h | 45 + builtins/ChangeLog | 0 builtins/Makefile | 267 ++ builtins/alias.def | 180 ++ builtins/bashgetopt.c | 136 + builtins/bashgetopt.h | 37 + builtins/bind.def | 219 ++ builtins/break.def | 110 + builtins/builtin.def | 67 + builtins/cd.def | 689 +++++ builtins/colon.def | 37 + builtins/command.def | 177 ++ builtins/common.c | 829 ++++++ builtins/common.h | 69 + builtins/declare.def | 290 ++ builtins/echo.def | 168 ++ builtins/enable.def | 156 + builtins/eval.def | 45 + builtins/exec.def | 163 ++ builtins/exit.def | 129 + builtins/fc.def | 691 +++++ builtins/fg_bg.def | 145 + builtins/getopt.c | 283 ++ builtins/getopt.h | 57 + builtins/getopts.def | 300 ++ builtins/hash.def | 222 ++ builtins/hashcom.h | 32 + builtins/help.def | 134 + builtins/history.def | 179 ++ builtins/inlib.def | 74 + builtins/jobs.def | 171 ++ builtins/kill.def | 281 ++ builtins/let.def | 77 + builtins/mkbuiltins.c | 1311 +++++++++ builtins/psize.c | 63 + builtins/psize.sh | 24 + builtins/read.def | 276 ++ builtins/reserved.def | 154 + builtins/return.def | 57 + builtins/set.def | 528 ++++ builtins/setattr.def | 253 ++ builtins/shift.def | 95 + builtins/source.def | 186 ++ builtins/suspend.def | 86 + builtins/test.def | 144 + builtins/times.def | 89 + builtins/trap.def | 204 ++ builtins/type.def | 325 +++ builtins/ulimit.def | 731 +++++ builtins/umask.def | 288 ++ builtins/wait.def | 132 + command.h | 215 ++ config.h | 186 ++ config.h.mini | 194 ++ configure | 8 + copy_cmd.c | 305 ++ cpp-Makefile | 1553 ++++++++++ dispose_cmd.c | 207 ++ dispose_cmd.h | 32 + documentation/FAQ | 795 ++++++ documentation/Makefile | 103 + documentation/README | 32 + documentation/article.ms | 1114 ++++++++ documentation/article.ps | 1368 +++++++++ documentation/article.txt | 1111 ++++++++ documentation/bash.1 | 5371 +++++++++++++++++++++++++++++++++++ documentation/bash.ps | 3959 ++++++++++++++++++++++++++ documentation/bash.txt | 3960 ++++++++++++++++++++++++++ documentation/builtins.1 | 15 + documentation/builtins.ps | 1367 +++++++++ documentation/builtins.txt | 1188 ++++++++ documentation/features.dvi | Bin 0 -> 191364 bytes documentation/features.info | 3011 ++++++++++++++++++++ documentation/features.ps | 3825 +++++++++++++++++++++++++ documentation/features.texi | 1907 +++++++++++++ documentation/readline.3 | 1216 ++++++++ documentation/readline.ps | 1052 +++++++ documentation/readline.txt | 1122 ++++++++ documentation/texinfo.tex | 4003 ++++++++++++++++++++++++++ endian.c | 148 + error.c | 244 ++ error.h | 34 + examples/alias-conv.sh | 22 + examples/functions/autoload | 103 + examples/functions/basename | 23 + examples/functions/csh-compat | 36 + examples/functions/dirfuncs | 142 + examples/functions/dirname | 21 + examples/functions/exitstat | 22 + examples/functions/external | 50 + examples/functions/fact | 13 + examples/functions/fstty | 59 + examples/functions/func | 27 + examples/functions/jj.bash | 12 + examples/functions/kshenv | 183 ++ examples/functions/manpage | 129 + examples/functions/notify.bash | 58 + examples/functions/shcat | 7 + examples/functions/substr | 79 + examples/functions/substr2 | 81 + examples/functions/term | 35 + examples/functions/whatis | 52 + examples/functions/whence | 59 + examples/scripts/adventure.sh | 545 ++++ examples/scripts/bcsh.sh | 1254 ++++++++ examples/scripts/precedence | 75 + examples/scripts/shprompt | 137 + examples/startup-files/Bash_aliases | 63 + examples/startup-files/Bash_profile | 20 + examples/startup-files/Bashrc | 72 + examples/startup-files/bash-profile | 54 + examples/startup-files/bashrc | 139 + examples/suncmd.termcap | 30 + execute_cmd.c | 3698 ++++++++++++++++++++++++ execute_cmd.h | 47 + expr.c | 902 ++++++ externs.h | 67 + filecntl.h | 36 + flags.c | 270 ++ flags.h | 65 + general.c | 1273 +++++++++ general.h | 247 ++ getcwd.c | 344 +++ hash.c | 297 ++ hash.h | 61 + input.c | 464 +++ input.h | 115 + jobs.c | 2755 ++++++++++++++++++ jobs.h | 345 +++ lib/doc-support/Makefile | 23 + lib/doc-support/getopt.h | 129 + lib/doc-support/texindex.c | 1666 +++++++++++ lib/glob/ChangeLog | 13 + lib/glob/Makefile | 95 + lib/glob/doc/Makefile | 5 + lib/glob/doc/glob.texi | 1 + lib/glob/fnmatch.c | 189 ++ lib/glob/fnmatch.h | 36 + lib/glob/glob.c | 574 ++++ lib/glob/ndir.h | 50 + lib/malloc/Makefile | 28 + lib/malloc/alloca.c | 480 ++++ lib/malloc/getpagesize.h | 49 + lib/malloc/i386-alloca.s | 16 + lib/malloc/malloc.c | 668 +++++ lib/malloc/x386-alloca.s | 63 + lib/malloc/xmalloc.c | 78 + lib/malloclib/Makefile | 53 + lib/malloclib/alloca.c | 189 ++ lib/malloclib/calloc.c | 39 + lib/malloclib/cfree.c | 43 + lib/malloclib/free.c | 212 ++ lib/malloclib/getpagesize.h | 56 + lib/malloclib/i386-alloca.s | 16 + lib/malloclib/malloc.c | 324 +++ lib/malloclib/malloc.h | 268 ++ lib/malloclib/mcheck.c | 133 + lib/malloclib/memalign.c | 61 + lib/malloclib/morecore.c | 44 + lib/malloclib/mstats.c | 39 + lib/malloclib/mtrace.awk | 36 + lib/malloclib/mtrace.c | 150 + lib/malloclib/realloc.c | 146 + lib/malloclib/valloc.c | 48 + lib/malloclib/x386-alloca.s | 63 + lib/malloclib/xmalloc.c | 69 + lib/posixheaders/ansi_stdlib.h | 41 + lib/posixheaders/filecntl.h | 36 + lib/posixheaders/memalloc.h | 56 + lib/posixheaders/posixstat.h | 149 + lib/posixheaders/stdc.h | 78 + lib/readline/COPYING | 257 ++ lib/readline/ChangeLog | 403 +++ lib/readline/Makefile | 134 + lib/readline/README | 6 + lib/readline/STANDALONE | 31 + lib/readline/ansi_stdlib.h | 41 + lib/readline/bind.c | 1487 ++++++++++ lib/readline/chardefs.h | 122 + lib/readline/complete.c | 1459 ++++++++++ lib/readline/display.c | 1276 +++++++++ lib/readline/doc/Makefile | 55 + lib/readline/doc/hist.texinfo | 113 + lib/readline/doc/history.dvi | Bin 0 -> 47376 bytes lib/readline/doc/history.info | 744 +++++ lib/readline/doc/history.ps | 2037 +++++++++++++ lib/readline/doc/hstech.texinfo | 489 ++++ lib/readline/doc/hsuser.texinfo | 198 ++ lib/readline/doc/readline.dvi | Bin 0 -> 154240 bytes lib/readline/doc/readline.info | 744 +++++ lib/readline/doc/readline.ps | 2037 +++++++++++++ lib/readline/doc/rlman.texinfo | 111 + lib/readline/doc/rltech.texinfo | 1406 +++++++++ lib/readline/doc/rluser.texinfo | 875 ++++++ lib/readline/doc/texindex.c | 1666 +++++++++++ lib/readline/emacs_keymap.c | 885 ++++++ lib/readline/examples/Inputrc | 65 + lib/readline/examples/Makefile | 12 + lib/readline/examples/fileman.c | 425 +++ lib/readline/examples/histexamp.c | 82 + lib/readline/examples/manexamp.c | 94 + lib/readline/funmap.c | 299 ++ lib/readline/history.c | 2218 +++++++++++++++ lib/readline/history.h | 181 ++ lib/readline/isearch.c | 378 +++ lib/readline/keymaps.c | 200 ++ lib/readline/keymaps.h | 95 + lib/readline/memalloc.h | 56 + lib/readline/parens.c | 130 + lib/readline/posixstat.h | 149 + lib/readline/readline.c | 3539 +++++++++++++++++++++++ lib/readline/readline.h | 289 ++ lib/readline/rlconf.h | 57 + lib/readline/rldefs.h | 212 ++ lib/readline/rltty.c | 705 +++++ lib/readline/search.c | 370 +++ lib/readline/signals.c | 287 ++ lib/readline/tilde.c | 380 +++ lib/readline/tilde.h | 38 + lib/readline/vi_keymap.c | 877 ++++++ lib/readline/vi_mode.c | 1329 +++++++++ lib/readline/xmalloc.c | 78 + lib/termcap/Makefile | 67 + lib/termcap/grot/COPYING | 339 +++ lib/termcap/grot/ChangeLog | 48 + lib/termcap/grot/INSTALL | 117 + lib/termcap/grot/Makefile.in | 118 + lib/termcap/grot/NEWS | 12 + lib/termcap/grot/README | 14 + lib/termcap/grot/configure | 346 +++ lib/termcap/grot/configure.in | 10 + lib/termcap/grot/termcap.info | 80 + lib/termcap/grot/termcap.info-1 | 1115 ++++++++ lib/termcap/grot/termcap.info-2 | 969 +++++++ lib/termcap/grot/termcap.info-3 | 1469 ++++++++++ lib/termcap/grot/termcap.info-4 | 218 ++ lib/termcap/grot/termcap.texi | 3603 +++++++++++++++++++++++ lib/termcap/grot/texinfo.tex | 3941 +++++++++++++++++++++++++ lib/termcap/termcap.c | 716 +++++ lib/termcap/termcap.h | 62 + lib/termcap/tparam.c | 325 +++ lib/termcap/version.c | 2 + lib/tilde/ChangeLog | 6 + lib/tilde/Makefile | 98 + lib/tilde/doc/Makefile | 5 + lib/tilde/doc/tilde.texi | 0 lib/tilde/memalloc.h | 56 + lib/tilde/tilde.c | 380 +++ lib/tilde/tilde.h | 38 + machines.h | 2392 ++++++++++++++++ mailcheck.c | 427 +++ make_cmd.c | 612 ++++ make_cmd.h | 55 + maxpath.h | 43 + memalloc.h | 60 + newversion.c | 281 ++ nojobs.c | 644 +++++ parse.y | 3005 ++++++++++++++++++++ parser-built | 0 parser.h | 8 + portbash/README | 1 + portbash/libc.sh | 172 ++ portbash/mkdesc.sh | 11 + portbash/pgrp.c | 48 + portbash/signals.sh | 64 + portbash/stdio.sh | 87 + portbash/strings.sh | 87 + portbash/syscalls.sh | 80 + posixstat.h | 149 + print_cmd.c | 827 ++++++ quit.h | 33 + sh | 1 + shell.c | 1792 ++++++++++++ shell.h | 107 + siglist.c | 219 ++ siglist.h | 40 + signames.c | 297 ++ stdc.h | 78 + subst.c | 4867 +++++++++++++++++++++++++++++++ subst.h | 181 ++ support/PORTING | 22 + support/SYMLINKS | 23 + support/bash.xbm | 59 + support/bashbug.sh | 84 + support/cat-s | 16 + support/clone-bash | 95 + support/cppmagic | 51 + support/fixlinks | 61 + support/getcppsyms.c | 428 +++ support/inpath | 19 + support/install.sh | 235 ++ support/mkdirs | 29 + support/mklinks | 41 + support/mkmachtype | 279 ++ support/mksysdefs | 497 ++++ support/printenv | 11 + support/recho.c | 32 + support/srcdir | 13 + support/texi2dvi | 263 ++ test.c | 1132 ++++++++ tests/README | 1 + tests/dollar-at.sh | 1 + tests/dollar-star.sh | 1 + tests/dollar.right | 3 + tests/exp-tests | 326 +++ tests/exp.right | 113 + tests/glob-test | 179 ++ tests/glob.right | 63 + tests/ifs-test-1.sh | 5 + tests/ifs-test-2.sh | 9 + tests/ifs-test-3.sh | 9 + tests/ifs.1.right | 1 + tests/ifs.2.right | 1 + tests/ifs.3.right | 1 + tests/input-line.sh | 4 + tests/input-line.sub | 2 + tests/input.right | 3 + tests/minus-e | 6 + tests/minus-e.right | 1 + tests/misc/chld-trap.sh | 14 + tests/misc/dot-test-1.sh | 3 + tests/misc/dot-test-1.sub | 1 + tests/misc/gotest | 26 + tests/misc/perf-script | 81 + tests/misc/redir.t1.sh | 26 + tests/misc/redir.t2.sh | 17 + tests/misc/redir.t3.sh | 8 + tests/misc/redir.t3.sub | 1 + tests/misc/redir.t4.sh | 12 + tests/misc/run.r1.sh | 1 + tests/misc/run.r2.sh | 1 + tests/misc/run.r3.sh | 3 + tests/misc/sigint.t1.sh | 9 + tests/misc/sigint.t2.sh | 7 + tests/misc/sigint.t3.sh | 11 + tests/misc/sigint.t4.sh | 13 + tests/misc/test-minus-e.1 | 12 + tests/misc/test-minus-e.2 | 14 + tests/new-exp.right | 33 + tests/new-exp.tests | 95 + tests/prec.right | 28 + tests/precedence | 75 + tests/run-all | 17 + tests/run-dollars | 3 + tests/run-exp-tests | 2 + tests/run-glob-test | 4 + tests/run-ifs-tests | 13 + tests/run-input-test | 2 + tests/run-minus-e | 2 + tests/run-new-exp | 2 + tests/run-precedence | 2 + tests/run-set-e-test | 2 + tests/run-strip | 2 + tests/run-varenv | 2 + tests/set-e-test | 16 + tests/set-e.right | 15 + tests/strip.right | 12 + tests/strip.tests | 22 + tests/tilde-tests | 16 + tests/tilde.right | 14 + tests/varenv.right | 14 + tests/varenv.sh | 94 + trap.c | 672 +++++ trap.h | 65 + unwind_prot.c | 272 ++ unwind_prot.h | 47 + variables.c | 1804 ++++++++++++ variables.h | 108 + version.c | 26 + vprint.c | 80 + y.tab.c | 4205 +++++++++++++++++++++++++++ y.tab.h | 43 + 402 files changed, 150297 insertions(+) create mode 100644 .distribution create mode 100644 .patchlevel create mode 100644 COPYING create mode 100644 CWRU/PLATFORMS create mode 100644 CWRU/POSIX.NOTES create mode 100644 CWRU/README create mode 100644 CWRU/changelog create mode 100644 CWRU/misc/aux-mach-desc create mode 100755 CWRU/misc/bison create mode 100644 CWRU/misc/open-files.c create mode 100644 CWRU/misc/pid.c create mode 100644 CWRU/misc/sigs.c create mode 100644 CWRU/misc/sigstat.c create mode 100644 CWRU/sh-redir-hack create mode 100644 INSTALL create mode 100644 MANIFEST create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 RELEASE create mode 100644 alias.c create mode 100644 alias.h create mode 100644 ansi_stdlib.h create mode 100644 bashansi.h create mode 100644 bashhist.c create mode 100644 bashhist.h create mode 100644 bashline.c create mode 100644 bashtypes.h create mode 100644 bracecomp.c create mode 100644 braces.c create mode 100644 builtins.h create mode 100644 builtins/ChangeLog create mode 100644 builtins/Makefile create mode 100644 builtins/alias.def create mode 100644 builtins/bashgetopt.c create mode 100644 builtins/bashgetopt.h create mode 100644 builtins/bind.def create mode 100644 builtins/break.def create mode 100644 builtins/builtin.def create mode 100644 builtins/cd.def create mode 100644 builtins/colon.def create mode 100644 builtins/command.def create mode 100644 builtins/common.c create mode 100644 builtins/common.h create mode 100644 builtins/declare.def create mode 100644 builtins/echo.def create mode 100644 builtins/enable.def create mode 100644 builtins/eval.def create mode 100644 builtins/exec.def create mode 100644 builtins/exit.def create mode 100644 builtins/fc.def create mode 100644 builtins/fg_bg.def create mode 100644 builtins/getopt.c create mode 100644 builtins/getopt.h create mode 100644 builtins/getopts.def create mode 100644 builtins/hash.def create mode 100644 builtins/hashcom.h create mode 100644 builtins/help.def create mode 100644 builtins/history.def create mode 100644 builtins/inlib.def create mode 100644 builtins/jobs.def create mode 100644 builtins/kill.def create mode 100644 builtins/let.def create mode 100644 builtins/mkbuiltins.c create mode 100644 builtins/psize.c create mode 100755 builtins/psize.sh create mode 100644 builtins/read.def create mode 100644 builtins/reserved.def create mode 100644 builtins/return.def create mode 100644 builtins/set.def create mode 100644 builtins/setattr.def create mode 100644 builtins/shift.def create mode 100644 builtins/source.def create mode 100644 builtins/suspend.def create mode 100644 builtins/test.def create mode 100644 builtins/times.def create mode 100644 builtins/trap.def create mode 100644 builtins/type.def create mode 100644 builtins/ulimit.def create mode 100644 builtins/umask.def create mode 100644 builtins/wait.def create mode 100644 command.h create mode 100644 config.h create mode 100644 config.h.mini create mode 100755 configure create mode 100644 copy_cmd.c create mode 100644 cpp-Makefile create mode 100644 dispose_cmd.c create mode 100644 dispose_cmd.h create mode 100644 documentation/FAQ create mode 100644 documentation/Makefile create mode 100644 documentation/README create mode 100644 documentation/article.ms create mode 100644 documentation/article.ps create mode 100644 documentation/article.txt create mode 100644 documentation/bash.1 create mode 100644 documentation/bash.ps create mode 100644 documentation/bash.txt create mode 100644 documentation/builtins.1 create mode 100644 documentation/builtins.ps create mode 100644 documentation/builtins.txt create mode 100644 documentation/features.dvi create mode 100644 documentation/features.info create mode 100644 documentation/features.ps create mode 100644 documentation/features.texi create mode 100644 documentation/readline.3 create mode 100644 documentation/readline.ps create mode 100644 documentation/readline.txt create mode 100644 documentation/texinfo.tex create mode 100644 endian.c create mode 100644 error.c create mode 100644 error.h create mode 100755 examples/alias-conv.sh create mode 100644 examples/functions/autoload create mode 100644 examples/functions/basename create mode 100644 examples/functions/csh-compat create mode 100644 examples/functions/dirfuncs create mode 100644 examples/functions/dirname create mode 100644 examples/functions/exitstat create mode 100644 examples/functions/external create mode 100644 examples/functions/fact create mode 100644 examples/functions/fstty create mode 100644 examples/functions/func create mode 100644 examples/functions/jj.bash create mode 100644 examples/functions/kshenv create mode 100644 examples/functions/manpage create mode 100644 examples/functions/notify.bash create mode 100644 examples/functions/shcat create mode 100644 examples/functions/substr create mode 100644 examples/functions/substr2 create mode 100644 examples/functions/term create mode 100644 examples/functions/whatis create mode 100644 examples/functions/whence create mode 100755 examples/scripts/adventure.sh create mode 100644 examples/scripts/bcsh.sh create mode 100644 examples/scripts/precedence create mode 100755 examples/scripts/shprompt create mode 100644 examples/startup-files/Bash_aliases create mode 100644 examples/startup-files/Bash_profile create mode 100644 examples/startup-files/Bashrc create mode 100644 examples/startup-files/bash-profile create mode 100644 examples/startup-files/bashrc create mode 100644 examples/suncmd.termcap create mode 100644 execute_cmd.c create mode 100644 execute_cmd.h create mode 100644 expr.c create mode 100644 externs.h create mode 100644 filecntl.h create mode 100644 flags.c create mode 100644 flags.h create mode 100644 general.c create mode 100644 general.h create mode 100644 getcwd.c create mode 100644 hash.c create mode 100644 hash.h create mode 100644 input.c create mode 100644 input.h create mode 100644 jobs.c create mode 100644 jobs.h create mode 100644 lib/doc-support/Makefile create mode 100644 lib/doc-support/getopt.h create mode 100644 lib/doc-support/texindex.c create mode 100644 lib/glob/ChangeLog create mode 100644 lib/glob/Makefile create mode 100644 lib/glob/doc/Makefile create mode 100644 lib/glob/doc/glob.texi create mode 100644 lib/glob/fnmatch.c create mode 100644 lib/glob/fnmatch.h create mode 100644 lib/glob/glob.c create mode 100644 lib/glob/ndir.h create mode 100644 lib/malloc/Makefile create mode 100644 lib/malloc/alloca.c create mode 100644 lib/malloc/getpagesize.h create mode 100644 lib/malloc/i386-alloca.s create mode 100644 lib/malloc/malloc.c create mode 100644 lib/malloc/x386-alloca.s create mode 100644 lib/malloc/xmalloc.c create mode 100644 lib/malloclib/Makefile create mode 100644 lib/malloclib/alloca.c create mode 100644 lib/malloclib/calloc.c create mode 100644 lib/malloclib/cfree.c create mode 100644 lib/malloclib/free.c create mode 100644 lib/malloclib/getpagesize.h create mode 100644 lib/malloclib/i386-alloca.s create mode 100644 lib/malloclib/malloc.c create mode 100644 lib/malloclib/malloc.h create mode 100644 lib/malloclib/mcheck.c create mode 100644 lib/malloclib/memalign.c create mode 100644 lib/malloclib/morecore.c create mode 100644 lib/malloclib/mstats.c create mode 100644 lib/malloclib/mtrace.awk create mode 100644 lib/malloclib/mtrace.c create mode 100644 lib/malloclib/realloc.c create mode 100644 lib/malloclib/valloc.c create mode 100644 lib/malloclib/x386-alloca.s create mode 100644 lib/malloclib/xmalloc.c create mode 100644 lib/posixheaders/ansi_stdlib.h create mode 100644 lib/posixheaders/filecntl.h create mode 100644 lib/posixheaders/memalloc.h create mode 100644 lib/posixheaders/posixstat.h create mode 100644 lib/posixheaders/stdc.h create mode 100644 lib/readline/COPYING create mode 100644 lib/readline/ChangeLog create mode 100644 lib/readline/Makefile create mode 100644 lib/readline/README create mode 100644 lib/readline/STANDALONE create mode 100644 lib/readline/ansi_stdlib.h create mode 100644 lib/readline/bind.c create mode 100644 lib/readline/chardefs.h create mode 100644 lib/readline/complete.c create mode 100644 lib/readline/display.c create mode 100644 lib/readline/doc/Makefile create mode 100644 lib/readline/doc/hist.texinfo create mode 100644 lib/readline/doc/history.dvi create mode 100644 lib/readline/doc/history.info create mode 100644 lib/readline/doc/history.ps create mode 100644 lib/readline/doc/hstech.texinfo create mode 100644 lib/readline/doc/hsuser.texinfo create mode 100644 lib/readline/doc/readline.dvi create mode 100644 lib/readline/doc/readline.info create mode 100644 lib/readline/doc/readline.ps create mode 100644 lib/readline/doc/rlman.texinfo create mode 100644 lib/readline/doc/rltech.texinfo create mode 100644 lib/readline/doc/rluser.texinfo create mode 100644 lib/readline/doc/texindex.c create mode 100644 lib/readline/emacs_keymap.c create mode 100644 lib/readline/examples/Inputrc create mode 100644 lib/readline/examples/Makefile create mode 100644 lib/readline/examples/fileman.c create mode 100644 lib/readline/examples/histexamp.c create mode 100644 lib/readline/examples/manexamp.c create mode 100644 lib/readline/funmap.c create mode 100644 lib/readline/history.c create mode 100644 lib/readline/history.h create mode 100644 lib/readline/isearch.c create mode 100644 lib/readline/keymaps.c create mode 100644 lib/readline/keymaps.h create mode 100644 lib/readline/memalloc.h create mode 100644 lib/readline/parens.c create mode 100644 lib/readline/posixstat.h create mode 100644 lib/readline/readline.c create mode 100644 lib/readline/readline.h create mode 100644 lib/readline/rlconf.h create mode 100644 lib/readline/rldefs.h create mode 100644 lib/readline/rltty.c create mode 100644 lib/readline/search.c create mode 100644 lib/readline/signals.c create mode 100644 lib/readline/tilde.c create mode 100644 lib/readline/tilde.h create mode 100644 lib/readline/vi_keymap.c create mode 100644 lib/readline/vi_mode.c create mode 100644 lib/readline/xmalloc.c create mode 100644 lib/termcap/Makefile create mode 100644 lib/termcap/grot/COPYING create mode 100644 lib/termcap/grot/ChangeLog create mode 100644 lib/termcap/grot/INSTALL create mode 100644 lib/termcap/grot/Makefile.in create mode 100644 lib/termcap/grot/NEWS create mode 100644 lib/termcap/grot/README create mode 100755 lib/termcap/grot/configure create mode 100644 lib/termcap/grot/configure.in create mode 100644 lib/termcap/grot/termcap.info create mode 100644 lib/termcap/grot/termcap.info-1 create mode 100644 lib/termcap/grot/termcap.info-2 create mode 100644 lib/termcap/grot/termcap.info-3 create mode 100644 lib/termcap/grot/termcap.info-4 create mode 100644 lib/termcap/grot/termcap.texi create mode 100644 lib/termcap/grot/texinfo.tex create mode 100644 lib/termcap/termcap.c create mode 100644 lib/termcap/termcap.h create mode 100644 lib/termcap/tparam.c create mode 100644 lib/termcap/version.c create mode 100644 lib/tilde/ChangeLog create mode 100644 lib/tilde/Makefile create mode 100644 lib/tilde/doc/Makefile create mode 100644 lib/tilde/doc/tilde.texi create mode 100644 lib/tilde/memalloc.h create mode 100644 lib/tilde/tilde.c create mode 100644 lib/tilde/tilde.h create mode 100644 machines.h create mode 100644 mailcheck.c create mode 100644 make_cmd.c create mode 100644 make_cmd.h create mode 100644 maxpath.h create mode 100644 memalloc.h create mode 100644 newversion.c create mode 100644 nojobs.c create mode 100644 parse.y create mode 100644 parser-built create mode 100644 parser.h create mode 100644 portbash/README create mode 100644 portbash/libc.sh create mode 100644 portbash/mkdesc.sh create mode 100644 portbash/pgrp.c create mode 100644 portbash/signals.sh create mode 100644 portbash/stdio.sh create mode 100644 portbash/strings.sh create mode 100644 portbash/syscalls.sh create mode 100644 posixstat.h create mode 100644 print_cmd.c create mode 100644 quit.h create mode 120000 sh create mode 100644 shell.c create mode 100644 shell.h create mode 100644 siglist.c create mode 100644 siglist.h create mode 100644 signames.c create mode 100644 stdc.h create mode 100644 subst.c create mode 100644 subst.h create mode 100644 support/PORTING create mode 100644 support/SYMLINKS create mode 100644 support/bash.xbm create mode 100644 support/bashbug.sh create mode 100644 support/cat-s create mode 100755 support/clone-bash create mode 100755 support/cppmagic create mode 100755 support/fixlinks create mode 100644 support/getcppsyms.c create mode 100755 support/inpath create mode 100755 support/install.sh create mode 100755 support/mkdirs create mode 100755 support/mklinks create mode 100755 support/mkmachtype create mode 100755 support/mksysdefs create mode 100755 support/printenv create mode 100644 support/recho.c create mode 100755 support/srcdir create mode 100755 support/texi2dvi create mode 100644 test.c create mode 100644 tests/README create mode 100755 tests/dollar-at.sh create mode 100755 tests/dollar-star.sh create mode 100644 tests/dollar.right create mode 100644 tests/exp-tests create mode 100644 tests/exp.right create mode 100644 tests/glob-test create mode 100644 tests/glob.right create mode 100644 tests/ifs-test-1.sh create mode 100644 tests/ifs-test-2.sh create mode 100644 tests/ifs-test-3.sh create mode 100644 tests/ifs.1.right create mode 100644 tests/ifs.2.right create mode 100644 tests/ifs.3.right create mode 100644 tests/input-line.sh create mode 100644 tests/input-line.sub create mode 100644 tests/input.right create mode 100644 tests/minus-e create mode 100644 tests/minus-e.right create mode 100755 tests/misc/chld-trap.sh create mode 100644 tests/misc/dot-test-1.sh create mode 100644 tests/misc/dot-test-1.sub create mode 100644 tests/misc/gotest create mode 100644 tests/misc/perf-script create mode 100644 tests/misc/redir.t1.sh create mode 100644 tests/misc/redir.t2.sh create mode 100755 tests/misc/redir.t3.sh create mode 100644 tests/misc/redir.t3.sub create mode 100644 tests/misc/redir.t4.sh create mode 100755 tests/misc/run.r1.sh create mode 100755 tests/misc/run.r2.sh create mode 100755 tests/misc/run.r3.sh create mode 100755 tests/misc/sigint.t1.sh create mode 100755 tests/misc/sigint.t2.sh create mode 100755 tests/misc/sigint.t3.sh create mode 100755 tests/misc/sigint.t4.sh create mode 100644 tests/misc/test-minus-e.1 create mode 100644 tests/misc/test-minus-e.2 create mode 100644 tests/new-exp.right create mode 100644 tests/new-exp.tests create mode 100644 tests/prec.right create mode 100755 tests/precedence create mode 100755 tests/run-all create mode 100755 tests/run-dollars create mode 100755 tests/run-exp-tests create mode 100755 tests/run-glob-test create mode 100755 tests/run-ifs-tests create mode 100755 tests/run-input-test create mode 100755 tests/run-minus-e create mode 100755 tests/run-new-exp create mode 100755 tests/run-precedence create mode 100755 tests/run-set-e-test create mode 100755 tests/run-strip create mode 100755 tests/run-varenv create mode 100644 tests/set-e-test create mode 100644 tests/set-e.right create mode 100644 tests/strip.right create mode 100644 tests/strip.tests create mode 100644 tests/tilde-tests create mode 100644 tests/tilde.right create mode 100644 tests/varenv.right create mode 100644 tests/varenv.sh create mode 100644 trap.c create mode 100644 trap.h create mode 100644 unwind_prot.c create mode 100644 unwind_prot.h create mode 100644 variables.c create mode 100644 variables.h create mode 100644 version.c create mode 100644 vprint.c create mode 100644 y.tab.c create mode 100644 y.tab.h 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 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d642012 --- /dev/null +++ b/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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + 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. + + , 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 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 + +lib/readline/*.c + - define READLINE_LIBRARY before including any files + - include only `local' copies of include files using #include "xxx.h" + rather than #include + + 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 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 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 if HAVE_TERMCAP_H is defined + - use 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 \ + +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 +#include +#include +#include + +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 + +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 +#include + +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 +#include +#include + +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 + } diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..e366406 --- /dev/null +++ b/INSTALL @@ -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 diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..783d193 --- /dev/null +++ b/NEWS @@ -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. diff --git a/README b/README new file mode 100644 index 0000000..6638c6e --- /dev/null +++ b/README @@ -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 diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000..6a5167e --- /dev/null +++ b/RELEASE @@ -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. diff --git a/alias.c b/alias.c new file mode 100644 index 0000000..f9be0b4 --- /dev/null +++ b/alias.c @@ -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 +#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; + } +} diff --git a/alias.h b/alias.h new file mode 100644 index 0000000..2a2d184 --- /dev/null +++ b/alias.h @@ -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 +#else +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include +#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 +#include +#include +#include "bashansi.h" +#include "posixstat.h" +#include "filecntl.h" +#include "shell.h" +#include "flags.h" +#include + +/* 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 +#include "bashansi.h" +#include +#include +#include +#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_funcname, 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 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 -- 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 + +#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 + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#include "shell.h" +#include + +/* 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 +#else /* !HAVE_STRING_H */ +# include +#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 + +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 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 +# 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 +#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 +#include "../shell.h" +#if defined (READLINE) +#include +#if !defined (errno) +extern int errno; +#endif /* !errno */ +#include +#include +#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 +#include + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#include +#include + +#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 (""); + 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 +#else /* !HAVE_STRING_H */ +# include +#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 +#include +#include "../posixstat.h" +#if defined (HAVE_VFPRINTF) +#include +#endif /* VFPRINTF */ + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 + +#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 + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +#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 +#include "../posixstat.h" +#include +#include + +#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 +#include +#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 +#include "../bashansi.h" +#include "../shell.h" +#if defined (HISTORY) +#include +#include +#include +#include +#include +#include "../builtins.h" +#include "../flags.h" +#include "../maxpath.h" +#include "../bashhist.h" +#include +#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 +#include +#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 +#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 + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +#include "../posixstat.h" + +#include + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +#include "../shell.h" +#include "../builtins.h" + +#if defined (USE_GLOB_LIBRARY) +# include +#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 +#include +#include "../filecntl.h" +#include "../posixstat.h" +#include "../bashhist.h" +#include + +/* 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 +#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 +#include + +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 +#include +#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 + +#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 +#include +#include +#include +#include "../filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +#include +#include +#include + +#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 +#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 +#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 +#else /* !HAVE_STRING_H */ +# include +#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 +#include +#include + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +#include +#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 +#else /* !HAVE_STRING_H */ +# include +#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 + +#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 +#else /* !_POSIX_VERSION && HAVE_RESOURCE */ +# include +# include +#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 , 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 +#include +#include "../shell.h" +#include "../trap.h" +#include "common.h" + +/* The trap command: + + trap + trap + 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 +#include +#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 +#include +#include +#include +#include "../shell.h" +#include "pipesize.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_RESOURCE) +# include +# include +#else +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LIMITS_H) +# include +#endif + +/* Check for the most basic symbols. If they aren't present, this + system's isn't very useful to us. */ +#if !defined (RLIMIT_FSIZE) || defined (GETRLIMIT_MISSING) +# 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 +#include +#include +#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 +#include +#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 ...] */ + + /* 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 <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 +# 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 +#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 + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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 +STREAM = -DHAVE_SYS_STREAM_H +#endif /* HAVE_SYS_STREAM_H */ + +#if defined (HAVE_SYS_PTEM_H) +/**/# This system has +PTEM = -DHAVE_SYS_PTEM_H +#endif /* HAVE_SYS_PTEM_H */ + +#if defined (HAVE_SYS_PTE_H) +/**/# This system has +PTE = -DHAVE_SYS_PTE_H +#endif /* HAVE_SYS_PTE_H */ + +/**/# This system has . +#if defined (HAVE_UNISTD_H) +UNISTD = -DHAVE_UNISTD_H +#endif + +/**/# This system has +#if defined (HAVE_STDLIB_H) +STDLIB = -DHAVE_STDLIB_H +#endif + +/**/# This system has +#if defined (HAVE_LIMITS_H) +LIMITSH = -DHAVE_LIMITS_H +#endif + +#if defined (HAVE_GETGROUPS) +/**/# This system has multiple groups. +GROUPS = -DHAVE_GETGROUPS +#endif + +#if defined (HAVE_RESOURCE) +/**/# This system has +RESOURCE = -DHAVE_RESOURCE +#endif + +#if defined (HAVE_SYS_PARAM) +/**/# This system has +PARAM = -DHAVE_SYS_PARAM +#endif + +#if defined (VOID_SIGHANDLER) +/**/# The signal () call provided by the system returns a pointer to +/**/# a function returning void. The signal handlers themselves are +/**/# thus void functions. +SIGHANDLER = -DVOID_SIGHANDLER +#endif + +#if defined (HAVE_STRERROR) +/**/# This system has the strerror () function. +STRERROR = -DHAVE_STRERROR +#endif + +#if defined (HAVE_WAIT_H) +/**/# This system has +WAITH = -DHAVE_WAIT_H +#endif + +#if defined (HAVE_GETWD) +/**/# This system has the getwd () call. +GETWD = -DHAVE_GETWD +#endif + +#if defined (HAVE_DUP2) +/**/# This system has a working version of dup2 (). +DUP2 = -DHAVE_DUP2 +#endif /* HAVE_DUP2 */ + +#if defined (HAVE_DIRENT) +/**/# This system uses struct dirent for reading directories with readdir. +DIRENT = -DHAVE_DIRENT +#endif /* HAVE_DIRENT */ + +#if defined (HAVE_DIRENT_H) +/**/# This system has /usr/include/dirent.h +DIRENTH = -DHAVE_DIRENT_H +#endif /* HAVE_DIRENT_H */ + +#if defined (HAVE_STRING_H) +/**/# This system has /usr/include/string.h +STRINGH = -DHAVE_STRING_H +#endif /* HAVE_STRING_H */ + +#if defined (HAVE_VARARGS_H) +/**/# This system has /usr/include/varargs.h +VARARGSH = -DHAVE_VARARGS_H +#endif /* HAVE_VARARGS_H */ + +#if defined (HAVE_STRCHR) +/**/# This system has strchr () and strrchr () string functions. +STRCHR = -DHAVE_STRCHR +#endif /* HAVE_STRCHR */ + +#if defined (HAVE_STRCASECMP) +STRCASE = -DHAVE_STRCASECMP +#endif /* HAVE_STRCASECMP */ + +#if defined (HAVE_DEV_FD) +/**/# This system has the /dev/fd directory for naming open files. +DEVFD = -DHAVE_DEV_FD +#endif /* HAVE_DEV_FD */ + +/**/# The GNU coding standards don't recognize the possibility that +/**/# other information besides optimization and debugging might be +/**/# passed to cc. A different name should have been used. +CFLAGS = -O -g + +SYSTEM_FLAGS = $(LINEBUF) $(VPRINTF) $(UNISTD) $(STDLIB) $(LIMITSH) \ + $(GROUPS) $(RESOURCE) $(PARAM) $(SIGHANDLER) $(SYSDEP) $(WAITH) \ + $(GETWD) $(DUP2) $(STRERROR) $(DIRENT) $(DIRENTH) $(STRINGH) \ + $(VARARGSH) $(STRCHR) $(STRCASE) $(DEVFD) \ + -D$(Machine) -D$(OS) +LDFLAGS = $(NOSHARE) $(SYSDEP_LD) $(EXTRA_LD_PATH) $(PROFILE_FLAGS) $(CFLAGS) +CCFLAGS = $(PROFILE_FLAGS) $(SYSTEM_FLAGS) -DSHELL $(ALLOCA_CFLAGS) \ + $(MALLOC_CFLAGS) $(CFLAGS) +CPPFLAGS= -I. -I$(srcdir) -I$(LIBSRC) +GCC_LINT_FLAGS = -ansi -Wall -Wshadow -Wpointer-arith -Wcast-qual \ + -Wwrite-strings -Werror -Wstrict-prototypes \ + -Wmissing-prototypes +GCC_LINT_CFLAGS = $(PROFILE_FLAGS) $(CFLAGS) $(SYSTEM_FLAGS) -DSHELL $(ALLOCA_CFLAGS) \ + $(MALLOC_CFLAGS) $(GCC_LINT_FLAGS) + +/* It is conceivable that you wish to edit some things beyond this point, + but I guess that it is highly unlikely, and may give you a headache. */ + +/* **************************************************************** */ +/* */ +/* How to Build the support libraries. */ +/* */ +/* **************************************************************** */ + +/**/# The location of sources for the support libraries. +LIBPATH = ./lib/ +LIBSRC = $(srcdir)/$(LIBPATH) + +/**/# Preface building with the full path of the current library source. +LIBINC_DECL = topdir=`sh $(srcdir)/support/srcdir $(srcdir)`; export topdir +LIBINC_USAGE = "-I$${topdir} -I$${topdir}/$(LIBPATH) -I$(LIBSRC)" + +/* Defines used when building libraries. */ +#define LIB_CFLAGS_DECL CFLAGS='$(LIBRARY_CFLAGS) '$(LIBINC_USAGE) +#define LIB_CPPFLAGS_DECL CPPFLAGS='$(CPPFLAGS)' +#define LIB_LDFLAGS_DECL LDFLAGS='$(LDFLAGS)' +#define LIBMAKE_FLAGS LIB_CFLAGS_DECL LIB_CPPFLAGS_DECL LIB_LDFLAGS_DECL \ + RANLIB='$(RANLIB)' AR='$(AR)' CC='$(CC)' RM='$(RM)' \ + +/* Macro used to build a library. */ +#define build_lib_in_dir(directory, target, srcdef, makefile) \ + @echo "Building in " directory "..."; \ + sh $(SUPPORT_SRC)mkdirs directory ; \ + ($(LIBINC_DECL); cd directory; \ + if [ ! -f Makefile ]; then cp makefile Makefile; fi; \ + $(MAKE) target $(MFLAGS) LIBMAKE_FLAGS srcdef) + +/* The builtins are somewhat special in that more information is needed + to compile them correctly. */ +#define build_builtins(target) \ + @sh $(SUPPORT_SRC)mkdirs $(DEFDIR) ; \ + ($(LIBINC_DECL); cd $(DEFDIR); \ + if [ ! -f Makefile ]; then \ + cp $(BUILTIN_ABSSRC)/Makefile Makefile; \ + fi; \ + $(MAKE) $(MFLAGS) target \ + srcdir=$(BUILTIN_ABSSRC) CPPFLAGS='$(CPPFLAGS)' \ + CFLAGS='$(CCFLAGS) '$(LIBINC_USAGE)' -I. -I$(BUILTIN_ABSSRC)' \ + LDFLAGS='$(LDFLAGS)' RANLIB='$(RANLIB)' AR='$(AR)' CC='$(CC)' \ + RM='$(RM)' RL_LIBSRC='$(RL_ABSSRC)' \ + DIRECTDEFINE='-D '$(srcdir)/$(DEFDIR)) + +/**/# Flags used when building libraries. +LIBRARY_CFLAGS = $(PROFILE_FLAGS) $(CFLAGS) $(SIGHANDLER) $(ALLOCA_CFLAGS) \ + $(SYSDEP) $(DIRENT) $(DIRENTH) $(STRINGH) $(VARARGSH) \ + $(PTEM) $(PTE) $(STREAM) $(STRERROR) $(RESOURCE) \ + $(STRCHR) -D$(Machine) -D$(OS) $(UNISTD) $(LIMITSH) \ + $(STRCASE) $(STDLIB) -DSHELL + +/**/# These are required for sending bug reports. +SYSTEM_NAME = $(Machine) +OS_NAME = $(OS) + +/**/# The name of this program. +Program = bash + +/**/# The type of machine and OS Bash is being compiled on. +HOSTTYPE_DECL = -DHOSTTYPE='$(SYSTEM_NAME)' -DOSTYPE='$(OS_NAME)' + +/**/# The group of configuration flags. These are for shell.c +CFG_FLAGS = -DOS_NAME='$(OS_NAME)' -DSYSTEM_NAME='$(SYSTEM_NAME)' \ + $(SIGLIST_FLAG) + +/* **************************************************************** */ +/* */ +/* Support for desired libraries. */ +/* This includes Termcap, Glob, Tilde, History, and Readline. */ +/* */ +/* **************************************************************** */ + +/* Does this machine's linker need a space after -L? */ +#if defined (HAVE_GCC) +# undef SEARCH_LIB_NEEDS_SPACE +#endif /* HAVE_GCC */ + +#if defined (SEARCH_LIB_NEEDS_SPACE) +/**/# The native compiler for this machines requires a space after '-L'. +SEARCH_LIB = -L $(UNSET_VARIABLE_CREATES_SPACE) +#else +/**/# The compiler being used to build Bash can handle -L/library/path. +SEARCH_LIB = -L +#endif /* !SEARCH_LIB_NEEDS_SPACE */ + +#if defined (EXTRA_LIB_SEARCH_PATH) +/**/# Additional instructions to the linker telling it how to find libraries. +LOCAL_LD_PATH = EXTRA_LIB_SEARCH_PATH +EXTRA_LD_PATH = $(SEARCH_LIB)$(LOCAL_LD_PATH) +#endif /* EXTRA_LIB_SEARCH_PATH */ + +/* Right now we assume that you have the full source code to Bash. If + you simply have the library and header files installed, then + undefine HAVE_READLINE_SOURCE. */ +#define HAVE_READLINE_SOURCE + +#if defined (HAVE_READLINE_SOURCE) + +RL_LIBSRC = $(LIBSRC)readline/ +RL_LIBDOC = $(RL_LIBSRC)doc/ +RL_LIBDIR = $(LIBPATH)readline/ +RL_ABSSRC = $${topdir}/$(RL_LIBDIR) + +READLINE_LIBRARY = $(RL_LIBDIR)libreadline.a + +/**/# The source, object and documentation of the GNU Readline library. +READLINE_SOURCE = $(RL_LIBSRC)rldefs.h $(RL_LIBSRC)rlconf.h \ + $(RL_LIBSRC)readline.h \ + $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)keymaps.h \ + $(RL_LIBSRC)funmap.c $(RL_LIBSRC)emacs_keymap.c \ + $(RL_LIBSRC)search.c $(RL_LIBSRC)vi_keymap.c \ + $(RL_LIBSRC)keymaps.c $(RL_LIBSRC)parens.c \ + $(RL_LIBSRC)vi_mode.c $(RL_LIBSRC)history.c \ + $(RL_LIBSRC)readline.c $(RL_LIBSRC)tilde.c \ + $(RL_LIBSRC)rltty.c $(RL_LIBSRC)complete.c \ + $(RL_LIBSRC)bind.c $(RL_LIBSRC)isearch.c \ + $(RL_LIBSRC)display.c $(RL_LIBSRC)signals.c \ + $(RL_LIBSRC)posixstat.h $(RL_LIBSRC)tilde.h \ + $(RL_LIBSRC)xmalloc.c + +READLINE_OBJ = $(RL_LIBDIR)readline.o $(RL_LIBDIR)funmap.o \ + $(RL_LIBDIR)parens.o $(RL_LIBDIR)search.o \ + $(RL_LIBDIR)keymaps.o $(RL_LIBDIR)history.o \ + $(RL_LIBDIR)rltty.o $(RL_LIBDIR)complete.o \ + $(RL_LIBDIR)bind.o $(RL_LIBDIR)isearch.o \ + $(RL_LIBDIR)display.o $(RL_LIBDIR)signals.o \ + $(RL_LIBDIR)tilde.o $(RL_LIBDIR)xmalloc.o + +READLINE_DOC = $(RL_LIBDOC)rlman.texinfo $(RL_LIBDOC)rluser.texinfo \ + $(RL_LIBDOC)rltech.texinfo + +READLINE_DOC_SUPPORT = $(RL_LIBDOC)Makefile $(RL_LIBDOC)readline.dvi \ + $(RL_LIBDOC)readline.info + +/**/# This has to be written funny to avoid looking like a C comment starter. +READLINE_EXAMPLES = $(RL_LIBSRC)examples/[a-zA-Z]*.[ch] \ + $(RL_LIBSRC)examples/Makefile $(RL_LIBSRC)examples/Inputrc + +/**/# Support files for GNU Readline. +READLINE_SUPPORT = $(RL_LIBSRC)Makefile $(RL_LIBSRC)ChangeLog \ + $(RL_LIBSRC)COPYING $(READLINE_EXAMPLES) \ + $(READLINE_DOC_SUPPORT) + +#else /* !HAVE_READLINE_SOURCE */ + +# if defined (READLINE) +READLINE_LIBRARY = -lreadline +# endif /* READLINE */ +RL_LIBDIR = $(srcdir)/$(LIBSRC)readline/ + +#endif /* !HAVE_READLINE_SOURCE */ + +/* Right now we assume that you have the full source code to Bash, + including the source code to the history library. If you only have + the library and header files installed, then you can undefine + HAVE_HISTORY_SOURCE. */ +#define HAVE_HISTORY_SOURCE + +#if defined (READLINE) && !defined (HISTORY) +# define HISTORY +#endif /* READLINE && !HISTORY */ + +# if defined (HISTORY) && !defined (READLINE) +/**/# You are compiling with history features but without line editing. +HISTORY_LIB = -lhistory +# endif /* HISTORY && !READLINE */ + +#if defined (HISTORY) +HIST_SUPPORT_SRC = bashhist.c +HIST_SUPPORT_OBJ = bashhist.o +#endif /* HISTORY */ + +#if defined (HAVE_HISTORY_SOURCE) + +HIST_LIBSRC = $(LIBSRC)readline/ +HIST_LIBDOC = $(HIST_LIBSRC)doc/ +HIST_LIBDIR = $(LIBPATH)readline/ +HIST_ABSSRC = $${topdir}/$(HIST_LIBDIR)/ + +/* If you are building with readline, then you do not explicitly need the + history library. */ +# if defined (READLINE) +HISTORY_LIBRARY = +# else +HISTORY_LIBRARY = $(HIST_LIBDIR)libhistory.a +# endif /* !READLINE */ + +/**/# The source, object and documentation of the history library. +HISTORY_SOURCE = $(HIST_LIBSRC)history.c $(HIST_LIBSRC)history.h +HISTORY_OBJ = $(HIST_LIBDIR)history.o +HISTORY_DOC = $(HIST_LIBDOC)hist.texinfo $(HIST_LIBDOC)hsuser.texinfo \ + $(HIST_LIBDOC)hstech.texinfo + +/**/# Directory list for -L so that the link editor (ld) can find -lhistory. +# if defined (HISTORY) && !defined (READLINE) +# if !defined (LD_HAS_NO_DASH_L) +HISTORY_LDFLAGS = $(SEARCH_LIB)$(HIST_LIBDIR) +# endif /* LD_HAS_NO_DASH_L */ +# endif /* HISTORY && !READLINE */ +#else /* !HAVE_HISTORY_SOURCE */ +# if defined (HISTORY) && !defined (READLINE) +HISTORY_LIBRARY = -lhistory +HISTORY_LDFLAGS = $(SEARCH_LIB)$(libdir) $(SEARCH_LIB)/usr/local/lib +# endif /* HISTORY && !READLINE */ +#endif /* !HAVE_HISTORY_SOURCE */ + +#if defined (USE_GNU_TERMCAP) +# define HAVE_TERMCAP_SOURCE +TERM_LIBSRC = $(LIBSRC)termcap/ +TERM_LIBDIR = $(LIBPATH)termcap/ +TERM_ABSSRC = $${topdir}/$(TERM_LIBDIR) + +/**/# The source, object and documentation for the GNU Termcap library. +TERMCAP_LIBRARY = $(TERM_LIBDIR)libtermcap.a + +TERMCAP_SOURCE = $(TERM_LIBSRC)termcap.c $(TERM_LIBSRC)tparam.c +TERMCAP_OBJ = $(TERM_LIBDIR)termcap.o $(TERM_LIBDIR)tparam.o +TERMCAP_DOC = $(TERM_LIBSRC)termcap.texinfo +TERMCAP_SUPPORT = $(TERM_LIBSRC)Makefile $(TERM_LIBSRC)ChangeLog + +# if !defined (LD_HAS_NO_DASH_L) +TERMCAP_LDFLAGS = $(SEARCH_LIB)$(TERM_LIBDIR) +# endif /* !LD_HAS_NO_DASH_L */ +#else /* !USE_GNU_TERMCAP */ + +/* Guessed at symbol for LIBRARIES, below. */ +# if defined (USE_TERMCAP_EMULATION) +TERMCAP_LIBRARY = -lcurses +# else /* !USE_TERMCAP_EMULATION */ +TERMCAP_LIBRARY = -ltermcap +# endif /* !USE_TERMCAP_EMULATION */ +#endif /* !USE_GNU_TERMCAP */ + +/* The glob library is always used. */ +#define USE_GLOB_LIBRARY + +#if defined (USE_GLOB_LIBRARY) +GLOB_LIBSRC = $(LIBSRC)glob/ +GLOB_LIBDIR = $(LIBPATH)glob/ +GLOB_ABSSRC = $${topdir}/$(GLOB_LIBDIR) + +GLOB_LIBRARY = $(GLOB_LIBDIR)libglob.a + +GLOB_SOURCE = $(GLOB_LIBSRC)glob.c $(GLOB_LIBSRC)fnmatch.c \ + $(GLOB_LIBSRC)fnmatch.h +GLOB_OBJ = $(GLOB_LIBDIR)glob.o $(GLOB_LIBDIR)fnmatch.o +GLOB_DOC = $(GLOB_LIBSRC)doc/glob.texi $(GLOB_LIBSRC)doc/Makefile +GLOB_SUPPORT= $(GLOB_LIBSRC)Makefile $(GLOB_LIBSRC)ChangeLog + +# if !defined (LD_HAS_NO_DASH_L) +GLOB_LDFLAGS = $(SEARCH_LIB)$(GLOB_LIBDIR) +# endif /* !LD_HAS_NO_DASH_L */ +GLOB_LIB = -lglob +#endif /* USE_GLOB_LIBRARY */ + +/* The source code for the tilde expansion library. */ +#if defined (HAVE_READLINE_SOURCE) +# define HAVE_TILDE_SOURCE +#endif /* HAVE_READLINE_SOURCE */ + +#if defined (HAVE_TILDE_SOURCE) +/**/# The source, object and documentation for the GNU Tilde library. +TILDE_LIBSRC = $(LIBSRC)tilde/ +TILDE_LIBDIR = $(LIBPATH)tilde/ +TILDE_ABSSRC = $${topdir}/$(TILDE_LIBDIR) + +TILDE_LIBRARY = $(TILDE_LIBDIR)libtilde.a + +TILDE_SOURCE = $(TILDE_LIBSRC)tilde.c $(TILDE_LIBSRC)tilde.h +TILDE_OBJ = $(TILDE_LIBDIR)tilde.o +TILDE_DOC = $(TILDE_LIBSRC)doc/tilde.texi $(TILDE_LIBSRC)doc/Makefile +TILDE_SUPPORT = $(TILDE_LIBSRC)Makefile $(TILDE_LIBSRC)ChangeLog + +TILDE_LIB = -ltilde + +# if !defined (LD_HAS_NO_DASH_L) +TILDE_LDFLAGS = $(SEARCH_LIB)$(TILDE_LIBDIR) +# endif /* !LD_HAS_NO_DASH_L */ + +#else /* !HAVE_TILDE_SOURCE */ +/**/# Guessed at location of the tilde +TILDE_LIBRARY = $(libdir)/libtilde.a +#endif /* !HAVE_TILDE_SOURCE */ + +#if defined (USE_GNU_MALLOC_LIBRARY) +/**/# Our malloc library. +MALLOC_LIBSRC = $(LIBSRC)malloclib/ +MALLOC_LIBDIR = $(LIBPATH)malloclib/ +MALLOC_ABSSRC = $${topdir}/$(MALLOC_LIBDIR) + +MALLOC_LIBRARY = $(MALLOC_LIBDIR)libmalloc.a + +MALLOC_SOURCE = $(MALLOC_LIBSRC)calloc.c $(MALLOC_LIBSRC)cfree.c \ + $(MALLOC_LIBSRC)free.c $(MALLOC_LIBSRC)malloc.c \ + $(MALLOC_LIBSRC)mcheck.c $(MALLOC_LIBSRC)memalign.c \ + $(MALLOC_LIBSRC)morecore.c $(MALLOC_LIBSRC)mstats.c \ + $(MALLOC_LIBSRC)mtrace.c $(MALLOC_LIBSRC)realloc.c \ + $(MALLOC_LIBSRC)valloc.c +MALLOC_OBJ = $(MALLOC_LIBDIR)calloc.c $(MALLOC_LIBDIR)cfree.c \ + $(MALLOC_LIBDIR)free.c $(MALLOC_LIBDIR)malloc.c \ + $(MALLOC_LIBDIR)mcheck.c $(MALLOC_LIBDIR)memalign.c \ + $(MALLOC_LIBDIR)morecore.c $(MALLOC_LIBDIR)mstats.c \ + $(MALLOC_LIBDIR)mtrace.c $(MALLOC_LIBDIR)realloc.c \ + $(MALLOC_LIBDIR)valloc.c + +MALLOC_SUPPORT= $(MALLOC_LIBSRC)Makefile +MALLOC_CFLAGS = -DUSE_GNU_MALLOC_LIBRARY + +# if !defined (LD_HAS_NO_DASH_L) +MALLOC_LDFLAGS = $(SEARCH_LIB)$(MALLOC_LIBDIR) +# endif /* !LD_HAS_NO_DASH_L */ +MALLOC_LIB = -lmalloc + +MALLOC_DEP = $(MALLOC_LIBRARY) +#else +MALLOC_LIBRARY = +#endif /* USE_GNU_MALLOC_LIBRARY */ + +BASHPOSIX_LIB = $(LIBSRC)posixheaders/ +BASHPOSIX_SUPPORT = $(BASHPOSIX_LIB)posixstat.h $(BASHPOSIX_LIB)ansi_stdlib.h \ + $(BASHPOSIX_LIB)memalloc.h $(BASHPOSIX_LIB)stdc.h + +/**/# Declare all of the sources for the libraries that we have. +LIBRARY_SOURCE = $(READLINE_SOURCE) $(HISTORY_SOURCE) $(TERMCAP_SOURCE) \ + $(GLOB_SOURCE) $(TILDE_SOURCE) $(MALLOC_SOURCE) +LIBRARY_DOC = $(READLINE_DOC) $(HISTORY_DOC) $(TERMCAP_DOC) $(GLOB_DOC) \ + $(TILDE_DOC) $(MALLOC_DOC) +LIBRARY_SUPPORT = $(READLINE_SUPPORT) $(HISTORY_SUPPORT) $(TERMCAP_SUPPORT) \ + $(GLOB_SUPPORT) $(TILDE_SUPPORT) $(MALLOC_SUPPORT) +LIBRARY_TAR = $(LIBRARY_SOURCE) $(LIBRARY_DOC) $(LIBRARY_SUPPORT) + +#if defined (READLINE) +/**/# You wish to compile with the line editing features installed. +READLINE_LIB = -lreadline + +/**/# You only need termcap (or curses) if you are linking with GNU Readline. +# if defined (USE_TERMCAP_EMULATION) +TERMCAP_LIB = -lcurses +# else /* !USE_TERMCAP_EMULATION */ +TERMCAP_LIB = -ltermcap +# endif /* !USE_TERMCAP_EMULATION */ + +/**/# Directory list for -L so that the link editor (ld) can find -lreadline. +# if !defined (LD_HAS_NO_DASH_L) +# if defined (HAVE_READLINE_SOURCE) +READLINE_LDFLAGS = $(SEARCH_LIB)$(RL_LIBDIR) $(TERMCAP_LDFLAGS) +# else +READLINE_LDFLAGS = $(TERMCAP_LDFLAGS) $(SEARCH_LIB)$(libdir) \ + $(SEARCH_LIB)/usr/local/lib +# endif /* HAVE_READLINE_SOURCE */ +# endif /* LD_HAS_NO_DASH_L */ + +/**/# The source and object of the bash<->readline interface code. +RL_SUPPORT_SRC = bashline.c bracecomp.c +RL_SUPPORT_OBJ = bashline.o $(BRACECOMP_OBJECT) +#endif /* READLINE */ + +/**/# The order is important. Most dependent first. +#if defined (LD_HAS_NO_DASH_L) +/**/# This linker does not know how to grok the -l flag, or perhaps how +/**/# to grok the -L flag, or both. +LIBRARIES = $(READLINE_LIBRARY) $(HISTORY_LIBRARY) $(TERMCAP_LIBRARY) \ + $(GLOB_LIBRARY) $(TILDE_LIBRARY) $(MALLOC_LIBRARY) $(LOCAL_LIBS) +#else /* !LD_HAS_NO_DASH_L */ +LIBRARIES = $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ + $(TILDE_LIB) $(MALLOC_LIB) $(LOCAL_LIBS) +#endif /* !LD_HAS_NO_DASH_L */ + +#if defined (READLINE) +# if defined (HAVE_TERMCAP_SOURCE) +TERMCAP_DEP = $(TERMCAP_LIBRARY) +# endif /* HAVE_TERMCAP_SOURCE */ +# if defined (HAVE_READLINE_SOURCE) +READLINE_DEP = $(READLINE_LIBRARY) +# endif /* HAVE_READLINE_SOURCE */ +#endif /* READLINE */ + +#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) && !defined (READLINE) +HISTORY_DEP = $(HISTORY_LIBRARY) +#endif + +#if defined (USE_GLOB_LIBRARY) +GLOB_DEP = $(GLOB_LIBRARY) +#else +GLOBC = glob.c fnmatch.c +GLOBO = glob.o fnmatch.o +#endif /* USE_GLOB_LIBRARY */ + +#if defined (HAVE_TILDE_SOURCE) +TILDE_DEP = $(TILDE_LIBRARY) +#endif + +/**/# Source files for libraries that Bash depends on. +LIBDEP = $(READLINE_DEP) $(TERMCAP_DEP) $(GLOB_DEP) $(HISTORY_DEP) $(TILDE_DEP) $(MALLOC_DEP) + +/**/# Rules for cleaning the readline and termcap sources. +#if defined (HAVE_READLINE_SOURCE) +CLEAN_READLINE = (cd $(RL_LIBDIR); $(MAKE) $(MFLAGS) $@) +#else +CLEAN_READLINE = : +#endif /* !HAVE_READLINE_SOURCE */ + +#if defined (HAVE_HISTORY_SOURCE) +# if !defined (READLINE) +CLEAN_HISTORY = (cd $(HIST_LIBDIR); $(MAKE) $(MFLAGS) $@) +# else +CLEAN_HISTORY = : +# endif /* READLINE */ +#endif /* !HAVE_HISTORY_SOURCE */ + +#if defined (HAVE_TERMCAP_SOURCE) +CLEAN_TERMCAP = (cd $(TERM_LIBDIR); $(MAKE) $(MFLAGS) $@) +#else +CLEAN_TERMCAP = : +#endif /* !HAVE_TERMCAP_SOURCE */ + +#if defined (USE_GLOB_LIBRARY) +CLEAN_GLOB = (cd $(GLOB_LIBDIR); $(MAKE) $(MFLAGS) $@) +#else +CLEAN_GLOB = : +#endif /* !USE_GLOB_LIBRARY */ + +#if defined (HAVE_TILDE_SOURCE) +CLEAN_TILDE = (cd $(TILDE_LIBDIR); $(MAKE) $(MFLAGS) $@) +#else +CLEAN_TILDE = : +#endif /* !HAVE_TILDE_SOURCE */ + +#if defined (USE_GNU_MALLOC_LIBRARY) +CLEAN_MALLOC = (cd $(MALLOC_LIBDIR); $(MAKE) $(MFLAGS) $@) +#else +CLEAN_MALLOC = : +#endif /* !USE_GNU_MALLOC_LIBRARY */ + +LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(TILDE_LDFLAGS) \ + $(GLOB_LDFLAGS) $(MALLOC_LDFLAGS) + +/**/# The directory which contains the source for malloc. The name must +/**/# end in a slash, as in "./lib/malloc/". +ALLOC_LIBSRC = $(LIBSRC)malloc/ +ALLOC_LIBDIR = $(LIBPATH)malloc/ +ALLOC_ABSSRC = $${topdir}/$(ALLOC_LIBDIR) + +/**/# Our malloc. +#if defined (USE_GNU_MALLOC) && !defined (USE_GNU_MALLOC_LIBRARY) + +MALLOC_OBJ = $(ALLOC_LIBDIR)malloc.o +MALLOC_SRC = $(ALLOC_LIBSRC)malloc.c +MALLOC_DEP = $(MALLOC_SRC) $(ALLOC_LIBSRC)getpagesize.h +MALLOC_FLAGS = -Drcheck -Dbotch=programming_error + +MALLOC_LIBRARY = + +#endif /* USE_GNU_MALLOC && !USE_GNU_MALLOC_LIBRARY */ + +/* If this user doesn't have alloca (), then we must try to supply them + with a working one. */ +#if !defined (HAVE_ALLOCA) +ALLOCA = $(ALLOC_LIBDIR)alloca.o +# if defined (ALLOCA_ASM) +ALLOCA_SOURCE = ALLOCA_ASM +ALLOCA_OBJECT = ALLOCA_OBJ +# else +ALLOCA_SOURCE = alloca.c +ALLOCA_OBJECT = alloca.o +# endif /* ALLOCA_ASM */ +ALLOCA_DEP = $(ALLOC_LIBSRC)$(ALLOCA_SOURCE) +#endif /* !HAVE_ALLOCA */ + +/* Compilation flags to use in the shell directory and to pass to builds + in subdirectories (readline, termcap) to ensure that alloca is treated + in a consistent fashion. */ +#if defined (HAVE_ALLOCA_H) +ALLOCA_H_DEFINE = -DHAVE_ALLOCA_H +#else +ALLOCA_H_DEFINE = +#endif /* HAVE_ALLOCA_H */ + +#if defined (HAVE_ALLOCA) +ALLOCA_DEFINE = -DHAVE_ALLOCA +#else +ALLOCA_DEFINE = +#endif /* HAVE_ALLOCA */ + +ALLOCA_CFLAGS = $(ALLOCA_DEFINE) $(ALLOCA_H_DEFINE) + +/* Protect the `i386' used in the definition of ALLOC_FILES. */ +#if defined (i386) +# undef i386 +# define i386_defined +#endif /* i386 */ + +ALLOC_HEADERS = $(ALLOC_LIBSRC)getpagesize.h +ALLOC_FILES = $(ALLOC_LIBSRC)malloc.c $(ALLOC_LIBSRC)alloca.c \ + $(ALLOC_LIBSRC)i386-alloca.s $(ALLOC_LIBSRC)x386-alloca.s \ + $(ALLOC_LIBSRC)xmalloc.c + +/* Perhaps restore the `i386' define. */ +#if defined (i386_defined) +# define i386 +# undef i386_defined +#endif /* i386_defined */ + +#if defined (USE_GNU_MALLOC) && !defined (USE_GNU_MALLOC_LIBRARY) +$(MALLOC_OBJ): $(MALLOC_DEP) + @sh $(SUPPORT_SRC)mkdirs $(ALLOC_LIBDIR) + @$(RM) $@ + @($(LIBINC_DECL); cd $(ALLOC_LIBDIR) ; \ + if [ ! -f Makefile ]; then cp $(ALLOC_ABSSRC)Makefile Makefile ; fi; \ + $(MAKE) $(MFLAGS) \ + CFLAGS='$(LIBRARY_CFLAGS) $(MALLOC_FLAGS)' \ + CPPFLAGS='$(CPPFLAGS)' MALLOC_SOURCE=$(MALLOC_SRC) \ + srcdir=$(ALLOC_ABSSRC) malloc.o ) +#endif /* USE_GNU_MALLOC && !USE_GNU_MALLOC_LIBRARY */ + +#if !defined (HAVE_ALLOCA) +$(ALLOCA): $(ALLOCA_DEP) + @sh $(SUPPORT_SRC)mkdirs $(ALLOC_LIBDIR) + @$(RM) $@ + @($(LIBINC_DECL); cd $(ALLOC_LIBDIR) ; \ + if [ ! -f Makefile ]; then cp $(ALLOC_ABSSRC)Makefile Makefile ; fi; \ + $(MAKE) $(MFLAGS) CC='$(CC)' \ + CFLAGS='$(LIBRARY_CFLAGS) $(MALLOC_FLAGS)' \ + CPPFLAGS='$(CPPFLAGS)' ALLOCA_SOURCE=$(ALLOCA_SOURCE) \ + ALLOCA_OBJECT=$(ALLOCA_OBJECT) \ + srcdir=$(ALLOC_ABSSRC) alloca.o ) +#endif /* !HAVE_ALLOCA */ + +/**/# The location of ranlib on your system. +#if defined (RANLIB_LOCATION) +RANLIB = RANLIB_LOCATION +#else +RANLIB = ranlib +#endif /* RANLIB_LOCATION */ + +/* **************************************************************** */ +/* */ +/* Support for optional object files */ +/* */ +/* **************************************************************** */ +#if !defined (HAVE_SYS_SIGLIST) +/**/# Since this system does not have sys_siglist, we define SIGLIST +/**/# as siglist.o. +SIGLIST = siglist.o +SIGLIST_FLAG=-DINITIALIZE_SIGLIST +#endif /* HAVE_SYS_SIGLIST */ + +#if !defined (HAVE_GETCWD) +/**/# Since this system does not have a correctly working getcwd (), +/**/# we define GETCWD as getcwd.o. +GETCWD = getcwd.o +#endif /* !HAVE_GETCWD */ + +/**/# The source and object of the curly brace expansion and completion code. +BRACES_SOURCE = braces.c +BRACECOMP_SOURCE = bracecomp.c +#if defined (BRACE_EXPANSION) +BRACES_OBJECT = braces.o +# if defined (READLINE) +BRACECOMP_OBJECT = bracecomp.o +# endif /* READLINE */ +#endif /* BRACE_EXPANSION */ + +#if defined (REQUIRED_LIBRARIES) +/**/# Locally required libraries. +LOCAL_LIBS = REQUIRED_LIBRARIES +#endif /* REQUIRED_LIBRARIES */ + +BUILTINS_LIB = builtins/libbuiltins.a + +/**/# The main source code for the Bourne Again SHell. +CSOURCES = shell.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \ + dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \ + expr.c copy_cmd.c flags.c subst.c hash.c mailcheck.c \ + test.c trap.c jobs.c nojobs.c $(ALLOC_FILES) $(BRACES_SOURCE) \ + vprint.c input.c bashhist.c \ + unwind_prot.c siglist.c getcwd.c $(RL_SUPPORT_SRC) error.c + +HSOURCES = shell.h flags.h trap.h hash.h jobs.h builtins.h alias.c y.tab.h \ + general.h variables.h config.h $(ALLOC_HEADERS) alias.h maxpath.h \ + quit.h machines.h posixstat.h filecntl.h unwind_prot.h parser.h \ + command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \ + subst.h externs.h siglist.h bashhist.h bashtypes.h + +SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) + +/**/# Matching object files. +OBJECTS = shell.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ + dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \ + expr.o flags.o jobs.o subst.o hash.o mailcheck.o test.o \ + trap.o alias.o $(MALLOC_OBJ) $(ALLOCA) $(BRACES_OBJECT) \ + unwind_prot.o $(VPRINT_OBJ) input.o $(HIST_SUPPORT_OBJ) \ + $(SIGLIST) $(GETCWD) version.o $(RL_SUPPORT_OBJ) $(BUILTINS_LIB) + +/**/# Where the source code of the shell builtins resides. +BUILTIN_SRCDIR=$(srcdir)/builtins/ +/**/# The trailing slash was left off this definition on purpose +BUILTIN_ABSSRC=$${topdir}/builtins +DEFDIR = builtins/ +BUILTIN_DEFS = $(DEFDIR)alias.def $(DEFDIR)bind.def $(DEFDIR)break.def \ + $(DEFDIR)builtin.def $(DEFDIR)cd.def $(DEFDIR)colon.def \ + $(DEFDIR)command.def $(DEFDIR)declare.def $(LOAD_DEF) \ + $(DEFDIR)echo.def $(DEFDIR)enable.def $(DEFDIR)eval.def \ + $(DEFDIR)exec.def $(DEFDIR)exit.def $(DEFDIR)fc.def \ + $(DEFDIR)fg_bg.def $(DEFDIR)hash.def $(DEFDIR)help.def \ + $(DEFDIR)history.def $(DEFDIR)jobs.def $(DEFDIR)kill.def \ + $(DEFDIR)let.def $(DEFDIR)read.def $(DEFDIR)return.def \ + $(DEFDIR)set.def $(DEFDIR)setattr.def $(DEFDIR)shift.def \ + $(DEFDIR)source.def $(DEFDIR)suspend.def $(DEFDIR)test.def \ + $(DEFDIR)times.def $(DEFDIR)trap.def $(DEFDIR)type.def \ + $(DEFDIR)ulimit.def $(DEFDIR)umask.def $(DEFDIR)wait.def \ + $(DEFDIR)getopts.def $(DEFDIR)reserved.def +BUILTIN_C_SRC = $(DEFDIR)mkbuiltins.c $(DEFDIR)common.c \ + $(DEFDIR)hashcom.h $(DEFDIR)/bashgetopt.c $(GETOPT_SOURCE) +BUILTIN_C_OBJ = $(GETOPTS_OBJ) $(DEFDIR)common.o $(DEFDIR)bashgetopt.o +BUILTIN_OBJS = $(DEFDIR)alias.o $(DEFDIR)bind.o $(DEFDIR)break.o \ + $(DEFDIR)builtin.o $(DEFDIR)cd.o $(DEFDIR)colon.o \ + $(DEFDIR)command.o $(DEFDIR)declare.o $(LOAD_OBJ) \ + $(DEFDIR)echo.o $(DEFDIR)enable.o $(DEFDIR)eval.o \ + $(DEFDIR)exec.o $(DEFDIR)exit.o $(DEFDIR)fc.o \ + $(DEFDIR)fg_bg.o $(DEFDIR)hash.o $(DEFDIR)help.o \ + $(DEFDIR)history.o $(DEFDIR)jobs.o $(DEFDIR)kill.o \ + $(DEFDIR)let.o $(DEFDIR)read.o $(DEFDIR)return.o \ + $(DEFDIR)set.o $(DEFDIR)setattr.o $(DEFDIR)shift.o \ + $(DEFDIR)source.o $(DEFDIR)suspend.o $(DEFDIR)test.o \ + $(DEFDIR)times.o $(DEFDIR)trap.o $(DEFDIR)type.o \ + $(DEFDIR)ulimit.o $(DEFDIR)umask.o $(DEFDIR)wait.o \ + $(BUILTIN_C_OBJ) +#if defined (GETOPTS_BUILTIN) +GETOPTS_OBJ = $(DEFDIR)getopts.o +#endif +GETOPT_SOURCE = $(DEFDIR)getopt.c $(DEFDIR)getopt.h +PSIZE_SOURCE = $(DEFDIR)psize.sh $(DEFDIR)psize.c +BUILTIN_SUPPORT = $(DEFDIR)Makefile $(DEFDIR)ChangeLog $(PSIZE_SOURCE) \ + $(BUILTIN_C_SRC) + +/**/# Documentation for the shell. +DOCDIR = $(srcdir)/documentation/ +BASH_TEXINFO = $(DOCDIR)*.texi $(DOCDIR)*.tex \ + $(DOCDIR)*.dvi $(DOCDIR)Makefile +BASH_MAN = $(DOCDIR)bash.1 +BASHDOCS = $(BASH_TEXINFO) $(BASH_MAN) INSTALL README RELEASE +DOCUMENTATION = $(BASHDOCS) $(LIBRARY_DOC) + +/**/# Some example files demonstrating use of the shell. +/* This has to be written funny to avoid looking like a comment starter. */ +EXAMPLES = examples/[a-zA-Z]* + +ENDIAN_SUPPORT = endian.c +#if !defined (HAVE_WAIT_H) +ENDIAN_HEADER = bash_endian.h +#else +ENDIAN_HEADER = +#endif +ENDIAN_OUTPUT = endian.aux $(ENDIAN_HEADER) + +SIGNAMES_SUPPORT = signames.c +SIGNAMES_OUTPUT = signames.aux signames.h + +SUPPORT_SRC = $(srcdir)/support/ +SDIR = ./support/ +MKTARFILE = $(SDIR)mktarfile +SCRIPTS_SUPPORT = $(SUPPORT_SRC)mksysdefs $(SUPPORT_SRC)cppmagic \ + $(SUPPORT_SRC)cat-s $(MKTARFILE) $(SUPPORT_SRC)mail-shell \ + $(SUPPORT_SRC)inform $(SUPPORT_SRC)/fixdist \ + $(SUPPORT_SRC)mklinks $(SUPPORT_SRC)PORTING \ + $(SUPPORT_SRC)/clone.bash +FAQ = $(SUPPORT_SRC)FAQ + +TEST_SUITE = ./test-suite/ +TEST_SUITE_SUPPORT = $(TEST_SUITE)[a-zA-Z0-9]* $(SUPPORT_SRC)recho.c + +CREATED_SUPPORT = $(ENDIAN_OUTPUT) $(SIGNAMES_OUTPUT) sysdefs.h \ + $(SDIR)getcppsyms recho tests/recho tests/printenv + +SUPPORT = configure $(ENDIAN_SUPPORT) $(SIGNAMES_SUPPORT) $(SCRIPTS_SUPPORT) \ + $(BUILTIN_SUPPORT) COPYING Makefile cpp-Makefile ChangeLog \ + .distribution newversion.c $(EXAMPLES) $(SUPPORT_SRC)bash.xbm \ + $(FAQ) $(SUPPORT_SRC)getcppsyms.c $(TEST_SUITE_SUPPORT) + +/**/# BAGGAGE consists of things that you want to keep with the shell for some +/**/# reason, but do not actually use; old source code, etc. +BAGGAGE = + +/**/# Things that the world at large needs. +THINGS_TO_TAR = $(SOURCES) $(LIBRARY_TAR) $(BASHDOCS) $(SUPPORT) $(BAGGAGE) + +/**/# Keep GNU Make from exporting the entire environment for small machines. +.NOEXPORT: + +.made: $(Program) bashbug + cp .machine .made + +$(Program): .build $(OBJECTS) $(LIBDEP) $(srcdir)/.distribution + $(RM) $@ + $(PURIFY) $(CC) $(LDFLAGS) $(LIBRARY_LDFLAGS) -o $(Program) $(OBJECTS) $(LIBRARIES) + ls -l $(Program) + size $(Program) + +.build: $(SOURCES) cpp-Makefile newversion.aux + if ./newversion.aux -dir $(srcdir) -build; then mv -f newversion.h version.h; fi + @echo + @echo " ***************************************************" + @echo " * *" + @echo " * Making Bash-`cat $(srcdir)/.distribution`.`cat $(srcdir)/.patchlevel` for a $(Machine) running $(OS)" + @echo " * *" + @echo " ***************************************************" + @echo + @echo "$(Program) last made for a $(Machine) running $(OS)" >.machine + +bashbug: $(SUPPORT_SRC)bashbug.sh cpp-Makefile newversion.aux + @sed -e "s:@MACHINE@:$(Machine):" -e "s:@OS@:$(OS):" \ + -e "s:@CFLAGS@:$(CCFLAGS):" -e "s:@CC@:$(CC):" \ + -e "s:@RELEASE@:`cat $(srcdir)/.distribution`:" \ + -e "s:@PATCHLEVEL@:`cat $(srcdir)/.patchlevel`:" \ + $(SUPPORT_SRC)bashbug.sh > $@ + @chmod a+rx bashbug + +version.h: newversion.aux + if ./newversion.aux -dir $(srcdir) -build; then mv -f newversion.h version.h; fi + +y.tab.c: parser-built +y.tab.h: parser-built +parser-built: parse.y parser.h command.h stdc.h input.h + $(RM) $@ + -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi + @echo expect 66 shift/reduce conflicts + $(BISON) -d $(srcdir)/parse.y + -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi + touch $@ + +#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) +$(READLINE_LIBRARY): $(READLINE_SOURCE) + build_lib_in_dir ($(RL_LIBDIR), libreadline.a, srcdir=$(RL_ABSSRC), $(RL_ABSSRC)Makefile) +#endif /* READLINE && HAVE_READLINE_SOURCE */ + +#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) && !defined (READLINE) +$(HISTORY_LIBRARY): $(HISTORY_SOURCE) + build_lib_in_dir ($(HIST_LIBDIR), libhistory.a, srcdir=$(HIST_ABSSRC), $(HIST_ABSSRC)Makefile) +#endif /* HISTORY && HAVE_HISTORY_SOURCE && !READLINE */ + +#if defined (HAVE_TERMCAP_SOURCE) +$(TERMCAP_LIBRARY): $(TERMCAP_SOURCE) + build_lib_in_dir ($(TERM_LIBDIR), libtermcap.a, srcdir=$(TERM_ABSSRC), $(TERM_ABSSRC)Makefile) +#endif /* HAVE_TERMCAP_SOURCE */ + +#if defined (USE_GLOB_LIBRARY) +$(GLOB_LIBRARY): $(GLOB_SOURCE) + build_lib_in_dir ($(GLOB_LIBDIR), libglob.a, srcdir=$(GLOB_ABSSRC), $(GLOB_ABSSRC)Makefile) +#endif /* USE_GLOB_LIBRARY */ + +#if defined (HAVE_TILDE_SOURCE) +$(TILDE_LIBRARY): $(TILDE_SOURCE) + build_lib_in_dir ($(TILDE_LIBDIR), libtilde.a, srcdir=$(TILDE_ABSSRC), $(TILDE_ABSSRC)Makefile) +#endif /* HAVE_TILDE_SOURCE */ + +#if defined (USE_GNU_MALLOC) && defined (USE_GNU_MALLOC_LIBRARY) +$(MALLOC_LIBRARY): $(MALLOC_SOURCE) + build_lib_in_dir ($(MALLOC_LIBDIR), libmalloc.a, srcdir=$(MALLOC_ABSSRC), $(MALLOC_ABSSRC)Makefile) +#endif /* USE_GNU_MALLOC && USE_GNU_MALLOC_LIBRARY */ + +version.o: version.c version.h + +shell.o: shell.c shell.h flags.h shell.c posixstat.h filecntl.h stdc.h $(ENDIAN_HEADER) parser.h + $(RM) $@ + $(CC) $(CFG_FLAGS) $(CCFLAGS) $(CPPFLAGS) -c $(srcdir)/shell.c + +#if !defined (HAVE_WAIT_H) +$(ENDIAN_HEADER): endian.aux + $(RM) $@ + ./endian.aux $@ +#endif + +signames.h: signames.aux + $(RM) $@ + ./signames.aux $@ + +variables.o: variables.c shell.h hash.h flags.h variables.h + $(RM) $@ + $(CC) -c $(CCFLAGS) $(HOSTTYPE_DECL) $(CPPFLAGS) $(srcdir)/variables.c + +builtins/libbuiltins.a: $(BUILTIN_OBJS) config.h memalloc.h + build_builtins (libbuiltins.a) + +#if 0 +/* This is a nice idea, but it does not work right, and the syntax is + not universally available. */ +$(BUILTIN_OBJS): $(BUILTIN_DEFS) + build_builtins ($(@F)) +#endif + +builtins/common.o: $(BUILTIN_SRCDIR)common.c + build_builtins (common.o) +builtins/bashgetopt.o: $(BUILTIN_SRCDIR)bashgetopt.c + build_builtins (bashgetopt.o) + +builtins/builtext.h: builtins/libbuiltins.a + +/* Dependencies for the main bash source. */ +copy_cmd.o: shell.h command.h stdc.h hash.h +copy_cmd.o: general.h variables.h config.h memalloc.h quit.h +copy_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +dispose_cmd.o: shell.h command.h stdc.h +dispose_cmd.o: general.h variables.h config.h memalloc.h quit.h +dispose_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +error.o: error.h +execute_cmd.o: shell.h command.h stdc.h y.tab.h posixstat.h flags.h jobs.h +execute_cmd.o: general.h variables.h config.h memalloc.h quit.h hash.h +execute_cmd.o: unwind_prot.h siglist.h builtins/builtext.h +execute_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h +expr.o: shell.h command.h stdc.h hash.h +expr.o: general.h variables.h config.h memalloc.h quit.h +expr.o: dispose_cmd.h make_cmd.h subst.h externs.h +flags.o: flags.h stdc.h config.h memalloc.h general.h quit.h +general.o: shell.h command.h stdc.h maxpath.h +general.o: general.h variables.h config.h memalloc.h quit.h machines.h +general.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +hash.o: shell.h command.h stdc.h hash.h +hash.o: general.h variables.h config.h memalloc.h quit.h +hash.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +jobs.o: shell.h command.h stdc.h hash.h trap.h jobs.h siglist.h +jobs.o: general.h variables.h config.h memalloc.h quit.h +jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h builtins/builtext.h +mailcheck.o: posixstat.h maxpath.h variables.h +mailcheck.o: hash.h quit.h +make_cmd.o: shell.h command.h stdc.h flags.h input.h bashtypes.h +make_cmd.o: general.h variables.h config.h memalloc.h quit.h +make_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +y.tab.o: shell.h command.h stdc.h flags.h maxpath.h alias.h +y.tab.o: general.h variables.h config.h memalloc.h quit.h +y.tab.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h +print_cmd.o: shell.h command.h stdc.h y.tab.h +print_cmd.o: general.h variables.h config.h memalloc.h quit.h +print_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +shell.o: shell.h command.h stdc.h flags.h machines.h +shell.o: general.h variables.h config.h memalloc.h quit.h +shell.o: dispose_cmd.h make_cmd.h subst.h externs.h +shell.o: posixstat.h filecntl.h jobs.h input.h +subst.o: shell.h command.h stdc.h flags.h jobs.h siglist.h bashtypes.h +subst.o: general.h variables.h config.h memalloc.h quit.h +subst.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h +test.o: posixstat.h +trap.o: trap.h shell.h command.h stdc.h hash.h unwind_prot.h signames.h +trap.o: general.h variables.h config.h memalloc.h quit.h +trap.o: dispose_cmd.h make_cmd.h subst.h externs.h +unwind_prot.o: config.h memalloc.h general.h unwind_prot.h +variables.o: shell.h command.h stdc.h hash.h flags.h +variables.o: config.h memalloc.h general.h variables.h quit.h +variables.o: execute_cmd.h dispose_cmd.h make_cmd.h subst.h externs.h +version.o: version.h .build + +alias.o: ansi_stdlib.h +bashline.o: ansi_stdlib.h +variables.o: ansi_stdlib.h +shell.o: ansi_stdlib.h +error.o: ansi_stdlib.h +hash.o: ansi_stdlib.h +signames.o: ansi_stdlib.h +expr.o: ansi_stdlib.h +general.o: ansi_stdlib.h +input.o: ansi_stdlib.h + +#if !defined (JOB_CONTROL) +jobs.o: nojobs.c +#endif /* !JOB_CONTROL */ + +#if defined (BRACE_EXPANSION) +braces.o: general.h shell.h variables.h quit.h config.h memalloc.h +braces.o: dispose_cmd.h make_cmd.h subst.h externs.h +braces.o: maxpath.h unwind_prot.h command.h stdc.h +# if defined (READLINE) +bracecomp.o: bracecomp.c +bracecomp.o: shell.h command.h hash.h builtins.h general.h variables.h +bracecomp.o: quit.h alias.h +bracecomp.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +# if defined (HAVE_READLINE_SOURCE) +bracecomp.o: $(RL_LIBSRC)readline.h +# endif /* HAVE_READLINE_SOURCE */ +# endif /* READLINE */ +#endif /* BRACE_EXPANSION */ + +#if defined (READLINE) +bashline.o: shell.h command.h stdc.h hash.h builtins.h execute_cmd.h +bashline.o: general.h variables.h config.h memalloc.h quit.h alias.h +bashline.o: dispose_cmd.h make_cmd.h subst.h externs.h +#endif /* READLINE */ + +/* Dependencies which rely on the user using the source to READLINE. */ +#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) +bashline.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h +y.tab.o: $(RL_LIBSRC)keymaps.h $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h +#endif /* READLINE && HAVE_READLINE_SOURCE */ + +#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) +subst.o: $(HIST_LIBSRC)history.h +bashline.o: $(HIST_LIBSRC)history.h +y.tab.o: $(HIST_LIBSRC)history.h +#endif /* HISTORY && HAVE_HISTORY_SOURCE */ + +#if defined (USE_GLOB_LIBRARY) +subst.o: $(GLOB_LIBSRC)fnmatch.h +execute_cmd.o: $(GLOB_LIBSRC)fnmatch.h +#endif /* USE_GLOB_LIBRARY */ + +#if defined (HAVE_TILDE_SOURCE) +execute_cmd.o: $(TILDE_LIBSRC)tilde.h +general.o: $(TILDE_LIBSRC)tilde.h +mailcheck.o: $(TILDE_LIBSRC)tilde.h +shell.o: $(TILDE_LIBSRC)tilde.h +subst.o: $(TILDE_LIBSRC)tilde.h +variables.o: $(TILDE_LIBSRC)tilde.h +#endif /* HAVE_TILDE_SOURCE */ + +/* Dependencies for the shell builtins. */ +builtins/common.o: shell.h command.h config.h memalloc.h general.h error.h +builtins/common.o: variables.h input.h $(DEFDIR)hashcom.h siglist.h +builtins/common.o: quit.h unwind_prot.h maxpath.h jobs.h builtins.h +builtins/common.o: dispose_cmd.h make_cmd.h subst.h externs.h bashhist.h +builtins/common.o: execute_cmd.h stdc.h +builtins/alias.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/alias.o: quit.h builtins/common.h +builtins/alias.o: shell.h command.h stdc.h unwind_prot.h variables.h +builtins/alias.o: dispose_cmd.h make_cmd.h subst.h externs.h +builtins/bind.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/bind.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/bind.o: shell.h unwind_prot.h variables.h quit.h +builtins/bind.o: $(DEFDIR)bashgetopt.h +builtins/break.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/break.o: shell.h unwind_prot.h variables.h quit.h +builtins/break.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/builtin.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/builtin.o: quit.h $(DEFDIR)common.h +builtins/builtin.o: shell.h unwind_prot.h variables.h +builtins/builtin.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/cd.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h +builtins/cd.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h +builtins/cd.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/command.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/command.o: quit.h $(DEFDIR)bashgetopt.h +builtins/command.o: shell.h unwind_prot.h variables.h +builtins/command.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/declare.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/declare.o: shell.h unwind_prot.h variables.h quit.h +builtins/declare.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/echo.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/echo.o: shell.h unwind_prot.h variables.h quit.h +builtins/echo.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/enable.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/enable.o: shell.h unwind_prot.h variables.h quit.h +builtins/enable.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/eval.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h +builtins/eval.o: shell.h unwind_prot.h variables.h +builtins/eval.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/exec.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h +builtins/exec.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h stdc.h +builtins/exec.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h +builtins/exec.o: flags.h +builtins/exit.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/exit.o: shell.h unwind_prot.h variables.h quit.h +builtins/exit.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/fc.o: builtins.h command.h stdc.h +builtins/fc.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h +builtins/fc.o: flags.h unwind_prot.h variables.h shell.h +builtins/fc.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/fc.o: $(DEFDIR)bashgetopt.h bashhist.h +builtins/fg_bg.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/fg_bg.o: shell.h unwind_prot.h variables.h quit.h +builtins/fg_bg.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/getopts.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/getopts.o: shell.h unwind_prot.h variables.h quit.h +builtins/getopts.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/hash.o: builtins.h command.h execute_cmd.h stdc.h +builtins/hash.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/hash.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h quit.h +builtins/help.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/help.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/help.o: shell.h unwind_prot.h variables.h quit.h +builtins/history.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/history.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/history.o: filecntl.h shell.h unwind_prot.h variables.h +builtins/history.o: bashhist.h +builtins/inlib.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/inlib.o: shell.h unwind_prot.h variables.h quit.h +builtins/inlib.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/jobs.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/jobs.o: quit.h $(DEFDIR)bashgetopt.h +builtins/jobs.o: shell.h unwind_prot.h variables.h +builtins/jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/kill.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/kill.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/kill.o: shell.h trap.h unwind_prot.h variables.h +builtins/let.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/let.o: shell.h unwind_prot.h variables.h +builtins/read.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/read.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/read.o: shell.h unwind_prot.h variables.h +builtins/return.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/return.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/return.o: shell.h unwind_prot.h variables.h +builtins/set.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/set.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h +builtins/set.o: shell.h unwind_prot.h variables.h flags.h stdc.h +builtins/setattr.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/setattr.o: quit.h $(DEFDIR)common.h $(DEFDIR)bashgetopt.h +builtins/setattr.o: shell.h unwind_prot.h variables.h +builtins/setattr.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/shift.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/shift.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/shift.o: shell.h unwind_prot.h variables.h +builtins/shift.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/source.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/source.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/source.o: shell.h unwind_prot.h variables.h +builtins/suspend.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/suspend.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/suspend.o: shell.h unwind_prot.h variables.h +builtins/test.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/test.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/test.o: shell.h unwind_prot.h variables.h +builtins/times.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/times.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/times.o: shell.h unwind_prot.h variables.h +builtins/trap.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/trap.o: quit.h $(DEFDIR)common.h +builtins/trap.o: shell.h unwind_prot.h variables.h +builtins/trap.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/type.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/type.o: quit.h $(DEFDIR)common.h +builtins/type.o: shell.h unwind_prot.h variables.h execute_cmd.h +builtins/type.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/ulimit.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/ulimit.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/ulimit.o: shell.h unwind_prot.h variables.h +builtins/umask.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/umask.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/umask.o: shell.h unwind_prot.h variables.h +builtins/wait.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/wait.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/wait.o: shell.h unwind_prot.h variables.h + +builtins/bashgetopt.o: bashansi.h ansi_stdlib.h +builtins/mkbuiltins.o: bashansi.h ansi_stdlib.h +builtins/fc.o: bashansi.h ansi_stdlib.h + +#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) +builtins/bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h +#endif /* READLINE && HAVE_READLINE_SOURCE */ + +#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) +builtins/bind.o: $(HIST_LIBSRC)history.h +builtins/fc.o: $(HIST_LIBSRC)history.h +builtins/history.o: $(HIST_LIBSRC)history.h +#endif /* HISTORY && HAVE_HISTORY_SOURCE */ + +#if defined (HAVE_TILDE_SOURCE) +builtins/common.o: $(TILDE_LIBSRC)tilde.h +builtins/cd.o: $(TILDE_LIBSRC)tilde.h +#endif /* HAVE_TILDE_SOURCE */ + +builtins/alias.o: builtins/alias.def +builtins/bind.o: builtins/bind.def +builtins/break.o: builtins/break.def +builtins/builtin.o: builtins/builtin.def +builtins/cd.o: builtins/cd.def +builtins/colon.o: builtins/colon.def +builtins/command.o: builtins/command.def +builtins/declare.o: builtins/declare.def +builtins/echo.o: builtins/echo.def +builtins/enable.o: builtins/enable.def +builtins/eval.o: builtins/eval.def +builtins/exec.o: builtins/exec.def +builtins/exit.o: builtins/exit.def +builtins/fc.o: builtins/fc.def +builtins/fg_bg.o: builtins/fg_bg.def +builtins/getopts.o: builtins/getopts.def +builtins/hash.o: builtins/hash.def +builtins/help.o: builtins/help.def +builtins/histctl.o: builtins/histctl.def +builtins/history.o: builtins/history.def +builtins/inlib.o: builtins/inlib.def +builtins/jobs.o: builtins/jobs.def +builtins/kill.o: builtins/kill.def +builtins/let.o: builtins/let.def +builtins/read.o: builtins/read.def +builtins/reserved.o: builtins/reserved.def +builtins/return.o: builtins/return.def +builtins/set.o: builtins/set.def +builtins/setattr.o: builtins/setattr.def +builtins/shift.o: builtins/shift.def +builtins/source.o: builtins/source.def +builtins/suspend.o: builtins/suspend.def +builtins/test.o: builtins/test.def +builtins/times.o: builtins/times.def +builtins/trap.o: builtins/trap.def +builtins/type.o: builtins/type.def +builtins/ulimit.o: builtins/ulimit.def +builtins/umask.o: builtins/umask.def +builtins/wait.o: builtins/wait.def + +$(Program).tar: $(THINGS_TO_TAR) .distribution + @$(MKTARFILE) $(Program) `cat .distribution` $(THINGS_TO_TAR) + +$(Program).tar$(COMPRESS_EXT): $(Program).tar + $(COMPRESS) < $(Program).tar > $@ + +clone: $(THINGS_TO_TAR) + @$(MKTARFILE) +notar $(Machine) $(OS) $(THINGS_TO_TAR) + +installdirs: + @${SHELL} $(SUPPORT_SRC)mkdirs $(bindir) + @${SHELL} $(SUPPORT_SRC)mkdirs $(mandir) $(man3dir) + @${SHELL} $(SUPPORT_SRC)mkdirs $(infodir) + +install: .made installdirs documentation + -if [ -f $(bindir)/$(Program) ]; then \ + rm -f $(bindir)/$(Program).old ;\ + ln $(bindir)/$(Program) $(bindir)/$(Program).old; \ + fi + $(INSTALL_PROGRAM) $(Program) $(bindir)/$(Program) + -if [ -f $(bindir)/bashbug ]; \ + then mv $(bindir)/bashbug $(bindir)/bashbug.old; \ + fi + $(INSTALL_PROGRAM) bashbug $(bindir)/bashbug + ( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) mandir=$(mandir) \ + man3dir=$(man3dir) infodir=$(infodir) $@ ) + +uninstall: .made + $(RM) $(bindir)/$(Program) installed-$(Program) $(bindir)/bashbug + ( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) mandir=$(mandir) man3dir=$(man3dir) infodir=$(infodir) $@ ) + +.distribution: + ./newversion.aux -dir $(srcdir) -dist `$(Program) -c 'echo $$BASH_VERSION'` + +distribution: $(Program) $(Program).tar$(COMPRESS_EXT) .distribution + @echo cp $(Program).tar$(COMPRESS_EXT) \ + $(Program)-`cat .distribution`.tar$(COMPRESS_EXT) + @cp $(Program).tar$(COMPRESS_EXT) \ + $(Program)-`cat .distribution`.tar$(COMPRESS_EXT) + +mailable: distribution + /bin/rm -rf uuencoded + mkdir uuencoded + $(SHELL) -c 'f=$(Program)-`cat .distribution`.tar.Z;uuencode $$f $$f | split -800 - uuencoded/$$f.uu.' + +newversion.aux: newversion.c + $(CC) $(CCFLAGS) -o $@ $(srcdir)/newversion.c + +newversion: newversion.aux + $(RM) .build + ./newversion.aux -dir $(srcdir) -dist + mv -f newversion.h version.h + $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) + +documentation: force + (cd $(DOCDIR); $(MAKE) $(MFLAGS)) + +force: + +tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + +TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ + +basic-clean: + $(RM) $(OBJECTS) $(Program) bashbug ansi-Makefile *.aux + $(RM) .build .made .machine version.h + $(RM) $(CREATED_SUPPORT) + $(RM) tags TAGS + +mostlyclean: + $(RM) $(OBJECTS) $(Program) bashbug + $(RM) .build .made .machine version.h + $(RM) tags TAGS + (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + (cd builtins && $(MAKE) $(MFLAGS) $@ ) + $(CLEAN_READLINE) ; + $(CLEAN_HISTORY) ; + $(CLEAN_TERMCAP) ; + $(CLEAN_GLOB) ; + $(CLEAN_TILDE) ; + $(CLEAN_MALLOC) ; + +distclean clean: basic-clean + (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + (cd builtins && $(MAKE) $(MFLAGS) $@ ) + $(CLEAN_READLINE) ; + $(CLEAN_HISTORY) ; + $(CLEAN_TERMCAP) ; + $(CLEAN_GLOB) ; + $(CLEAN_TILDE) ; + $(CLEAN_MALLOC) ; + $(RM) bash-Makefile + +realclean maintainer-clean: basic-clean + $(RM) y.tab.c y.tab.h parser-built + (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + (cd builtins && $(MAKE) $(MFLAGS) $@ ) + $(CLEAN_READLINE) ; + $(CLEAN_HISTORY) ; + $(CLEAN_TERMCAP) ; + $(CLEAN_GLOB) ; + $(CLEAN_TILDE) ; + $(CLEAN_MALLOC) ; + $(RM) bash-Makefile + +recho: $(SUPPORT_SRC)recho.c + @$(CC) -o $@ $(SUPPORT_SRC)recho.c + +tests check: force $(Program) recho + @cp recho $(SUPPORT_SRC)printenv tests + ( cd tests ; sh run-all ) + +/**/# Here is a convenient rule when you arrive at a new site and wish to +/**/# install bash on several different architectures. It creates a new +/**/# directory to hold the results of compilation. The directory is +/**/# named Machine-OS. +architecture: $(Machine)-$(OS)/$(Program) + +$(Machine)-$(OS): + -mkdir $(Machine)-$(OS) + +$(Machine)-$(OS)/$(Program): $(Machine)-$(OS) $(Program) + mv $(Program) $(Machine)-$(OS) + mv sysdefs.h $(Machine)-$(OS) + mv $(SDIR)getcppsyms $(Machine)-$(OS) + $(MAKE) $(MFLAGS) clean + +DEFINES: config.h memalloc.h cpp-Makefile sysdefs.h + echo $(CCFLAGS) $(CPPFLAGS) >DEFINES diff --git a/dispose_cmd.c b/dispose_cmd.c 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 + $(&p, <&p) + weirdly-scoped functions + typeset +f to list all function names without definitions + text of command history kept in a file, not memory + builtins: alias -x, cd old new, fc -e -, newgrp, print, + read -p/-s/u/var?prompt, set -A/-o gmacs/-o keyword/ + -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, + typeset -H/-L/-R/-A/-ft/-fu/-fx/-l/-u/-t, whence + +Implementation differences: + ksh runs last command of a pipeline in parent shell context + ksh ulimit sets hard and soft limits by default + bash has brace expansion by default + bash has fixed startup file for all interactive shells; ksh reads $ENV + bash has exported functions + bash command search finds functions before builtins + +8) What is the bash `posix mode'? + +Although bash is an implementation of the Posix.2 shell +specification, there are areas where the bash default behavior +differs from that spec. The bash `posix mode' changes the bash +behavior in these areas so that it obeys the spec more closely. + +Posix mode is entered by starting bash with the -posix option or +executing `set -o posix' after bash is running. + +The specific aspects of bash which change when posix mode is +active are listed in the file CWRU/POSIX.NOTES in the bash +distribution. + +9) How can I build bash with gcc? + +Type + make CC=gcc CPPNAME='$(CC) -E' + +10) Why does bash run a different version of `command' than + `which command' says it will? + +`which' is actually a csh script that assumes you're running csh. +It reads the csh startup files from your home directory and uses +those to determine which `command' will be invoked. Since bash +doesn't use any of those startup files, there's a good chance +that your bash environment differs from your csh environment. + +11) How can I make my csh aliases work when I convert to bash? + +Bash uses a different syntax to support aliases than csh does. +The details can be found in the documentation. We have provided +a shell script which does most of the work of conversion for you; +this script can be found in ./examples/alias-conv.sh. Here is +how you use it: + +Start csh in the normal way for you. (e.g., `csh') + +Pipe the output of `alias' through `alias-conv.sh', saving the +results into `bash_aliases': + + alias | alias-conv.sh >bash_aliases + +Edit `bash_aliases', carefully reading through any created +functions. You will need to change the names of csh specific +variables (like $cwd) to the bash equivalents (like $PWD). You +will also need to remove recursive references to commands which +are defined as functions. For example, the csh alias: + + alias cd 'cd \!*;echo $cwd' + +is converted to the bash function: + + cd () + { + cd $*; + echo $cwd + } + +This function contains a self-pointing reference to `cd', which +should be changed to use the `builtin' version. It also uses +the csh variable `$cwd' which has an equivalent in bash. +Precede the recursive reference with the word `builtin', and +change the name of the variable: + + cd () { builtin cd $*; echo $PWD; } + +Merge the edited file into your ~/.bashrc. + +12) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +There are features in ksh-88 that do not have direct bash equivalents. +Most, however, can be emulated with very little trouble. + +ksh-88 feature Bash equivalent +-------------- --------------- +[[...]] can usually use [...]; minor differences +compiled-in aliases set up aliases in .bashrc; some ksh aliases are + bash builtins (hash, history, type) +$(&2; read var + +13) Why is the bash builtin `test' slightly different from /bin/test? + +The specific example used here is [ ! x -o x ], which is false. + +Bash's builtin `test' implements the Posix.2 spec, which can be +summarized as follows (the wording is due to David Korn): + +Here is the set of rules for processing test arguments. + + 0 Args: False + 1 Arg: True iff argument is not null. + 2 Args: If first arg is !, True iff second argument is null. + If first argument is unary, then true if unary test is true + Otherwise error. + 3 Args: If second argument is a binary operator, do binary test of $1 $3 + If first argument is !, negate two argument test of $2 $3 + Otherwise error. + 4 Args: If first argument is !, negate three argument test of $2 $3 $4. + Otherwise unspecified + 5 or more Args: unspecified. (Historical shells would use their + current algorithm). + +The operators -a and -o are considered binary operators for the purpose +of the 3 Arg case. + +As you can see, the test becomes (not (x or x)), which is false. + +14) Why does bash sometimes say `Broken pipe'? + +If a sequence of commands appear in a pipeline, and one of the +reading commands finishes before the writer has finished, the +writer receives a SIGPIPE signal. Many other shells special-case +SIGPIPE as an exit status in the pipeline and do not report it. +For example, in: + + ps -aux | head + +`head' can finish before `ps' writes all of its output, and ps +will try to write on a pipe without a reader. In that case, bash +will print `Broken pipe' to stderr when ps is killed by a +SIGPIPE. + +15) How can I get bash to read and display eight-bit characters? + +This is a process requiring several steps. + +First, you must ensure that the `physical' data path is a full eight +bits. For xterms, for example, the `vt100' resources `eightBitInput' +and `eightBitOutput' should be set to `true'. + +Once you have set up an eight-bit path, you must tell the kernel and +tty driver to leave the eigth bit of characters alone when processing +keyboard input. Use `stty' to do this: + + stty cs8 -istrip -parenb + +For old BSD-style systems, you can use + + stty pass8 + +You may also need + + stty even odd + +Finally, you need to tell readline that you will be inputting and +displaying eight-bit characters. You use readline variables to do +this. These variables can be set in your .inputrc or using the bash +`bind' builtin. Here's an example using `bind': + + bash$ bind 'set convert-meta off' + bash$ bind 'set meta-flag on' + bash$ bind 'set output-meta on' + +The `set' commands between the single quotes may also be placed +in ~/.inputrc. + +16) Why can't I use command line editing in my `cmdtool'? + +The problem is `cmdtool' and bash fighting over the input. When +scrolling is enabled in a cmdtool window, cmdtool puts the tty in +`raw mode' to permit command-line editing using the mouse for +applications that cannot do it themselves. As a result, bash and +cmdtool each try to read keyboard input immediately, with neither +getting enough of it to be useful. + +This mode also causes cmdtool to not implement many of the +terminal functions and control sequences appearing in the +`sun-cmd' termcap entry. For a more complete explanation, see +that file examples/suncmd.termcap in the bash distribution. + +`xterm' is a better choice, and gets along with bash much more +smoothly. + +17) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? + +This is what the `command' and `builtin' builtins are for. The +`command' builtin executes the command supplied as its first +argument, skipping over any function defined with that name. The +`builtin' builtin executes the builtin command given as its first +argument directly. + +For example, to write a function to replace `cd' that writes the +hostname and current directory to an xterm title bar, use +something like the following: + + cd() + { + builtin cd "$@" && xtitle $HOST: $PWD + } + +This could also be written using `command' instead of `builtin'; +the version above is marginally more efficient. + +18) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? + +Bash does not know that the terminal escape sequences do not take +up space on the screen. The redisplay code assumes, unless told +otherwise, that each character in the prompt is a `printable' +character that takes up one character position on the screen. + +You can use the bash prompt expansion facility (see the PROMPTING +section in the manual page) to tell readline that sequences of +characters in the prompt strings take up no screen space. + +Use the \[ escape to begin a sequence of non-printing characters, +and the \] escape to signal the end of such a sequence. + +19) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? + +This is the consequence of building bash on SunOS 5 and linking +with the libraries in /usr/ucblib, but using the definitions +and strutures from files in /usr/include. + +The actual conflict is between the dirent structure in +/usr/include/dirent.h and the struct returned by the version of +`readdir' in libucb.a (a 4.3-BSD style `struct direct'). + +Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH +when building bash. This will ensure that you use /usr/ccs/bin/cc +or acc instead of /usr/ucb/cc and that you link with libc before +libucb. + +If you have installed the Sun C compiler, you may also need to +put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before +/usr/ucb. + +20) Why doesn't bash treat brace expansions exactly like csh? + +The only difference between bash and csh brace expansion is that +bash requires a brace expression to contain at least on unquoted +comma if it is to be expanded. Any brace-surrounded word not +containing an unquoted comma is left unchanged by the brace +expansion code. This affords the greatest degree of sh +compatibility. + +Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. + +21) Why does bash dump core after I interrupt username completion on a + machine running NIS? + +This is a famous and long-standing bug in the SunOS YP (sorry, NIS) +client library, which is part of libc. + +The YP library code keeps static state -- a pointer into the data +returned from the server. When YP initializes itself (setpwent), +it looks at this pointer and calls free on it if it's non-null. +So far, so good. + +If one of the YP functions is interrupted during getpwent (the +exact function is interpretwithsave()), and returns NULL, the +pointer is freed without being reset to NULL, and the function +returns. The next time getpwent is called, it sees that this +pointer is non-null, calls free, and the bash free() blows up +because it's being asked to free freed memory. + +The traditional Unix mallocs allow memory to be freed multiple +times; that's probably why this has never been fixed. You can +probably stop it by adding an #undef USE_GNU_MALLOC to the +appropriate machine description in machines.h. + +22) I'm running SVR4.2. Why is the line erased every time I type `@'? + +The `@' character is the default `line kill' character in most +versions of System V, including SVR4.2. You can change this +character to whatever you want using `stty'. For example, to +change the line kill character to control-u, type + + stty kill ^U + +where the `^' and `U' can be two separate characters. + +23) How can I find the value of a shell variable whose name is the value + of another shell variable? + +Use the `eval' builtin. The important thing to remember is that +`eval' expands the arguments you give it again, so you need to +quote the parts of the arguments that you want `eval' to act on. + +For example, this expression prints the value of the last positional +parameter: + + eval echo \$\{$#\} + +The expansion of the quoted portions of this expression will be +deferred until `eval' runs, while the `$#' will be expanded +before `eval' is executed. + +24) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? + +This has to do with the parent-child relationship between Unix +processes. + +Each element of a pipeline runs in a separate process, a child of +the shell running the pipeline. A subprocess cannot affect its +parent's environment. When the `read' command sets the variable +to the input, that variable is set only in the subshell, not the +parent shell. When the subshell exits, the value of the variable +is lost. + +Many pipelines that end with `read variable' can be converted +into command substitutions, which will capture the output into a +variable: + + grep ^gnu /usr/lib/news/active | wc -l | read ngroup + +can be converted into + + ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) + +This does not, unfortunately, work to split the text among +multiple variables, as read does when given multiple variable +arguments. + +25) I just changed my shell to bash, and now I can't FTP into my machine. + Why not? + +You must add the full pathname to bash to the file /etc/shells. +Many versions of ftpd use this file to prohibit `special' users +such as `uucp' and `news' from using FTP. + +26) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? + +This is the behavior of echo on most Unix System V machines. + +The bash builtin `echo' is modelled after the 9th Edition +Research Unix version of `echo'. It does not interpret +backslash-escaped characters in its argument strings by default, +but requires the use of the -e option to enable the +interpretation. The System V echo provides no way to disable the +special characters; the bash echo has a -E option to disable +them. + +There is a compile-time option that will make bash behave like +the System V echo and interpret things like \t by default. +Change config.h so that DEFAULT_ECHO_TO_USG is defined, remove +builtins/libbuiltins.a and builtins/echo.o, and rebuild. + +27) Why doesn't bash have csh variable modifiers? + +Posix has specified a more powerful, albeit somewhat more confusing, +mechanism cribbed from ksh, and bash implements it. + +${parameter%word} + Remove smallest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the suffix matched by the pattern deleted. + + x=file.c + echo ${x%.c}.o + -->file.o + +${parameter%%word} + + Remove largest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the suffix matched by the pattern deleted. + + x=posix/src/std + echo ${x%%/*} + -->posix + +${parameter#word} + Remove smallest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the prefix matched by the pattern deleted. + + x=$HOME/src/cmd + echo ${x#$HOME} + -->/src/cmd + +${parameter##word} + Remove largest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the prefix matched by the pattern deleted. + + x=/one/two/three + echo ${x##*/} + -->three + + +Given + a=/a/b/c/d + b=b.xxx + + csh bash result + --- ---- ------ + $a:h ${a%/*} /a/b/c + $a:t ${a##*/} d + $b:r ${b%.*} b + $b:e ${b##*.} xxx + + +28) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? + +The actual command in question is something like + + < file ( command ) + +According to the grammar given in the Posix.2 standard, this construct +is, in fact, a syntax error. Redirections may only precede `simple +commands'. A subshell construct such as the above is one of the shell's +`compound commands'. A redirection may only follow a compound command. + +The file CWRU/sh-redir-hack in the 1.14.6 distribution is an (unofficial) +patch to parse.y that will modify the grammar to support this construct. +Note that if you apply this, you must recompile with -DREDIRECTION_HACK. +This introduces a large number of reduce/reduce conflicts into the shell +grammar. + +29) How do I report bugs in bash, and where should I look for fixes and + advice? + +Use the `bashbug' script to report bugs. It is built and +installed at the same time as bash. It provides a standard +template for reporting a problem and automatically includes +information about your configuration and build environment. + +`bashbug' sends its reports to bug-bash@prep.ai.mit.edu, which +is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. + +Bug fixes, answers to questions, and announcements of new releases +are all posted to gnu.bash.bug. Discussions concerning bash features +and problems also take place there. + +To reach the bash maintainers directly, send mail to +bash-maintainers@prep.ai.mit.edu. + +30) What kind of bash documentation is there? + +First, look in the documentation directory in the bash distribution. +It should contain the following files: + +bash.1 an extensive, thorough Unix-style manual page +builtins.1 a manual page covering just bash builtin commands +features.texi a Gnu-style info file overview +FAQ this file +article.ms text of an article written for The Linux Journal +readline.3 a man page describing readline + +Postscript files created from the above source are also present in +the distribution. + +There is additional documentation available for anonymous FTP from host +slc2.ins.cwru.edu in the `pub/bash' directory. + +Cameron Newham is in the midst of writing a book on bash, to be +published by O'Reilly and Associates. Look for it sometime this +year. + +31) What's coming in future versions? + +There will be no new features in future releases of version 1.14. + +The next major release, bash-2.0, will contain extensive changes and new +features. Here's a short list: + +one-dimensional arrays with a new compound assignment statement, + appropriate expansion constructs and modifications to some + of the builtins (read, declare, etc.) to use them +new expansions to do ANSI-C string expansion, substring extraction, + pattern replacement, and indirect variable expansion +new builtins: `disown' and `shopt' +new variables: HISTIGNORE, SHELLOPTS, PIPESTATUS, DIRSTACK +special handling of many unused or redundant variables removed +dynamic loading of new builtin commands; many loadable examples provided +new prompt expansions: \e, \n, \H, \T +new readline variables: enable-keypad, mark-directories, input-meta +new readline commands to manipulate the mark and operate on the region +new readline emacs mode commands and bindings for ksh-88 compatibility +updated and extended builtins +new DEBUG trap +expanded (and now documented) restricted shell mode + +implementation stuff: +autoconf-based configuration +nearly all of the bugs reported since version 1.14 have been fixed +most builtins converted to use builtin `getopt' for consistency +most builtins use -p option to display output in a reusable form + (for consistency) +grammar tighter and smaller (66 reduce-reduce conflicts gone) +lots of code now smaller and faster +test suite greatly expanded + +32) What's on the bash `wish list'? + +internationalization with a variable expansion to translate a string + according to a particular message catalog +Programmable completion a la zsh +menu completion a la tcsh +the ksh egrep-style extended pattern matching operators +associative arrays (not really all that hard) +breaking some of the shell functionality into embeddable libraries +a bash debugger + +Much of this will not be in bash-2.0. + +33) When will the next release appear? + +Version 1.14.6 will probably be the last release for version 1.14. + +The next version will appear sometime in 1996. Never make predictions. + + +This document is copyright Chester Ramey, 1995. + +Permission is hereby granted, without written agreement and +without license or royalty fees, to use, copy, and distribute +this document for any purpose, provided that the above copyright +notice appears in all copies of this document and that the +contents of this document remain unaltered. diff --git a/documentation/Makefile b/documentation/Makefile 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 F172 319.2 Q F0 .494(option to the)2.994 F F1(set)2.994 E F0 -.2 +(bu)2.994 G .494(iltin \(equi).2 F -.25(va)-.25 G .494(lent to).25 F F1 .494 +(set -o ph)2.994 F(ysical)-.15 E F0 .493(\); the v)B .493 +(ariable is retained for backw)-.25 F .493(ards compati-)-.1 F(bility)72 331.2 +Q 5.196(.T)-.65 G .196(he v)106.276 331.2 R .196(ersion string contained in) +-.15 F F1($B)2.696 E(ASH_VERSION)-.3 E F0(no)2.696 E 2.696(wi)-.25 G .196 +(ncludes an indication of the patch le)335.558 331.2 R -.15(ve)-.25 G 2.696(la) +.15 G(s)500.11 331.2 Q .665(well as the `)72 343.2 R(`b)-.74 E .665(uild v)-.2 +F(ersion')-.15 E 3.165('. Some)-.74 F .665(little-used features ha)3.165 F .965 +-.15(ve b)-.2 H .665(een remo).15 F -.15(ve)-.15 G 3.165(d: the).15 F F1(by) +3.165 E(e)-.1 E F0(synon)3.165 E .665(ym for)-.15 F F1(exit)3.165 E F0(and) +3.165 E(the)72 355.2 Q F1($NO_PR)3.498 E(OMPT_V)-.3 E(ARS)-1.35 E F0 -.25(va) +3.498 G .998(riable are gone.).25 F .998(There is no)5.998 F 3.498(wa)-.25 G +3.498(no)331.114 355.2 S -2.19 -.18(rg a)344.612 355.2 T .998 +(nized test suite that can be run as a).18 F(re)72 367.2 Q +(gression test when b)-.15 E(uilding a ne)-.2 E 2.5(wv)-.25 G(ersion of Bash.) +222.34 367.2 Q 1.696(The documentation has been thoroughly o)97 382.8 R -.15 +(ve)-.15 G 1.696(rhauled: there is a ne).15 F 4.196(wm)-.25 G 1.695 +(anual page on the readline)392.25 382.8 R .467(library and the)72 394.8 R F3 +(info)2.967 E F0 .467(\214le has been updated to re\215ect the current v)2.967 +F 2.968(ersion. As)-.15 F(al)2.968 E -.1(wa)-.1 G .468(ys, as man).1 F 2.968 +(yb)-.15 G .468(ugs as possi-)451.954 394.8 R(ble ha)72 406.8 Q .3 -.15(ve b) +-.2 H(een \214x).15 E(ed, although some surely remain.)-.15 E F1 2.5 +(5.2. Other)72 430.8 R -.25(Fe)2.5 G(atur).25 E(es)-.18 E F0 1.68 +(There are a fe)97 446.4 R 4.18(wf)-.25 G 1.68 +(eatures that I hope to include in later Bash releases.)171.76 446.4 R 1.68 +(Some are based on w)6.68 F(ork)-.1 E(already done in other shells.)72 458.4 Q +.958(In addition to simple v)97 474 R .959 +(ariables, a future release of Bash will include one-dimensional arrays, using) +-.25 F .206(the ksh implementation of arrays as a model.)72 486 R .205 +(Additions to the ksh syntax, such as)5.205 F F3(varname)2.705 E F0 .205 +(=\( ... \) to assign)B 2.587(al)72 498 S .087(ist of w)81.807 498 R .088 +(ords directly to an array and a mechanism to allo)-.1 F 2.588(wt)-.25 G(he) +320.248 498 Q F1 -.18(re)2.588 G(ad).18 E F0 -.2(bu)2.588 G .088 +(iltin to read a list of v).2 F .088(alues directly)-.25 F .092(into an array) +72 510 R 2.592(,w)-.65 G .092(ould be desirable.)134.286 510 R(Gi)5.092 E -.15 +(ve)-.25 G 2.592(nt).15 G .092(hose e)239.794 510 R .092(xtensions, the ksh) +-.15 F F1 .092(set \255A)2.592 F F0 .091(syntax may not be w)2.591 F .091 +(orth support-)-.1 F(ing \(the)72 522 Q F12.5 E F0 +(option assigns a list of v)2.5 E(alues to an array)-.25 E 2.5(,b)-.65 G +(ut is a rather peculiar special case\).)292.41 522 Q .76 +(Some shells include a means of)97 537.6 R F3(pr)3.26 E -.1(og)-.45 G -.15(ra) +.1 G(mmable).15 E F0 -.1(wo)3.26 G .76 +(rd completion, where the user speci\214es on a per).1 F(-)-.2 E .163 +(command basis ho)72 549.6 R 2.663(wt)-.25 G .163(he ar)159.179 549.6 R .163(g\ +uments of the command are to be treated when completion is attempted: as \214l\ +e-)-.18 F .194(names, hostnames, e)72 561.6 R -.15(xe)-.15 G .194 +(cutable \214les, and so on.).15 F .195 +(The other aspects of the current Bash implementation could)5.195 F .482 +(remain as-is; the e)72 573.6 R .482(xisting heuristics w)-.15 F .481 +(ould still be v)-.1 F 2.981(alid. Only)-.25 F .481(when completing the ar) +2.981 F .481(guments to a simple)-.18 F(command w)72 585.6 Q +(ould the programmable completion be in ef)-.1 E(fect.)-.25 E .479(It w)97 +601.2 R .479(ould also be nice to gi)-.1 F .779 -.15(ve t)-.25 H .479 +(he user \214ner).15 F .479(-grained control o)-.2 F -.15(ve)-.15 G 2.98(rw).15 +G .48(hich commands are sa)363.92 601.2 R -.15(ve)-.2 G 2.98(do).15 G .48 +(nto the)476.02 601.2 R 1.786(history list.)72 613.2 R 1.786 +(One proposal is for a v)6.786 F 1.786(ariable, tentati)-.25 F -.15(ve)-.25 G +1.786(ly named).15 F F1(HISTIGNORE)4.286 E F0 4.285(,w)C 1.785(hich w)415.145 +613.2 R 1.785(ould contain a)-.1 F .496(colon-separated list of commands.)72 +625.2 R .496(Lines be)5.496 F .496 +(ginning with these commands, after the restrictions of)-.15 F F1($HIST)2.997 E +(-)-.92 E(CONTR)72 637.2 Q(OL)-.3 E F0(ha)2.65 E .45 -.15(ve b)-.2 H .15 +(een applied, w).15 F .15(ould not be placed onto the history list.)-.1 F .15 +(The shell pattern-matching capa-)5.15 F(bilities could also be a)72 649.2 Q +-.25(va)-.2 G(ilable when specifying the contents of).25 E F1($HISTIGNORE)2.5 E +F0(.)A .729(One thing that ne)97 664.8 R .729(wer shells such as)-.25 F F1 +(wksh)3.229 E F0 .729(\(also kno)3.229 F .729(wn as)-.25 F F1(dtksh)3.23 E F0 +3.23(\)p)C(ro)370.79 664.8 Q .73(vide is a command to dynami-)-.15 F 1.189 +(cally load code implementing additional b)72 676.8 R 1.189 +(uiltin commands into a running shell.)-.2 F 1.188(This ne)6.188 F 3.688(wb) +-.25 G 1.188(uiltin w)454.292 676.8 R(ould)-.1 E(tak)72 688.8 Q 2.69(ea)-.1 G +2.69(no)95.69 688.8 S .19(bject \214le or shared library implementing the `) +108.38 688.8 R(`body')-.74 E 2.69('o)-.74 G 2.69(ft)327.83 688.8 S .19(he b) +336.63 688.8 R .19(uiltin \()-.2 F F3(xxx_b)A(uiltin\(\))-.2 E F0 .19 +(for those f)2.69 F(amiliar)-.1 E .052 +(with Bash internals\) and a structure containing the name of the ne)72 700.8 R +2.552(wc)-.25 G .051(ommand, the function to call when the)349.544 700.8 R(ne) +72 712.8 Q 3.458(wb)-.25 G .958(uiltin is in)96.668 712.8 R -.2(vo)-.4 G -.1 +(ke).2 G 3.458(d\().1 G .959 +(presumably de\214ned in the shared object speci\214ed as an ar)169.682 712.8 R +.959(gument\), and the docu-)-.18 F 1.352(mentation to be printed by the)72 +724.8 R F1(help)3.851 E F0 1.351 +(command \(possibly present in the shared object as well\).)3.851 F 1.351(It w) +6.351 F(ould)-.1 E EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(0-)288 48 S +(manage the details of e)72 84 Q(xtending the internal table of b)-.15 E +(uiltins.)-.2 E 3.291(Af)97 99.6 S 1.291 -.25(ew o)110.841 99.6 T .791(ther b) +.25 F .791(uiltins w)-.2 F .791(ould also be desirable: tw)-.1 F 3.291(oa)-.1 G +.791(re the POSIX.2)307.609 99.6 R/F1 10/Times-Bold@0 SF(getconf)3.292 E F0 +.792(command, which prints)3.292 F 1.412(the v)72 111.6 R 1.412 +(alues of system con\214guration v)-.25 F 1.411 +(ariables de\214ned by POSIX.2, and a)-.25 F F1(diso)3.911 E(wn)-.1 E F0 -.2 +(bu)3.911 G 1.411(iltin, which causes a).2 F 1.173 +(shell running with job control acti)72 123.6 R 1.473 -.15(ve t)-.25 H 3.673 +(o`).15 G(`for)240.45 123.6 Q 1.173(get about')-.18 F 3.673('o)-.74 G 1.173 +(ne or more background jobs in its internal jobs)307.966 123.6 R 3.465 +(table. Using)72 135.6 R F1(getconf)3.465 E F0 3.465(,f)C .965(or e)167.655 +135.6 R .965(xample, a user could retrie)-.15 F 1.264 -.15(ve a v)-.25 H .964 +(alue for)-.1 F F1($P)3.464 E -.95(AT)-.74 G(H).95 E F0 .964 +(guaranteed to \214nd all of the)3.464 F .884 +(POSIX standard utilities, or \214nd out ho)72 147.6 R 3.385(wl)-.25 G .885 +(ong \214lenames may be in the \214le system containing a speci\214ed)247.39 +147.6 R(directory)72 159.6 Q(.)-.65 E 1.521 +(There are no implementation timetables for an)97 175.2 R 4.021(yo)-.15 G 4.021 +(ft)305.517 175.2 S 1.52(hese features, nor are there concrete plans to)315.648 +175.2 R(include them.)72 187.2 Q(If an)5 E +(yone has comments on these proposals, feel free to send me electronic mail.) +-.15 E F1 2.5(6. Re\215ections)72 211.2 R(and Lessons Lear)2.5 E(ned)-.15 E F0 +.433(The lesson that has been repeated most often during Bash de)97 226.8 R +-.15(ve)-.25 G .433(lopment is that there are dark corners).15 F .093 +(in the Bourne Shell, and people use all of them.)72 238.8 R .092 +(In the original description of the Bourne shell, quoting and)5.093 F .073(the\ + shell grammar are both poorly speci\214ed and incomplete; subsequent descript\ +ions ha)72 250.8 R .373 -.15(ve n)-.2 H .073(ot helped much.).15 F 1.856 +(The grammar presented in Bourne')72 262.8 R 4.356(sp)-.55 G 1.856 +(aper describing the shell distrib)232.64 262.8 R 1.855(uted with the Se)-.2 F +-.15(ve)-.25 G 1.855(nth Edition of).15 F/F2 9/Times-Roman@0 SF(UNIX)72 274.8 Q +F0 2.5<8769>C 2.5(ss)104.771 274.8 S 2.5(of)115.051 274.8 S(ar of)125.781 274.8 +Q 2.5(ft)-.25 G(hat it does not allo)152.741 274.8 Q 2.5(wt)-.25 G(he command) +238.881 274.8 Q/F3 10/Courier@0 SF(who|wc)2.5 E F0 5(.I)C 2.5(nf)339.591 274.8 +S(act, as T)350.321 274.8 Q(om Duf)-.8 E 2.5(fs)-.25 G(tates:)423.421 274.8 Q +1.375(Nobody really kno)97 290.4 R 1.375(ws what the Bourne shell')-.25 F 3.875 +(sg)-.55 G 1.375(rammar is.)296.635 290.4 R(Ev)6.376 E 1.376(en e)-.15 F 1.376 +(xamination of the source)-.15 F(code is little help.\210)97 302.4 Q .382 +(The POSIX.2 standard includes a)72 318 R/F4 10/Times-Italic@0 SF(yacc)2.882 E +F0 .382(grammar that comes close to capturing the Bourne shell')2.882 F 2.882 +(sb)-.55 G(eha)472.11 318 Q(vior)-.2 E(,)-.4 E -.2(bu)72 330 S 3.246(ti).2 G +3.246(td)90.606 330 S(isallo)101.632 330 Q .747(ws some constructs which sh ac\ +cepts without complaint \255 and there are scripts out there that)-.25 F .501 +(use them.)72 342 R .501(It took a fe)5.501 F 3.001(wv)-.25 G .501 +(ersions and se)176.256 342 R -.15(ve)-.25 G .501(ral b).15 F .5 +(ug reports before Bash implemented sh-compatible quoting,)-.2 F .094 +(and there are still some `)72 354 R(`le)-.74 E -.05(ga)-.15 G(l').05 E 2.594 +('s)-.74 G 2.594(hc)205.294 354 S .094 +(onstructs which Bash \215ags as syntax errors.)217.328 354 R .095 +(Complete sh compatibility)5.095 F(is a tough nut.)72 366 Q 1.231 +(The shell is bigger and slo)97 381.6 R 1.231(wer than I w)-.25 F 1.231 +(ould lik)-.1 F 1.23(e, though the current v)-.1 F 1.23 +(ersion is substantially f)-.15 F(aster)-.1 E .086(than pre)72 393.6 R(viously) +-.25 E 5.086(.T)-.65 G .087(he readline library could stand a substantial re) +146.822 393.6 R 2.587(write. A)-.25 F .087(hand-written parser to replace the) +2.587 F(current)72 405.6 Q F4(yacc)2.978 E F0 .478(-generated one w)B .477 +(ould probably result in a speedup, and w)-.1 F .477(ould solv)-.1 F 2.977(eo) +-.15 G .477(ne glaring problem:)406.469 405.6 R(the)5.477 E .199 +(shell could parse commands in `)72 417.6 R(`$\(...\)')-.74 E 2.699('c)-.74 G +.199(onstructs as the)236.954 417.6 R 2.699(ya)-.15 G .2 +(re entered, rather than reporting errors when the)311.001 417.6 R +(construct is e)72 429.6 Q(xpanded.)-.15 E 1.064(As al)97 445.2 R -.1(wa)-.1 G +1.064(ys, there is some chaf).1 F 3.564(ft)-.25 G 3.564(og)230.404 445.2 S +3.564(ow)243.968 445.2 S 1.064(ith the wheat.)259.752 445.2 R 1.063 +(Areas of duplicated functionality need to be)6.063 F .382(cleaned up.)72 457.2 +R .382(There are se)5.382 F -.15(ve)-.25 G .382 +(ral cases where Bash treats a v).15 F .382 +(ariable specially to enable functionality a)-.25 F -.25(va)-.2 G(ilable).25 E +.185(another w)72 469.2 R .185(ay \()-.1 F F1($notify)A F0(vs.)2.684 E F1 .184 +(set -o notify)5.184 F F0(and)2.684 E F1($nolinks)2.684 E F0(vs.)2.684 E F1 +.184(set -o ph)2.684 F(ysical)-.15 E F0 2.684(,f)C .184 +(or instance\); the special treatment)368.294 469.2 R 3.421(of the v)72 481.2 R +3.421(ariable name should probably be remo)-.25 F -.15(ve)-.15 G 5.921(d. A).15 +F(fe)5.921 E 5.921(wm)-.25 G 3.422(ore things could stand remo)346.47 481.2 R +-.25(va)-.15 G 3.422(l; the).25 F F1($allo)72 493.2 Q(w_null_glob_expansion)-.1 +E F0(and)4.112 E F1($glob_dot_\214lenames)4.112 E F0 -.25(va)4.111 G 1.611 +(riables are of particularly questionable v).25 F(alue.)-.25 E(The)72 505.2 Q +F1($[...])3.977 E F0 1.477(arithmetic e)3.977 F -.25(va)-.25 G 1.478 +(luation syntax is redundant no).25 F 3.978(wt)-.25 G 1.478 +(hat the POSIX-mandated)312.76 505.2 R F1($\(\(...\)\))3.978 E F0 1.478 +(construct has)3.978 F .326(been implemented, and could be deleted.)72 517.2 R +.326(It w)5.326 F .326(ould be nice if the te)-.1 F .326(xt output by the)-.15 +F F1(help)2.825 E F0 -.2(bu)2.825 G .325(iltin were e).2 F(xter)-.15 E(-)-.2 E +.061(nal to the shell rather than compiled into it.)72 529.2 R .062(The beha) +5.062 F .062(vior enabled by)-.2 F F1($command_oriented_history)2.562 E F0 +2.562(,w)C(hich)486.78 529.2 Q 1.125(causes the shell to attempt to sa)72 541.2 +R 1.424 -.15(ve a)-.2 H 1.124 +(ll lines of a multi-line command in a single history entry).15 F 3.624(,s)-.65 +G 1.124(hould be)468.156 541.2 R(made the def)72 553.2 Q(ault and the v)-.1 E +(ariable remo)-.25 E -.15(ve)-.15 G(d.).15 E F1 2.5(7. A)72 577.2 R -.1(va)-1 G +(ilability).1 E F0 8.538(As with all other GNU softw)97 592.8 R 8.538 +(are, Bash is a)-.1 F -.25(va)-.2 G 8.539(ilable for anon).25 F 8.539 +(ymous FTP from)-.15 F F4(pr)72 604.8 Q(ep.ai.mit.edu:/pub/gnu)-.37 E F0 4.552 +(and from other GNU softw)8.718 F 4.552(are mirror sites.)-.1 F 4.552 +(The current v)9.552 F 4.552(ersion is in)-.15 F F4(bash-1.14.1.tar)72 616.8 Q +(.gz)-1.11 E F0 .074(in that directory)4.24 F 5.075(.U)-.65 G(se)226.084 616.8 +Q F4(ar)2.575 E -.15(ch)-.37 G(ie).15 E F0 .075(to \214nd the nearest archi) +4.241 F .375 -.15(ve s)-.25 H 2.575(ite. The).15 F .075(latest v)2.575 F .075 +(ersion is al)-.15 F -.1(wa)-.1 G(ys).1 E -.2(av)72 628.8 S 3.659 +(ailable for FTP from)-.05 F F4(bash.CWR)6.159 E -.25(U.)-.4 G(Edu:/pub/dist.) +.25 E F0 3.658(Bash documentation is a)7.825 F -.25(va)-.2 G 3.658 +(ilable for FTP from).25 F F4(bash.CWR)72 640.8 Q -.25(U.)-.4 G(Edu:/pub/bash.) +.25 E F0 1.168(The Free Softw)97 656.4 R 1.168(are F)-.1 F 1.168 +(oundation sells tapes and CD-R)-.15 F 1.169 +(OMs containing Bash; send electronic mail to)-.4 F F3(gnu@prep.ai.mit.edu)72 +668.4 Q F0(or call)2.5 E F3(+1-617-876-3296)2.5 E F0(for more information.)2.5 +E .32 LW 76 678.4 72 678.4 DL 80 678.4 76 678.4 DL 84 678.4 80 678.4 DL 88 +678.4 84 678.4 DL 92 678.4 88 678.4 DL 96 678.4 92 678.4 DL 100 678.4 96 678.4 +DL 104 678.4 100 678.4 DL 108 678.4 104 678.4 DL 112 678.4 108 678.4 DL 116 +678.4 112 678.4 DL 120 678.4 116 678.4 DL 124 678.4 120 678.4 DL 128 678.4 124 +678.4 DL 132 678.4 128 678.4 DL 136 678.4 132 678.4 DL 140 678.4 136 678.4 DL +144 678.4 140 678.4 DL/F5 8/Times-Roman@0 SF 1.39(\207S. R. Bourne, `)72 688.4 +R 1.389(`UNIX T)-.592 F 1.389(ime-Sharing System:)-.28 F 1.389(The UNIX Shell') +5.389 F(',)-.592 E/F6 8/Times-Italic@0 SF 1.389(Bell System T)3.389 F(ec)-.736 +E 1.389(hnical J)-.12 F(ournal)-.2 E F5 3.389(,5)C 1.389(7\(6\), July-August,) +408.171 688.4 R(1978, pp. 1971-1990.)72 698.4 Q<8854>72 708.4 Q .684(om Duf) +-.64 F .684(f, `)-.2 F .684(`Rc \255 A Shell for Plan 9 and)-.592 F/F7 7 +/Times-Roman@0 SF(UNIX)2.684 E F5(systems')2.684 E(',)-.592 E F6(Pr)2.684 E +.684(oc. of the Summer 1990 EUUG Confer)-.36 F(ence)-.296 E F5 2.685(,L)C .685 +(ondon, July)428.499 708.4 R(,)-.52 E(1990, pp. 21-33.)72 718.4 Q EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(1-)288 48 S .695 +(Bash is also distrib)97 84 R .694(uted with se)-.2 F -.15(ve)-.25 G .694 +(ral v).15 F .694(ersions of)-.15 F/F1 9/Times-Roman@0 SF(UNIX)3.194 E F0 .694 +(-compatible systems.)B .694(It is included as /bin/sh)5.694 F .948 +(and /bin/bash on se)72 96 R -.15(ve)-.25 G .948(ral Linux distrib).15 F .948 +(utions \(more about the dif)-.2 F .948(ference in a moment\), and as contrib) +-.25 F(uted)-.2 E(softw)72 108 Q(are in BSDI')-.1 E 2.5(sB)-.55 G +(SD/386* and FreeBSD.)157.73 108 Q .599(The Linux distrib)97 123.6 R .599 +(ution deserv)-.2 F .599(es special mention.)-.15 F .598(There are tw)5.599 F +3.098(oc)-.1 G .598(on\214gurations included in the stan-)364.948 123.6 R .547 +(dard Bash distrib)72 135.6 R .547(ution: a `)-.2 F(`normal')-.74 E 3.047('c) +-.74 G .548 +(on\214guration, in which all of the standard features are included, and a) +222.755 135.6 R -.74(``)72 147.6 S(minimal').74 E 2.792('c)-.74 G .292(on\214g\ +uration, which omits job control, aliases, history and command line editing, t\ +he directory)124.412 147.6 R .747(stack and)72 159.6 R/F2 10/Times-Bold@0 SF +(pushd/popd/dirs,)3.247 E F0 .747 +(process substitution, prompt string special character decoding, and the)3.247 +F/F3 10/Times-Italic@0 SF(select)3.247 E F0 3.369(construct. This)72 171.6 R +.869(minimal v)3.369 F .869 +(ersion is designed to be a drop-in replacement for the traditional)-.15 F F1 +(UNIX)3.368 E F0(/bin/sh,)3.368 E(and is included as the Linux /bin/sh in se)72 +183.6 Q -.15(ve)-.25 G(ral packagings.).15 E F2 2.5(8. Conclusion)72 207.6 R F0 +.8(Bash is a w)97 223.2 R(orth)-.1 E 3.3(ys)-.05 G .8(uccessor to sh.)173.379 +223.2 R .8(It is suf)5.8 F .8(\214ciently portable to run on nearly e)-.25 F +-.15(ve)-.25 G .8(ry v).15 F .8(ersion of)-.15 F F1(UNIX)3.3 E F0 .311 +(from 4.3 BSD to SVR4.2, and se)72 235.2 R -.15(ve)-.25 G(ral).15 E F1(UNIX) +2.811 E F0 -.1(wo)2.811 G(rkalik).1 E 2.811(es. It)-.1 F .31(is rob)2.81 F .31 +(ust enough to replace sh on most of those)-.2 F 1.515(systems, and pro)72 +247.2 R 1.515(vides more functionality)-.15 F 6.515(.I)-.65 G 4.015(th)254.315 +247.2 S 1.515(as se)266.11 247.2 R -.15(ve)-.25 G 1.515(ral thousand re).15 F +1.515(gular users, and their feedback has)-.15 F(helped to mak)72 259.2 Q 2.5 +(ei)-.1 G 2.5(ta)138.28 259.2 S 2.5(sg)148 259.2 S +(ood as it is today \255 a testament to the bene\214ts of free softw)159.39 +259.2 Q(are.)-.1 E .32 LW 76 698 72 698 DL 80 698 76 698 DL 84 698 80 698 DL 88 +698 84 698 DL 92 698 88 698 DL 96 698 92 698 DL 100 698 96 698 DL 104 698 100 +698 DL 108 698 104 698 DL 112 698 108 698 DL 116 698 112 698 DL 120 698 116 698 +DL 124 698 120 698 DL 128 698 124 698 DL 132 698 128 698 DL 136 698 132 698 DL +140 698 136 698 DL 144 698 140 698 DL/F4 8/Times-Roman@0 SF +(*BSD/386 is a trademark of Berk)72 708 Q(ele)-.08 E 2(yS)-.12 G(oftw)198.896 +708 Q(are Design, Inc.)-.08 E EP +%%Trailer +end +%%EOF diff --git a/documentation/article.txt b/documentation/article.txt 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 & && ; ;; ( ) | \fP +.if n \fB|| & && ; ;; ( ) | \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 . +.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 . If a \fB\e\fP pair +appears, and the backslash is not quoted, the \fB\e\fP +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 . +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 +``''. +.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 , +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 +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 F2108 280.8 Q F3(string)4.166 E F0 .504(If the)158 280.8 +R F23.004 E F0 .505(\215ag is present, then commands are read from)3.004 +F F3(string)3.005 E F0 5.505(.I).22 G 3.005(ft)417.425 280.8 S .505 +(here are ar)426.54 280.8 R .505(guments after the)-.18 F F3(string)158 292.8 Q +F0 2.5(,t).22 G(he)189.34 292.8 Q 2.5(ya)-.15 G +(re assigned to the positional parameters, starting with)210.57 292.8 Q F2($0) +2.5 E F0(.)A F2108 304.8 Q F0(If the)158 304.8 Q F22.5 E F0 +(\215ag is present, the shell is)2.5 E F3(inter)2.5 E(active)-.15 E F0(.).18 E +F2108 316.8 Q F0 .305(If the)158 316.8 R F22.805 E F0 .305 +(\215ag is present, or if no ar)2.805 F .305 +(guments remain after option processing, then commands are)-.18 F 1.711 +(read from the standard input.)158 328.8 R 1.711(This option allo)6.711 F 1.712 +(ws the positional parameters to be set when)-.25 F(in)158 340.8 Q -.2(vo)-.4 G +(king an interacti).2 E .3 -.15(ve s)-.25 H(hell.).15 E F2108 352.8 Q F0 +3.373(As)158 352.8 S(ingle)172.483 352.8 Q F23.373 E F0 .873 +(signals the end of options and disables further option processing.)3.373 F(An) +5.872 E 3.372(ya)-.15 G -.18(rg)502.96 352.8 S(uments).18 E .044(after the)158 +364.8 R F22.544 E F0 .044(are treated as \214lenames and ar)2.544 F 2.544 +(guments. An)-.18 F(ar)2.544 E .044(gument of)-.18 F F22.544 E F0 .044 +(is equi)2.544 F -.25(va)-.25 G .045(lent to an ar).25 F(gu-)-.18 E(ment of)158 +376.8 Q F22.5 E F0(.)A F2(Bash)108 393.6 Q F0 .15 +(also interprets a number of multi\255character options.)2.65 F .149 +(These options must appear on the command line)5.149 F +(before the single\255character options to be recognized.)108 405.6 Q F2 +(\255nor)108 422.4 Q(c)-.18 E F0 .282(Do not read and e)158 422.4 R -.15(xe) +-.15 G .282(cute the personal initialization \214le).15 F F3(~/.bashr)2.782 E +(c)-.37 E F0 .282(if the shell is interacti)2.782 F -.15(ve)-.25 G 5.282(.T).15 +G(his)528.33 422.4 Q(option is on by def)158 434.4 Q(ault if the shell is in) +-.1 E -.2(vo)-.4 G -.1(ke).2 G 2.5(da).1 G(s)342.75 434.4 Q F2(sh)2.5 E F0(.)A +F2(\255nopr)108 446.4 Q(o\214le)-.18 E F0 .223 +(Do not read either the system\255wide startup \214le)6.14 F F3(/etc/pr)4.389 E +(o\214le)-.45 E F0 .223(or an)4.389 F 2.722(yo)-.15 G 2.722(ft)431.844 446.4 S +.222(he personal initialization)440.676 446.4 R(\214les)158 458.4 Q F3 +(~/.bash_pr)4.066 E(o\214le)-.45 E F0(,).18 E F3(~/.bash_lo)4.066 E(gin)-.1 E +F0 4.066(,o).24 G(r)308.408 458.4 Q F3(~/.pr)4.066 E(o\214le)-.45 E F0 6.566 +(.B).18 G 4.066(yd)365.99 458.4 S(ef)380.056 458.4 Q(ault,)-.1 E F2(bash)4.066 +E F0 1.567(normally reads these \214les)4.067 F(when it is in)158 470.4 Q -.2 +(vo)-.4 G -.1(ke).2 G 2.5(da).1 G 2.5(sal)237.85 470.4 S(ogin shell \(see) +253.96 470.4 Q F1(INV)2.5 E(OCA)-.405 E(TION)-.855 E F0(belo)2.25 E(w\).)-.25 E +F2108 482.4 Q(c\214le)-.18 E F3(\214le)2.5 E F0(Ex)8.1 E .452 +(ecute commands from)-.15 F F3(\214le)2.952 E F0 .452 +(instead of the standard personal initialization \214le)2.952 F F3(~/.bashr) +2.951 E(c)-.37 E F0 2.951(,i).31 G 2.951(ft)521.499 482.4 S(he)530.56 482.4 Q +(shell is interacti)158 494.4 Q .3 -.15(ve \()-.25 H(see).15 E F1(INV)2.5 E +(OCA)-.405 E(TION)-.855 E F0(belo)2.25 E(w\).)-.25 E F2108 506.4 Q +(ersion)-.1 E F0(Sho)158 506.4 Q 2.5(wt)-.25 G(he v)185.81 506.4 Q +(ersion number of this instance of)-.15 E F2(bash)2.5 E F0(when starting.)2.5 E +F2(\255quiet)108 518.4 Q F0 .71(Do not be v)158 518.4 R .71 +(erbose when starting up \(do not sho)-.15 F 3.21(wt)-.25 G .71(he shell v) +366.9 518.4 R .71(ersion or an)-.15 F 3.21(yo)-.15 G .71(ther information\).) +468.19 518.4 R(This is the def)158 530.4 Q(ault.)-.1 E F2(\255login)108 542.4 Q +F0(Mak)158 542.4 Q(e)-.1 E F2(bash)2.5 E F0(act as if it had been in)2.5 E -.2 +(vo)-.4 G -.1(ke).2 G 2.5(da).1 G 2.5(sal)324.12 542.4 S(ogin shell.)340.23 +542.4 Q F2(\255nobraceexpansion)108 554.4 Q F0(Do not perform curly brace e)158 +566.4 Q(xpansion \(see)-.15 E F2(Brace Expansion)2.5 E F0(belo)2.5 E(w\).)-.25 +E F2(\255nolineediting)108 578.4 Q F0(Do not use the GNU)158 590.4 Q F3 -.37 +(re)2.5 G(adline).37 E F0(library to read command lines if interacti)2.5 E -.15 +(ve)-.25 G(.).15 E F2(\255posix)108 602.4 Q F0 1.001(Change the beha)158 602.4 +R 1.001(vior of bash where the def)-.2 F 1.001(ault operation dif)-.1 F 1 +(fers from the Posix 1003.2 stan-)-.25 F(dard to match the standard)158 614.4 Q +F1(ARGUMENTS)72 631.2 Q F0 .016(If ar)108 643.2 R .016 +(guments remain after option processing, and neither the)-.18 F F22.516 E +F0 .016(nor the)2.516 F F22.516 E F0 .016 +(option has been supplied, the \214rst)2.516 F(ar)108 655.2 Q .041 +(gument is assumed to be the name of a \214le containing shell commands.)-.18 F +(If)5.041 E F2(bash)2.541 E F0 .041(is in)2.541 F -.2(vo)-.4 G -.1(ke).2 G +2.541(di).1 G 2.541(nt)483.628 655.2 S .041(his f)493.949 655.2 R(ashion,)-.1 E +F2($0)108 667.2 Q F0 .936(is set to the name of the \214le, and the positional\ + parameters are set to the remaining ar)3.435 F(guments.)-.18 E F2(Bash)5.936 E +F0 .225(reads and e)108 679.2 R -.15(xe)-.15 G .224 +(cutes commands from this \214le, then e).15 F(xits.)-.15 E F2(Bash')5.224 E(s) +-.37 E F0 -.15(ex)2.724 G .224(it status is the e).15 F .224 +(xit status of the last com-)-.15 F(mand e)108 691.2 Q -.15(xe)-.15 G +(cuted in the script.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(1)535 768 Q +EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 9/Times-Bold@0 SF(DEFINITIONS)72 84 Q/F2 10/Times-Bold@0 SF(blank)108 96 Q +F0 2.5(As)144 96 S(pace or tab)157.61 96 Q(.)-.4 E F2 -.1(wo)108 108 S(rd).1 E +F0 2.5(As)144 108 S +(equence of characters considered as a single unit by the shell.)157.61 108 Q +(Also kno)5 E(wn as a)-.25 E F2(tok)2.5 E(en)-.1 E F0(.)A F2(name)108 120 Q F0 +(A)144 120 Q/F3 10/Times-Italic@0 SF(wor)2.75 E(d)-.37 E F0 .251 +(consisting only of alphanumeric characters and underscores, and be)2.75 F .251 +(ginning with an alpha-)-.15 F(betic character or an underscore.)144 132 Q +(Also referred to as an)5 E F2(identi\214er)2.5 E F0(.)A F2(metacharacter)108 +144 Q F0 2.5(Ac)144 156 S(haracter that, when unquoted, separates w)158.16 156 +Q 2.5(ords. One)-.1 F(of the follo)2.5 E(wing:)-.25 E F2 5(|&;\(\)<>s)144 168 S +2.5(pace tab)214.81 168 R(contr)108 180 Q(ol operator)-.18 E F0(A)144 192 Q F3 +(tok)2.5 E(en)-.1 E F0(that performs a control function.)2.5 E +(It is one of the follo)5 E(wing symbols:)-.25 E/F4 10/Symbol SF 1.666144 +204 S F2 5(&&)3.334 G 5(&;;)182.206 204 S 5(;\(\)|<)207.196 204 S(newline>) +245.086 204 Q F1(RESER)72 220.8 Q(VED W)-.495 E(ORDS)-.09 E F3 .307 +(Reserved wor)108 232.8 R(ds)-.37 E F0 .307(are w)2.807 F .307(ords that ha)-.1 +F .607 -.15(ve a s)-.2 H .306(pecial meaning to the shell.).15 F .306 +(The follo)5.306 F .306(wing w)-.25 F .306(ords are recognized as)-.1 F(reserv) +108 244.8 Q .227(ed when unquoted and either the \214rst w)-.15 F .227 +(ord of a simple command \(see)-.1 F F1 .227(SHELL GRAMMAR)2.727 F F0(belo) +2.477 E .227(w\) or)-.25 F(the third w)108 256.8 Q(ord of a)-.1 E F2(case)2.5 E +F0(or)2.5 E F2 -.25(fo)2.5 G(r).25 E F0(command:)2.5 E F2 11.916(!c)144 273.6 S +9.416(ase do done elif else esac \214 f)163.686 273.6 R 9.415 +(or function if in select then until)-.25 F 7.5(while { })144 285.6 R F1 +(SHELL GRAMMAR)72 302.4 Q F2(Simple Commands)87 314.4 Q F0(A)108 326.4 Q F3 +.383(simple command)2.883 F F0 .383(is a sequence of optional v)2.883 F .384 +(ariable assignments follo)-.25 F .384(wed by)-.25 F F3(blank)2.884 E F0 .384 +(\255separated w)B .384(ords and)-.1 F .816(redirections, and terminated by a) +108 338.4 R F3(contr)3.316 E .815(ol oper)-.45 F(ator)-.15 E F0 5.815(.T)C .815 +(he \214rst w)326.97 338.4 R .815(ord speci\214es the command to be e)-.1 F +-.15(xe)-.15 G(cuted.).15 E(The remaining w)108 350.4 Q(ords are passed as ar) +-.1 E(guments to the in)-.18 E -.2(vo)-.4 G -.1(ke).2 G 2.5(dc).1 G(ommand.) +358.08 350.4 Q .175(The return v)108 367.2 R .175(alue of a)-.25 F F3 .175 +(simple command)2.675 F F0 .175(is its e)2.675 F .175(xit status, or 128+)-.15 +F F3(n)A F0 .176(if the command is terminated by signal)3.508 F F3(n)2.676 E F0 +(.).24 E F2(Pipelines)87 384 Q F0(A)108 396 Q F3(pipeline)2.92 E F0 .42 +(is a sequence of one or more commands separated by the character)2.92 F F2(|) +2.919 E F0 5.419(.T)C .419(he format for a pipeline)443.904 396 R(is:)108 408 Q +2.5([!])144 424.8 S F3(command)A F0([)2.5 E F2(|)2.5 E F3(command2)2.5 E F0 +(... ])2.5 E .418(The standard output of)108 441.6 R F3(command)2.918 E F0 .418 +(is connected to the standard input of)2.918 F F3(command2)2.918 E F0 5.418(.T) +.02 G .419(his connection is per)453.124 441.6 R(-)-.2 E(formed before an)108 +453.6 Q 2.5(yr)-.15 G(edirections speci\214ed by the command \(see)187.54 453.6 +Q F1(REDIRECTION)2.5 E F0(belo)2.25 E(w\).)-.25 E .238(If the reserv)108 470.4 +R .238(ed w)-.15 F(ord)-.1 E F2(!)2.737 E F0 .237(precedes a pipeline, the e) +5.237 F .237(xit status of that pipeline is the logical NO)-.15 F 2.737(To)-.4 +G 2.737(ft)486.949 470.4 S .237(he e)495.796 470.4 R .237(xit sta-)-.15 F .612 +(tus of the last command.)108 482.4 R .612 +(Otherwise, the status of the pipeline is the e)5.612 F .612 +(xit status of the last command.)-.15 F(The)5.613 E(shell w)108 494.4 Q +(aits for all commands in the pipeline to terminate before returning a v)-.1 E +(alue.)-.25 E(Each command in a pipeline is e)108 511.2 Q -.15(xe)-.15 G +(cuted as a separate process \(i.e., in a subshell\).).15 E F2(Lists)87 528 Q +F0(A)108 540 Q F3(list)2.727 E F0 .227 +(is a sequence of one or more pipelines separated by one of the operators)2.727 +F F2(;)2.727 E F0(,)A F2(&)2.727 E F0(,)A F2(&&)2.727 E F0 2.727(,o)C(r)475.563 +540 Q F4 1.6662.727 G F0 2.727(,a)-1.666 G .227(nd termi-)502.833 540 R +(nated by one of)108 552 Q F2(;)2.5 E F0(,)A F2(&)2.5 E F0 2.5(,o)C(r)199.09 +552 Q F2()2.5 E F0(.)A .563(Of these list operators,)108 568.8 R F2 +(&&)3.063 E F0(and)3.063 E F4 1.6663.063 G F0(ha)1.397 E .863 -.15(ve e) +-.2 H .564(qual precedence, follo).15 F .564(wed by)-.25 F F2(;)3.064 E F0(and) +3.064 E F2(&,)3.064 E F0 .564(which ha)3.064 F .864 -.15(ve e)-.2 H .564 +(qual prece-).15 F(dence.)108 580.8 Q .029 +(If a command is terminated by the control operator)108 597.6 R F2(&)2.529 E F0 +2.529(,t)C .029(he shell e)330.75 597.6 R -.15(xe)-.15 G .029 +(cutes the command in the).15 F F3(bac)2.528 E(kgr)-.2 E(ound)-.45 E F0(in) +2.528 E 2.875(as)108 609.6 S 2.875(ubshell. The)119.205 609.6 R .375 +(shell does not w)2.875 F .375 +(ait for the command to \214nish, and the return status is 0.)-.1 F .376 +(Commands sepa-)5.376 F .849(rated by a)108 621.6 R F2(;)3.349 E F0 .849(are e) +3.349 F -.15(xe)-.15 G .848(cuted sequentially; the shell w).15 F .848 +(aits for each command to terminate in turn.)-.1 F .848(The return)5.848 F +(status is the e)108 633.6 Q(xit status of the last command e)-.15 E -.15(xe) +-.15 G(cuted.).15 E(The control operators)108 650.4 Q F2(&&)2.5 E F0(and)2.5 E +F4 1.6662.5 G F0(denote AND lists and OR lists, respecti).834 E -.15(ve) +-.25 G(ly).15 E 5(.A)-.65 G 2.5(nA)435.116 650.4 S(ND list has the form)449.836 +650.4 Q F3(command)144 667.2 Q F2(&&)2.5 E F3(command2)2.5 E(command2)108 684 Q +F0(is e)2.5 E -.15(xe)-.15 G(cuted if, and only if,).15 E F3(command)2.5 E F0 +(returns an e)2.5 E(xit status of zero.)-.15 E(An OR list has the form)108 +700.8 Q F3(command)144 717.6 Q F4 1.6662.5 G F3(command2).834 E F0 +185.675(GNU 1995)72 768 R(May 5)2.5 E(2)535 768 Q EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Italic@0 SF(command2)108 84 Q F0 .911(is e)3.411 F -.15(xe)-.15 G +.911(cuted if and only if).15 F F1(command)3.412 E F0 .912 +(returns a non\255zero e)3.412 F .912(xit status.)-.15 F .912 +(The return status of AND)5.912 F(and OR lists is the e)108 96 Q +(xit status of the last command e)-.15 E -.15(xe)-.15 G(cuted in the list.).15 +E/F2 10/Times-Bold@0 SF(Compound Commands)87 112.8 Q F0(A)108 124.8 Q F1 +(compound command)2.5 E F0(is one of the follo)2.5 E(wing:)-.25 E(\()108 141.6 +Q F1(list)A F0(\))A F1(list)144 141.6 Q F0 1.12(is e)3.62 F -.15(xe)-.15 G 1.12 +(cuted in a subshell.).15 F -1.11(Va)6.119 G 1.119(riable assignments and b) +1.11 F 1.119(uiltin commands that af)-.2 F 1.119(fect the shell')-.25 F(s)-.55 +E(en)144 153.6 Q 1.068(vironment do not remain in ef)-.4 F 1.069 +(fect after the command completes.)-.25 F 1.069(The return status is the e) +6.069 F(xit)-.15 E(status of)144 165.6 Q F1(list)2.5 E F0(.)A({)108 182.4 Q F1 +(list)2.5 E F0 2.5(;})C F1(list)3.89 E F0 .326(is simply e)2.826 F -.15(xe)-.15 +G .326(cuted in the current shell en).15 F 2.826(vironment. This)-.4 F .325 +(is kno)2.826 F .325(wn as a)-.25 F F1(gr)2.825 E .325(oup command)-.45 F F0 +5.325(.T)C(he)530.56 182.4 Q(return status is the e)144 194.4 Q(xit status of) +-.15 E F1(list)2.5 E F0(.)A F2 -.25(fo)108 211.2 S(r).25 E F1(name)2.5 E F0([) +2.5 E F2(in)2.5 E F1(wor)2.5 E(d)-.37 E F0 2.5(;])C F2(do)A F1(list)2.5 E F0(;) +2.5 E F2(done)2.5 E F0 .423(The list of w)144 223.2 R .423(ords follo)-.1 F +(wing)-.25 E F2(in)2.923 E F0 .423(is e)2.923 F .423 +(xpanded, generating a list of items.)-.15 F .424(The v)5.424 F(ariable)-.25 E +F1(name)2.924 E F0 .424(is set to)2.924 F .653 +(each element of this list in turn, and)144 235.2 R F1(list)3.153 E F0 .653 +(is e)3.153 F -.15(xe)-.15 G .653(cuted each time.).15 F .653(If the)5.653 F F2 +(in)3.153 E F1(wor)3.153 E(d)-.37 E F0 .653(is omitted, the)3.153 F F2 -.25(fo) +3.153 G(r).25 E F0(command e)144 247.2 Q -.15(xe)-.15 G(cutes).15 E F1(list)2.5 +E F0(once for each positional parameter that is set \(see)2.5 E/F3 9 +/Times-Bold@0 SF -.666(PA)2.5 G(RAMETERS).666 E F0(belo)2.25 E(w\).)-.25 E F2 +(select)108 264 Q F1(name)2.5 E F0([)2.5 E F2(in)2.5 E F1(wor)2.5 E(d)-.37 E F0 +2.5(;])C F2(do)A F1(list)2.5 E F0(;)2.5 E F2(done)2.5 E F0 .432(The list of w) +144 276 R .432(ords follo)-.1 F(wing)-.25 E F2(in)2.932 E F0 .432(is e)2.932 F +.432(xpanded, generating a list of items.)-.15 F .433(The set of e)5.433 F .433 +(xpanded w)-.15 F(ords)-.1 E .843(is printed on the standard error)144 288 R +3.342(,e)-.4 G .842(ach preceded by a number)281.126 288 R 5.842(.I)-.55 G +3.342(ft)400.576 288 S(he)410.028 288 Q F2(in)3.342 E F1(wor)3.342 E(d)-.37 E +F0 .842(is omitted, the posi-)3.342 F .064(tional parameters are printed \(see) +144 300 R F3 -.666(PA)2.564 G(RAMETERS).666 E F0(belo)2.314 E 2.564(w\). The) +-.25 F F2(PS3)2.564 E F0 .064(prompt is then displayed and a)2.564 F .798 +(line read from the standard input.)144 312 R .797 +(If the line consists of the number corresponding to one of the)5.798 F .951 +(displayed w)144 324 R .951(ords, then the v)-.1 F .951(alue of)-.25 F F1(name) +3.451 E F0 .952(is set to that w)3.451 F 3.452(ord. If)-.1 F .952 +(the line is empty)3.452 F 3.452(,t)-.65 G .952(he w)484.876 324 R .952 +(ords and)-.1 F .066(prompt are displayed ag)144 336 R 2.566(ain. If)-.05 F +.065(EOF is read, the command completes.)2.566 F(An)5.065 E 2.565(yo)-.15 G +.065(ther v)452.035 336 R .065(alue read causes)-.25 F F1(name)144 348 Q F0 +.809(to be set to null.)3.309 F .809(The line read is sa)5.809 F -.15(ve)-.2 G +3.31(di).15 G 3.31(nt)338.36 348 S .81(he v)349.45 348 R(ariable)-.25 E F2 +(REPL)3.31 E(Y)-.92 E F0 5.81(.T)C(he)444.86 348 Q F1(list)3.31 E F0 .81(is e) +3.31 F -.15(xe)-.15 G .81(cuted after).15 F .667(each selection until a)144 360 +R F2(br)3.167 E(eak)-.18 E F0(or)3.167 E F2 -.18(re)3.167 G(tur).18 E(n)-.15 E +F0 .667(command is e)3.167 F -.15(xe)-.15 G 3.167(cuted. The).15 F -.15(ex) +3.167 G .667(it status of).15 F F2(select)3.167 E F0 .667(is the e)3.167 F(xit) +-.15 E(status of the last command e)144 372 Q -.15(xe)-.15 G(cuted in).15 E F1 +(list)2.5 E F0 2.5(,o).68 G 2.5(rz)324.09 372 S(ero if no commands were e) +334.36 372 Q -.15(xe)-.15 G(cuted.).15 E F2(case)108 388.8 Q F1(wor)2.5 E(d) +-.37 E F2(in)2.5 E F0([)2.5 E F1(pattern)2.5 E F0([)2.5 E F2(|)2.5 E F1 +(pattern)2.5 E F0 2.5(].)2.5 G(.. \))249.27 388.8 Q F1(list)2.5 E F0(;; ] ...) +2.5 E F2(esac)2.5 E F0(A)144 400.8 Q F2(case)3.264 E F0 .764(command \214rst e) +3.264 F(xpands)-.15 E F1(wor)3.264 E(d)-.37 E F0 3.264(,a)C .764 +(nd tries to match it ag)303.324 400.8 R .764(ainst each)-.05 F F1(pattern) +3.264 E F0 .765(in turn, using the)3.264 F 2.028 +(same matching rules as for pathname e)144 412.8 R 2.027(xpansion \(see)-.15 F +F2 -.1(Pa)4.527 G 2.027(thname Expansion).1 F F0(belo)4.527 E 4.527(w\). When) +-.25 F(a)4.527 E .89(match is found, the corresponding)144 424.8 R F1(list)3.39 +E F0 .89(is e)3.39 F -.15(xe)-.15 G 3.39(cuted. After).15 F .89 +(the \214rst match, no subsequent matches)3.39 F .308(are attempted.)144 436.8 +R .308(The e)5.308 F .307(xit status is zero if no patterns are matches.)-.15 F +.307(Otherwise, it is the e)5.307 F .307(xit status of)-.15 F +(the last command e)144 448.8 Q -.15(xe)-.15 G(cuted in).15 E F1(list)2.5 E F0 +(.)A F2(if)108 465.6 Q F1(list)2.5 E F2(then)2.5 E F1(list)2.5 E F0([)2.5 E F2 +(elif)2.5 E F1(list)2.5 E F2(then)2.5 E F1(list)2.5 E F0 2.5(].)2.5 G(.. [) +248.3 465.6 Q F2(else)2.5 E F1(list)2.5 E F0(])2.5 E F2<8c>2.5 E F0(The)144 +477.6 Q F2(if)2.534 E F1(list)2.534 E F0 .034(is e)2.534 F -.15(xe)-.15 G 2.534 +(cuted. If).15 F .034(its e)2.534 F .034(xit status is zero, the)-.15 F F2 +(then)2.534 E F1(list)2.534 E F0 .034(is e)2.534 F -.15(xe)-.15 G 2.534 +(cuted. Otherwise,).15 F(each)2.534 E F2(elif)2.534 E F1(list)2.534 E F0(is) +2.534 E -.15(exe)144 489.6 S .316(cuted in turn, and if its e).15 F .316 +(xit status is zero, the corresponding)-.15 F F2(then)2.816 E F1(list)2.816 E +F0 .316(is e)2.816 F -.15(xe)-.15 G .316(cuted and the com-).15 F .658 +(mand completes.)144 501.6 R .658(Otherwise, the)5.658 F F2(else)3.158 E F1 +(list)3.158 E F0 .658(is e)3.158 F -.15(xe)-.15 G .658(cuted, if present.).15 F +.658(The e)5.658 F .658(xit status is the e)-.15 F .659(xit status)-.15 F +(of the last command e)144 513.6 Q -.15(xe)-.15 G +(cuted, or zero if no condition tested true.).15 E F2(while)108 530.4 Q F1 +(list)2.5 E F2(do)2.5 E F1(list)2.5 E F2(done)2.5 E(until)108 542.4 Q F1(list) +2.5 E F2(do)2.5 E F1(list)2.5 E F2(done)2.5 E F0(The)144 554.4 Q F2(while)3.104 +E F0 .603(command continuously e)3.104 F -.15(xe)-.15 G .603(cutes the).15 F F2 +(do)3.103 E F1(list)3.103 E F0 .603(as long as the last command in)3.103 F F1 +(list)3.103 E F0(returns)3.103 E .47(an e)144 566.4 R .47(xit status of zero.) +-.15 F(The)5.47 E F2(until)2.97 E F0 .471(command is identical to the)2.97 F F2 +(while)2.971 E F0 .471(command, e)2.971 F .471(xcept that the test)-.15 F .055 +(is ne)144 578.4 R -.05(ga)-.15 G .055(ted; the).05 F F2(do)2.555 E F1(list) +2.555 E F0 .055(is e)2.555 F -.15(xe)-.15 G .055 +(cuted as long as the last command in).15 F F1(list)2.555 E F0 .054 +(returns a non\255zero e)2.554 F .054(xit status.)-.15 F 1.306(The e)144 590.4 +R 1.306(xit status of the)-.15 F F2(while)3.806 E F0(and)3.806 E F2(until)3.807 +E F0 1.307(commands is the e)3.807 F 1.307(xit status of the last)-.15 F F2(do) +3.807 E F1(list)3.807 E F0(command)3.807 E -.15(exe)144 602.4 S +(cuted, or zero if none w).15 E(as e)-.1 E -.15(xe)-.15 G(cuted.).15 E([)108 +619.2 Q F2(function)2.5 E F0(])2.5 E F1(name)2.5 E F0(\(\) {)2.5 E F1(list)2.5 +E F0 2.5(;})C .385(This de\214nes a function named)144 631.2 R F1(name)2.884 E +F0 5.384(.T)C(he)304.616 631.2 Q F1(body)2.884 E F0 .384 +(of the function is the)2.884 F F1(list)2.884 E F0 .384(of commands between {) +2.884 F .785(and }.)144 643.2 R .785(This list is e)5.785 F -.15(xe)-.15 G .785 +(cuted whene).15 F -.15(ve)-.25 G(r).15 E F1(name)3.285 E F0 .785 +(is speci\214ed as the name of a simple command.)3.285 F(The)5.786 E -.15(ex) +144 655.2 S .64(it status of a function is the e).15 F .64 +(xit status of the last command e)-.15 F -.15(xe)-.15 G .64(cuted in the body) +.15 F 5.64(.\()-.65 G(See)494.43 655.2 Q F3(FUNC-)3.14 E(TIONS)144 667.2 Q F0 +(belo)2.25 E -.65(w.)-.25 G(\)).65 E F3(COMMENTS)72 684 Q F0 .785 +(In a non\255interacti)108 696 R 1.085 -.15(ve s)-.25 H .785 +(hell, or an interacti).15 F 1.086 -.15(ve s)-.25 H .786(hell in which the).15 +F F2 .786(-o interacti)3.286 F -.1(ve)-.1 G(\255comments).1 E F0 .786 +(option to the)3.286 F F2(set)3.286 E F0 -.2(bu)108 708 S .343 +(iltin is enabled, a w).2 F .342(ord be)-.1 F .342(ginning with)-.15 F F2(#) +2.842 E F0 .342(causes that w)2.842 F .342 +(ord and all remaining characters on that line to be)-.1 F 5.693(ignored. An) +108 720 R(interacti)5.693 E 3.493 -.15(ve s)-.25 H 3.193(hell without the).15 F +F2 3.193(-o interacti)5.693 F -.1(ve)-.1 G(\255comments).1 E F0 3.194 +(option enabled does not allo)5.693 F(w)-.25 E 185.675(GNU 1995)72 768 R(May 5) +2.5 E(3)535 768 Q EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(comments.)108 84 Q/F1 9/Times-Bold@0 SF -.09(QU)72 100.8 S -.36(OT).09 G(ING) +.36 E/F2 10/Times-Italic@0 SF(Quoting)108 112.8 Q F0 .478(is used to remo)2.978 +F .777 -.15(ve t)-.15 H .477(he special meaning of certain characters or w).15 +F .477(ords to the shell.)-.1 F .477(Quoting can be)5.477 F .184 +(used to disable special treatment for special characters, to pre)108 124.8 R +-.15(ve)-.25 G .185(nt reserv).15 F .185(ed w)-.15 F .185 +(ords from being recognized as)-.1 F(such, and to pre)108 136.8 Q -.15(ve)-.25 +G(nt parameter e).15 E(xpansion.)-.15 E .289(Each of the)108 153.6 R F2(metac) +2.789 E(har)-.15 E(acter)-.15 E(s)-.1 E F0 .288(listed abo)2.789 F .588 -.15 +(ve u)-.15 H(nder).15 E F1(DEFINITIONS)2.788 E F0 .288 +(has special meaning to the shell and must be)2.538 F .242(quoted if the)108 +165.6 R 2.742(ya)-.15 G .242(re to represent themselv)171.066 165.6 R 2.742 +(es. There)-.15 F .242(are three quoting mechanisms: the)2.742 F F2 .242 +(escape c)2.742 F(har)-.15 E(acter)-.15 E F0 2.742(,s).73 G(in-)528.89 165.6 Q +(gle quotes, and double quotes.)108 177.6 Q 2.975(An)108 194.4 S .475 +(on-quoted backslash \()123.195 194.4 R/F3 10/Times-Bold@0 SF(\\)A F0 2.974 +(\)i)C 2.974(st)223.768 194.4 S(he)233.412 194.4 Q F2 .474(escape c)2.974 F +(har)-.15 E(acter)-.15 E F0 5.474(.I).73 G 2.974(tp)326.624 194.4 S(reserv) +337.378 194.4 Q .474(es the literal v)-.15 F .474(alue of the ne)-.25 F .474 +(xt character that)-.15 F(follo)108 206.4 Q .024(ws, with the e)-.25 F .024 +(xception of . If)-.25 F(a)2.524 E F3(\\)2.524 E F0( pair appears, and the backslash is not quoted, the)-.25 F F3(\\) +108 218.4 Q F0( is treated as a line continuation \(that is, it is ef)-.25 E(fecti)-.25 +E -.15(ve)-.25 G(ly ignored\).).15 E .295 +(Enclosing characters in single quotes preserv)108 235.2 R .295 +(es the literal v)-.15 F .295(alue of each character within the quotes.)-.25 F +2.795(As)5.295 G(in-)528.89 235.2 Q +(gle quote may not occur between single quotes, e)108 247.2 Q -.15(ve)-.25 G +2.5(nw).15 G(hen preceded by a backslash.)328.67 247.2 Q .033 +(Enclosing characters in double quotes preserv)108 264 R .034(es the literal v) +-.15 F .034(alue of all characters within the quotes, with the)-.25 F -.15(ex) +108 276 S 1.267(ception of).15 F F3($)3.767 E F0(,)A F3(`)3.766 E F0 3.766(,a)C +(nd)187.896 276 Q F3(\\)3.766 E F0 6.266(.T)C 1.266(he characters)219.318 276 R +F3($)3.766 E F0(and)3.766 E F3(`)3.766 E F0 1.266 +(retain their special meaning within double quotes.)3.766 F(The)6.266 E .637 +(backslash retains its special meaning only when follo)108 288 R .637 +(wed by one of the follo)-.25 F .637(wing characters:)-.25 F F3($)3.137 E F0(,) +A F3(`)3.137 E F0(,)A F3(")3.97 E F0(,).833 E F3(\\)3.137 E F0 3.137(,o)C(r) +536.67 288 Q F3()108 300 Q F0 5(.A)C(double quote may be quoted withi\ +n double quotes by preceding it with a backslash.)169.4 300 Q +(The special parameters)108 316.8 Q F3(*)2.5 E F0(and)2.5 E F3(@)2.5 E F0(ha) +2.5 E .3 -.15(ve s)-.2 H(pecial meaning when in double quotes \(see).15 E F1 +-.666(PA)2.5 G(RAMETERS).666 E F0(belo)2.25 E(w\).)-.25 E F1 -.666(PA)72 333.6 +S(RAMETERS).666 E F0(A)108 345.6 Q F2(par)3.334 E(ameter)-.15 E F0 .833 +(is an entity that stores v)3.334 F .833(alues, some)-.25 F .833(what lik)-.25 +F 3.333(eav)-.1 G .833(ariable in a con)362.805 345.6 R -.15(ve)-.4 G .833 +(ntional programming lan-).15 F 2.51(guage. It)108 357.6 R .01(can be a)2.51 F +F2(name)2.51 E F0 2.51(,an).18 G(umber)222.1 357.6 Q 2.51(,o)-.4 G 2.511(ro) +257.26 357.6 S .011(ne of the special characters listed belo)268.101 357.6 R +2.511(wu)-.25 G(nder)434.828 357.6 Q F3 .011(Special P)2.511 F(arameters)-.1 E +F0(.)A -.15(Fo)108 369.6 S 2.5(rt).15 G(he shell')127.02 369.6 Q 2.5(sp)-.55 G +(urposes, a)172.02 369.6 Q F2(variable)2.5 E F0(is a parameter denoted by a)2.5 +E F2(name)2.5 E F0(.).18 E 2.755(Ap)108 386.4 S .255 +(arameter is set if it has been assigned a v)122.975 386.4 R 2.754(alue. The) +-.25 F .254(null string is a v)2.754 F .254(alid v)-.25 F 2.754(alue. Once)-.25 +F 2.754(av)2.754 G .254(ariable is set, it)478.688 386.4 R +(may be unset only by using the)108 398.4 Q F3(unset)2.5 E F0 -.2(bu)2.5 G +(iltin command \(see).2 E F1(SHELL B)2.5 E(UIL)-.09 E(TIN COMMANDS)-.828 E F0 +(belo)2.25 E(w\).)-.25 E(A)108 415.2 Q F2(variable)2.5 E F0 +(may be assigned to by a statement of the form)2.5 E F2(name)144 432 Q F0(=[)A +F2(value)A F0(])A(If)108 448.8 Q F2(value)2.792 E F0 .293(is not gi)2.793 F +-.15(ve)-.25 G .293(n, the v).15 F .293(ariable is assigned the null string.) +-.25 F(All)5.293 E F2(values)2.793 E F0(under)2.793 E .293(go tilde e)-.18 F +.293(xpansion, parameter)-.15 F 1.314(and v)108 460.8 R 1.314(ariable e)-.25 F +1.314(xpansion, command substitution, arithmetic e)-.15 F 1.313 +(xpansion, and quote remo)-.15 F -.25(va)-.15 G 3.813(l. If).25 F 1.313(the v) +3.813 F(ariable)-.25 E .432(has its)108 472.8 R F32.932 E F0(attrib)2.932 +E .432(ute set \(see)-.2 F F3(declar)2.932 E(e)-.18 E F0(belo)2.932 E 2.932(wi) +-.25 G(n)280.946 472.8 Q F1 .432(SHELL B)2.932 F(UIL)-.09 E .432(TIN COMMANDS) +-.828 F/F4 9/Times-Roman@0 SF(\))A F0(then)2.682 E F2(value)2.933 E F0 .433 +(is subject to arith-)2.933 F .455(metic e)108 484.8 R .455(xpansion e)-.15 F +-.15(ve)-.25 G 2.955(ni).15 G 2.955(ft)200.745 484.8 S .455 +(he $[...] syntax does not appear)209.81 484.8 R 5.455(.W)-.55 G .454 +(ord splitting is not performed, with the e)353.1 484.8 R(xcep-)-.15 E(tion of) +108 496.8 Q F3("$@")2.5 E F0(as e)2.5 E(xplained belo)-.15 E 2.5(wu)-.25 G +(nder)248.54 496.8 Q F3(Special P)2.5 E(arameters)-.1 E F0 5(.P)C(athname e) +364.1 496.8 Q(xpansion is not performed.)-.15 E F3 -.2(Po)87 513.6 S +(sitional P).2 E(arameters)-.1 E F0(A)108 525.6 Q F2 .815(positional par)3.315 +F(ameter)-.15 E F0 .816 +(is a parameter denoted by one or more digits, other than the single digit 0.) +3.315 F(Posi-)5.816 E .445(tional parameters are assigned from the shell')108 +537.6 R 2.944(sa)-.55 G -.18(rg)303.574 537.6 S .444(uments when it is in).18 F +-.2(vo)-.4 G -.1(ke).2 G .444(d, and may be reassigned using).1 F(the)108 549.6 +Q F3(set)3.333 E F0 -.2(bu)3.333 G .833(iltin command.).2 F .834 +(Positional parameters may not be assigned to with assignment statements.)5.833 +F(The)5.834 E .334 +(positional parameters are temporarily replaced when a shell function is e)108 +561.6 R -.15(xe)-.15 G .333(cuted \(see).15 F F1(FUNCTIONS)2.833 E F0(belo) +2.583 E(w\).)-.25 E 1.403 +(When a positional parameter consisting of more than a single digit is e)108 +578.4 R 1.404(xpanded, it must be enclosed in)-.15 F(braces \(see)108 590.4 Q +F1(EXP)2.5 E(ANSION)-.666 E F0(belo)2.25 E(w\).)-.25 E F3(Special P)87 607.2 Q +(arameters)-.1 E F0 1.675(The shell treats se)108 619.2 R -.15(ve)-.25 G 1.675 +(ral parameters specially).15 F 6.675(.T)-.65 G 1.674 +(hese parameters may only be referenced; assignment to)306.95 619.2 R +(them is not allo)108 631.2 Q(wed.)-.25 E F3(*)108 643.2 Q F0 .605 +(Expands to the positional parameters, starting from one.)144 643.2 R .606 +(When the e)5.605 F .606(xpansion occurs within dou-)-.15 F .084 +(ble quotes, it e)144 655.2 R .084(xpands to a single w)-.15 F .084 +(ord with the v)-.1 F .084 +(alue of each parameter separated by the \214rst char)-.25 F(-)-.2 E .943 +(acter of the)144 667.2 R F1(IFS)3.444 E F0 .944(special v)3.194 F 3.444 +(ariable. That)-.25 F .944(is, `)3.444 F(`)-.74 E F3($*)A F0 2.424 -.74('' i)D +3.444(se).74 G(qui)357.352 667.2 Q -.25(va)-.25 G .944(lent to `).25 F(`)-.74 E +F3($1)A F2(c)A F3($2)A F2(c)A F3(...)A F0 -.74('')C 3.444(,w).74 G(here)470.124 +667.2 Q F2(c)3.444 E F0 .944(is the \214rst)3.444 F .583(character of the v)144 +679.2 R .583(alue of the)-.25 F F1(IFS)3.083 E F0 -.25(va)2.833 G 3.083 +(riable. If).25 F F1(IFS)3.083 E F0 .583 +(is null or unset, the parameters are separated by)2.833 F(spaces.)144 691.2 Q +F3(@)108 703.2 Q F0 .605 +(Expands to the positional parameters, starting from one.)144 703.2 R .606 +(When the e)5.605 F .606(xpansion occurs within dou-)-.15 F 1.387 +(ble quotes, each parameter e)144 715.2 R 1.386(xpands as a separate w)-.15 F +3.886(ord. That)-.1 F 1.386(is, `)3.886 F(`)-.74 E F3($@)3.886 E F0 2.866 -.74 +('' i)D 3.886(se).74 G(qui)465.888 715.2 Q -.25(va)-.25 G 1.386(lent to `).25 F +(`)-.74 E F3($1)A F0 -.74('')C -.74(``)144 727.2 S F3($2).74 E F0 1.666 -.74 +('' .)D 2.686(.. When).74 F .186(there are no positional parameters, `)2.686 F +(`)-.74 E F3($@)A F0 1.666 -.74('' a)D(nd).74 E F3($@)2.686 E F0 -.15(ex)2.686 +G .187(pand to nothing \(i.e., the).15 F 2.687(ya)-.15 G(re)532.23 727.2 Q +185.675(GNU 1995)72 768 R(May 5)2.5 E(4)535 768 Q EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(remo)144 84 Q -.15(ve)-.15 G(d\).).15 E/F1 10/Times-Bold@0 SF(#)108 96 Q F0 +(Expands to the number of positional parameters in decimal.)144 96 Q F1(?)108 +108 Q F0(Expands to the status of the most recently e)144 108 Q -.15(xe)-.15 G +(cuted fore).15 E(ground pipeline.)-.15 E F1108 120 Q F0 .882 +(Expands to the current option \215ags as speci\214ed upon in)144 120 R -.2(vo) +-.4 G .881(cation, by the).2 F F1(set)3.381 E F0 -.2(bu)3.381 G .881 +(iltin command, or).2 F(those set by the shell itself \(such as the)144 132 Q +F12.5 E F0(\215ag\).)2.5 E F1($)108 144 Q F0 .214 +(Expands to the process ID of the shell.)144 144 R .214 +(In a \(\) subshell, it e)5.214 F .214(xpands to the process ID of the current) +-.15 F(shell, not the subshell.)144 156 Q F1(!)108 168 Q F0 +(Expands to the process ID of the most recently e)144 168 Q -.15(xe)-.15 G +(cuted background \(asynchronous\) command.).15 E F1(0)108 180 Q F0 1.692 +(Expands to the name of the shell or shell script.)144 180 R 1.691 +(This is set at shell initialization.)6.692 F(If)6.691 E F1(bash)4.191 E F0(is) +4.191 E(in)144 192 Q -.2(vo)-.4 G -.1(ke).2 G 3.077(dw).1 G .577 +(ith a \214le of commands,)185.817 192 R F1($0)3.077 E F0 .578 +(is set to the name of that \214le.)3.077 F(If)5.578 E F1(bash)3.078 E F0 .578 +(is started with the)3.078 F F13.078 E F0 .369(option, then)144 204 R F1 +($0)2.869 E F0 .369(is set to the \214rst ar)2.869 F .369 +(gument after the string to be e)-.18 F -.15(xe)-.15 G .369 +(cuted, if one is present.).15 F(Other)5.368 E(-)-.2 E +(wise, it is set to the pathname used to in)144 216 Q -.2(vo)-.4 G -.1(ke).2 G +F1(bash)2.6 E F0 2.5(,a)C 2.5(sg)354.13 216 S -2.15 -.25(iv e)365.52 216 T 2.5 +(nb).25 G 2.5(ya)389.84 216 S -.18(rg)401.78 216 S(ument zero.).18 E F1(_)108 +228 Q F0 .361(Expands to the last ar)144 228 R .362(gument to the pre)-.18 F +.362(vious command, after e)-.25 F 2.862(xpansion. Also)-.15 F .362 +(set to the full path-)2.862 F(name of each command e)144 240 Q -.15(xe)-.15 G +(cuted and placed in the en).15 E(vironment e)-.4 E(xported to that command.) +-.15 E F1(Shell V)87 256.8 Q(ariables)-.92 E F0(The follo)108 268.8 Q(wing v) +-.25 E(ariables are set by the shell:)-.25 E F1(PPID)108 285.6 Q F0 +(The process ID of the shell')144 285.6 Q 2.5(sp)-.55 G(arent.)266.2 285.6 Q F1 +(PWD)108 297.6 Q F0(The current w)144 297.6 Q(orking directory as set by the) +-.1 E F1(cd)2.5 E F0(command.)2.5 E F1(OLDPWD)108 309.6 Q F0(The pre)144 321.6 +Q(vious w)-.25 E(orking directory as set by the)-.1 E F1(cd)2.5 E F0(command.) +2.5 E F1(REPL)108 333.6 Q(Y)-.92 E F0(Set to the line of input read by the)144 +345.6 Q F1 -.18(re)2.5 G(ad).18 E F0 -.2(bu)2.5 G(iltin command when no ar).2 E +(guments are supplied.)-.18 E F1(UID)108 357.6 Q F0 +(Expands to the user ID of the current user)144 357.6 Q 2.5(,i)-.4 G +(nitialized at shell startup.)318.56 357.6 Q F1(EUID)108 369.6 Q F0 +(Expands to the ef)144 369.6 Q(fecti)-.25 E .3 -.15(ve u)-.25 H +(ser ID of the current user).15 E 2.5(,i)-.4 G(nitialized at shell startup.) +355.39 369.6 Q F1 -.3(BA)108 381.6 S(SH).3 E F0 +(Expands to the full pathname used to in)9.07 E -.2(vo)-.4 G .2 -.1(ke t).2 H +(his instance of).1 E F1(bash)2.5 E F0(.)A F1 -.3(BA)108 393.6 S(SH_VERSION).3 +E F0(Expands to the v)144 405.6 Q(ersion number of this instance of)-.15 E F1 +(bash)2.5 E F0(.)A F1(SHL)108 417.6 Q(VL)-.92 E F0 +(Incremented by one each time an instance of)144 429.6 Q F1(bash)2.5 E F0 +(is started.)2.5 E F1(RANDOM)108 441.6 Q F0 .944 +(Each time this parameter is referenced, a random inte)144 453.6 R .943 +(ger is generated.)-.15 F .943(The sequence of random)5.943 F .91 +(numbers may be initialized by assigning a v)144 465.6 R .91(alue to)-.25 F/F2 +9/Times-Bold@0 SF(RANDOM)3.41 E/F3 9/Times-Roman@0 SF(.)A F0(If)5.41 E F2 +(RANDOM)3.41 E F0 .91(is unset, it loses its)3.16 F(special properties, e)144 +477.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)243.02 477.6 S 2.5(ti)251.63 477.6 S +2.5(ss)259.69 477.6 S(ubsequently reset.)269.97 477.6 Q F1(SECONDS)108 489.6 Q +F0 .795 +(Each time this parameter is referenced, the number of seconds since shell in) +144 501.6 R -.2(vo)-.4 G .795(cation is returned.).2 F .712(If a v)144 513.6 R +.712(alue is assigned to)-.25 F F2(SECONDS)3.212 E F3(,)A F0 .712(the v)2.962 F +.712(alue returned upon subsequent references is the number)-.25 F .408 +(of seconds since the assignment plus the v)144 525.6 R .408(alue assigned.) +-.25 F(If)5.408 E F2(SECONDS)2.908 E F0 .407(is unset, it loses its special) +2.658 F(properties, e)144 537.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)212.75 +537.6 S 2.5(ti)221.36 537.6 S 2.5(ss)229.42 537.6 S(ubsequently reset.)239.7 +537.6 Q F1(LINENO)108 549.6 Q F0 1.408(Each time this parameter is referenced,\ + the shell substitutes a decimal number representing the)144 561.6 R .078(curr\ +ent sequential line number \(starting with 1\) within a script or function.)144 +573.6 R .078(When not in a script or)5.078 F .603(function, the v)144 585.6 R +.603(alue substituted is not guaranteed to be meaningful.)-.25 F .604 +(When in a function, the v)5.603 F(alue)-.25 E .601(is not the number of the s\ +ource line that the command appears on \(that information has been lost)144 +597.6 R .461(by the time the function is e)144 609.6 R -.15(xe)-.15 G .461 +(cuted\), b).15 F .461(ut is an approximation of the number of)-.2 F/F4 10 +/Times-Italic@0 SF .462(simple commands)2.962 F F0 -.15(exe)144 621.6 S 1.02 +(cuted in the current function.).15 F(If)6.019 E F2(LINENO)3.519 E F0 1.019 +(is unset, it loses its special properties, e)3.269 F -.15(ve)-.25 G 3.519(ni) +.15 G 3.519(fi)517.402 621.6 S 3.519(ti)527.031 621.6 S(s)536.11 621.6 Q +(subsequently reset.)144 633.6 Q F1(HISTCMD)108 645.6 Q F0 .355 +(The history number)144 657.6 R 2.855(,o)-.4 G 2.855(ri)233.545 657.6 S(nde) +242.51 657.6 Q 2.856(xi)-.15 G 2.856(nt)267.436 657.6 S .356 +(he history list, of the current command.)278.072 657.6 R(If)5.356 E F2 +(HISTCMD)2.856 E F0 .356(is unset, it)2.606 F(loses its special properties, e) +144 669.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)277.47 669.6 S 2.5(ti)286.08 +669.6 S 2.5(ss)294.14 669.6 S(ubsequently reset.)304.42 669.6 Q F1(OPT)108 +681.6 Q(ARG)-.9 E F0 1.627(The v)144 693.6 R 1.627(alue of the last option ar) +-.25 F 1.627(gument processed by the)-.18 F F1(getopts)4.127 E F0 -.2(bu)4.127 +G 1.626(iltin command \(see).2 F F2(SHELL)4.126 E -.09(BU)144 705.6 S(IL).09 E +(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E 185.675(GNU 1995)72 768 R +(May 5)2.5 E(5)535 768 Q EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(OPTIND)108 84 Q F0 1.651(The inde)144 96 R 4.151(xo)-.15 +G 4.151(ft)194.922 96 S 1.651(he ne)205.183 96 R 1.651(xt ar)-.15 F 1.652 +(gument to be processed by the)-.18 F F1(getopts)4.152 E F0 -.2(bu)4.152 G +1.652(iltin command \(see).2 F/F2 9/Times-Bold@0 SF(SHELL)4.152 E -.09(BU)144 +108 S(IL).09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E F1(HOSTTYPE)108 +120 Q F0 .223(Automatically set to a string that uniquely describes the type o\ +f machine on which)144 132 R F1(bash)2.722 E F0 .222(is e)2.722 F -.15(xe)-.15 +G(cut-).15 E 2.5(ing. The)144 144 R(def)2.5 E(ault is system-dependent.)-.1 E +F1(OSTYPE)108 156 Q F0 .329 +(Automatically set to a string that describes the operating system on which)144 +168 R F1(bash)2.83 E F0 .33(is e)2.83 F -.15(xe)-.15 G 2.83(cuting. The).15 F +(def)144 180 Q(ault is system-dependent.)-.1 E .994(The follo)108 196.8 R .994 +(wing v)-.25 F .994(ariables are used by the shell.)-.25 F .994(In some cases,) +5.994 F F1(bash)3.494 E F0 .994(assigns a def)3.494 F .994(ault v)-.1 F .993 +(alue to a v)-.25 F(ariable;)-.25 E(these cases are noted belo)108 208.8 Q -.65 +(w.)-.25 G F1(IFS)108 225.6 Q F0(The)144 225.6 Q/F3 10/Times-Italic@0 SF .637 +(Internal F)3.137 F .637(ield Separ)-.45 F(ator)-.15 E F0 .637 +(that is used for w)3.137 F .638(ord splitting after e)-.1 F .638 +(xpansion and to split lines into)-.15 F -.1(wo)144 237.6 S(rds with the).1 E +F1 -.18(re)2.5 G(ad).18 E F0 -.2(bu)2.5 G(iltin command.).2 E(The def)5 E +(ault v)-.1 E(alue is `)-.25 E(`')-.25 E('.)-.74 E +F1 -.74(PA)108 249.6 S(TH)-.21 E F0 .588(The search path for commands.)9.91 F +.587(It is a colon-separated list of directories in which the shell looks)5.588 +F .211(for commands \(see)144 261.6 R F2 .212(COMMAND EXECUTION)2.712 F F0 +(belo)2.462 E 2.712(w\). The)-.25 F(def)2.712 E .212 +(ault path is system\255dependent, and)-.1 F 12.209 +(is set by the administrator who installs)144 273.6 R F1(bash)385.854 273.6 Q +F0 17.209(.A)C 12.209(common v)447.502 273.6 R 12.209(alue is)-.25 F -.74(``) +144 285.6 S(/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.).74 E -.74('') +-.7 G(.).74 E F1(HOME)108 297.6 Q F0 +(The home directory of the current user; the def)144 309.6 Q(ault ar)-.1 E +(gument for the)-.18 E F1(cd)2.5 E F0 -.2(bu)2.5 G(iltin command.).2 E F1(CDP) +108 321.6 Q -.95(AT)-.74 G(H).95 E F0 1.247(The search path for the)144 333.6 R +F1(cd)3.747 E F0 3.747(command. This)3.747 F 1.248 +(is a colon-separated list of directories in which the)3.747 F +(shell looks for destination directories speci\214ed by the)144 345.6 Q F1(cd) +2.5 E F0 2.5(command. A)2.5 F(sample v)2.5 E(alue is `)-.25 E(`.:~:/usr')-.74 E +('.)-.74 E F1(ENV)108 357.6 Q F0 .506(If this parameter is set when)144 357.6 R +F1(bash)3.006 E F0 .506(is e)3.006 F -.15(xe)-.15 G .505 +(cuting a shell script, its v).15 F .505(alue is interpreted as a \214lename) +-.25 F 1.968(containing commands to initialize the shell, as in)144 369.6 R F3 +(.bashr)4.469 E(c)-.37 E F0 6.969(.T).31 G 1.969(he v)403.037 369.6 R 1.969 +(alue of)-.25 F F2(ENV)4.469 E F0 1.969(is subjected to)4.219 F .47 +(parameter e)144 381.6 R .47(xpansion, command substitution, and arithmetic e) +-.15 F .47(xpansion before being interpreted as)-.15 F 2.5(ap)144 393.6 S +(athname.)155.94 393.6 Q F2 -.666(PA)5 G(TH)-.189 E F0 +(is not used to search for the resultant pathname.)2.25 E F1(MAIL)108 405.6 Q +F0 .336(If this parameter is set to a \214lename and the)8.78 F F2(MAILP)2.837 +E -.855(AT)-.666 G(H).855 E F0 -.25(va)2.587 G .337(riable is not set,).25 F F1 +(bash)2.837 E F0 .337(informs the user)2.837 F(of the arri)144 417.6 Q -.25(va) +-.25 G 2.5(lo).25 G 2.5(fm)202.65 417.6 S(ail in the speci\214ed \214le.)216.26 +417.6 Q F1(MAILCHECK)108 429.6 Q F0 .099(Speci\214es ho)144 441.6 R 2.599(wo) +-.25 G .099(ften \(in seconds\))207.278 441.6 R F1(bash)2.598 E F0 .098 +(checks for mail.)2.598 F .098(The def)5.098 F .098(ault is 60 seconds.)-.1 F +.098(When it is time)5.098 F .779 +(to check for mail, the shell does so before prompting.)144 453.6 R .779 +(If this v)5.779 F .779(ariable is unset, the shell disables)-.25 F +(mail checking.)144 465.6 Q F1(MAILP)108 477.6 Q -.95(AT)-.74 G(H).95 E F0 +3.512(Ac)144 489.6 S 1.012(olon-separated list of pathnames to be check)159.172 +489.6 R 1.011(ed for mail.)-.1 F 1.011(The message to be printed may be)6.011 F +.635(speci\214ed by separating the pathname from the message with a `?'.)144 +501.6 R .636($_ stands for the name of the)5.635 F(current mail\214le.)144 +513.6 Q(Example:)5 E F1(MAILP)144 525.6 Q -.95(AT)-.74 G(H).95 E F0 +(='/usr/spool/mail/bfox?"Y)A(ou ha)-1.1 E .3 -.15(ve m)-.2 H +(ail":~/shell-mail?"$_ has mail!"').15 E F1(Bash)144 537.6 Q F0 .389 +(supplies a def)2.889 F .389(ault v)-.1 F .389(alue for this v)-.25 F .389 +(ariable, b)-.25 F .388 +(ut the location of the user mail \214les that it uses is)-.2 F +(system dependent \(e.g., /usr/spool/mail/)144 549.6 Q F1($USER)A F0(\).)A F1 +(MAIL_W)108 561.6 Q(ARNING)-1.2 E F0 1.932(If set, and a \214le that)144 573.6 +R F1(bash)4.432 E F0 1.932 +(is checking for mail has been accessed since the last time it w)4.432 F(as)-.1 +E(check)144 585.6 Q(ed, the message `)-.1 E(`The mail in)-.74 E F3(mail\214le) +2.5 E F0(has been read')2.5 E 2.5('i)-.74 G 2.5(sp)385.41 585.6 S(rinted.)396.8 +585.6 Q F1(PS1)108 597.6 Q F0 .065(The v)144 597.6 R .065 +(alue of this parameter is e)-.25 F .065(xpanded \(see)-.15 F F2(PR)2.565 E +(OMPTING)-.27 E F0(belo)2.315 E .065(w\) and used as the primary prompt)-.25 F +2.5(string. The)144 609.6 R(def)2.5 E(ault v)-.1 E(alue is `)-.25 E(`)-.74 E F1 +(bash\\$)A F0 -.74('')2.5 G(.).74 E F1(PS2)108 621.6 Q F0 .688(The v)144 621.6 +R .688(alue of this parameter is e)-.25 F .689 +(xpanded and used as the secondary prompt string.)-.15 F .689(The def)5.689 F +.689(ault is)-.1 F -.74(``)144 633.6 S F1(>).74 E F0 -.74('')2.5 G(.).74 E F1 +(PS3)108 645.6 Q F0 1.15(The v)144 645.6 R 1.15 +(alue of this parameter is used as the prompt for the)-.25 F F3(select)3.649 E +F0 1.149(command \(see)3.649 F F2 1.149(SHELL GRAM-)3.649 F(MAR)144 657.6 Q F0 +(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1(PS4)108 669.6 Q F0 .628(The v)144 669.6 +R .628(alue of this parameter is e)-.25 F .629(xpanded and the v)-.15 F .629 +(alue is printed before each command)-.25 F F1(bash)3.129 E F0(dis-)3.129 E +.702(plays during an e)144 681.6 R -.15(xe)-.15 G .701(cution trace.).15 F .701 +(The \214rst character of)5.701 F F2(PS4)3.201 E F0 .701 +(is replicated multiple times, as neces-)2.951 F(sary)144 693.6 Q 2.5(,t)-.65 G +2.5(oi)167.79 693.6 S(ndicate multiple le)178.07 693.6 Q -.15(ve)-.25 G +(ls of indirection.).15 E(The def)5 E(ault is `)-.1 E(`)-.74 E F1(+)A F0 -.74 +('')2.5 G(.).74 E F1(HISTSIZE)108 705.6 Q F0 1.942 +(The number of commands to remember in the command history \(see)144 717.6 R F2 +(HIST)4.443 E(OR)-.162 E(Y)-.315 E F0(belo)4.193 E 4.443(w\). The)-.25 F(def) +144 729.6 Q(ault v)-.1 E(alue is 500.)-.25 E 185.675(GNU 1995)72 768 R(May 5) +2.5 E(6)535 768 Q EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(HISTFILE)108 84 Q F0 1.386 +(The name of the \214le in which command history is sa)144 96 R -.15(ve)-.2 G +3.886(d. \(See).15 F/F2 9/Times-Bold@0 SF(HIST)3.886 E(OR)-.162 E(Y)-.315 E F0 +(belo)3.636 E -.65(w.)-.25 G 6.386(\)T).65 G 1.385(he def)499.005 96 R(ault)-.1 +E -.25(va)144 108 S .034(lue is).25 F/F3 10/Times-Italic@0 SF(~/.bash_history) +2.534 E F0 5.034(.I)C 2.534(fu)248.292 108 S .035 +(nset, the command history is not sa)259.156 108 R -.15(ve)-.2 G 2.535(dw).15 G +.035(hen an interacti)424.04 108 R .335 -.15(ve s)-.25 H .035(hell e).15 F +(xits.)-.15 E F1(HISTFILESIZE)108 120 Q F0 1.623 +(The maximum number of lines contained in the history \214le.)144 132 R 1.622 +(When this v)6.623 F 1.622(ariable is assigned a)-.25 F -.25(va)144 144 S .311 +(lue, the history \214le is truncated, if necessary).25 F 2.811(,t)-.65 G 2.811 +(oc)339.168 144 S .311(ontain no more than that number of lines.)351.419 144 R +(The)5.312 E(def)144 156 Q(ault v)-.1 E(alue is 500.)-.25 E F1(OPTERR)108 168 Q +F0 .39(If set to the v)144 180 R .39(alue 1,)-.25 F F1(bash)2.89 E F0 .389 +(displays error messages generated by the)2.889 F F1(getopts)2.889 E F0 -.2(bu) +2.889 G .389(iltin command \(see).2 F F2 .359(SHELL B)144 192 R(UIL)-.09 E .359 +(TIN COMMANDS)-.828 F F0(belo)2.609 E(w\).)-.25 E F2(OPTERR)5.359 E F0 .36 +(is initialized to 1 each time the shell is in)2.609 F -.2(vo)-.4 G -.1(ke).2 G +(d).1 E(or a shell script is e)144 204 Q -.15(xe)-.15 G(cuted.).15 E F1(PR)108 +216 Q(OMPT_COMMAND)-.3 E F0(If set, the v)144 228 Q(alue is e)-.25 E -.15(xe) +-.15 G(cuted as a command prior to issuing each primary prompt.).15 E F1 +(IGNOREEOF)108 240 Q F0 .14(Controls the action of the shell on receipt of an) +144 252 R F2(EOF)2.639 E F0 .139(character as the sole input.)2.389 F .139 +(If set, the v)5.139 F .139(alue is)-.25 F 1.493(the number of consecuti)144 +264 R -.15(ve)-.25 G F2(EOF)4.143 E F0 1.494 +(characters typed as the \214rst characters on an input line before)3.744 F F1 +(bash)144 276 Q F0 -.15(ex)3.333 G 3.333(its. If).15 F .833(the v)3.333 F .832 +(ariable e)-.25 F .832(xists b)-.15 F .832(ut does not ha)-.2 F 1.132 -.15 +(ve a n)-.2 H .832(umeric v).15 F .832(alue, or has no v)-.25 F .832 +(alue, the def)-.25 F(ault)-.1 E -.25(va)144 288 S .585(lue is 10.).25 F .585 +(If it does not e)5.585 F(xist,)-.15 E F2(EOF)3.085 E F0 .586 +(signi\214es the end of input to the shell.)2.835 F .586(This is only in ef) +5.586 F(fect)-.25 E(for interacti)144 300 Q .3 -.15(ve s)-.25 H(hells.).15 E F1 +(TMOUT)108 312 Q F0 1.113(If set to a v)144 324 R 1.113 +(alue greater than zero, the v)-.25 F 1.112 +(alue is interpreted as the number of seconds to w)-.25 F 1.112(ait for)-.1 F +.558(input after issuing the primary prompt.)144 336 R F1(Bash)5.558 E F0 .558 +(terminates after w)3.058 F .558(aiting for that number of seconds)-.1 F +(if input does not arri)144 348 Q -.15(ve)-.25 G(.).15 E F1(FCEDIT)108 360 Q F0 +(The def)144 372 Q(ault editor for the)-.1 E F1(fc)2.5 E F0 -.2(bu)2.5 G +(iltin command.).2 E F1(FIGNORE)108 384 Q F0 2.599(Ac)144 396 S .098 +(olon-separated list of suf)158.259 396 R<8c78>-.25 E .098 +(es to ignore when performing \214lename completion \(see)-.15 F F2(READLINE) +2.598 E F0(belo)144 408 Q 2.704(w\). A)-.25 F .204(\214lename whose suf)2.704 F +.205(\214x matches one of the entries in)-.25 F F2(FIGNORE)2.705 E F0 .205 +(is e)2.455 F .205(xcluded from the list)-.15 F(of matched \214lenames.)144 420 +Q 2.5(As)5 G(ample v)250.65 420 Q(alue is `)-.25 E(`.o:~')-.74 E('.)-.74 E F1 +(INPUTRC)108 432 Q F0 1.637(The \214lename for the readline startup \214le, o) +144 444 R -.15(ve)-.15 G 1.637(rriding the def).15 F 1.636(ault of)-.1 F F3 +(~/.inputr)5.802 E(c)-.37 E F0(\(see)5.802 E F2(READLINE)4.136 E F0(belo)144 +456 Q(w\).)-.25 E F1(notify)108 468 Q F0 .031(If set,)144 468 R F1(bash)2.531 E +F0 .031(reports terminated background jobs immediately)2.531 F 2.532(,r)-.65 G +.032(ather than w)394.13 468 R .032(aiting until before print-)-.1 F +(ing the ne)144 480 Q(xt primary prompt \(see also the)-.15 E F12.5 E F0 +(option to the)2.5 E F1(set)2.5 E F0 -.2(bu)2.5 G(iltin command\).).2 E F1 +(history_contr)108 492 Q(ol)-.18 E(HISTCONTR)108 504 Q(OL)-.3 E F0 .881 +(If set to a v)144 516 R .881(alue of)-.25 F F3(ignor)3.381 E(espace)-.37 E F0 +3.381(,l).18 G .881(ines which be)281.367 516 R .881(gin with a)-.15 F F1 +(space)3.38 E F0 .88(character are not entered on the)3.38 F .401 +(history list.)144 528 R .401(If set to a v)5.401 F .401(alue of)-.25 F F3 +(ignor)2.901 E(edups)-.37 E F0 2.901(,l).27 G .401 +(ines matching the last history line are not entered.)325.029 528 R(A)5.402 E +-.25(va)144 540 S 1.304(lue of).25 F F3(ignor)3.804 E(eboth)-.37 E F0 1.304 +(combines the tw)3.804 F 3.804(oo)-.1 G 3.804(ptions. If)310.534 540 R 1.303 +(unset, or if set to an)3.804 F 3.803(yo)-.15 G 1.303(ther v)453.301 540 R +1.303(alue than those)-.25 F(abo)144 552 Q -.15(ve)-.15 G 2.5(,a).15 G +(ll lines read by the parser are sa)177.02 552 Q -.15(ve)-.2 G 2.5(do).15 G 2.5 +(nt)324.96 552 S(he history list.)335.24 552 Q F1(command_oriented_history)108 +568.8 Q F0 .472(If set,)144 580.8 R F1(bash)2.973 E F0 .473(attempts to sa) +2.973 F .773 -.15(ve a)-.2 H .473 +(ll lines of a multiple\255line command in the same history entry).15 F 5.473 +(.T)-.65 G(his)528.33 580.8 Q(allo)144 592.8 Q +(ws easy re\255editing of multi\255line commands.)-.25 E F1 +(glob_dot_\214lenames)108 609.6 Q F0(If set,)144 621.6 Q F1(bash)2.5 E F0 +(includes \214lenames be)2.5 E(ginning with a `.)-.15 E 2.5('i)-.7 G 2.5(nt) +351.75 621.6 S(he results of pathname e)362.03 621.6 Q(xpansion.)-.15 E F1 +(allo)108 638.4 Q(w_null_glob_expansion)-.1 E F0 .652(If set,)144 650.4 R F1 +(bash)3.152 E F0(allo)3.152 E .651 +(ws pathname patterns which match no \214les \(see)-.25 F F1 -.1(Pa)3.151 G +.651(thname Expansion).1 F F0(belo)3.151 E .651(w\) to)-.25 F -.15(ex)144 662.4 +S(pand to a null string, rather than themselv).15 E(es.)-.15 E F1(histchars)108 +679.2 Q F0 2.069(The tw)144 691.2 R 4.57(oo)-.1 G 4.57(rt)188.589 691.2 S 2.07 +(hree characters which control history e)199.269 691.2 R 2.07(xpansion and tok) +-.15 F 2.07(enization \(see)-.1 F F2(HIST)4.57 E(OR)-.162 E(Y)-.315 E(EXP)144 +703.2 Q(ANSION)-.666 E F0(belo)2.965 E 3.215(w\). The)-.25 F .714 +(\214rst character is the)3.215 F F3 .714(history e)3.214 F .714(xpansion c)-.2 +F(har)-.15 E(acter)-.15 E F0 3.214(,t).73 G .714(hat is, the character)460.108 +703.2 R .141(which signals the start of a history e)144 715.2 R .141 +(xpansion, normally `)-.15 F F1(!)A F0 2.641('. The)B .142 +(second character is the)2.641 F F3(quic)2.642 E 2.642(ks)-.2 G(ub-)526.67 +715.2 Q(stitution)144 727.2 Q F0(character)4.635 E 4.635(,w)-.4 G 2.134 +(hich is used as shorthand for re-running the pre)232.02 727.2 R 2.134 +(vious command entered,)-.25 F 185.675(GNU 1995)72 768 R(May 5)2.5 E(7)535 768 +Q EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +.466(substituting one string for another in the command.)144 84 R .466(The def) +5.466 F .466(ault is `)-.1 F/F1 10/Times-Bold@0 SF(^)A F0 2.966('. The)B .466 +(optional third charac-)2.966 F .414(ter is the character which signi\214es th\ +at the remainder of the line is a comment, when found as the)144 96 R .389 +(\214rst character of a w)144 108 R .389(ord, normally `)-.1 F F1(#)A F0 2.889 +('. The)B .39(history comment character causes history substitution)2.889 F .25 +(to be skipped for the remaining w)144 120 R .25(ords on the line.)-.1 F .25 +(It does not necessarily cause the shell parser to)5.25 F +(treat the rest of the line as a comment.)144 132 Q F1(nolinks)108 148.8 Q F0 +.44(If set, the shell does not follo)144 160.8 R 2.94(ws)-.25 G .44 +(ymbolic links when e)276.82 160.8 R -.15(xe)-.15 G .44 +(cuting commands that change the current).15 F -.1(wo)144 172.8 S .981 +(rking directory).1 F 5.981(.I)-.65 G 3.481(tu)227.972 172.8 S .981(ses the ph) +239.233 172.8 R .981(ysical directory structure instead.)-.05 F .981(By def) +5.981 F(ault,)-.1 E F1(bash)3.48 E F0(follo)3.48 E .98(ws the)-.25 F .585(logi\ +cal chain of directories when performing commands which change the current dir\ +ectory)144 184.8 R 3.085(,s)-.65 G(uch)525.56 184.8 Q(as)144 196.8 Q F1(cd)2.65 +E F0 5.15(.S)C .149(ee also the description of the)178.19 196.8 R F12.649 +E F0 .149(option to the)2.649 F F1(set)2.649 E F0 -.2(bu)2.649 G .149(iltin \() +.2 F/F2 9/Times-Bold@0 SF .149(SHELL B)2.649 F(UIL)-.09 E .149(TIN COMMANDS) +-.828 F F0(belo)144 208.8 Q(w\).)-.25 E F1(hostname_completion_\214le)108 220.8 +Q(HOSTFILE)108 232.8 Q F0 1.015 +(Contains the name of a \214le in the same format as)144 244.8 R/F3 10 +/Times-Italic@0 SF(/etc/hosts)5.181 E F0 1.015 +(that should be read when the shell)5.181 F 1.425 +(needs to complete a hostname.)144 256.8 R 1.424 +(The \214le may be changed interacti)6.424 F -.15(ve)-.25 G 1.424(ly; the ne) +.15 F 1.424(xt time hostname)-.15 F(completion is attempted)144 268.8 Q F1 +(bash)2.5 E F0(adds the contents of the ne)2.5 E 2.5<778c>-.25 G +(le to the already e)386.52 268.8 Q(xisting database.)-.15 E F1(noclob)108 +285.6 Q(ber)-.1 E F0 .38(If set,)144 297.6 R F1(bash)2.88 E F0 .38(does not o) +2.88 F -.15(ve)-.15 G .38(rwrite an e).15 F .381(xisting \214le with the)-.15 F +F1(>)2.881 E F0(,)A F1(>&)2.881 E F0 2.881(,a)C(nd)403.766 297.6 Q F1(<>)2.881 +E F0 .381(redirection operators.)2.881 F(This)5.381 E -.25(va)144 309.6 S .465 +(riable may be o).25 F -.15(ve)-.15 G .464 +(rridden when creating output \214les by using the redirection operator).15 F +F1(>|)2.964 E F0(instead)2.964 E(of)144 321.6 Q F1(>)2.5 E F0(\(see also the) +2.5 E F12.5 E F0(option to the)2.5 E F1(set)2.5 E F0 -.2(bu)2.5 G +(iltin command\).).2 E F1(auto_r)108 338.4 Q(esume)-.18 E F0 .53(This v)144 +350.4 R .53(ariable controls ho)-.25 F 3.03(wt)-.25 G .531 +(he shell interacts with the user and job control.)257.83 350.4 R .531 +(If this v)5.531 F .531(ariable is set,)-.25 F .539(single w)144 362.4 R .538(\ +ord simple commands without redirections are treated as candidates for resumpt\ +ion of an)-.1 F -.15(ex)144 374.4 S .366(isting stopped job).15 F 5.366(.T)-.4 +G .366(here is no ambiguity allo)238.718 374.4 R .366 +(wed; if there is more than one job be)-.25 F .367(ginning with)-.15 F 1.157 +(the string typed, the job most recently accessed is selected.)144 386.4 R(The) +6.156 E F3(name)3.656 E F0 1.156(of a stopped job, in this)3.656 F(conte)144 +398.4 Q 1.132(xt, is the command line used to start it.)-.15 F 1.133 +(If set to the v)6.133 F(alue)-.25 E F3 -.2(ex)3.633 G(act).2 E F0 3.633(,t).68 +G 1.133(he string supplied must)443.541 398.4 R .625 +(match the name of a stopped job e)144 410.4 R .624(xactly; if set to)-.15 F F3 +(substring)3.124 E F0 3.124(,t).22 G .624(he string supplied needs to match a) +395.716 410.4 R .924(substring of the name of a stopped job)144 422.4 R 5.924 +(.T)-.4 G(he)317.642 422.4 Q F3(substring)3.424 E F0 -.25(va)3.424 G .925 +(lue pro).25 F .925(vides functionality analogous to)-.15 F(the)144 434.4 Q F1 +(%?)2.545 E F0 .045(job id \(see)5.045 F F2 .044(JOB CONTR)2.545 F(OL)-.27 E F0 +(belo)2.294 E 2.544(w\). If)-.25 F .044(set to an)2.544 F 2.544(yo)-.15 G .044 +(ther v)380.512 434.4 R .044(alue, the supplied string must be a)-.25 F +(pre\214x of a stopped job')144 446.4 Q 2.5(sn)-.55 G(ame; this pro)248.16 +446.4 Q(vides functionality analogous to the)-.15 E F1(%)2.5 E F0(job id.)2.5 E +F1(no_exit_on_failed_exec)108 463.2 Q F0 .69(If this v)144 475.2 R .69 +(ariable e)-.25 F .69(xists, a non-interacti)-.15 F .99 -.15(ve s)-.25 H .691 +(hell will not e).15 F .691(xit if it cannot e)-.15 F -.15(xe)-.15 G .691 +(cute the \214le speci\214ed in).15 F(the)144 487.2 Q F1(exec)2.5 E F0 -.2(bu) +2.5 G(iltin command.).2 E(An interacti)5 E .3 -.15(ve s)-.25 H(hell does not e) +.15 E(xit if)-.15 E F1(exec)2.5 E F0 -.1(fa)2.5 G(ils.).1 E F1(cdable_v)108 504 +Q(ars)-.1 E F0 .834(If this is set, an ar)144 516 R .834(gument to the)-.18 F +F1(cd)3.334 E F0 -.2(bu)3.334 G .834 +(iltin command that is not a directory is assumed to be the).2 F(name of a v) +144 528 Q(ariable whose v)-.25 E(alue is the directory to change to.)-.25 E F2 +(EXP)72 544.8 Q(ANSION)-.666 E F0 .76 +(Expansion is performed on the command line after it has been split into w)108 +556.8 R 3.26(ords. There)-.1 F .76(are se)3.26 F -.15(ve)-.25 G 3.26(nk).15 G +.76(inds of)511.74 556.8 R -.15(ex)108 568.8 S .37(pansion performed:).15 F F3 +(br)2.869 E .369(ace e)-.15 F(xpansion)-.2 E F0(,).24 E F3 .369(tilde e)2.869 F +(xpansion)-.2 E F0(,).24 E F3(par)2.869 E .369(ameter and variable e)-.15 F +(xpansion)-.2 E F0(,).24 E F3 .369(command sub-)2.869 F(stitution)108 580.8 Q +F0(,).24 E F3(arithmetic e)2.5 E(xpansion)-.2 E F0(,).24 E F3(wor)2.5 E 2.5(ds) +-.37 G(plitting)261.81 580.8 Q F0 2.5(,a).22 G(nd)300.37 580.8 Q F3(pathname e) +2.5 E(xpansion)-.2 E F0(.).24 E .16(The order of e)108 597.6 R .16 +(xpansions is: brace e)-.15 F .16(xpansion, tilde e)-.15 F .16 +(xpansion, parameter)-.15 F 2.66(,v)-.4 G .16(ariable, command, and arithmetic) +405.38 597.6 R(substitution \(done in a left\255to\255right f)108 609.6 Q +(ashion\), w)-.1 E(ord splitting, and pathname e)-.1 E(xpansion.)-.15 E +(On systems that can support it, there is an additional e)108 626.4 Q +(xpansion a)-.15 E -.25(va)-.2 G(ilable:).25 E F3(pr)2.5 E(ocess substitution) +-.45 E F0(.)A 1.487(Only brace e)108 643.2 R 1.487(xpansion, w)-.15 F 1.487 +(ord splitting, and pathname e)-.1 F 1.487(xpansion can change the number of w) +-.15 F 1.486(ords of the)-.1 F -.15(ex)108 655.2 S 1.36(pansion; other e).15 F +1.36(xpansions e)-.15 F 1.36(xpand a single w)-.15 F 1.36(ord to a single w)-.1 +F 3.86(ord. The)-.1 F 1.36(single e)3.86 F 1.36(xception to this is the)-.15 F +-.15(ex)108 667.2 S(pansion of `).15 E(`)-.74 E F1($@)A F0 1.48 -.74('' a)D 2.5 +(se).74 G(xplained abo)205.49 667.2 Q .3 -.15(ve \()-.15 H(see).15 E F2 -.666 +(PA)2.5 G(RAMETERS).666 E/F4 9/Times-Roman@0 SF(\).)A F1(Brace Expansion)87 684 +Q F3(Br)108 696 Q .661(ace e)-.15 F(xpansion)-.2 E F0 .661 +(is a mechanism by which arbitrary strings may be generated.)3.161 F .66 +(This mechanism is similar)5.66 F(to)108 708 Q F3 .415(pathname e)2.915 F +(xpansion)-.2 E F0 2.915(,b)C .415(ut the \214lenames generated need not e) +211.615 708 R 2.915(xist. P)-.15 F .415(atterns to be brace e)-.15 F .415 +(xpanded tak)-.15 F 2.915(et)-.1 G(he)530.56 708 Q .889(form of an optional)108 +720 R F3(pr)3.388 E(eamble)-.37 E F0 3.388(,f).18 G(ollo)238.342 720 Q .888 +(wed by a series of comma-separated strings between a pair of braces,)-.25 F +185.675(GNU 1995)72 768 R(May 5)2.5 E(8)535 768 Q EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(follo)108 84 Q .402(wed by an optional)-.25 F/F1 10/Times-Italic@0 SF +(postamble)2.902 E F0 5.402(.T).18 G .402 +(he preamble is prepended to each string contained within the braces,)262.43 84 +R(and the postamble is then appended to each resulting string, e)108 96 Q +(xpanding left to right.)-.15 E .719(Brace e)108 112.8 R .719 +(xpansions may be nested.)-.15 F .719(The results of each e)5.719 F .719 +(xpanded string are not sorted; left to right order is)-.15 F(preserv)108 124.8 +Q 2.5(ed. F)-.15 F(or e)-.15 E(xample, a)-.15 E/F2 10/Times-Bold@0 SF({)A F0 +(d,c,b)A F2(})A F0 2.5(ee)C(xpands into `ade ace abe'.)252.18 124.8 Q .581 +(Brace e)108 141.6 R .581(xpansion is performed before an)-.15 F 3.081(yo)-.15 +G .581(ther e)283.356 141.6 R .581(xpansions, and an)-.15 F 3.082(yc)-.15 G +.582(haracters special to other e)391.192 141.6 R(xpansions)-.15 E .016 +(are preserv)108 153.6 R .016(ed in the result.)-.15 F .016(It is strictly te) +5.016 F(xtual.)-.15 E F2(Bash)5.016 E F0 .015(does not apply an)2.516 F 2.515 +(ys)-.15 G .015(yntactic interpretation to the con-)406.63 153.6 R(te)108 165.6 +Q(xt of the e)-.15 E(xpansion or the te)-.15 E(xt between the braces.)-.15 E +3.632(Ac)108 182.4 S 1.132(orrectly-formed brace e)123.292 182.4 R 1.132 +(xpansion must contain unquoted opening and closing braces, and at least one) +-.15 F(unquoted comma.)108 194.4 Q(An)5 E 2.5(yi)-.15 G +(ncorrectly formed brace e)207.01 194.4 Q(xpansion is left unchanged.)-.15 E +1.476(This construct is typically used as shorthand when the common pre\214x o\ +f the strings to be generated is)108 211.2 R(longer than in the abo)108 223.2 Q +.3 -.15(ve ex)-.15 H(ample:).15 E(mkdir /usr/local/src/bash/{old,ne)144 240 Q +-.65(w,)-.25 G(dist,b).65 E(ugs})-.2 E(or)108 252 Q(cho)144 264 Q +(wn root /usr/{ucb/{e)-.25 E(x,edit},lib/{e)-.15 E(x?.?*,ho)-.15 E(w_e)-.25 E +(x}})-.15 E 1.177(Brace e)108 280.8 R 1.177 +(xpansion introduces a slight incompatibility with traditional v)-.15 F 1.177 +(ersions of)-.15 F F2(sh)3.677 E F0 3.677(,t)C 1.177(he Bourne shell.)456.747 +280.8 R F2(sh)6.178 E F0 .015 +(does not treat opening or closing braces specially when the)108 292.8 R 2.515 +(ya)-.15 G .015(ppear as part of a w)355.73 292.8 R .014(ord, and preserv)-.1 F +.014(es them in)-.15 F .693(the output.)108 304.8 R F2(Bash)5.693 E F0(remo) +3.193 E -.15(ve)-.15 G 3.193(sb).15 G .694(races from w)223.252 304.8 R .694 +(ords as a consequence of brace e)-.1 F 3.194(xpansion. F)-.15 F .694(or e)-.15 +F .694(xample, a w)-.15 F(ord)-.1 E 1.45(entered to)108 316.8 R F2(sh)3.95 E F0 +(as)3.95 E F1(\214le{1,2})3.95 E F0 1.45(appears identically in the output.) +3.95 F 1.45(The same w)6.45 F 1.45(ord is output as)-.1 F F1 1.45 +(\214le1 \214le2)3.95 F F0(after)3.95 E -.15(ex)108 328.8 S .576(pansion by).15 +F F2(bash)3.076 E F0 5.576(.I)C 3.076(fs)195.968 328.8 S .576 +(trict compatibility with)206.264 328.8 R F2(sh)3.077 E F0 .577 +(is desired, start)3.077 F F2(bash)3.077 E F0 .577(with the)3.077 F F2 +(\255nobraceexpansion)3.077 E F0(\215ag)3.077 E(\(see)108 340.8 Q/F3 9 +/Times-Bold@0 SF(OPTIONS)2.598 E F0(abo)2.348 E -.15(ve)-.15 G 2.598(\)o).15 G +2.598(rd)204.063 340.8 S .098(isable brace e)214.991 340.8 R .098 +(xpansion with the)-.15 F F2 .097(+o braceexpand)2.598 F F0 .097(option to the) +2.597 F F2(set)2.597 E F0 .097(command \(see)2.597 F F3(SHELL B)108 352.8 Q +(UIL)-.09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E F2 -.18(Ti)87 369.6 +S(lde Expansion).18 E F0 .432(If a w)108 381.6 R .432(ord be)-.1 F .432 +(gins with a tilde character \(`)-.15 F F2(~)A F0 .433 +('\), all of the characters preceding the \214rst slash \(or all characters,)B +.986(if there is no slash\) are treated as a possible)108 393.6 R F1(lo)3.486 E +.985(gin name)-.1 F F0 3.485(.I)C 3.485(ft)348.85 393.6 S(his)358.445 393.6 Q +F1(lo)3.485 E .985(gin name)-.1 F F0 .985(is the null string, the tilde is) +3.485 F .353(replaced with the v)108 405.6 R .353(alue of the parameter)-.25 F +F3(HOME)2.853 E/F4 9/Times-Roman@0 SF(.)A F0(If)4.853 E F3(HOME)2.854 E F0 .354 +(is unset, the home directory of the user e)2.604 F -.15(xe)-.15 G(cut-).15 E +(ing the shell is substituted instead.)108 417.6 Q .638(If a `+' follo)108 +434.4 R .638(ws the tilde, the v)-.25 F .638(alue of)-.25 F F3(PWD)3.138 E F0 +.638(replaces the tilde and `+'.)2.888 F .638(If a `\255' follo)5.638 F .638 +(ws, the v)-.25 F .637(alue of)-.25 F F3(OLD-)3.137 E(PWD)108 446.4 Q F0 1.345 +(is substituted.)3.595 F 1.345(If the v)6.345 F 1.345(alue follo)-.25 F 1.345 +(wing the tilde is a v)-.25 F(alid)-.25 E F1(lo)3.846 E 1.346(gin name)-.1 F F0 +3.846(,t)C 1.346(he tilde and)424.78 446.4 R F1(lo)3.846 E 1.346(gin name)-.1 F +F0(are)3.846 E .659 +(replaced with the home directory associated with that name.)108 458.4 R .659 +(If the name is in)5.659 F -.25(va)-.4 G .658(lid, or the tilde e).25 F +(xpansion)-.15 E -.1(fa)108 470.4 S(ils, the w).1 E(ord is unchanged.)-.1 E +1.162(Each v)108 487.2 R 1.162(ariable assignment is check)-.25 F 1.162 +(ed for unquoted instances of tildes follo)-.1 F 1.162(wing a)-.25 F F2(:)3.663 +E F0(or)3.663 E F2(=)3.663 E F0 6.163(.I)C 3.663(nt)483.524 487.2 S 1.163 +(hese cases,)494.967 487.2 R 1.043(tilde substitution is also performed.)108 +499.2 R(Consequently)6.043 E 3.543(,o)-.65 G 1.043 +(ne may use pathnames with tildes in assignments to)324.998 499.2 R F3 -.666 +(PA)108 511.2 S(TH)-.189 E F4(,)A F3(MAILP)2.25 E -.855(AT)-.666 G(H).855 E F4 +(,)A F0(and)2.25 E F3(CDP)2.5 E -.855(AT)-.666 G(H).855 E F4(,)A F0 +(and the shell assigns the e)2.25 E(xpanded v)-.15 E(alue.)-.25 E F2 -.1(Pa)87 +528 S(rameter Expansion).1 E F0 1.605(The `)108 540 R F2($)A F0 4.105('c)C +1.605(haracter introduces parameter e)147.86 540 R 1.606 +(xpansion, command substitution, or arithmetic e)-.15 F 4.106(xpansion. The) +-.15 F .407(parameter name or symbol to be e)108 552 R .407 +(xpanded may be enclosed in braces, which are optional b)-.15 F .406(ut serv) +-.2 F 2.906(et)-.15 G 2.906(op)515.434 552 S(ro-)528.34 552 Q .032(tect the v) +108 564 R .032(ariable to be e)-.25 F .032 +(xpanded from characters immediately follo)-.15 F .033 +(wing it which could be interpreted as part)-.25 F(of the name.)108 576 Q(${) +108 592.8 Q F1(par)A(ameter)-.15 E F0(})A 1.346(The v)144 604.8 R 1.346 +(alue of)-.25 F F1(par)3.846 E(ameter)-.15 E F0 1.346(is substituted.)3.846 F +1.346(The braces are required when)6.346 F F1(par)3.845 E(ameter)-.15 E F0 +1.345(is a positional)3.845 F .38(parameter with more than one digit, or when) +144 616.8 R F1(par)2.881 E(ameter)-.15 E F0 .381(is follo)2.881 F .381 +(wed by a character which is not to)-.25 F(be interpreted as part of its name.) +144 628.8 Q .334(In each of the cases belo)108 645.6 R -.65(w,)-.25 G F1(wor) +3.484 E(d)-.37 E F0 .334(is subject to tilde e)2.834 F .334 +(xpansion, parameter e)-.15 F .334(xpansion, command substitution,)-.15 F .861 +(and arithmetic e)108 657.6 R(xpansion.)-.15 E F2(Bash)5.861 E F0 .862 +(tests for a parameter that is unset or null; omitting the colon results in a) +3.361 F(test only for a parameter that is unset.)108 669.6 Q(${)108 686.4 Q F1 +(par)A(ameter)-.15 E F2<3aad>A F1(wor)A(d)-.37 E F0(})A F2 .929(Use Default V) +144 698.4 R(alues)-.92 E F0 5.929(.I)C(f)237.797 698.4 Q F1(par)3.429 E(ameter) +-.15 E F0 .929(is unset or null, the e)3.429 F .928(xpansion of)-.15 F F1(wor) +3.428 E(d)-.37 E F0 .928(is substituted.)3.428 F(Other)5.928 E(-)-.2 E +(wise, the v)144 710.4 Q(alue of)-.25 E F1(par)2.5 E(ameter)-.15 E F0 +(is substituted.)2.5 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(9)535 768 Q EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(${)108 84 Q/F1 10/Times-Italic@0 SF(par)A(ameter)-.15 E/F2 10/Times-Bold@0 SF +(:=)A F1(wor)A(d)-.37 E F0(})A F2 .085(Assign Default V)144 96 R(alues)-.92 E +F0 5.085(.I)C(f)248.055 96 Q F1(par)2.585 E(ameter)-.15 E F0 .086 +(is unset or null, the e)2.585 F .086(xpansion of)-.15 F F1(wor)2.586 E(d)-.37 +E F0 .086(is assigned to)2.586 F F1(par)2.586 E(am-)-.15 E(eter)144 108 Q F0 +6.311(.T).73 G 1.311(he v)175.201 108 R 1.311(alue of)-.25 F F1(par)3.811 E +(ameter)-.15 E F0 1.311(is then substituted.)3.811 F 1.311 +(Positional parameters and special parameters)6.311 F +(may not be assigned to in this w)144 120 Q(ay)-.1 E(.)-.65 E(${)108 132 Q F1 +(par)A(ameter)-.15 E F2(:?)A F1(wor)A(d)-.37 E F0(})A F2 .645(Display Err)144 +144 R .645(or if Null or Unset)-.18 F F0 5.645(.I)C(f)286.57 144 Q F1(par)3.145 +E(ameter)-.15 E F0 .645(is null or unset, the e)3.145 F .645(xpansion of)-.15 F +F1(wor)3.145 E(d)-.37 E F0 .645(\(or a mes-)3.145 F .715(sage to that ef)144 +156 R .715(fect if)-.25 F F1(wor)3.215 E(d)-.37 E F0 .714 +(is not present\) is written to the standard error and the shell, if it is not) +3.215 F(interacti)144 168 Q -.15(ve)-.25 G 2.5(,e).15 G 2.5(xits. Otherwise,) +195.1 168 R(the v)2.5 E(alue of)-.25 E F1(par)2.5 E(ameter)-.15 E F0 +(is substituted.)2.5 E(${)108 180 Q F1(par)A(ameter)-.15 E F2(:+)A F1(wor)A(d) +-.37 E F0(})A F2 .886(Use Alter)144 192 R .886(nate V)-.15 F(alue)-.92 E F0 +5.886(.I)C(f)242.508 192 Q F1(par)3.386 E(ameter)-.15 E F0 .887 +(is null or unset, nothing is substituted, otherwise the e)3.386 F(xpan-)-.15 E +(sion of)144 204 Q F1(wor)2.5 E(d)-.37 E F0(is substituted.)2.5 E(${)108 216 Q +F2(#)A F1(par)A(ameter)-.15 E F0(})A 1.509(The length in characters of the v) +144 228 R 1.508(alue of)-.25 F F1(par)4.008 E(ameter)-.15 E F0 1.508 +(is substituted.)4.008 F(If)6.508 E F1(par)4.008 E(ameter)-.15 E F0(is)4.008 E +F2(*)4.008 E F0(or)4.008 E F2(@)4.008 E F0 4.008(,t)C(he)530.56 228 Q +(length substituted is the length of)144 240 Q F2(*)2.5 E F0 -.15(ex)2.5 G +(panded within double quotes.).15 E(${)108 252 Q F1(par)A(ameter)-.15 E F2(#)A +F1(wor)A(d)-.37 E F0(})A(${)108 264 Q F1(par)A(ameter)-.15 E F2(##)A F1(wor)A +(d)-.37 E F0(})A(The)144 276 Q F1(wor)3.06 E(d)-.37 E F0 .56(is e)3.06 F .56 +(xpanded to produce a pattern just as in pathname e)-.15 F 3.06(xpansion. If) +-.15 F .56(the pattern matches)3.06 F 1.183(the be)144 288 R 1.183 +(ginning of the v)-.15 F 1.183(alue of)-.25 F F1(par)3.683 E(ameter)-.15 E F0 +3.683(,t).73 G 1.183(hen the e)319.661 288 R 1.182(xpansion is the v)-.15 F +1.182(alue of)-.25 F F1(par)3.682 E(ameter)-.15 E F0 1.182(with the)3.682 F .17 +(shortest matching pattern deleted \(the `)144 300 R(`)-.74 E F2(#)A F0 1.651 +-.74('' c)D .171(ase\) or the longest matching pattern deleted \(the `).74 F(`) +-.74 E F2(##)A F0 -.74('')C(case\).)144 312 Q(${)108 328.8 Q F1(par)A(ameter) +-.15 E F2(%)A F1(wor)A(d)-.37 E F0(})A(${)108 340.8 Q F1(par)A(ameter)-.15 E F2 +(%%)A F1(wor)A(d)-.37 E F0(})A(The)144 352.8 Q F1(wor)2.619 E(d)-.37 E F0 .119 +(is e)2.619 F .119(xpanded to produce a pattern just as in pathname e)-.15 F +2.619(xpansion. If)-.15 F .118(the pattern matches a)2.619 F .825 +(trailing portion of the v)144 364.8 R .825(alue of)-.25 F F1(par)3.325 E +(ameter)-.15 E F0 3.326(,t).73 G .826(hen the e)322.866 364.8 R .826 +(xpansion is the v)-.15 F .826(alue of)-.25 F F1(par)3.326 E(ameter)-.15 E F0 +.826(with the)3.326 F 1.672(shortest matching pattern deleted \(the `)144 376.8 +R(`)-.74 E F2(%)A F0 3.152 -.74('' c)D 1.671 +(ase\) or the longest matching pattern deleted \(the).74 F -.74(``)144 388.8 S +F2(%%).74 E F0 1.48 -.74('' c)D(ase\).).74 E F2(Command Substitution)87 405.6 Q +F1 1.697(Command substitution)108 417.6 R F0(allo)4.197 E 1.697 +(ws the output of a command to replace the command name.)-.25 F 1.698 +(There are tw)6.698 F(o)-.1 E(forms:)108 429.6 Q F2($\()144 451.2 Q F1(command) +A F2(\))1.666 E F0(or)108 463.2 Q F2(`)144 475.2 Q F1(command)A F2(`)A(Bash)108 +492 Q F0 .02(performs the e)2.52 F .02(xpansion by e)-.15 F -.15(xe)-.15 G +(cuting).15 E F1(command)2.519 E F0 .019 +(and replacing the command substitution with the stan-)2.519 F +(dard output of the command, with an)108 504 Q 2.5(yt)-.15 G(railing ne)266.17 +504 Q(wlines deleted.)-.25 E 1.559(When the old\255style backquote form of sub\ +stitution is used, backslash retains its literal meaning e)108 520.8 R(xcept) +-.15 E 1.259(when follo)108 532.8 R 1.259(wed by)-.25 F F2($)3.759 E F0(,)A F2 +(`)3.758 E F0 3.758(,o)C(r)212.083 532.8 Q F2(\\)3.758 E F0 6.258(.W)C 1.258 +(hen using the $\()240.149 532.8 R F1(command).833 E F0 3.758(\)f)1.666 G 1.258 +(orm, all characters between the parentheses)359.88 532.8 R(mak)108 544.8 Q 2.5 +(eu)-.1 G 2.5(pt)137.06 544.8 S(he command; none are treated specially)147.34 +544.8 Q(.)-.65 E .229(Command substitutions may be nested.)108 561.6 R 1.829 +-.8(To n)5.229 H .23 +(est when using the old form, escape the inner backquotes with).8 F +(backslashes.)108 573.6 Q .422 +(If the substitution appears within double quotes, w)108 590.4 R .422 +(ord splitting and pathname e)-.1 F .422(xpansion are not performed)-.15 F +(on the results.)108 602.4 Q F2(Arithmetic Expansion)87 619.2 Q F0 1.034 +(Arithmetic e)108 631.2 R 1.034(xpansion allo)-.15 F 1.034(ws the e)-.25 F -.25 +(va)-.25 G 1.034(luation of an arithmetic e).25 F 1.035 +(xpression and the substitution of the result.)-.15 F(There are tw)108 643.2 Q +2.5(of)-.1 G(ormats for arithmetic e)169.26 643.2 Q(xpansion:)-.15 E F2($[)144 +660 Q F1 -.2(ex)C(pr).2 E(ession)-.37 E F2(])A($\(\()144 676.8 Q F1 -.2(ex)C +(pr).2 E(ession)-.37 E F2(\)\))A F0(The)108 693.6 Q F1 -.2(ex)3.03 G(pr).2 E +(ession)-.37 E F0 .53(is treated as if it were within double quotes, b)3.03 F +.53(ut a double quote inside the braces or paren-)-.2 F .215 +(theses is not treated specially)108 705.6 R 5.215(.A)-.65 G .215(ll tok) +239.795 705.6 R .215(ens in the e)-.1 F .215(xpression under)-.15 F .215 +(go parameter e)-.18 F .215(xpansion, command substi-)-.15 F +(tution, and quote remo)108 717.6 Q -.25(va)-.15 G 2.5(l. Arithmetic).25 F +(substitutions may be nested.)2.5 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(10) +530 768 Q EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +1.379(The e)108 84 R -.25(va)-.25 G 1.378 +(luation is performed according to the rules listed belo).25 F 3.878(wu)-.25 G +(nder)381.541 84 Q/F1 9/Times-Bold@0 SF 1.378(ARITHMETIC EV)3.878 F(ALU)-1.215 +E -.855(AT)-.54 G(ION).855 E/F2 9/Times-Roman@0 SF(.)A F0(If)5.878 E/F3 10 +/Times-Italic@0 SF -.2(ex)108 96 S(pr).2 E(ession)-.37 E F0(is in)2.5 E -.25 +(va)-.4 G(lid,).25 E/F4 10/Times-Bold@0 SF(bash)2.5 E F0 +(prints a message indicating f)2.5 E(ailure and no substitution occurs.)-.1 E +F4(Pr)87 112.8 Q(ocess Substitution)-.18 E F3(Pr)108 124.8 Q .97 +(ocess substitution)-.45 F F0 .971 +(is supported on systems that support named pipes \()3.47 F F3(FIFOs)A F0 3.471 +(\)o)C 3.471(rt)442.936 124.8 S(he)452.517 124.8 Q F4(/de)3.471 E(v/fd)-.15 E +F0 .971(method of)3.471 F .022(naming open \214les.)108 136.8 R .021(It tak) +5.022 F .021(es the form of)-.1 F F4(<\()2.521 E F3(list)A F4(\)).833 E F0(or) +2.521 E F4(>\()2.521 E F3(list)A F4(\)).833 E F0 5.021(.T)C .021(he process) +343.68 136.8 R F3(list)2.521 E F0 .021(is run with its input or output con-) +2.521 F .058(nected to a)108 148.8 R F3(FIFO)2.558 E F0 .058(or some \214le in) +2.558 F F4(/de)2.558 E(v/fd)-.15 E F0 5.058(.T)C .058 +(he name of this \214le is passed as an ar)282.522 148.8 R .059 +(gument to the current com-)-.18 F .131(mand as the result of the e)108 160.8 R +2.631(xpansion. If)-.15 F(the)2.63 E F4(>\()2.63 E F3(list)A F4(\)).833 E F0 +.13(form is used, writing to the \214le will pro)2.63 F .13(vide input for)-.15 +F F3(list)2.63 E F0(.)A(If the)108 172.8 Q F4(<\()2.5 E F3(list)A F4(\)).833 E +F0(form is used, the \214le passed as an ar)2.5 E +(gument should be read to obtain the output of)-.18 E F3(list)2.5 E F0(.)A .713 +(On systems that support it,)108 189.6 R F3(pr)3.213 E .713(ocess substitution) +-.45 F F0 .713(is performed simultaneously with)3.213 F F3(par)3.213 E .713 +(ameter and variable)-.15 F -.2(ex)108 201.6 S(pansion).2 E F0(,).24 E F3 +(command substitution)2.5 E F0 2.5(,a).24 G(nd)251.33 201.6 Q F3(arithmetic e) +2.5 E(xpansion)-.2 E F0(.).24 E F4 -.75(Wo)87 218.4 S(rd Splitting).75 E F0 +1.143(The shell scans the results of parameter e)108 230.4 R 1.142 +(xpansion, command substitution, and arithmetic e)-.15 F 1.142(xpansion that) +-.15 F(did not occur within double quotes for)108 242.4 Q F3(wor)2.5 E 2.5(ds) +-.37 G(plitting)290.4 242.4 Q F0(.).22 E .063 +(The shell treats each character of)108 259.2 R F1(IFS)2.563 E F0 .063 +(as a delimiter)2.313 F 2.563(,a)-.4 G .063 +(nd splits the results of the other e)322.193 259.2 R .063(xpansions into w) +-.15 F(ords)-.1 E .227(on these characters.)108 271.2 R .227(If the v)5.227 F +.227(alue of)-.25 F F1(IFS)2.726 E F0 .226(is e)2.476 F(xactly)-.15 E F4 +()2.726 E F0 2.726(,t)C .226(he def)421.326 271.2 R .226 +(ault, then an)-.1 F 2.726(ys)-.15 G(equence)507.24 271.2 Q(of)108 283.2 Q F1 +(IFS)3.211 E F0 .711(characters serv)2.961 F .711(es to delimit w)-.15 F 3.212 +(ords. If)-.1 F F1(IFS)3.212 E F0 .712(has a v)2.962 F .712 +(alue other than the def)-.25 F .712(ault, then sequences of the)-.1 F 1.628 +(whitespace characters)108 295.2 R F4(space)4.128 E F0(and)4.128 E F4(tab)4.128 +E F0 1.627(are ignored at the be)4.127 F 1.627(ginning and end of the w)-.15 F +1.627(ord, as long as the)-.1 F .563(whitespace character is in the v)108 307.2 +R .564(alue of)-.25 F F1(IFS)3.064 E F0(\(an)2.814 E F1(IFS)3.064 E F0 .564 +(whitespace character\).)2.814 F(An)5.564 E 3.064(yc)-.15 G .564(haracter in) +436.496 307.2 R F1(IFS)3.064 E F0 .564(that is not)2.814 F F1(IFS)108 319.2 Q +F0 1.29(whitespace, along with an)3.54 F 3.789(ya)-.15 G(djacent)246.362 319.2 +Q F1(IFS)3.789 E F0 1.289(whitespace characters, delimits a \214eld.)3.539 F +3.789(As)6.289 G 1.289(equence of)477.328 319.2 R F1(IFS)3.789 E F0 .04 +(whitespace characters is also treated as a delimiter)108 331.2 R 5.041(.I)-.55 +G 2.541(ft)319.931 331.2 S .041(he v)328.582 331.2 R .041(alue of)-.25 F F1 +(IFS)2.541 E F0 .041(is null, no w)2.291 F .041(ord splitting occurs.)-.1 F F1 +(IFS)5.041 E F0(cannot be unset.)108 343.2 Q .857(Explicit null ar)108 360 R +.857(guments \()-.18 F F4 .833("").833 G F0(or)2.524 E F4 .833('')4.19 G F0 +3.357(\)a)C .857(re retained.)258.207 360 R .857(Implicit null ar)5.857 F .857 +(guments, resulting from the e)-.18 F .857(xpansion of)-.15 F F3(par)108 372 Q +(ameter)-.15 E(s)-.1 E F0(that ha)2.5 E .3 -.15(ve n)-.2 H 2.5(ov).15 G +(alues, are remo)211.58 372 Q -.15(ve)-.15 G(d.).15 E(Note that if no e)108 +388.8 Q(xpansion occurs, no splitting is performed.)-.15 E F4 -.1(Pa)87 405.6 S +(thname Expansion).1 E F0 .383(After w)108 417.6 R .383 +(ord splitting, unless the)-.1 F F42.883 E F0 .383(option has been set,) +2.883 F F4(bash)2.883 E F0 .384(scans each)2.884 F F3(wor)2.884 E(d)-.37 E F0 +.384(for the characters)2.884 F F4(*)2.884 E F0(,)A F4(?)2.884 E F0 2.884(,a)C +(nd)521.286 417.6 Q F4([)2.884 E F0(.)A .678 +(If one of these characters appears, then the w)108 429.6 R .677(ord is re)-.1 +F -.05(ga)-.15 G .677(rded as a).05 F F3(pattern)3.177 E F0 3.177(,a).24 G .677 +(nd replaced with an alphabeti-)416.212 429.6 R .071 +(cally sorted list of pathnames matching the pattern.)108 441.6 R .071 +(If no matching pathnames are found, and the shell v)5.071 F(ari-)-.25 E(able) +108 453.6 Q F4(allo)2.516 E(w_null_glob_expansion)-.1 E F0 .016 +(is unset, the w)2.516 F .016(ord is left unchanged.)-.1 F .016(If the v)5.016 +F .015(ariable is set, and no matches)-.25 F .487(are found, the w)108 465.6 R +.487(ord is remo)-.1 F -.15(ve)-.15 G 2.988(d. When).15 F 2.988(ap)2.988 G .488 +(attern is used for pathname generation, the character)282.29 465.6 R F4 -.63 +(``)2.988 G -.55(.').63 G(')-.08 E F0 .488(at the)5.488 F 1.789 +(start of a name or immediately follo)108 477.6 R 1.789 +(wing a slash must be matched e)-.25 F(xplicitly)-.15 E 4.288(,u)-.65 G 1.788 +(nless the shell v)444.066 477.6 R(ariable)-.25 E F4(glob_dot_\214lenames)108 +489.6 Q F0 .418(is set.)2.918 F .418(The slash character must al)5.418 F -.1 +(wa)-.1 G .418(ys be matched e).1 F(xplicitly)-.15 E 5.418(.I)-.65 G 2.918(no) +452.948 489.6 S .418(ther cases, the)465.866 489.6 R F4 -.63(``)2.918 G -.55 +(.').63 G(')-.08 E F0(character is not treated specially)108 501.6 Q(.)-.65 E +(The special pattern characters ha)108 518.4 Q .3 -.15(ve t)-.2 H(he follo).15 +E(wing meanings:)-.25 E F4(*)108 535.2 Q F0(Matches an)144 535.2 Q 2.5(ys)-.15 +G(tring, including the null string.)201.06 535.2 Q F4(?)108 547.2 Q F0 +(Matches an)144 547.2 Q 2.5(ys)-.15 G(ingle character)201.06 547.2 Q(.)-.55 E +F4([...])108 559.2 Q F0 1.992(Matches an)144 559.2 R 4.492(yo)-.15 G 1.992 +(ne of the enclosed characters.)206.154 559.2 R 4.491(Ap)6.991 G 1.991 +(air of characters separated by a minus sign)355.833 559.2 R 1.113(denotes a) +144 571.2 R F3 -.15(ra)3.613 G(ng).15 E(e)-.1 E F0 3.613(;a).18 G 1.413 -.15 +(ny c)220.309 571.2 T 1.113(haracter le).15 F 1.113(xically between those tw) +-.15 F 3.613(oc)-.1 G 1.113(haracters, inclusi)396.537 571.2 R -.15(ve)-.25 G +3.613(,i).15 G 3.613(sm)483.343 571.2 S 3.614(atched. If)498.626 571.2 R .15 +(the \214rst character follo)144 583.2 R .15(wing the)-.25 F F4([)2.65 E F0 .15 +(is a)2.65 F F4(!)2.65 E F0 .15(or a)5.15 F F4(^)2.65 E F0 .15(then an)2.65 F +2.65(yc)-.15 G .15(haracter not enclosed is matched.)368.7 583.2 R(A)5.15 E F4 +2.65 E F0(or)2.65 E F4(])2.65 E F0 +(may be matched by including it as the \214rst or last character in the set.) +144 595.2 Q F4(Quote Remo)87 612 Q -.1(va)-.1 G(l).1 E F0 +(After the preceding e)108 624 Q +(xpansions, all unquoted occurrences of the characters)-.15 E F4(\\)2.5 E F0(,) +A F4(`)2.5 E F0 2.5(,a)C(nd)429.14 624 Q F4(")3.333 E F0(are remo)3.333 E -.15 +(ve)-.15 G(d.).15 E F1(REDIRECTION)72 640.8 Q F0 .593(Before a command is e)108 +652.8 R -.15(xe)-.15 G .593(cuted, its input and output may be).15 F F3 -.37 +(re)3.093 G(dir).37 E(ected)-.37 E F0 .593 +(using a special notation interpreted)3.093 F .617(by the shell.)108 664.8 R +.617(Redirection may also be used to open and close \214les for the current sh\ +ell e)5.617 F -.15(xe)-.15 G .616(cution en).15 F(viron-)-.4 E 3.353(ment. The) +108 676.8 R(follo)3.353 E .853 +(wing redirection operators may precede or appear an)-.25 F .854 +(ywhere within a)-.15 F F3 .854(simple command)3.354 F F0(or)3.354 E(may follo) +108 688.8 Q 2.5(wa)-.25 G F3(command)A F0 5(.R).77 G +(edirections are processed in the order the)216.84 688.8 Q 2.5(ya)-.15 G(ppear) +392.47 688.8 Q 2.5(,f)-.4 G(rom left to right.)422.61 688.8 Q .448 +(In the follo)108 705.6 R .447(wing descriptions, if the \214le descriptor num\ +ber is omitted, and the \214rst character of the redirec-)-.25 F .365 +(tion operator is)108 717.6 R F4(<)2.865 E F0 2.865(,t)C .366 +(he redirection refers to the standard input \(\214le descriptor 0\).)185.99 +717.6 R .366(If the \214rst character of the)5.366 F(redirection operator is) +108 729.6 Q F4(>)2.5 E F0 2.5(,t)C +(he redirection refers to the standard output \(\214le descriptor 1\).)212.29 +729.6 Q 185.675(GNU 1995)72 768 R(May 5)2.5 E(11)530 768 Q EP +%%Page: 12 12 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +.077(The w)108 84 R .077(ord that follo)-.1 F .077 +(ws the redirection operator in the follo)-.25 F .076 +(wing descriptions is subjected to brace e)-.25 F(xpansion,)-.15 E 1.984 +(tilde e)108 96 R 1.984(xpansion, parameter e)-.15 F 1.984 +(xpansion, command substitution, arithmetic e)-.15 F 1.984 +(xpansion, quote remo)-.15 F -.25(va)-.15 G 1.984(l, and).25 F(pathname e)108 +108 Q 2.5(xpansion. If)-.15 F(it e)2.5 E(xpands to more than one w)-.15 E(ord,) +-.1 E/F1 10/Times-Bold@0 SF(bash)2.5 E F0(reports an error)2.5 E(.)-.55 E +(Note that the order of redirections is signi\214cant.)108 124.8 Q -.15(Fo)5 G +2.5(re).15 G(xample, the command)325.17 124.8 Q(ls)144 141.6 Q F1(>)2.5 E F0 +(dirlist 2)2.5 E F1(>&)A F0(1)A +(directs both standard output and standard error to the \214le)108 158.4 Q/F2 +10/Times-Italic@0 SF(dirlist)2.5 E F0 2.5(,w).68 G(hile the command)374.21 +158.4 Q(ls 2)144 175.2 Q F1(>&)A F0(1)A F1(>)2.5 E F0(dirlist)2.5 E .388 +(directs only the standard output to \214le)108 192 R F2(dirlist)2.888 E F0 +2.888(,b).68 G .387(ecause the standard error w)299.844 192 R .387 +(as duplicated as standard output)-.1 F(before the standard output w)108 204 Q +(as redirected to)-.1 E F2(dirlist)2.5 E F0(.).68 E F1(Redir)87 220.8 Q +(ecting Input)-.18 E F0 .453 +(Redirection of input causes the \214le whose name results from the e)108 232.8 +R .453(xpansion of)-.15 F F2(wor)2.953 E(d)-.37 E F0 .453 +(to be opened for read-)2.953 F(ing on \214le descriptor)108 244.8 Q F2(n)2.5 E +F0 2.5(,o).24 G 2.5(rt)208.79 244.8 S +(he standard input \(\214le descriptor 0\) if)217.4 244.8 Q F2(n)2.5 E F0 +(is not speci\214ed.)2.5 E(The general format for redirecting input is:)108 +261.6 Q([)144 278.4 Q F2(n)A F0(])A F1(<)A F2(wor)A(d)-.37 E F1(Redir)87 295.2 +Q(ecting Output)-.18 E F0 .236 +(Redirection of output causes the \214le whose name results from the e)108 +307.2 R .236(xpansion of)-.15 F F2(wor)2.736 E(d)-.37 E F0 .236 +(to be opened for writ-)2.736 F .852(ing on \214le descriptor)108 319.2 R F2(n) +3.353 E F0 3.353(,o).24 G 3.353(rt)213.052 319.2 S .853 +(he standard output \(\214le descriptor 1\) if)222.515 319.2 R F2(n)3.353 E F0 +.853(is not speci\214ed.)3.353 F .853(If the \214le does not)5.853 F -.15(ex) +108 331.2 S(ist it is created; if it does e).15 E +(xist it is truncated to zero size.)-.15 E +(The general format for redirecting output is:)108 348 Q([)144 364.8 Q F2(n)A +F0(])A F1(>)A F2(wor)A(d)-.37 E F0 .127(If the redirection operator is)108 +381.6 R F1(>|)2.627 E F0 2.627(,t)C .127(hen the v)239.132 381.6 R .127 +(alue of the)-.25 F F1(-C)2.627 E F0 .127(option to the)2.627 F F1(set)2.626 E +F0 -.2(bu)2.626 G .126(iltin command is not tested, and).2 F +(\214le creation is attempted.)108 393.6 Q(\(See also the description of)5 E F1 +(noclob)2.5 E(ber)-.1 E F0(under)2.5 E F1(Shell V)2.5 E(ariables)-.92 E F0(abo) +2.5 E -.15(ve)-.15 G(.\)).15 E F1 -.25(Ap)87 410.4 S(pending Redir).25 E +(ected Output)-.18 E F0 .703(Redirection of output in this f)108 422.4 R .703 +(ashion causes the \214le whose name results from the e)-.1 F .704(xpansion of) +-.15 F F2(wor)3.204 E(d)-.37 E F0 .704(to be)3.204 F .506 +(opened for appending on \214le descriptor)108 434.4 R F2(n)3.005 E F0 3.005 +(,o).24 G 3.005(rt)286.75 434.4 S .505 +(he standard output \(\214le descriptor 1\) if)295.865 434.4 R F2(n)3.005 E F0 +.505(is not speci\214ed.)3.005 F(If)5.505 E(the \214le does not e)108 446.4 Q +(xist it is created.)-.15 E(The general format for appending output is:)108 +463.2 Q([)144 480 Q F2(n)A F0(])A F1(>>)A F2(wor)A(d)-.37 E F1(Redir)87 501.6 Q +(ecting Standard Output and Standard Err)-.18 E(or)-.18 E(Bash)108 513.6 Q F0 +(allo)3.141 E .642(ws both the standard output \(\214le descriptor 1\) and the\ + standard error output \(\214le descriptor 2\) to)-.25 F +(be redirected to the \214le whose name is the e)108 525.6 Q(xpansion of)-.15 E +F2(wor)2.5 E(d)-.37 E F0(with this construct.)2.5 E(There are tw)108 542.4 Q +2.5(of)-.1 G(ormats for redirecting standard output and standard error:)169.26 +542.4 Q F1(&>)144 559.2 Q F2(wor)A(d)-.37 E F0(and)108 571.2 Q F1(>&)144 583.2 +Q F2(wor)A(d)-.37 E F0(Of the tw)108 600 Q 2.5(of)-.1 G +(orms, the \214rst is preferred.)156.5 600 Q(This is semantically equi)5 E -.25 +(va)-.25 G(lent to).25 E F1(>)144 616.8 Q F2(wor)A(d)-.37 E F0(2)2.5 E F1(>&)A +F0(1)A F1(Her)87 633.6 Q 2.5(eD)-.18 G(ocuments)117.64 633.6 Q F0 .33(This typ\ +e of redirection instructs the shell to read input from the current source unt\ +il a line containing only)108 645.6 R F2(wor)108 657.6 Q(d)-.37 E F0 .736 +(\(with no trailing blanks\) is seen.)3.236 F .737 +(All of the lines read up to that point are then used as the standard)5.736 F +(input for a command.)108 669.6 Q(The format of here-documents is as follo)108 +686.4 Q(ws:)-.25 E F1(<<)144 703.2 Q F0([)A F1A F0(])A F2(wor)A(d)-.37 E +(her)164 715.2 Q(e-document)-.37 E(delimiter)144 727.2 Q F0 185.675(GNU 1995)72 +768 R(May 5)2.5 E(12)530 768 Q EP +%%Page: 13 13 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +.128(No parameter e)108 84 R .127(xpansion, command substitution, pathname e) +-.15 F .127(xpansion, or arithmetic e)-.15 F .127(xpansion is performed)-.15 F +(on)108 96 Q/F1 10/Times-Italic@0 SF(wor)2.609 E(d)-.37 E F0 5.109(.I).77 G +2.609(fa)152.508 96 S .409 -.15(ny c)162.887 96 T .109(haracters in).15 F F1 +(wor)2.609 E(d)-.37 E F0 .109(are quoted, the)2.609 F F1(delimiter)2.609 E F0 +.109(is the result of quote remo)2.609 F -.25(va)-.15 G 2.609(lo).25 G(n) +477.053 96 Q F1(wor)2.609 E(d)-.37 E F0 2.609(,a).77 G .109(nd the)515.171 96 R +1.113(lines in the here-document are not e)108 108 R 3.613(xpanded. Otherwise,) +-.15 F 1.112(all lines of the here-document are subjected to)3.613 F .769 +(parameter e)108 120 R .769(xpansion, command substitution, and arithmetic e) +-.15 F 3.269(xpansion. In)-.15 F .769(the latter case, the pair)3.269 F/F2 10 +/Times-Bold@0 SF(\\)108 132 Q F0(is ignored, and)2.5 E F2(\\) +2.5 E F0(must be used to quote the characters)2.5 E F2(\\)2.5 E F0(,)A F2($)2.5 +E F0 2.5(,a)C(nd)368.39 132 Q F2(`)2.5 E F0(.)A .602 +(If the redirection operator is)108 148.8 R F2(<<\255)3.101 E F0 3.101(,t)C +.601(hen all leading tab characters are stripped from input lines and the line) +251.178 148.8 R(containing)108 160.8 Q F1(delimiter)2.5 E F0 5(.T).73 G +(his allo)203.17 160.8 Q +(ws here-documents within shell scripts to be indented in a natural f)-.25 E +(ashion.)-.1 E F2(Duplicating File Descriptors)87 177.6 Q F0 +(The redirection operator)108 189.6 Q([)144 206.4 Q F1(n)A F0(])A F2(<&)A F1 +(wor)A(d)-.37 E F0 .188(is used to duplicate input \214le descriptors.)108 +223.2 R(If)5.188 E F1(wor)2.688 E(d)-.37 E F0 -.15(ex)2.688 G .189 +(pands to one or more digits, the \214le descriptor denoted).15 F(by)108 235.2 +Q F1(n)3.095 E F0 .594(is made to be a cop)3.095 F 3.094(yo)-.1 G 3.094(ft) +222.086 235.2 S .594(hat \214le descriptor)231.29 235.2 R 5.594(.I)-.55 G(f) +313.342 235.2 Q F1(wor)3.094 E(d)-.37 E F0 -.25(eva)3.094 G .594(luates to).25 +F F23.094 E F0 3.094<2c8c>C .594(le descriptor)410.582 235.2 R F1(n)3.094 E +F0 .594(is closed.)3.094 F(If)5.594 E F1(n)3.094 E F0(is)3.094 E +(not speci\214ed, the standard input \(\214le descriptor 0\) is used.)108 247.2 +Q(The operator)108 264 Q([)144 280.8 Q F1(n)A F0(])A F2(>&)A F1(wor)A(d)-.37 E +F0 .021(is used similarly to duplicate output \214le descriptors.)108 297.6 R +(If)5.021 E F1(n)2.521 E F0 .021 +(is not speci\214ed, the standard output \(\214le descriptor)2.521 F .382 +(1\) is used.)108 309.6 R .382(As a special case, if)5.382 F F1(n)2.882 E F0 +.382(is omitted, and)2.882 F F1(wor)2.882 E(d)-.37 E F0 .382(does not e)2.882 F +.381(xpand to one or more digits, the standard)-.15 F +(output and standard error are redirected as described pre)108 321.6 Q(viously) +-.25 E(.)-.65 E F2(Opening File Descriptors f)87 338.4 Q +(or Reading and Writing)-.25 E F0(The redirection operator)108 350.4 Q([)144 +367.2 Q F1(n)A F0(])A F2(<>)A F1(wor)A(d)-.37 E F0 1.407 +(causes the \214le whose name is the e)108 384 R 1.407(xpansion of)-.15 F F1 +(wor)3.907 E(d)-.37 E F0 1.408 +(to be opened for both reading and writing on \214le)3.907 F(descriptor)108 396 +Q F1(n)2.715 E F0 2.715(,o).24 G 2.715(ra)166.16 396 S 2.715(st)176.645 396 S +.215(he standard input and standard output if)186.03 396 R F1(n)2.715 E F0 .214 +(is not speci\214ed.)2.715 F .214(If the \214le does not e)5.214 F .214 +(xist, it is)-.15 F(created.)108 408 Q/F3 9/Times-Bold@0 SF(FUNCTIONS)72 424.8 +Q F0 3.467(As)108 436.8 S .967(hell function, de\214ned as described abo) +122.577 436.8 R 1.267 -.15(ve u)-.15 H(nder).15 E F3 .967(SHELL GRAMMAR)3.467 F +/F4 9/Times-Roman@0 SF(,)A F0 .968(stores a series of commands for)3.217 F +1.277(later e)108 448.8 R -.15(xe)-.15 G 3.777(cution. Functions).15 F 1.277 +(are e)3.777 F -.15(xe)-.15 G 1.277(cuted in the conte).15 F 1.276 +(xt of the current shell; no ne)-.15 F 3.776(wp)-.25 G 1.276 +(rocess is created to)460.362 448.8 R .952 +(interpret them \(contrast this with the e)108 460.8 R -.15(xe)-.15 G .952 +(cution of a shell script\).).15 F .953(When a function is e)5.952 F -.15(xe) +-.15 G .953(cuted, the ar).15 F(gu-)-.18 E 1.102 +(ments to the function become the positional parameters during its e)108 472.8 +R -.15(xe)-.15 G 3.602(cution. The).15 F 1.102(special parameter)3.602 F F2(#) +3.602 E F0(is)3.602 E(updated to re\215ect the change.)108 484.8 Q +(Positional parameter 0 is unchanged.)5 E -1.11(Va)108 501.6 S .655 +(riables local to the function may be declared with the)1.11 F F2(local)3.155 E +F0 -.2(bu)3.156 G .656(iltin command.).2 F(Ordinarily)5.656 E 3.156(,v)-.65 G +.656(ariables and)491.304 501.6 R(their v)108 513.6 Q +(alues are shared between the function and its caller)-.25 E(.)-.55 E .044 +(If the b)108 530.4 R .043(uiltin command)-.2 F F2 -.18(re)2.543 G(tur).18 E(n) +-.15 E F0 .043(is e)2.543 F -.15(xe)-.15 G .043 +(cuted in a function, the function completes and e).15 F -.15(xe)-.15 G .043 +(cution resumes with).15 F .311(the ne)108 542.4 R .311 +(xt command after the function call.)-.15 F .311 +(When a function completes, the v)5.311 F .312(alues of the positional parame-) +-.25 F(ters and the special parameter)108 554.4 Q F2(#)2.5 E F0 +(are restored to the v)2.5 E(alues the)-.25 E 2.5(yh)-.15 G +(ad prior to function e)363.64 554.4 Q -.15(xe)-.15 G(cution.).15 E 1.359 +(Function names and de\214nitions may be listed with the)108 571.2 R F2 +3.858 E F0 1.358(option to the)3.858 F F2(declar)3.858 E(e)-.18 E F0(or)3.858 E +F2(typeset)3.858 E F0 -.2(bu)3.858 G 1.358(iltin com-).2 F 2.787 +(mands. Functions)108 583.2 R .287(may be e)2.787 F .287 +(xported so that subshells automatically ha)-.15 F .588 -.15(ve t)-.2 H .288 +(hem de\214ned with the).15 F F22.788 E F0 .288(option to)2.788 F(the)108 +595.2 Q F2(export)2.5 E F0 -.2(bu)2.5 G(iltin.).2 E(Functions may be recursi) +108 612 Q -.15(ve)-.25 G 5(.N).15 G 2.5(ol)232.58 612 S +(imit is imposed on the number of recursi)242.86 612 Q .3 -.15(ve c)-.25 H +(alls.).15 E F3(ALIASES)72 628.8 Q F0 .335(The shell maintains a list of)108 +640.8 R F1(aliases)2.835 E F0 .335(that may be set and unset with the)2.835 F +F2(alias)2.834 E F0(and)2.834 E F2(unalias)2.834 E F0 -.2(bu)2.834 G .334 +(iltin commands).2 F(\(see)108 652.8 Q F3 .763(SHELL B)3.263 F(UIL)-.09 E .763 +(TIN COMMANDS)-.828 F F0(belo)3.013 E 3.263(w\). The)-.25 F .763(\214rst w) +3.263 F .763(ord of each command, if unquoted, is check)-.1 F .764(ed to)-.1 F +.634(see if it has an alias.)108 664.8 R .634(If so, that w)5.634 F .633 +(ord is replaced by the te)-.1 F .633(xt of the alias.)-.15 F .633 +(The alias name and the replace-)5.633 F .58(ment te)108 676.8 R .58 +(xt may contain an)-.15 F 3.08(yv)-.15 G .581(alid shell input, including the) +223.95 676.8 R F1(metac)3.081 E(har)-.15 E(acter)-.15 E(s)-.1 E F0 .581 +(listed abo)3.081 F -.15(ve)-.15 G 3.081(,w).15 G .581(ith the e)472.328 676.8 +R(xception)-.15 E .997(that the alias name may not contain)108 688.8 R F1(=) +3.497 E F0 5.997(.T)C .997(he \214rst w)280.486 688.8 R .996 +(ord of the replacement te)-.1 F .996(xt is tested for aliases, b)-.15 F .996 +(ut a)-.2 F -.1(wo)108 700.8 S .494(rd that is identical to an alias being e).1 +F .495(xpanded is not e)-.15 F .495(xpanded a second time.)-.15 F .495 +(This means that one may)5.495 F(alias)108 712.8 Q F2(ls)3.02 E F0(to)3.02 E F2 +.52(ls \255F)3.02 F F0 3.02(,f)C .52(or instance, and)180.19 712.8 R F2(bash) +3.02 E F0 .519(does not try to recursi)3.02 F -.15(ve)-.25 G .519(ly e).15 F +.519(xpand the replacement te)-.15 F 3.019(xt. If)-.15 F .519(the last)3.019 F +.441(character of the alias v)108 724.8 R .441(alue is a)-.25 F F1(blank)2.941 +E F0 2.941(,t).67 G .441(hen the ne)267.738 724.8 R .441(xt command w)-.15 F +.441(ord follo)-.1 F .441(wing the alias is also check)-.25 F .442(ed for)-.1 F +185.675(GNU 1995)72 768 R(May 5)2.5 E(13)530 768 Q EP +%%Page: 14 14 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(alias e)108 84 Q(xpansion.)-.15 E(Aliases are created and listed with the)108 +100.8 Q/F1 10/Times-Bold@0 SF(alias)2.5 E F0(command, and remo)2.5 E -.15(ve) +-.15 G 2.5(dw).15 G(ith the)389.87 100.8 Q F1(unalias)2.5 E F0(command.)2.5 E +.546(There is no mechanism for using ar)108 117.6 R .546 +(guments in the replacement te)-.18 F .545(xt, as in)-.15 F F1(csh)3.045 E F0 +5.545(.I)C 3.045(fa)435.54 117.6 S -.18(rg)446.355 117.6 S .545 +(uments are needed, a).18 F(shell function should be used.)108 129.6 Q +(Aliases are not e)108 146.4 Q(xpanded when the shell is not interacti)-.15 E +-.15(ve)-.25 G(.).15 E .435 +(The rules concerning the de\214nition and use of aliases are some)108 163.2 R +.436(what confusing.)-.25 F F1(Bash)5.436 E F0(al)2.936 E -.1(wa)-.1 G .436 +(ys reads at least).1 F .338(one complete line of input before e)108 175.2 R +-.15(xe)-.15 G .338(cuting an).15 F 2.838(yo)-.15 G 2.838(ft)309.104 175.2 S +.338(he commands on that line.)318.052 175.2 R .337(Aliases are e)5.337 F .337 +(xpanded when)-.15 F 3.403(ac)108 187.2 S .904 +(ommand is read, not when it is e)120.283 187.2 R -.15(xe)-.15 G 3.404 +(cuted. Therefore,).15 F .904 +(an alias de\214nition appearing on the same line as)3.404 F .729 +(another command does not tak)108 199.2 R 3.229(ee)-.1 G -.25(ff)245.685 199.2 +S .728(ect until the ne).25 F .728(xt line of input is read.)-.15 F .728 +(This means that the commands)5.728 F(follo)108 211.2 Q .699 +(wing the alias de\214nition on that line are not af)-.25 F .699 +(fected by the ne)-.25 F 3.199(wa)-.25 G 3.199(lias. This)397.126 211.2 R(beha) +3.199 E .699(vior is also an issue)-.2 F .073(when functions are e)108 223.2 R +-.15(xe)-.15 G 2.573(cuted. Aliases).15 F .073(are e)2.573 F .072 +(xpanded when the function de\214nition is read, not when the func-)-.15 F .88 +(tion is e)108 235.2 R -.15(xe)-.15 G .88 +(cuted, because a function de\214nition is itself a compound command.).15 F .88 +(As a consequence, aliases)5.88 F .085(de\214ned in a function are not a)108 +247.2 R -.25(va)-.2 G .085(ilable until after that function is e).25 F -.15(xe) +-.15 G 2.585(cuted. T).15 F 2.585(ob)-.8 G 2.584(es)427.03 247.2 S .084 +(afe, al)437.944 247.2 R -.1(wa)-.1 G .084(ys put alias de\214-).1 F +(nitions on a separate line, and do not use)108 259.2 Q F1(alias)2.5 E F0 +(in compound commands.)2.5 E(Note that for almost e)108 276 Q -.15(ve)-.25 G +(ry purpose, aliases are superseded by shell functions.).15 E/F2 9/Times-Bold@0 +SF(JOB CONTR)72 292.8 Q(OL)-.27 E/F3 10/Times-Italic@0 SF -.25(Jo)108 304.8 S +4.601(bc).25 G(ontr)131.231 304.8 Q(ol)-.45 E F0 2.101 +(refers to the ability to selecti)4.601 F -.15(ve)-.25 G 2.101(ly stop \().15 F +F3(suspend)A F0 4.601(\)t)C 2.102(he e)373.44 304.8 R -.15(xe)-.15 G 2.102 +(cution of processes and continue).15 F(\()108 316.8 Q F3 -.37(re)C(sume).37 E +F0 3.202(\)t)C .702(heir e)149.152 316.8 R -.15(xe)-.15 G .702 +(cution at a later point.).15 F 3.202(Au)5.702 G .702(ser typically emplo) +292.906 316.8 R .702(ys this f)-.1 F .702(acility via an interacti)-.1 F 1.001 +-.15(ve i)-.25 H(nterf).15 E(ace)-.1 E(supplied jointly by the system')108 +328.8 Q 2.5(st)-.55 G(erminal dri)239.96 328.8 Q -.15(ve)-.25 G 2.5(ra).15 G +(nd)303.43 328.8 Q F1(bash)2.5 E F0(.)A .893(The shell associates a)108 345.6 R +F3(job)3.394 E F0 .894(with each pipeline.)3.394 F .894(It k)5.894 F .894 +(eeps a table of currently e)-.1 F -.15(xe)-.15 G .894 +(cuting jobs, which may be).15 F .341(listed with the)108 357.6 R F1(jobs)2.841 +E F0 2.841(command. When)2.841 F F1(bash)2.841 E F0 .341 +(starts a job asynchronously \(in the)2.841 F F3(bac)2.84 E(kgr)-.2 E(ound)-.45 +E F0 .34(\), it prints a line).77 F(that looks lik)108 369.6 Q(e:)-.1 E +([1] 25647)144 386.4 Q .241(indicating that this job is job number 1 and that \ +the process ID of the last process in the pipeline associated)108 403.2 R .733 +(with this job is 25647.)108 415.2 R .732 +(All of the processes in a single pipeline are members of the same job)5.733 F +(.)-.4 E F1(Bash)5.732 E F0(uses)3.232 E(the)108 427.2 Q F3(job)2.5 E F0 +(abstraction as the basis for job control.)2.5 E 2.563 -.8(To f)108 444 T .963 +(acilitate the implementation of the user interf).7 F .964 +(ace to job control, the system maintains the notion of a)-.1 F F3(curr)108 456 +Q .723(ent terminal pr)-.37 F .723(ocess gr)-.45 F .723(oup ID)-.45 F F0 5.723 +(.M)C .723(embers of this process group \(processes whose process group ID is) +265.055 456 R .341(equal to the current terminal process group ID\) recei)108 +468 R .642 -.15(ve k)-.25 H -.15(ey).05 G .342(board-generated signals such as) +.15 F F2(SIGINT)2.842 E/F4 9/Times-Roman@0 SF(.)A F0(These)4.842 E .216 +(processes are said to be in the)108 480 R F3(for)2.716 E -.4(eg)-.37 G -.45 +(ro).4 G(und).45 E F0(.).77 E F3(Bac)5.216 E(kgr)-.2 E(ound)-.45 E F0 .215 +(processes are those whose process group ID dif)2.716 F(fers)-.25 E .3 +(from the terminal')108 492 R .3(s; such processes are immune to k)-.55 F -.15 +(ey)-.1 G .3(board-generated signals.).15 F .3(Only fore)5.3 F .3 +(ground processes)-.15 F .253(are allo)108 504 R .253 +(wed to read from or write to the terminal.)-.25 F .252 +(Background processes which attempt to read from \(write)5.252 F 1.03 +(to\) the terminal are sent a)108 516 R F2 1.031(SIGTTIN \(SIGTT)3.531 F(OU\)) +-.162 E F0 1.031(signal by the terminal dri)3.281 F -.15(ve)-.25 G 1.831 -.4 +(r, w).15 H 1.031(hich, unless caught, sus-).4 F(pends the process.)108 528 Q +.679(If the operating system on which)108 544.8 R F1(bash)3.179 E F0 .678 +(is running supports job control,)3.178 F F1(bash)3.178 E F0(allo)3.178 E .678 +(ws you to use it.)-.25 F -.8(Ty)5.678 G(ping).8 E(the)108 556.8 Q F3(suspend) +2.681 E F0 .182(character \(typically)2.681 F F1(^Z)2.682 E F0 2.682(,C)C .182 +(ontrol-Z\) while a process is running causes that process to be stopped) +259.988 556.8 R .007(and returns you to)108 568.8 R F1(bash)2.507 E F0 5.007 +(.T)C .007(yping the)215.845 568.8 R F3 .007(delayed suspend)2.507 F F0 .007 +(character \(typically)2.507 F F1(^Y)2.506 E F0 2.506(,C)C .006 +(ontrol-Y\) causes the process)426.402 568.8 R .004(to be stopped when it atte\ +mpts to read input from the terminal, and control to be returned to)108 580.8 R +F1(bash)2.504 E F0 5.004(.Y)C .004(ou may)510.276 580.8 R .619 +(then manipulate the state of this job, using the)108 592.8 R F1(bg)3.118 E F0 +.618(command to continue it in the background, the)3.118 F F1(fg)3.118 E F0 +(com-)3.118 E .825(mand to continue it in the fore)108 604.8 R .825 +(ground, or the)-.15 F F1(kill)3.325 E F0 .825(command to kill it.)3.325 F(A) +5.825 E F1(^Z)3.326 E F0(tak)3.326 E .826(es ef)-.1 F .826(fect immediately) +-.25 F 3.326(,a)-.65 G(nd)530 604.8 Q(has the additional side ef)108 616.8 Q +(fect of causing pending output and typeahead to be discarded.)-.25 E 1.098 +(There are a number of w)108 633.6 R 1.097(ays to refer to a job in the shell.) +-.1 F 1.097(The character)6.097 F F1(%)3.597 E F0 1.097(introduces a job name.) +3.597 F(Job)6.097 E(number)108 645.6 Q F3(n)2.796 E F0 .296 +(may be referred to as)2.796 F F1(%n)2.796 E F0 5.296(.A)C .296 +(job may also be referred to using a pre\214x of the name used to start)270.904 +645.6 R .277(it, or using a substring that appears in its command line.)108 +657.6 R -.15(Fo)5.277 G 2.777(re).15 G(xample,)360.737 657.6 Q F1(%ce)2.777 E +F0 .277(refers to a stopped)2.777 F F1(ce)2.777 E F0(job)2.777 E 5.277(.I)-.4 G +2.777(fa)529.453 657.6 S .38(pre\214x matches more than one job,)108 669.6 R F1 +(bash)2.88 E F0 .38(reports an error)2.88 F 5.38(.U)-.55 G(sing)348.71 669.6 Q +F1(%?ce)2.88 E F0 2.88(,o)C 2.88(nt)402.52 669.6 S .38 +(he other hand, refers to an)413.18 669.6 R 2.88(yj)-.15 G(ob)530 669.6 Q .623 +(containing the string)108 681.6 R F1(ce)3.123 E F0 .622(in its command line.) +3.123 F .622(If the substring matches more than one job,)5.622 F F1(bash)3.122 +E F0 .622(reports an)3.122 F(error)108 693.6 Q 5.143(.T)-.55 G .143(he symbols) +140.633 693.6 R F1(%%)2.643 E F0(and)2.643 E F1(%+)2.643 E F0 .143 +(refer to the shell')2.643 F 2.643(sn)-.55 G .143(otion of the)326.77 693.6 R +F3(curr)2.643 E .143(ent job)-.37 F F0 2.643(,w).23 G .143 +(hich is the last job stopped)432.895 693.6 R .119(while it w)108 705.6 R .119 +(as in the fore)-.1 F 2.619(ground. The)-.15 F F3(pr)2.618 E -.15(ev)-.37 G +.118(ious job).15 F F0 .118(may be referenced using)2.618 F F1<25ad>2.618 E F0 +5.118(.I)C 2.618(no)433.968 705.6 S .118(utput pertaining to jobs)446.586 705.6 +R .076(\(e.g., the output of the)108 717.6 R F1(jobs)2.576 E F0 .076 +(command\), the current job is al)2.576 F -.1(wa)-.1 G .076 +(ys \215agged with a).1 F F1(+)2.576 E F0 2.576(,a)C .076(nd the pre)442.726 +717.6 R .076(vious job with)-.25 F(a)108 729.6 Q F12.5 E F0(.)A 185.675 +(GNU 1995)72 768 R(May 5)2.5 E(14)530 768 Q EP +%%Page: 15 15 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +.444(Simply naming a job can be used to bring it into the fore)108 84 R +(ground:)-.15 E/F1 10/Times-Bold@0 SF(%1)2.943 E F0 .443(is a synon)2.943 F +.443(ym for)-.15 F F1 -.63(``)2.943 G .443(fg %1').63 F(')-.63 E F0 2.943(,b)C +(ringing)511.11 84 Q 1.472(job 1 from the background into the fore)108 96 R +3.972(ground. Similarly)-.15 F(,)-.65 E F1 -.63(``)3.973 G 1.473(%1 &').63 F(') +-.63 E F0 1.473(resumes job 1 in the background,)3.973 F(equi)108 108 Q -.25 +(va)-.25 G(lent to).25 E F1 -.63(``)2.5 G(bg %1').63 E(')-.63 E F0(.)A .131 +(The shell learns immediately whene)108 124.8 R -.15(ve)-.25 G 2.631(raj).15 G +.131(ob changes state.)277.796 124.8 R(Normally)5.131 E(,)-.65 E F1(bash)2.631 +E F0 -.1(wa)2.63 G .13(its until it is about to print a).1 F .276 +(prompt before reporting changes in a job')108 136.8 R 2.776(ss)-.55 G .276 +(tatus so as to not interrupt an)286.292 136.8 R 2.776(yo)-.15 G .276 +(ther output.)416.124 136.8 R .276(If the)5.276 F F1(-b)2.776 E F0 .276 +(option to)2.776 F(the)108 148.8 Q F1(set)2.872 E F0 -.2(bu)2.872 G .372 +(iltin command is set,).2 F F1(bash)2.871 E F0 .371 +(reports such changes immediately)2.871 F 5.371(.\()-.65 G .371 +(See also the description of)405.105 148.8 R F1(notify)2.871 E F0 -.25(va)108 +160.8 S(riable under).25 E F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15 +(ve)-.15 G(.\)).15 E .529(If you attempt to e)108 177.6 R(xit)-.15 E F1(bash) +3.029 E F0 .529(while jobs are stopped, the shell prints a message w)3.029 F +.529(arning you.)-.1 F -1.1(Yo)5.529 G 3.029(um)1.1 G .529(ay then)510.311 +177.6 R .644(use the)108 189.6 R F1(jobs)3.144 E F0 .644 +(command to inspect their status.)3.144 F .644(If you do this, or try to e) +5.644 F .644(xit ag)-.15 F .644(ain immediately)-.05 F 3.144(,y)-.65 G .644 +(ou are not)498.722 189.6 R -.1(wa)108 201.6 S(rned ag).1 E +(ain, and the stopped jobs are terminated.)-.05 E/F2 9/Times-Bold@0 SF(SIGN)72 +218.4 Q(ALS)-.18 E F0(When)108 230.4 Q F1(bash)2.632 E F0 .132(is interacti) +2.632 F -.15(ve)-.25 G 2.632(,i).15 G 2.632(ti)216.178 230.4 S(gnores)224.37 +230.4 Q F2(SIGTERM)2.632 E F0 .132(\(so that)2.382 F F1 .132(kill 0)2.632 F F0 +.133(does not kill an interacti)2.633 F .433 -.15(ve s)-.25 H .133(hell\), and) +.15 F F2(SIGINT)2.633 E F0 .331(is caught and handled \(so that the)108 242.4 R +F1(wait)2.831 E F0 -.2(bu)2.831 G .331(iltin is interruptible\).).2 F .33 +(In all cases,)5.33 F F1(bash)2.83 E F0(ignores)2.83 E F2(SIGQ)2.83 E(UIT)-.09 +E/F3 9/Times-Roman@0 SF(.)A F0 .33(If job)4.83 F(control is in ef)108 254.4 Q +(fect,)-.25 E F1(bash)2.5 E F0(ignores)2.5 E F2(SIGTTIN)2.5 E F3(,)A F2(SIGTT) +2.25 E(OU)-.162 E F3(,)A F0(and)2.25 E F2(SIGTSTP)2.5 E F3(.)A F0 1.657 +(Synchronous jobs started by)108 271.2 R F1(bash)4.157 E F0(ha)4.157 E 1.957 +-.15(ve s)-.2 H 1.658(ignals set to the v).15 F 1.658 +(alues inherited by the shell from its parent.)-.25 F 1.43 +(When job control is not in ef)108 283.2 R 1.429 +(fect, background jobs \(jobs started with)-.25 F F1(&)3.929 E F0 3.929(\)i)C +(gnore)419.073 283.2 Q F2(SIGINT)3.929 E F0(and)3.679 E F2(SIGQ)3.929 E(UIT) +-.09 E F3(.)A F0 1.95 +(Commands run as a result of command substitution ignore the k)108 295.2 R -.15 +(ey)-.1 G 1.95(board-generated job control signals).15 F F2(SIGTTIN)108 307.2 Q +F3(,)A F2(SIGTT)2.25 E(OU)-.162 E F3(,)A F0(and)2.25 E F2(SIGTSTP)2.5 E F3(.)A +F2(COMMAND EXECUTION)72 324 Q F0 .547(After a command has been split into w)108 +336 R .546(ords, if it results in a simple command and an optional list of ar) +-.1 F(gu-)-.18 E(ments, the follo)108 348 Q(wing actions are tak)-.25 E(en.)-.1 +E .379 +(If the command name contains no slashes, the shell attempts to locate it.)108 +364.8 R .379(If there e)5.379 F .379(xists a shell function by)-.15 F .246 +(that name, that function is in)108 376.8 R -.2(vo)-.4 G -.1(ke).2 G 2.746(da) +.1 G 2.746(sd)254.597 376.8 S .246(escribed abo)266.233 376.8 R .546 -.15(ve i) +-.15 H(n).15 E F2(FUNCTIONS)2.746 E F3(.)A F0 .246 +(If the name does not match a func-)4.746 F +(tion, the shell searches for it in the list of shell b)108 388.8 Q 2.5 +(uiltins. If)-.2 F 2.5(am)2.5 G(atch is found, that b)356.4 388.8 Q +(uiltin is in)-.2 E -.2(vo)-.4 G -.1(ke).2 G(d.).1 E .309 +(If the name is neither a shell function nor a b)108 405.6 R .31 +(uiltin, and contains no slashes,)-.2 F F1(bash)2.81 E F0 .31 +(searches each element of)2.81 F(the)108 417.6 Q F2 -.666(PA)2.778 G(TH)-.189 E +F0 .277(for a directory containing an e)2.528 F -.15(xe)-.15 G .277 +(cutable \214le by that name.).15 F .277 +(If the search is unsuccessful, the shell)5.277 F +(prints an error message and returns a nonzero e)108 429.6 Q(xit status.)-.15 E +1.089(If the search is successful, or if the command name contains one or more\ + slashes, the shell e)108 446.4 R -.15(xe)-.15 G 1.09(cutes the).15 F .049 +(named program.)108 458.4 R(Ar)5.049 E .049(gument 0 is set to the name gi)-.18 +F -.15(ve)-.25 G .049(n, and the remaining ar).15 F .049 +(guments to the command are set)-.18 F(to the ar)108 470.4 Q(guments gi)-.18 E +-.15(ve)-.25 G(n, if an).15 E -.65(y.)-.15 G 1.809(If this e)108 487.2 R -.15 +(xe)-.15 G 1.809(cution f).15 F 1.809(ails because the \214le is not in e)-.1 F +-.15(xe)-.15 G 1.809(cutable format, and the \214le is not a directory).15 F +4.309(,i)-.65 G 4.309(ti)526.241 487.2 S(s)536.11 487.2 Q .678(assumed to be a) +108 499.2 R/F4 10/Times-Italic@0 SF .678(shell script)3.178 F F0 3.178(,a\214)C +.678(le containing shell commands.)240.516 499.2 R 3.178(As)5.678 G .678 +(ubshell is spa)384.176 499.2 R .677(wned to e)-.15 F -.15(xe)-.15 G .677 +(cute it.).15 F(This)5.677 E .329 +(subshell reinitializes itself, so that the ef)108 511.2 R .329 +(fect is as if a ne)-.25 F 2.83(ws)-.25 G .33(hell had been in)348.36 511.2 R +-.2(vo)-.4 G -.1(ke).2 G 2.83(dt).1 G 2.83(oh)442.3 511.2 S .33 +(andle the script, with)455.13 511.2 R 1.219(the e)108 523.2 R 1.219 +(xception that the locations of commands remembered by the parent \(see)-.15 F +F1(hash)3.719 E F0(belo)3.719 E 3.719(wu)-.25 G(nder)488.496 523.2 Q F2(SHELL) +3.719 E -.09(BU)108 535.2 S(IL).09 E(TIN COMMANDS)-.828 E F3(\))A F0 +(are retained by the child.)2.25 E .347(If the program is a \214le be)108 552 R +.347(ginning with)-.15 F F1(#!)2.847 E F0 2.847(,t)C .348 +(he remainder of the \214rst line speci\214es an interpreter for the pro-) +281.513 552 R 3.178(gram. The)108 564 R .678(shell e)3.178 F -.15(xe)-.15 G +.678(cutes the speci\214ed interpreter on operating systems that do not handle\ + this e).15 F -.15(xe)-.15 G(cutable).15 E 1.192(format themselv)108 576 R +3.692(es. The)-.15 F(ar)3.693 E 1.193 +(guments to the interpreter consist of a single optional ar)-.18 F 1.193 +(gument follo)-.18 F 1.193(wing the)-.25 F 1.131 +(interpreter name on the \214rst line of the program, follo)108 588 R 1.13 +(wed by the name of the program, follo)-.25 F 1.13(wed by the)-.25 F +(command ar)108 600 Q(guments, if an)-.18 E -.65(y.)-.15 G F2(ENVIR)72 616.8 Q +(ONMENT)-.27 E F0 2.353(When a program is in)108 628.8 R -.2(vo)-.4 G -.1(ke).2 +G 4.853(di).1 G 4.853(ti)235.435 628.8 S 4.853(sg)245.848 628.8 S -2.15 -.25 +(iv e)259.591 628.8 T 4.853(na).25 G 4.853(na)285.704 628.8 S 2.353 +(rray of strings called the)299.997 628.8 R F4(en)4.853 E(vir)-.4 E(onment)-.45 +E F0 7.353(.T).68 G 2.354(his is a list of)477.245 628.8 R F4(name)108 640.8 Q +F0A F4(value)A F0(pairs, of the form)2.5 E F4(name)2.5 E F0(=)A F4(value)A +F0(.).18 E .173(The shell allo)108 657.6 R .173(ws you to manipulate the en) +-.25 F .172(vironment in se)-.4 F -.15(ve)-.25 G .172(ral w).15 F 2.672 +(ays. On)-.1 F(in)2.672 E -.2(vo)-.4 G .172(cation, the shell scans its o).2 F +(wn)-.25 E(en)108 669.6 Q .186(vironment and creates a parameter for each name\ + found, automatically marking it for)-.4 F F4 -.2(ex)2.687 G(port).2 E F0 .187 +(to child pro-)2.687 F 2.704(cesses. Ex)108 681.6 R .203 +(ecuted commands inherit the en)-.15 F 2.703(vironment. The)-.4 F F1(export) +2.703 E F0(and)2.703 E F1(declar)2.703 E 2.703<65ad>-.18 G(x)433.271 681.6 Q F0 +.203(commands allo)2.703 F 2.703(wp)-.25 G(aram-)516.68 681.6 Q 1.153 +(eters and functions to be added to and deleted from the en)108 693.6 R 3.653 +(vironment. If)-.4 F 1.153(the v)3.653 F 1.154(alue of a parameter in the)-.25 +F(en)108 705.6 Q .64(vironment is modi\214ed, the ne)-.4 F 3.14(wv)-.25 G .64 +(alue becomes part of the en)251.96 705.6 R .64(vironment, replacing the old.) +-.4 F .64(The en)5.64 F(viron-)-.4 E .58(ment inherited by an)108 717.6 R 3.08 +(ye)-.15 G -.15(xe)204.45 717.6 S .58(cuted command consists of the shell').15 +F 3.08(si)-.55 G .58(nitial en)373.88 717.6 R .58(vironment, whose v)-.4 F .58 +(alues may be)-.25 F .301(modi\214ed in the shell, less an)108 729.6 R 2.801 +(yp)-.15 G .301(airs remo)236.046 729.6 R -.15(ve)-.15 G 2.801(db).15 G 2.801 +(yt)295.778 729.6 S(he)306.359 729.6 Q F1(unset)2.801 E F0 .3(command, plus an) +2.8 F 2.8(ya)-.15 G .3(dditions via the)429.92 729.6 R F1(export)2.8 E F0(and) +2.8 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(15)530 768 Q EP +%%Page: 16 16 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(declar)108 84 Q 2.5<65ad>-.18 G(x)147.12 84 Q F0 +(commands.)2.5 E .636(The en)108 100.8 R .636(vironment for an)-.4 F(y)-.15 E +/F2 10/Times-Italic@0 SF .636(simple command)3.136 F F0 .637 +(or function may be augmented temporarily by pre\214xing it with)3.137 F .203 +(parameter assignments, as described abo)108 112.8 R .502 -.15(ve i)-.15 H(n) +.15 E/F3 9/Times-Bold@0 SF -.666(PA)2.702 G(RAMETERS).666 E/F4 9/Times-Roman@0 +SF(.)A F0 .202(These assignment statements af)4.702 F .202(fect only the)-.25 F +(en)108 124.8 Q(vironment seen by that command.)-.4 E .592(If the)108 141.6 R +F13.092 E F0 .592(\215ag is set \(see the)3.092 F F1(set)3.093 E F0 -.2 +(bu)3.093 G .593(iltin command belo).2 F .593(w\), then)-.25 F F2(all)3.093 E +F0 .593(parameter assignments are placed in the)3.093 F(en)108 153.6 Q +(vironment for a command, not just those that precede the command name.)-.4 E +(When)108 170.4 Q F1(bash)3.164 E F0(in)3.164 E -.2(vo)-.4 G -.1(ke).2 G 3.164 +(sa).1 G 3.163(ne)196.232 170.4 S .663(xternal command, the v)208.685 170.4 R +(ariable)-.25 E F1(_)3.163 E F0 .663 +(is set to the full path name of the command and)3.163 F +(passed to that command in its en)108 182.4 Q(vironment.)-.4 E F3(EXIT ST)72 +199.2 Q -.855(AT)-.81 G(US).855 E F0 -.15(Fo)108 211.2 S 2.903(rt).15 G .403 +(he purposes of the shell, a command which e)127.423 211.2 R .403 +(xits with a zero e)-.15 F .403(xit status has succeeded.)-.15 F .404(An e) +5.404 F .404(xit status)-.15 F .322(of zero indicates success.)108 223.2 R +2.821(An)5.322 G .321(on\255zero e)230.409 223.2 R .321(xit status indicates f) +-.15 F 2.821(ailure. When)-.1 F 2.821(ac)2.821 G .321(ommand terminates on a f) +419.946 223.2 R(atal)-.1 E(signal,)108 235.2 Q F1(bash)2.5 E F0(uses the v)2.5 +E(alue of 128+)-.25 E F1(signal)A F0(as the e)2.5 E(xit status.)-.15 E .404 +(If a command is not found, the child process created to e)108 252 R -.15(xe) +-.15 G .404(cute it returns a status of 127.).15 F .405(If a command is)5.405 F +(found b)108 264 Q(ut is not e)-.2 E -.15(xe)-.15 G +(cutable, the return status is 126.).15 E F1(Bash)108 280.8 Q F0 .202 +(itself returns the e)2.702 F .202(xit status of the last command e)-.15 F -.15 +(xe)-.15 G .201(cuted, unless a syntax error occurs, in which case).15 F(it e) +108 292.8 Q(xits with a non\255zero v)-.15 E 2.5(alue. See)-.25 F(also the)2.5 +E F1(exit)2.5 E F0 -.2(bu)2.5 G(iltin command belo).2 E -.65(w.)-.25 G F3(PR)72 +309.6 Q(OMPTING)-.27 E F0 .644(When e)108 321.6 R -.15(xe)-.15 G .644 +(cuting interacti).15 F -.15(ve)-.25 G(ly).15 E(,)-.65 E F1(bash)3.144 E F0 +.645(displays the primary prompt)3.145 F F3(PS1)3.145 E F0 .645 +(when it is ready to read a command,)2.895 F 1.826(and the secondary prompt)108 +333.6 R F3(PS2)4.326 E F0 1.825 +(when it needs more input to complete a command.)4.076 F F1(Bash)6.825 E F0 +(allo)4.325 E 1.825(ws these)-.25 F 1.499(prompt strings to be customized by i\ +nserting a number of backslash-escaped special characters that are)108 345.6 R +(decoded as follo)108 357.6 Q(ws:)-.25 E F1(\\t)144 369.6 Q F0 +(the current time in HH:MM:SS format)180 369.6 Q F1(\\d)144 381.6 Q F0 +(the date in "W)180 381.6 Q(eekday Month Date" format \(e.g., "T)-.8 E +(ue May 26"\))-.45 E F1(\\n)144 393.6 Q F0(ne)180 393.6 Q(wline)-.25 E F1(\\s) +144 405.6 Q F0(the name of the shell, the basename of)180 405.6 Q F1($0)2.5 E +F0(\(the portion follo)2.5 E(wing the \214nal slash\))-.25 E F1(\\w)144 417.6 Q +F0(the current w)180 417.6 Q(orking directory)-.1 E F1(\\W)144 429.6 Q F0 +(the basename of the current w)180 429.6 Q(orking directory)-.1 E F1(\\u)144 +441.6 Q F0(the username of the current user)180 441.6 Q F1(\\h)144 453.6 Q F0 +(the hostname)180 453.6 Q F1(\\#)144 465.6 Q F0 +(the command number of this command)180 465.6 Q F1(\\!)144 477.6 Q F0 +(the history number of this command)180 477.6 Q F1(\\$)144 489.6 Q F0 +(if the ef)180 489.6 Q(fecti)-.25 E .3 -.15(ve U)-.25 H(ID is 0, a).15 E F1(#) +2.5 E F0 2.5(,o)C(therwise a)301.54 489.6 Q F1($)2.5 E(\\nnn)144 501.6 Q F0 +(the character corresponding to the octal number)180 501.6 Q F1(nnn)2.5 E(\\\\) +144 513.6 Q F0 2.5(ab)180 513.6 S(ackslash)191.94 513.6 Q F1(\\[)144 525.6 Q F0 +(be)180 525.6 Q 1.257(gin a sequence of non-printing characters, which could b\ +e used to embed a terminal)-.15 F(control sequence into the prompt)180 537.6 Q +F1(\\])144 549.6 Q F0(end a sequence of non-printing characters)180 549.6 Q +.119(The command number and the history number are usually dif)108 566.4 R .12 +(ferent: the history number of a command is its)-.25 F 1.585(position in the h\ +istory list, which may include commands restored from the history \214le \(see) +108 578.4 R F3(HIST)4.084 E(OR)-.162 E(Y)-.315 E F0(belo)108 590.4 Q .541 +(w\), while the command number is the position in the sequence of commands e) +-.25 F -.15(xe)-.15 G .541(cuted during the cur).15 F(-)-.2 E .546 +(rent shell session.)108 602.4 R .546(After the string is decoded, it is e) +5.546 F .546(xpanded via parameter e)-.15 F .546(xpansion, command substitu-) +-.15 F(tion, arithmetic e)108 614.4 Q(xpansion, and w)-.15 E(ord splitting.)-.1 +E F3(READLINE)72 631.2 Q F0 1.374 +(This is the library that handles reading input when using an interacti)108 +643.2 R 1.674 -.15(ve s)-.25 H 1.374(hell, unless the).15 F F1 +(\255nolineediting)3.874 E F0 .033(option is gi)108 655.2 R -.15(ve)-.25 G +2.533(n. By).15 F(def)2.533 E .032 +(ault, the line editing commands are similar to those of emacs.)-.1 F 2.532(Av) +5.032 G .032(i-style line editing)467.156 655.2 R(interf)108 667.2 Q +(ace is also a)-.1 E -.25(va)-.2 G(ilable.).25 E .567 +(In this section, the emacs-style notation is used to denote k)108 684 R -.15 +(ey)-.1 G(strok).15 E 3.068(es. Control)-.1 F -.1(ke)3.068 G .568 +(ys are denoted by C\255)-.05 F F2 -.1(ke)C(y)-.2 E F0(,)A 1.196 +(e.g., C\255n means Control\255N.)108 696 R(Similarly)6.196 E(,)-.65 E F2(meta) +3.696 E F0 -.1(ke)3.695 G 1.195(ys are denoted by M\255)-.05 F F2 -.1(ke)C(y) +-.2 E F0 3.695(,s)C 3.695(oM)421.18 696 S 1.195(\255x means Meta\255X.)438.765 +696 R(\(On)6.195 E -.1(ke)108 708 S .932(yboards without a)-.05 F F2(meta)3.432 +E F0 -.1(ke)3.432 G 2.232 -.65(y, M)-.05 H.65 E F2(x)A F0 .932(means ESC) +3.432 F F2(x)3.433 E F0 3.433(,i)C .933(.e., press the Escape k)322.8 708 R +1.233 -.15(ey t)-.1 H .933(hen the).15 F F2(x)3.433 E F0 -.1(ke)3.433 G 4.733 +-.65(y. T)-.05 H .933(his mak).65 F(es)-.1 E .6(ESC the)108 720 R F2 .6 +(meta pr)3.1 F(e\214x)-.37 E F0 5.6(.T)C .6(he combination M\255C\255)203.91 +720 R F2(x)A F0 .599(means ESC\255Control\255)3.099 F F2(x)A F0 3.099(,o)C +3.099(rp)407.796 720 S .599(ress the Escape k)419.225 720 R .899 -.15(ey t)-.1 +H .599(hen hold).15 F 185.675(GNU 1995)72 768 R(May 5)2.5 E(16)530 768 Q EP +%%Page: 17 17 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(the Control k)108 84 Q .3 -.15(ey w)-.1 H(hile pressing the).15 E/F1 10 +/Times-Italic@0 SF(x)2.5 E F0 -.1(ke)2.5 G -.65(y.)-.05 G(\)).65 E 1.125 +(The def)108 100.8 R 1.126(ault k)-.1 F -.15(ey)-.1 G 1.126 +(-bindings may be changed with an).15 F F1(~/.inputr)5.292 E(c)-.37 E F0 3.626 +(\214le. The)5.292 F -.25(va)3.626 G 1.126(lue of the shell v).25 F(ariable) +-.25 E/F2 9/Times-Bold@0 SF(INPU-)3.626 E(TRC)108 112.8 Q/F3 9/Times-Roman@0 SF +(,)A F0 .106(if set, is used instead of)2.357 F F1(~/.inputr)2.606 E(c)-.37 E +F0 5.106(.O).31 G .106(ther programs that use this library may add their o) +280.89 112.8 R .106(wn commands)-.25 F(and bindings.)108 124.8 Q -.15(Fo)108 +141.6 S 2.5(re).15 G(xample, placing)128.53 141.6 Q(M\255Control\255u: uni)144 +158.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(or)108 170.4 Q +(C\255Meta\255u: uni)144 182.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E +(into the)108 194.4 Q F1(~/.inputr)4.166 E(c)-.37 E F0 -.1(wo)4.166 G(uld mak) +.1 E 2.5(eM)-.1 G(\255C\255u e)244.092 194.4 Q -.15(xe)-.15 G +(cute the readline command).15 E F1(univer)2.5 E(sal\255ar)-.1 E(gument)-.37 E +F0(.).68 E 1.26(The follo)108 211.2 R 1.261 +(wing symbolic character names are recognized:)-.25 F F1 -.4(RU)3.761 G(BOUT).4 +E F0(,)1.27 E F1(DEL)3.761 E F0(,).53 E F1(ESC)3.761 E F0(,).72 E F1(LFD)3.761 +E F0(,).28 E F1(NEWLINE)3.761 E F0(,).73 E F1(RET)3.761 E F0(,)1.27 E F1 +(RETURN)108 223.2 Q F0(,)1.1 E F1(SPC)3.155 E F0(,).72 E F1(SP)3.155 E -.3(AC) +-.9 G(E).3 E F0 3.155(,a).73 G(nd)216.315 223.2 Q F1 -.5(TA)3.155 G(B).5 E F0 +5.655(.I).27 G 3.155(na)258.505 223.2 S .655 +(ddition to command names, readline allo)271.1 223.2 R .655(ws k)-.25 F -.15 +(ey)-.1 G 3.154(st).15 G 3.154(ob)475.724 223.2 S 3.154(eb)488.878 223.2 S .654 +(ound to a)501.472 223.2 R(string that is inserted when the k)108 235.2 Q .3 +-.15(ey i)-.1 H 2.5(sp).15 G(ressed \(a)263.85 235.2 Q F1(macr)2.5 E(o)-.45 E +F0(\).)A .827 +(Readline is customized by putting commands in an initialization \214le.)108 +252 R .827(The name of this \214le is tak)5.827 F .828(en from)-.1 F 1.325 +(the v)108 264 R 1.325(alue of the)-.25 F F2(INPUTRC)3.825 E F0 -.25(va)3.575 G +3.825(riable. If).25 F 1.324(that v)3.825 F 1.324(ariable is unset, the def) +-.25 F 1.324(ault is)-.1 F F1(~/.inputr)3.824 E(c)-.37 E F0 6.324(.W).31 G +1.324(hen a program)479.592 264 R 1.158 +(which uses the readline library starts up, the init \214le is read, and the k) +108 276 R 1.459 -.15(ey b)-.1 H 1.159(indings and v).15 F 1.159 +(ariables are set.)-.25 F .029(There are only a fe)108 288 R 2.529(wb)-.25 G +.029(asic constructs allo)198.135 288 R .028(wed in the readline init \214le.) +-.25 F .028(Blank lines are ignored.)5.028 F .028(Lines be)5.028 F(gin-)-.15 E +.553(ning with a)108 300 R/F4 10/Times-Bold@0 SF(#)3.053 E F0 .554 +(are comments.)3.053 F .554(Lines be)5.554 F .554(ginning with a)-.15 F F4($) +3.054 E F0 .554(indicate conditional constructs.)3.054 F .554 +(Other lines denote)5.554 F -.1(ke)108 312 S 2.5(yb)-.05 G(indings and v)129.69 +312 Q(ariable settings.)-.25 E .724(The syntax for controlling k)108 328.8 R +1.024 -.15(ey b)-.1 H .724(indings in the).15 F F1(~/.inputr)3.224 E(c)-.37 E +F0 .724(\214le is simple.)3.224 F .723(All that is required is the name of) +5.724 F .938(the command or the te)108 340.8 R .938(xt of a macro and a k)-.15 +F 1.238 -.15(ey s)-.1 H .938 +(equence to which it should be bound. The name may be).15 F .168 +(speci\214ed in one of tw)108 352.8 R 2.668(ow)-.1 G .168(ays: as a symbolic k) +209.46 352.8 R .468 -.15(ey n)-.1 H .167(ame, possibly with).15 F F1(Meta-) +2.667 E F0(or)2.667 E F1(Contr)2.667 E(ol-)-.45 E F0(pre\214x)2.667 E .167 +(es, or as a k)-.15 F -.15(ey)-.1 G 3.2(sequence. When)108 364.8 R .7 +(using the form)3.2 F F4 -.1(ke)3.2 G(yname).1 E F0(:)A F1(function-name)A F0 +(or)3.201 E F1(macr)3.201 E(o)-.45 E F0(,)A F1 -.1(ke)3.201 G(yname)-.2 E F0 +.701(is the name of a k)3.201 F 1.001 -.15(ey s)-.1 H(pelled).15 E +(out in English.)108 376.8 Q -.15(Fo)5 G 2.5(re).15 G(xample:)192.15 376.8 Q +(Control-u: uni)144 400.8 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E +(Meta-Rubout: backw)144 412.8 Q(ard-kill-w)-.1 E(ord)-.1 E +(Control-o: ">&output")144 424.8 Q .443(In the abo)108 441.6 R .743 -.15(ve ex) +-.15 H(ample,).15 E F1(C-u)2.943 E F0 .443(is bound to the function)2.943 F F4 +(uni)2.942 E -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0(,)A F1(M-DEL)2.942 E +F0 .442(is bound to the function)2.942 F F4(backward\255kill\255w)108 453.6 Q +(ord)-.1 E F0 2.579(,a)C(nd)207.719 453.6 Q F1(C-o)2.579 E F0 .079 +(is bound to run the macro e)2.579 F .08 +(xpressed on the right hand side \(that is, to insert)-.15 F(the te)108 465.6 Q +(xt)-.15 E F1(>&output)2.5 E F0(into the line\).)2.5 E .36(In the second form,) +108 482.4 R F4("k)2.86 E(eyseq")-.1 E F0(:)A F1(function-name)A F0(or)2.859 E +F1(macr)2.859 E(o)-.45 E F0(,)A F4 -.1(ke)2.859 G(yseq).1 E F0(dif)2.859 E .359 +(fers from)-.25 F F4 -.1(ke)2.859 G(yname).1 E F0(abo)2.859 E .659 -.15(ve i) +-.15 H 2.859(nt).15 G .359(hat strings)498.251 482.4 R 1.284 +(denoting an entire k)108 494.4 R 1.584 -.15(ey s)-.1 H 1.284 +(equence may be speci\214ed by placing the sequence within double quotes.).15 F +(Some)6.284 E(GNU Emacs style k)108 506.4 Q .3 -.15(ey e)-.1 H +(scapes can be used, as in the follo).15 E(wing e)-.25 E(xample.)-.15 E +("\\C-u": uni)144 530.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E +("\\C-x\\C-r": re\255read\255init\255\214le)144 542.4 Q("\\e[11~": "Function K) +144 554.4 Q .3 -.15(ey 1)-.25 H(").15 E .238(In this e)108 571.2 R(xample,)-.15 +E F1(C-u)2.738 E F0 .238(is ag)2.738 F .238(ain bound to the function)-.05 F F4 +(uni)2.738 E -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0(.)A F1 .237(C-x C-r) +5.238 F F0 .237(is bound to the function)2.737 F F4 -.18(re)108 583.2 S +.18 E(ead\255init\255\214le)-.18 E F0 3.909(,a)C(nd)191.139 583.2 Q F1 1.409 +(ESC [ 1 1 ~)3.909 F F0 1.409(is bound to insert the te)3.909 F(xt)-.15 E F4 +1.41(Function K)3.91 F 1.41(ey 1)-.25 F F0 6.41(.T)C 1.41 +(he full set of escape)454.94 583.2 R(sequences is)108 595.2 Q F4<5c43ad>144 +612 Q F0(control pre\214x)180 612 Q F4(\\M-)144 628.8 Q F0(meta pre\214x)180 +628.8 Q F4(\\e)144 645.6 Q F0(an escape character)180 645.6 Q F4(\\\\)144 662.4 +Q F0(backslash)180 662.4 Q F4(\\")144 679.2 Q F0(literal ")180 679.2 Q F4(\\') +144 696 Q F0(literal ')180 696 Q .74(When entering the te)108 712.8 R .74(xt o\ +f a macro, single or double quotes should be used to indicate a macro de\214ni\ +tion.)-.15 F 1.226(Unquoted te)108 724.8 R 1.226 +(xt is assumed to be a function name.)-.15 F 1.227(Backslash will quote an) +6.226 F 3.727(yc)-.15 G 1.227(haracter in the macro te)430.552 724.8 R(xt,)-.15 +E 185.675(GNU 1995)72 768 R(May 5)2.5 E(17)530 768 Q EP +%%Page: 18 18 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(including " and '.)108 84 Q/F1 10/Times-Bold@0 SF(Bash)108 100.8 Q F0(allo) +2.93 E .43(ws the current readline k)-.25 F .73 -.15(ey b)-.1 H .429 +(indings to be displayed or modi\214ed with the).15 F F1(bind)2.929 E F0 -.2 +(bu)2.929 G .429(iltin command.).2 F .045 +(The editing mode may be switched during interacti)108 112.8 R .345 -.15(ve u) +-.25 H .046(se by using the).15 F F12.546 E F0 .046(option to the)2.546 F +F1(set)2.546 E F0 -.2(bu)2.546 G .046(iltin command).2 F(\(see)108 124.8 Q/F2 9 +/Times-Bold@0 SF(SHELL B)2.5 E(UIL)-.09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E +(w\).)-.25 E .044(Readline has v)108 141.6 R .044 +(ariables that can be used to further customize its beha)-.25 F(vior)-.2 E +5.044(.A)-.55 G -.25(va)413.902 141.6 S .043(riable may be set in the).25 F/F3 +10/Times-Italic@0 SF(inpu-)2.543 E(tr)108 153.6 Q(c)-.37 E F0 +(\214le with a statement of the form)2.5 E F1(set)144 170.4 Q F3 +(variable\255name value)2.5 E F0 .488(Except where noted, readline v)108 187.2 +R .489(ariables can tak)-.25 F 2.989(et)-.1 G .489(he v)307.12 187.2 R(alues) +-.25 E F1(On)2.989 E F0(or)2.989 E F1(Off)2.989 E F0 5.489(.T)C .489(he v) +404.025 187.2 R .489(ariables and their def)-.25 F .489(ault v)-.1 F(al-)-.25 E +(ues are:)108 199.2 Q F1(horizontal\255scr)108 216 Q(oll\255mode \(Off\))-.18 E +F0 .449(When set to)144 228 R F1(On)2.949 E F0 2.949(,m)C(ak)222.186 228 Q .448 +(es readline use a single line for display)-.1 F 2.948(,s)-.65 G .448 +(crolling the input horizontally on a)398.6 228 R 1.194(single screen line whe\ +n it becomes longer than the screen width rather than wrapping to a ne)144 240 +R(w)-.25 E(line.)144 252 Q F1(editing\255mode \(emacs\))108 264 Q F0 .253 +(Controls whether readline be)144 276 R .253(gins with a set of k)-.15 F .553 +-.15(ey b)-.1 H .253(indings similar to).15 F F3(emacs)2.752 E F0(or)2.752 E F3 +(vi)2.752 E F0(.)A F1(editing\255mode)5.252 E F0(can be set to either)144 288 Q +F1(emacs)2.5 E F0(or)2.5 E F1(vi)2.5 E F0(.)A F1 +(mark\255modi\214ed\255lines \(Off\))108 300 Q F0(If set to)144 312 Q F1(On)2.5 +E F0 2.5(,h)C(istory lines that ha)200.39 312 Q .3 -.15(ve b)-.2 H +(een modi\214ed are displayed with a preceding asterisk \().15 E F1(*)A F0(\).) +A F1(bell\255style \(audible\))108 324 Q F0 .01 +(Controls what happens when readline w)144 336 R .011 +(ants to ring the terminal bell.)-.1 F .011(If set to)5.011 F F1(none)2.511 E +F0 2.511(,r)C .011(eadline ne)486.799 336 R -.15(ve)-.25 G(r).15 E .94 +(rings the bell.)144 348 R .94(If set to)5.94 F F1(visible)3.44 E F0 3.44(,r)C +.94(eadline uses a visible bell if one is a)278.91 348 R -.25(va)-.2 G 3.44 +(ilable. If).25 F .94(set to)3.44 F F1(audible)3.44 E F0(,)A +(readline attempts to ring the terminal')144 360 Q 2.5(sb)-.55 G(ell.)306.21 +360 Q F1(comment\255begin \(`)108 372 Q(`#')-.63 E('\))-.63 E F0 +(The string that is inserted in)144 384 Q F1(vi)2.5 E F0(mode when the)2.5 E F1 +(vi\255comment)2.5 E F0(command is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 +(meta\255\215ag \(Off\))108 396 Q F0 .227(If set to)144 408 R F1(On)2.727 E F0 +2.727(,r)C .228(eadline will enable eight-bit input \(that is, it will not str\ +ip the high bit from the char)199.628 408 R(-)-.2 E(acters it reads\), re)144 +420 Q -.05(ga)-.15 G(rdless of what the terminal claims it can support.).05 E +F1(con)108 432 Q -.1(ve)-.4 G(rt\255meta \(On\)).1 E F0 .613(If set to)144 444 +R F1(On)3.113 E F0 3.113(,r)C .613(eadline will con)201.172 444 R -.15(ve)-.4 G +.613(rt characters with the eighth bit set to an ASCII k).15 F .912 -.15(ey s) +-.1 H .612(equence by).15 F 1.238 +(stripping the eighth bit and prepending an escape character \(in ef)144 456 R +1.238(fect, using escape as the)-.25 F F3(meta)3.738 E(pr)144 468 Q(e\214x)-.37 +E F0(\).)A F1(output\255meta \(Off\))108 480 Q F0 .507(If set to)144 492 R F1 +(On)3.007 E F0 3.007(,r)C .507(eadline will display characters with the eighth\ + bit set directly rather than as a meta-)200.748 492 R(pre\214x)144 504 Q +(ed escape sequence.)-.15 E F1(completion\255query\255items \(100\))108 516 Q +F0 .529(This determines when the user is queried about vie)144 528 R .53 +(wing the number of possible completions gen-)-.25 F .561(erated by the)144 540 +R F1(possible\255completions)3.061 E F0 3.061(command. It)3.061 F .561 +(may be set to an)3.061 F 3.06(yi)-.15 G(nte)428.2 540 Q .56(ger v)-.15 F .56 +(alue greater than or)-.25 F .782(equal to zero.)144 552 R .783 +(If the number of possible completions is greater than or equal to the v)5.782 +F .783(alue of this)-.25 F -.25(va)144 564 S .237(riable, the user is ask).25 F +.237(ed whether or not he wishes to vie)-.1 F 2.737(wt)-.25 G .237 +(hem; otherwise the)389.255 564 R 2.737(ya)-.15 G .237(re simply listed)477.856 +564 R(on the terminal.)144 576 Q F1 -.1(ke)108 588 S(ymap \(emacs\)).1 E F0 +2.323(Set the current readline k)144 600 R -.15(ey)-.1 G 4.823(map. The).15 F +2.323(set of le)4.823 F -.05(ga)-.15 G 4.823(lk).05 G -.15(ey)368.477 600 S +2.323(map names is).15 F F3 2.324(emacs, emacs-standar)4.823 F(d,)-.37 E .809 +(emacs-meta, emacs-ctlx, vi, vi-mo)144 612 R(ve)-.1 E 3.308(,v)-.1 G(i-command) +300.864 612 Q F0 3.308(,a)C(nd)356.102 612 Q F3(vi-insert)3.308 E F0(.).68 E F3 +(vi)5.808 E F0 .808(is equi)3.308 F -.25(va)-.25 G .808(lent to).25 F F3 +(vi-command)3.308 E F0(;)A F3(emacs)144 624 Q F0 1.123(is equi)3.623 F -.25(va) +-.25 G 1.124(lent to).25 F F3(emacs-standar)3.624 E(d)-.37 E F0 6.124(.T)C +1.124(he def)317.338 624 R 1.124(ault v)-.1 F 1.124(alue is)-.25 F F3(emacs) +3.624 E F0 3.624(;t).27 G 1.124(he v)431.468 624 R 1.124(alue of)-.25 F F1 +(editing\255mode)3.624 E F0(also af)144 636 Q(fects the def)-.25 E(ault k)-.1 E +-.15(ey)-.1 G(map.).15 E F1(sho)108 648 Q(w\255all\255if\255ambiguous \(Off\)) +-.1 E F0 .478(This alters the def)144 660 R .478(ault beha)-.1 F .478 +(vior of the completion functions.)-.2 F .477(If set to)5.477 F F1(on)2.977 E +F0 2.977(,w)C .477(ords which ha)450.329 660 R .777 -.15(ve m)-.2 H(ore).15 E +1.264(than one possible completion cause the matches to be listed immediately \ +instead of ringing the)144 672 R(bell.)144 684 Q F1(expand\255tilde \(Off\))108 +696 Q F0(If set to)144 708 Q F1(on)2.5 E F0 2.5(,t)C(ilde e)195.39 708 Q +(xpansion is performed when readline attempts w)-.15 E(ord completion.)-.1 E +.05(Readline implements a f)108 724.8 R .05(acility similar in spirit to the c\ +onditional compilation features of the C preprocessor)-.1 F 185.675(GNU 1995)72 +768 R(May 5)2.5 E(18)530 768 Q EP +%%Page: 19 19 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +1.49(which allo)108 84 R 1.49(ws k)-.25 F 1.79 -.15(ey b)-.1 H 1.49 +(indings and v).15 F 1.49 +(ariable settings to be performed as the result of tests.)-.25 F 1.49 +(There are three)6.49 F(parser directi)108 96 Q -.15(ve)-.25 G 2.5(su).15 G +(sed.)180.91 96 Q/F1 10/Times-Bold@0 SF($if)108 112.8 Q F0(The)144 112.8 Q F1 +($if)2.963 E F0 .463(construct allo)2.963 F .462 +(ws bindings to be made based on the editing mode, the terminal being used,) +-.25 F .477(or the application using readline.)144 124.8 R .477(The te)5.477 F +.477(xt of the test e)-.15 F .477(xtends to the end of the line; no characters) +-.15 F(are required to isolate it.)144 136.8 Q F1(mode)144 153.6 Q F0(The)180 +153.6 Q F1(mode=)3.712 E F0 1.212(form of the)3.712 F F1($if)3.711 E F0 +(directi)3.711 E 1.511 -.15(ve i)-.25 H 3.711(su).15 G 1.211 +(sed to test whether readline is in emacs or vi)351.631 153.6 R 3.065 +(mode. This)180 165.6 R .565(may be used in conjunction with the)3.065 F F1 +.565(set k)3.065 F(eymap)-.1 E F0 .565(command, for instance, to)3.065 F .03 +(set bindings in the)180 177.6 R/F2 10/Times-Italic@0 SF(emacs-standar)2.529 E +(d)-.37 E F0(and)2.529 E F2(emacs-ctlx)2.529 E F0 -.1(ke)2.529 G .029 +(ymaps only if readline is starting out)-.05 F(in emacs mode.)180 189.6 Q F1 +(term)144 206.4 Q F0(The)180 206.4 Q F1(term=)3.196 E F0 .696 +(form may be used to include terminal-speci\214c k)3.196 F .996 -.15(ey b)-.1 H +.697(indings, perhaps to bind).15 F .654(the k)180 218.4 R .954 -.15(ey s)-.1 H +.654(equences output by the terminal').15 F 3.154(sf)-.55 G .654(unction k) +360.138 218.4 R -.15(ey)-.1 G 3.154(s. The).15 F -.1(wo)3.154 G .654 +(rd on the right side of).1 F(the)180 230.4 Q F1(=)3.003 E F0 .503 +(is tested ag)3.003 F .504 +(ainst the full name of the terminal and the portion of the terminal name)-.05 +F(before the \214rst)180 242.4 Q F12.5 E F0 5(.T)C(his allo)260.13 242.4 Q +(ws)-.25 E F2(sun)2.5 E F0(to match both)2.5 E F2(sun)2.5 E F0(and)2.5 E F2 +(sun\255cmd)2.5 E F0 2.5(,f).77 G(or instance.)456.28 242.4 Q F1(application) +144 259.2 Q F0(The)180 271.2 Q F1(application)2.772 E F0 .272 +(construct is used to include application\255speci\214c settings.)2.772 F .272 +(Each program)5.272 F .114(using the readline library sets the)180 283.2 R F2 +.114(application name)2.614 F F0 2.614(,a)C .114 +(nd an initialization \214le can test for a)395.052 283.2 R .501(particular v) +180 295.2 R 3.001(alue. This)-.25 F .501(could be used to bind k)3.001 F .801 +-.15(ey s)-.1 H .5(equences to functions useful for a spe-).15 F .396 +(ci\214c program.)180 307.2 R -.15(Fo)5.396 G 2.896(ri).15 G .396 +(nstance, the follo)261.308 307.2 R .396(wing command adds a k)-.25 F .696 -.15 +(ey s)-.1 H .397(equence that quotes the).15 F(current or pre)180 319.2 Q +(vious w)-.25 E(ord in Bash:)-.1 E F1($if)180 331.2 Q F0(Bash)2.5 E 2.5(#Q)180 +343.2 S(uote the current or pre)194.72 343.2 Q(vious w)-.25 E(ord)-.1 E +("\\C-xq": "\\eb\\"\\ef\\"")180 355.2 Q F1($endif)180 367.2 Q($endif)108 384 Q +F0(This command, as you sa)9.33 E 2.5(wi)-.15 G 2.5(nt)257.73 384 S(he pre) +268.01 384 Q(vious e)-.25 E(xample, terminates an)-.15 E F1($if)2.5 E F0 +(command.)2.5 E F1($else)108 400.8 Q F0(Commands in this branch of the)144 +400.8 Q F1($if)2.5 E F0(directi)2.5 E .3 -.15(ve a)-.25 H(re e).15 E -.15(xe) +-.15 G(cuted if the test f).15 E(ails.)-.1 E .62(Readline commands may be gi) +108 417.6 R -.15(ve)-.25 G 3.119(nn).15 G(umeric)255.959 417.6 Q F2(ar)3.119 E +(guments)-.37 E F0 3.119(,w).27 G .619(hich normally act as a repeat count.) +341.807 417.6 R(Sometimes,)5.619 E(ho)108 429.6 Q(we)-.25 E -.15(ve)-.25 G +1.418 -.4(r, i).15 H 3.118(ti).4 G 3.119(st)158.456 429.6 S .619 +(he sign of the ar)168.245 429.6 R .619(gument that is signi\214cant.)-.18 F +-.15(Pa)5.619 G .619(ssing a ne).15 F -.05(ga)-.15 G(ti).05 E .919 -.15(ve a) +-.25 H -.18(rg).15 G .619(ument to a command that).18 F 1.019(acts in the forw) +108 441.6 R 1.018(ard direction \(e.g.,)-.1 F F1(kill\255line)3.518 E F0 3.518 +(\)c)C 1.018(auses that command to act in a backw)298.478 441.6 R 1.018 +(ard direction.)-.1 F(Com-)6.018 E(mands whose beha)108 453.6 Q(vior with ar) +-.2 E(guments de)-.18 E(viates from this are noted.)-.25 E .811 +(When a command is described as)108 470.4 R F2(killing)3.311 E F0(te)3.311 E +.811(xt, the te)-.15 F .811(xt deleted is sa)-.15 F -.15(ve)-.2 G 3.311(df).15 +G .812(or possible future retrie)403.403 470.4 R -.25(va)-.25 G 3.312(l\().25 G +F2(yank-)517.79 470.4 Q(ing)108 482.4 Q F0 3.439(\). The)B .939(killed te)3.439 +F .939(xt is sa)-.15 F -.15(ve)-.2 G 3.439(di).15 G 3.438(na)234.794 482.4 S F2 +(kill\255ring)A F0 5.938(.C)C(onsecuti)302.418 482.4 Q 1.238 -.15(ve k)-.25 H +.938(ills cause the te).15 F .938(xt to be accumulated into one)-.15 F .331 +(unit, which can be yank)108 494.4 R .331(ed all at once.)-.1 F .331 +(Commands which do not kill te)5.331 F .331(xt separate the chunks of te)-.15 F +.331(xt on the)-.15 F(kill\255ring.)108 506.4 Q 1.392(The follo)108 523.2 R +1.391(wing is a list of the names of the commands and the def)-.25 F 1.391 +(ault k)-.1 F 1.691 -.15(ey s)-.1 H 1.391(equences to which the).15 F 3.891(ya) +-.15 G(re)532.23 523.2 Q(bound.)108 535.2 Q F1(Commands f)87 552 Q(or Mo)-.25 E +(ving)-.1 E(beginning\255of\255line \(C\255a\))108 564 Q F0(Mo)144 576 Q .3 +-.15(ve t)-.15 H 2.5(ot).15 G(he start of the current line.)182.59 576 Q F1 +(end\255of\255line \(C\255e\))108 588 Q F0(Mo)144 600 Q .3 -.15(ve t)-.15 H 2.5 +(ot).15 G(he end of the line.)182.59 600 Q F1 -.25(fo)108 612 S +(rward\255char \(C\255f\)).25 E F0(Mo)144 624 Q .3 -.15(ve f)-.15 H(orw).15 E +(ard a character)-.1 E(.)-.55 E F1(backward\255char \(C\255b\))108 636 Q F0(Mo) +144 648 Q .3 -.15(ve b)-.15 H(ack a character).15 E(.)-.55 E F1 -.25(fo)108 660 +S(rward\255w).25 E(ord \(M\255f\))-.1 E F0(Mo)144 672 Q .822 -.15(ve f)-.15 H +(orw).15 E .522(ard to the end of the ne)-.1 F .523(xt w)-.15 F 3.023(ord. W) +-.1 F .523(ords are composed of alphanumeric characters \(let-)-.8 F +(ters and digits\).)144 684 Q F1(backward\255w)108 696 Q(ord \(M\255b\))-.1 E +F0(Mo)144 708 Q .749 -.15(ve b)-.15 H .449 +(ack to the start of this, or the pre).15 F .449(vious, w)-.25 F 2.949(ord. W) +-.1 F .448(ords are composed of alphanumeric char)-.8 F(-)-.2 E +(acters \(letters and digits\).)144 720 Q 185.675(GNU 1995)72 768 R(May 5)2.5 E +(19)530 768 Q EP +%%Page: 20 20 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(clear\255scr)108 84 Q(een \(C\255l\))-.18 E F0 .993 +(Clear the screen lea)144 96 R .993 +(ving the current line at the top of the screen.)-.2 F -.4(Wi)5.993 G .993 +(th an ar).4 F .993(gument, refresh the)-.18 F +(current line without clearing the screen.)144 108 Q F1 -.18(re)108 120 S +(draw\255curr).18 E(ent\255line)-.18 E F0(Refresh the current line.)144 132 Q +(By def)5 E(ault, this is unbound.)-.1 E F1(Commands f)87 148.8 Q +(or Manipulating the History)-.25 E(accept\255line \(Newline, Retur)108 160.8 Q +(n\))-.15 E F0 .037(Accept the line re)144 172.8 R -.05(ga)-.15 G .037 +(rdless of where the cursor is.).05 F .037(If this line is non\255empty)5.037 F +2.537(,a)-.65 G .036(dd it to the history list)451.748 172.8 R .699 +(according to the state of the)144 184.8 R/F2 9/Times-Bold@0 SF(HISTCONTR)3.199 +E(OL)-.27 E F0 -.25(va)2.949 G 3.199(riable. If).25 F .699 +(the line is a modi\214ed history line, then)3.199 F +(restore the history line to its original state.)144 196.8 Q F1(pr)108 208.8 Q +-.15(ev)-.18 G(ious\255history \(C\255p\)).15 E F0(Fetch the pre)144 220.8 Q +(vious command from the history list, mo)-.25 E(ving back in the list.)-.15 E +F1(next\255history \(C\255n\))108 232.8 Q F0(Fetch the ne)144 244.8 Q +(xt command from the history list, mo)-.15 E(ving forw)-.15 E(ard in the list.) +-.1 E F1(beginning\255of\255history \(M\255<\))108 256.8 Q F0(Mo)144 268.8 Q .3 +-.15(ve t)-.15 H 2.5(ot).15 G(he \214rst line in the history)182.59 268.8 Q(.) +-.65 E F1(end\255of\255history \(M\255>\))108 280.8 Q F0(Mo)144 292.8 Q .3 -.15 +(ve t)-.15 H 2.5(ot).15 G(he end of the input history)182.59 292.8 Q 2.5(,i) +-.65 G(.e., the line currently being entered.)294.99 292.8 Q F1 -2.29 -.18 +(re v)108 304.8 T(erse\255sear).08 E(ch\255history \(C\255r\))-.18 E F0 1.471 +(Search backw)144 316.8 R 1.471(ard starting at the current line and mo)-.1 F +1.47(ving `up' through the history as necessary)-.15 F(.)-.65 E +(This is an incremental search.)144 328.8 Q F1 -.25(fo)108 340.8 S +(rward\255sear).25 E(ch\255history \(C\255s\))-.18 E F0 1.131(Search forw)144 +352.8 R 1.131(ard starting at the current line and mo)-.1 F 1.132(ving `do)-.15 +F 1.132(wn' through the history as necessary)-.25 F(.)-.65 E +(This is an incremental search.)144 364.8 Q F1(non\255incr)108 376.8 Q +(emental\255r)-.18 E -2.3 -.15(ev e)-.18 H(rse\255sear).15 E +(ch\255history \(M\255p\))-.18 E F0 1.089(Search backw)144 388.8 R 1.088(ard t\ +hrough the history starting at the current line using a non\255incremental sea\ +rch)-.1 F(for a string supplied by the user)144 400.8 Q(.)-.55 E F1 +(non\255incr)108 412.8 Q(emental\255f)-.18 E(orward\255sear)-.25 E +(ch\255history \(M\255n\))-.18 E F0 1.188(Search forw)144 424.8 R 1.189(ard th\ +rough the history using a non\255incremental search for a string supplied by t\ +he)-.1 F(user)144 436.8 Q(.)-.55 E F1(history\255sear)108 448.8 Q(ch\255f)-.18 +E(orward)-.25 E F0 .249(Search forw)144 460.8 R .249(ard through the history f\ +or the string of characters between the start of the current line)-.1 F +(and the current point.)144 472.8 Q(This is a non-incremental search.)5 E +(By def)5 E(ault, this command is unbound.)-.1 E F1(history\255sear)108 484.8 Q +(ch\255backward)-.18 E F0 .95(Search backw)144 496.8 R .951(ard through the hi\ +story for the string of characters between the start of the current)-.1 F 2.721 +(line and the current point.)144 508.8 R 2.721 +(This is a non-incremental search.)7.721 F 2.72(By def)7.721 F 2.72 +(ault, this command is)-.1 F(unbound.)144 520.8 Q F1(yank\255nth\255ar)108 +532.8 Q 2.5(g\()-.1 G<4dad43ad7929>175.14 532.8 Q F0 .622 +(Insert the \214rst ar)144 544.8 R .622(gument to the pre)-.18 F .622 +(vious command \(usually the second w)-.25 F .622(ord on the pre)-.1 F .622 +(vious line\))-.25 F .682(at point \(the current cursor position\).)144 556.8 R +-.4(Wi)5.682 G .682(th an ar).4 F(gument)-.18 E/F3 10/Times-Italic@0 SF(n)3.182 +E F0 3.182(,i).24 G .682(nsert the)390.17 556.8 R F3(n)3.182 E F0 .682(th w)B +.681(ord from the pre)-.1 F(vious)-.25 E .729(command \(the w)144 568.8 R .729 +(ords in the pre)-.1 F .729(vious command be)-.25 F .729(gin with w)-.15 F .729 +(ord 0\).)-.1 F 3.23(An)5.73 G -2.25 -.15(eg a)441.56 568.8 T(ti).15 E 1.03 +-.15(ve a)-.25 H -.18(rg).15 G .73(ument inserts).18 F(the)144 580.8 Q F3(n)2.5 +E F0(th w)A(ord from the end of the pre)-.1 E(vious command.)-.25 E F1 +(yank\255last\255ar)108 592.8 Q 2.5(g\()-.1 G -1.667(M\255. ,)175.69 592.8 R +-1.667(M\255_ \))2.5 F F0 1.077(Insert the last ar)144 604.8 R 1.077 +(gument to the pre)-.18 F 1.077(vious command \(the last w)-.25 F 1.077 +(ord on the pre)-.1 F 1.077(vious line\).)-.25 F -.4(Wi)6.076 G 1.076(th an).4 +F(ar)144 616.8 Q(gument, beha)-.18 E .3 -.15(ve ex)-.2 H(actly lik).15 E(e)-.1 +E F1(yank-nth-ar)2.5 E(g)-.1 E F0(.)A F1 +(shell\255expand\255line \(M\255C\255e\))108 628.8 Q F0 .223 +(Expand the line the w)144 640.8 R .223(ay the shell does when it reads it.)-.1 +F .224(This performs alias and history e)5.224 F(xpansion)-.15 E .161 +(as well as all of the shell w)144 652.8 R .161(ord e)-.1 F 2.661 +(xpansions. See)-.15 F F2(HIST)2.661 E(OR)-.162 E 2.411(YE)-.315 G(XP)387.555 +652.8 Q(ANSION)-.666 E F0(belo)2.411 E 2.661(wf)-.25 G .16(or a description of) +466.479 652.8 R(history e)144 664.8 Q(xpansion.)-.15 E F1 +(history\255expand\255line \(M\255^\))108 676.8 Q F0 .938(Perform history e)144 +688.8 R .939(xpansion on the current line.)-.15 F(See)5.939 E F2(HIST)3.439 E +(OR)-.162 E 3.189(YE)-.315 G(XP)407.662 688.8 Q(ANSION)-.666 E F0(belo)3.189 E +3.439(wf)-.25 G .939(or a descrip-)488.142 688.8 R(tion of history e)144 700.8 +Q(xpansion.)-.15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(20)530 768 Q EP +%%Page: 21 21 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(insert\255last\255ar)108 84 Q(gument \(M\255.)-.1 E 2.5 +(,M).833 G -1.667(\255_ \))239.143 84 R F0 2.5(As)144 96 S(ynon)157.61 96 Q +(ym for)-.15 E F1(yank\255last\255ar)2.5 E(g)-.1 E F0(.)A F1 +(operate-and-get-next \(C\255o\))108 108 Q F0 .948 +(Accept the current line for e)144 120 R -.15(xe)-.15 G .948 +(cution and fetch the ne).15 F .948(xt line relati)-.15 F 1.247 -.15(ve t)-.25 +H 3.447(ot).15 G .947(he current line from the)441.792 120 R +(history for editing.)144 132 Q(An)5 E 2.5(ya)-.15 G -.18(rg)247.73 132 S +(ument is ignored.).18 E F1(Commands f)87 148.8 Q(or Changing T)-.25 E(ext)-.92 +E(delete\255char \(C\255d\))108 160.8 Q F0 .486 +(Delete the character under the cursor)144 172.8 R 5.486(.I)-.55 G 2.987(fp) +304.636 172.8 S .487(oint is at the be)315.953 172.8 R .487 +(ginning of the line, there are no charac-)-.15 F +(ters in the line, and the last character typed w)144 184.8 Q(as not)-.1 E F1 +(C\255d)2.5 E F0 2.5(,t)C(hen return)377.34 184.8 Q/F2 9/Times-Bold@0 SF(EOF) +2.5 E/F3 9/Times-Roman@0 SF(.)A F1(backward\255delete\255char \(Rubout\))108 +196.8 Q F0 .553(Delete the character behind the cursor)144 208.8 R 5.553(.W) +-.55 G .553(hen gi)315.598 208.8 R -.15(ve)-.25 G 3.053(nan).15 G .553 +(umeric ar)370.457 208.8 R .552(gument, sa)-.18 F .852 -.15(ve t)-.2 H .552 +(he deleted te).15 F .552(xt on)-.15 F(the kill\255ring.)144 220.8 Q F1 +(quoted\255insert \(C\255q, C\255v\))108 232.8 Q F0 1.228(Add the ne)144 244.8 +R 1.228(xt character that you type to the line v)-.15 F 3.728(erbatim. This) +-.15 F 1.228(is ho)3.728 F 3.729(wt)-.25 G 3.729(oi)446.163 244.8 S 1.229 +(nsert characters lik)457.672 244.8 R(e)-.1 E F1(C\255q)144 256.8 Q F0 2.5(,f)C +(or e)170.81 256.8 Q(xample.)-.15 E F1(tab\255insert \(C-v T)108 268.8 Q(AB\)) +-.9 E F0(Insert a tab character)144 280.8 Q(.)-.55 E F1 +(self\255insert \(a, b, A, 1, !, ...\))108 292.8 Q F0 +(Insert the character typed.)144 304.8 Q F1(transpose\255chars \(C\255t\))108 +316.8 Q F0 .424(Drag the character before point forw)144 328.8 R .424(ard o)-.1 +F -.15(ve)-.15 G 2.924(rt).15 G .424(he character at point.)331.218 328.8 R +.424(Point mo)5.424 F -.15(ve)-.15 G 2.924(sf).15 G(orw)477.882 328.8 Q .424 +(ard as well.)-.1 F 1.03 +(If point is at the end of the line, then transpose the tw)144 340.8 R 3.531 +(oc)-.1 G 1.031(haracters before point.)382.266 340.8 R(Ne)6.031 E -.05(ga)-.15 +G(ti).05 E 1.331 -.15(ve a)-.25 H -.18(rg).15 G(u-).18 E(ments don')144 352.8 Q +2.5(tw)-.18 G(ork.)200.94 352.8 Q F1(transpose\255w)108 364.8 Q +(ords \(M\255t\))-.1 E F0 .683(Drag the w)144 376.8 R .682 +(ord behind the cursor past the w)-.1 F .682(ord in front of the cursor mo)-.1 +F .682(ving the cursor o)-.15 F -.15(ve)-.15 G 3.182(rt).15 G(hat)527.78 376.8 +Q -.1(wo)144 388.8 S(rd as well.).1 E F1(upcase\255w)108 400.8 Q +(ord \(M\255u\))-.1 E F0 .702(Uppercase the current \(or follo)144 412.8 R .702 +(wing\) w)-.25 F 3.202(ord. W)-.1 F .702(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E +1.002 -.15(ve a)-.25 H -.18(rg).15 G .702(ument, do the pre).18 F .703(vious w) +-.25 F .703(ord, b)-.1 F(ut)-.2 E(do not mo)144 424.8 Q .3 -.15(ve p)-.15 H +(oint.).15 E F1(do)108 436.8 Q(wncase\255w)-.1 E(ord \(M\255l\))-.1 E F0(Lo)144 +448.8 Q .641(wercase the current \(or follo)-.25 F .641(wing\) w)-.25 F 3.141 +(ord. W)-.1 F .641(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E .941 -.15(ve a)-.25 H +-.18(rg).15 G .64(ument, do the pre).18 F .64(vious w)-.25 F .64(ord, b)-.1 F +(ut)-.2 E(do not mo)144 460.8 Q .3 -.15(ve p)-.15 H(oint.).15 E F1 +(capitalize\255w)108 472.8 Q(ord \(M\255c\))-.1 E F0 .82 +(Capitalize the current \(or follo)144 484.8 R .82(wing\) w)-.25 F 3.32(ord. W) +-.1 F .82(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E 1.12 -.15(ve a)-.25 H -.18(rg) +.15 G .82(ument, do the pre).18 F .82(vious w)-.25 F .82(ord, b)-.1 F(ut)-.2 E +(do not mo)144 496.8 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(Killing and Y)87 +513.6 Q(anking)-.85 E(kill\255line \(C\255k\))108 525.6 Q F0(Kill the te)144 +537.6 Q(xt from the current cursor position to the end of the line.)-.15 E F1 +(backward\255kill\255line \(C\255x C\255Rubout\))108 549.6 Q F0(Kill backw)144 +561.6 Q(ard to the be)-.1 E(ginning of the line.)-.15 E F1 +(unix\255line\255discard \(C\255u\))108 573.6 Q F0(Kill backw)144 585.6 Q +(ard from point to the be)-.1 E(ginning of the line.)-.15 E F1 +(kill\255whole\255line)108 597.6 Q F0 +(Kill all characters on the current line, no matter where the cursor is.)144 +609.6 Q(By def)5 E(ault, this is unbound.)-.1 E F1(kill\255w)108 621.6 Q +(ord \(M\255d\))-.1 E F0 1.044 +(Kill from the cursor to the end of the current w)144 633.6 R 1.043 +(ord, or if between w)-.1 F 1.043(ords, to the end of the ne)-.1 F(xt)-.15 E +-.1(wo)144 645.6 S 2.5(rd. W).1 F(ord boundaries are the same as those used by) +-.8 E F1 -.25(fo)2.5 G(rward\255w).25 E(ord)-.1 E F0(.)A F1 +(backward\255kill\255w)108 657.6 Q(ord \(M\255Rubout\))-.1 E F0 3.26 +(Kill the w)144 669.6 R 3.26(ord behind the cursor)-.1 F 8.26(.W)-.55 G 3.26 +(ord boundaries are the same as those used by)304.31 669.6 R F1(back-)5.76 E +(ward\255w)144 681.6 Q(ord)-.1 E F0(.)A F1(unix\255w)108 693.6 Q +(ord\255rubout \(C\255w\))-.1 E F0 .482(Kill the w)144 705.6 R .482 +(ord behind the cursor)-.1 F 2.982(,u)-.4 G .482(sing white space as a w) +281.652 705.6 R .482(ord boundary)-.1 F 5.482(.T)-.65 G .482(he w)445.076 705.6 +R .481(ord boundaries are)-.1 F(dif)144 717.6 Q(ferent from backw)-.25 E +(ard\255kill\255w)-.1 E(ord.)-.1 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(21)530 +768 Q EP +%%Page: 22 22 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(delete\255horizontal\255space)108 84 Q F0 +(Delete all spaces and tabs around point.)144 96 Q(By def)5 E +(ault, this is unbound.)-.1 E F1(yank \(C\255y\))108 108 Q F0 -1(Ya)144 120 S +(nk the top of the kill ring into the b)1 E(uf)-.2 E(fer at the cursor)-.25 E +(.)-.55 E F1(yank\255pop \(M\255y\))108 132 Q F0 +(Rotate the kill\255ring, and yank the ne)144 144 Q 2.5(wt)-.25 G 2.5(op. Only) +302.71 144 R -.1(wo)2.5 G(rks follo).1 E(wing)-.25 E F1(yank)2.5 E F0(or)2.5 E +F1(yank\255pop)2.5 E F0(.)A F1(Numeric Ar)87 160.8 Q(guments)-.1 E(digit\255ar) +108 172.8 Q(gument \(M\2550, M\2551, ..., M\255\255\))-.1 E F0 .641 +(Add this digit to the ar)144 184.8 R .641 +(gument already accumulating, or start a ne)-.18 F 3.141(wa)-.25 G -.18(rg) +425.942 184.8 S 3.142(ument. M\255\255).18 F .642(starts a ne)3.142 F(g-)-.15 E +(ati)144 196.8 Q .3 -.15(ve a)-.25 H -.18(rg).15 G(ument.).18 E F1(uni)108 +208.8 Q -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0 .783(Each time this is e) +144 220.8 R -.15(xe)-.15 G .783(cuted, the ar).15 F .782 +(gument count is multiplied by four)-.18 F 5.782(.T)-.55 G .782(he ar)437.062 +220.8 R .782(gument count is ini-)-.18 F .175(tially one, so e)144 232.8 R -.15 +(xe)-.15 G .175(cuting this function the \214rst time mak).15 F .176(es the ar) +-.1 F .176(gument count four)-.18 F 5.176(.B)-.55 G 2.676(yd)485.028 232.8 S +(ef)497.704 232.8 Q .176(ault, this)-.1 F(is not bound to a k)144 244.8 Q -.15 +(ey)-.1 G(.)-.5 E F1(Completing)87 261.6 Q(complete \(T)108 273.6 Q(AB\))-.9 E +F0 1.137(Attempt to perform completion on the te)144 285.6 R 1.137 +(xt before point.)-.15 F F1(Bash)6.137 E F0 1.137 +(attempts completion treating the)3.637 F(te)144 297.6 Q .532(xt as a v)-.15 F +.532(ariable \(if the te)-.25 F .532(xt be)-.15 F .533(gins with)-.15 F F1($) +3.033 E F0 .533(\), username \(if the te)B .533(xt be)-.15 F .533(gins with) +-.15 F F1(~)3.033 E F0 .533(\), hostname \(if the)B(te)144 309.6 Q .702(xt be) +-.15 F .702(gins with)-.15 F F1(@)3.202 E F0 .701 +(\), or command \(including aliases and functions\) in turn.)B .701 +(If none of these pro-)5.701 F +(duces a match, \214lename completion is attempted.)144 321.6 Q F1 +(possible\255completions \(M-?\))108 333.6 Q F0 +(List the possible completions of the te)144 345.6 Q(xt before point.)-.15 E F1 +(insert\255completions)108 357.6 Q F0 3.372(Insert all completions of the te) +144 369.6 R 3.372(xt before point that w)-.15 F 3.372(ould ha)-.1 F 3.672 -.15 +(ve b)-.2 H 3.372(een generated by).15 F F1(possi-)5.873 E(ble\255completions) +144 381.6 Q F0 5(.B)C 2.5(yd)227.76 381.6 S(ef)240.26 381.6 Q +(ault, this is not bound to a k)-.1 E -.15(ey)-.1 G(.)-.5 E F1 +(complete\255\214lename \(M\255/\))108 393.6 Q F0 +(Attempt \214lename completion on the te)144 405.6 Q(xt before point.)-.15 E F1 +(possible\255\214lename\255completions \(C\255x /\))108 417.6 Q F0 +(List the possible completions of the te)144 429.6 Q +(xt before point, treating it as a \214lename.)-.15 E F1(complete\255user)108 +441.6 Q(name \(M\255~\))-.15 E F0(Attempt completion on the te)144 453.6 Q +(xt before point, treating it as a username.)-.15 E F1(possible\255user)108 +465.6 Q(name\255completions \(C\255x ~\))-.15 E F0 +(List the possible completions of the te)144 477.6 Q +(xt before point, treating it as a username.)-.15 E F1(complete\255v)108 489.6 +Q(ariable \(M\255$\))-.1 E F0(Attempt completion on the te)144 501.6 Q +(xt before point, treating it as a shell v)-.15 E(ariable.)-.25 E F1 +(possible\255v)108 513.6 Q(ariable\255completions \(C\255x $\))-.1 E F0 +(List the possible completions of the te)144 525.6 Q +(xt before point, treating it as a shell v)-.15 E(ariable.)-.25 E F1 +(complete\255hostname \(M\255@\))108 537.6 Q F0(Attempt completion on the te) +144 549.6 Q(xt before point, treating it as a hostname.)-.15 E F1 +(possible\255hostname\255completions \(C\255x @\))108 561.6 Q F0 +(List the possible completions of the te)144 573.6 Q +(xt before point, treating it as a hostname.)-.15 E F1 +(complete\255command \(M\255!\))108 585.6 Q F0 .581 +(Attempt completion on the te)144 597.6 R .581 +(xt before point, treating it as a command name.)-.15 F .58(Command comple-) +5.58 F .238(tion attempts to match the te)144 609.6 R .238(xt ag)-.15 F .239 +(ainst aliases, reserv)-.05 F .239(ed w)-.15 F .239(ords, shell functions, b) +-.1 F .239(uiltins, and \214nally)-.2 F -.15(exe)144 621.6 S +(cutable \214lenames, in that order).15 E(.)-.55 E F1 +(possible\255command\255completions \(C\255x !\))108 633.6 Q F0 +(List the possible completions of the te)144 645.6 Q +(xt before point, treating it as a command name.)-.15 E F1 +(dynamic\255complete\255history \(M-T)108 657.6 Q(AB\))-.9 E F0 .425 +(Attempt completion on the te)144 669.6 R .425 +(xt before point, comparing the te)-.15 F .425(xt ag)-.15 F .424 +(ainst lines from the history list)-.05 F(for possible completion matches.)144 +681.6 Q F1(complete\255into\255braces \(M\255{\))108 693.6 Q F0 .272(Perform \ +\214lename completion and return the list of possible completions enclosed wit\ +hin braces so)144 705.6 R(the list is a)144 717.6 Q -.25(va)-.2 G +(ilable to the shell \(see).25 E F1(Brace Expansion)2.5 E F0(abo)2.5 E -.15(ve) +-.15 G(\).).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(22)530 768 Q EP +%%Page: 23 23 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF -.25(Ke)87 84 S(yboard Macr).25 E(os)-.18 E +(start\255kbd\255macr)108 96 Q 2.5(o\()-.18 G(C-x \()188.93 96 Q(\)).833 E F0 +(Be)144 108 Q(gin sa)-.15 E(ving the characters typed into the current k)-.2 E +-.15(ey)-.1 G(board macro.).15 E F1(end\255kbd\255macr)108 120 Q 2.5(o\()-.18 G +(C-x \))184.5 120 Q(\)).833 E F0(Stop sa)144 132 Q +(ving the characters typed into the current k)-.2 E -.15(ey)-.1 G +(board macro and sa).15 E .3 -.15(ve t)-.2 H(he de\214nition.).15 E F1 +(call\255last\255kbd\255macr)108 144 Q 2.5(o\()-.18 G(C-x e\))204.64 144 Q F0 +(Re-e)144 156 Q -.15(xe)-.15 G 1(cute the last k).15 F -.15(ey)-.1 G .999 +(board macro de\214ned, by making the characters in the macro appear as if).15 +F(typed at the k)144 168 Q -.15(ey)-.1 G(board.).15 E F1(Miscellaneous)87 184.8 +Q -.18(re)108 196.8 S.18 E(ead\255init\255\214le \(C\255x C\255r\))-.18 E +F0 .54(Read in the contents of your init \214le, and incorporate an)144 208.8 R +3.041(yb)-.15 G .541(indings or v)385.876 208.8 R .541 +(ariable assignments found)-.25 F(there.)144 220.8 Q F1(abort \(C\255g\))108 +232.8 Q F0 3.249(Abort the current editing command and ring the terminal')144 +244.8 R 5.748(sb)-.55 G 3.248(ell \(subject to the setting of)414.6 244.8 R F1 +(bell\255style)144 256.8 Q F0(\).)A F1(do\255upper)108 268.8 Q(case\255v)-.18 E +(ersion \(M\255a, M\255b, ...\))-.1 E F0 +(Run the command that is bound to the corresponding uppercase character)144 +280.8 Q(.)-.55 E F1(pr)108 292.8 Q(e\214x\255meta \(ESC\))-.18 E F0 +(Metafy the ne)144 304.8 Q(xt character typed.)-.15 E/F2 9/Times-Bold@0 SF(ESC) +5 E F1(f)2.25 E F0(is equi)2.5 E -.25(va)-.25 G(lent to).25 E F1(Meta\255f)2.5 +E F0(.)A F1(undo \(C\255_, C\255x C\255u\))108 316.8 Q F0 +(Incremental undo, separately remembered for each line.)144 328.8 Q F1 -2.29 +-.18(re v)108 340.8 T(ert\255line \(M\255r\)).08 E F0 .244 +(Undo all changes made to this line.)144 352.8 R .245(This is lik)5.245 F 2.745 +(et)-.1 G .245(yping the)341.895 352.8 R F1(undo)2.745 E F0 .245 +(command enough times to return)2.745 F(the line to its initial state.)144 +364.8 Q F1(tilde\255expand \(M\255~\))108 376.8 Q F0(Perform tilde e)144 388.8 +Q(xpansion on the current w)-.15 E(ord.)-.1 E F1(dump\255functions)108 400.8 Q +F0 .627(Print all of the functions and their k)144 412.8 R .927 -.15(ey b)-.1 H +.626(indings to the readline output stream.).15 F .626(If a numeric ar)5.626 F +(gu-)-.18 E(ment is supplied, the output is formatted in such a w)144 424.8 Q +(ay that it can be made part of an)-.1 E/F3 10/Times-Italic@0 SF(inputr)2.5 E +(c)-.37 E F0(\214le.)2.5 E F1(display\255shell\255v)108 436.8 Q +(ersion \(C\255x C\255v\))-.1 E F0(Display v)144 448.8 Q +(ersion information about the current instance of)-.15 E F1(bash)2.5 E F0(.)A +F2(HIST)72 465.6 Q(OR)-.162 E(Y)-.315 E F0 .227(When interacti)108 477.6 R -.15 +(ve)-.25 G 2.727(,t).15 G .227(he shell pro)184.424 477.6 R .227 +(vides access to the)-.15 F F3 .227(command history)2.727 F F0 2.727(,t)C .228 +(he list of commands pre)386.34 477.6 R .228(viously typed.)-.25 F .12(The te) +108 489.6 R .12(xt of the last)-.15 F F2(HISTSIZE)2.62 E F0 .12(commands \(def) +2.37 F .119(ault 500\) is sa)-.1 F -.15(ve)-.2 G 2.619(di).15 G 2.619(nah) +367.958 489.6 S .119(istory list.)387.636 489.6 R .119 +(The shell stores each com-)5.119 F .124 +(mand in the history list prior to parameter and v)108 501.6 R .125(ariable e) +-.25 F .125(xpansion \(see)-.15 F F2(EXP)2.625 E(ANSION)-.666 E F0(abo)2.375 E +-.15(ve)-.15 G 2.625(\)b).15 G .125(ut after history)480.87 501.6 R -.15(ex)108 +513.6 S .267(pansion is performed, subject to the v).15 F .267 +(alues of the shell v)-.25 F(ariables)-.25 E F1(command_oriented_history)2.767 +E F0(and)2.767 E F2(HIST)2.767 E(-)-.828 E(CONTR)108 525.6 Q(OL)-.27 E/F4 9 +/Times-Roman@0 SF(.)A F0 1.191 +(On startup, the history is initialized from the \214le named by the v)5.69 F +(ariable)-.25 E F2(HISTFILE)3.691 E F0(\(def)3.441 E(ault)-.1 E F3 +(~/.bash_history)108 537.6 Q F0(\).)A F2(HISTFILE)5.632 E F0 .632 +(is truncated, if necessary)2.882 F 3.131(,t)-.65 G 3.131(oc)333.656 537.6 S +.631(ontain no more than)346.227 537.6 R F2(HISTFILESIZE)3.131 E F0 3.131 +(lines. The)2.881 F -.2(bu)108 549.6 S .168(iltin command).2 F F1(fc)2.668 E F0 +(\(see)2.668 E F2 .168(SHELL B)2.668 F(UIL)-.09 E .168(TIN COMMANDS)-.828 F F0 +(belo)2.418 E .168(w\) may be used to list or edit and re-e)-.25 F -.15(xe)-.15 +G .168(cute a).15 F .102(portion of the history list.)108 561.6 R(The)5.102 E +F1(history)2.602 E F0 -.2(bu)2.602 G .101 +(iltin can be used to display the history list and manipulate the his-).2 F +.464(tory \214le.)108 573.6 R .464 +(When using the command-line editing, search commands are a)5.464 F -.25(va)-.2 +G .464(ilable in each editing mode that).25 F(pro)108 585.6 Q .483 +(vide access to the history list.)-.15 F .483(When an interacti)5.483 F .783 +-.15(ve s)-.25 H .483(hell e).15 F .483(xits, the last)-.15 F F2(HISTSIZE)2.983 +E F0 .482(lines are copied from)2.733 F 1.047(the history list to)108 597.6 R +F2(HISTFILE)3.547 E F4(.)A F0(If)5.548 E F2(HISTFILE)3.548 E F0 1.048 +(is unset, or if the history \214le is unwritable, the history is not)3.298 F +(sa)108 609.6 Q -.15(ve)-.2 G(d.).15 E F2(HIST)72 626.4 Q(OR)-.162 E 2.25(YE) +-.315 G(XP)121.284 626.4 Q(ANSION)-.666 E F0 .611 +(The shell supports a history e)108 638.4 R .611 +(xpansion feature that is similar to the history e)-.15 F .61(xpansion in)-.15 +F F1(csh.)3.11 E F0 .61(This section)5.61 F .87 +(describes what syntax features are a)108 650.4 R -.25(va)-.2 G 3.371 +(ilable. This).25 F .871(feature is enabled by def)3.371 F .871 +(ault for interacti)-.1 F 1.171 -.15(ve s)-.25 H .871(hells, and).15 F 2.014 +(can be disabled using the)108 662.4 R F1(+H)4.514 E F0 2.014(option to the) +4.514 F F1(set)4.514 E F0 -.2(bu)4.514 G 2.014(iltin command \(see).2 F F2 +2.013(SHELL B)4.513 F(UIL)-.09 E 2.013(TIN COMMANDS)-.828 F F0(belo)108 674.4 Q +2.5(w\). Non-interacti)-.25 F .3 -.15(ve s)-.25 H +(hells do not perform history e).15 E(xpansion.)-.15 E 1.163(History e)108 +691.2 R 1.163(xpansion is performed immediately after a complete line is read,\ + before the shell breaks it into)-.15 F -.1(wo)108 703.2 S 2.585(rds. It).1 F +(tak)2.585 E .085(es place in tw)-.1 F 2.585(op)-.1 G 2.585(arts. The)228.19 +703.2 R .084(\214rst is to determine which line from the pre)2.585 F .084 +(vious history to use dur)-.25 F(-)-.2 E .915(ing substitution.)108 715.2 R +.915(The second is to select portions of that line for inclusion into the curr\ +ent one.)5.915 F .915(The line)5.915 F .603(selected from the pre)108 727.2 R +.603(vious history is the)-.25 F F3 -.15(ev)3.103 G(ent).15 E F0 3.103(,a)C +.602(nd the portions of that line that are acted upon are)305.444 727.2 R F3 +(wor)3.102 E(ds)-.37 E F0(.)A 185.675(GNU 1995)72 768 R(May 5)2.5 E(23)530 768 +Q EP +%%Page: 24 24 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +1.748(The line is brok)108 84 R 1.749(en into w)-.1 F 1.749(ords in the same f) +-.1 F 1.749(ashion as when reading input, so that se)-.1 F -.15(ve)-.25 G(ral) +.15 E/F1 10/Times-Italic@0 SF(metac)4.249 E(har)-.15 E(ac-)-.15 E(ter)108 96 Q +F0 1.785(\255separated w)B 1.785 +(ords surrounded by quotes are considered as one w)-.1 F 4.284(ord. Only)-.1 F +1.784(backslash \()4.284 F/F2 10/Times-Bold@0 SF(\\).833 E F0 4.284(\)a).833 G +1.784(nd single)501.826 96 R(quotes can quote the history escape character)108 +108 Q 2.5(,w)-.4 G(hich is)300.32 108 Q F2(!)3.333 E F0(by def)3.333 E(ault.) +-.1 E 2.2(The shell allo)108 124.8 R 2.2(ws control of the v)-.25 F 2.2 +(arious characters used by the history e)-.25 F 2.2 +(xpansion mechanism \(see the)-.15 F(description of)108 136.8 Q F2(histchars) +2.5 E F0(abo)2.5 E .3 -.15(ve u)-.15 H(nder).15 E F2(Shell V)2.5 E(ariables) +-.92 E F0(\).)A F2(Ev)87 153.6 Q(ent Designators)-.1 E F0(An e)108 165.6 Q -.15 +(ve)-.25 G +(nt designator is a reference to a command line entry in the history list.).15 +E F2(!)108 182.4 Q F0(Start a history substitution, e)144 182.4 Q +(xcept when follo)-.15 E(wed by a)-.25 E F2(blank)2.5 E F0 2.5(,n)C -.25(ew) +398.6 182.4 S(line, = or \(.).25 E F2(!!)108 194.4 Q F0(Refer to the pre)144 +194.4 Q(vious command.)-.25 E(This is a synon)5 E(ym for `!\2551'.)-.15 E F2(!) +108 206.4 Q F1(n)A F0(Refer to command line)144 206.4 Q F1(n)2.5 E F0(.).24 E +F2<21ad>108 218.4 Q F1(n)A F0(Refer to the current command line minus)144 218.4 +Q F1(n)2.5 E F0(.).24 E F2(!)108 230.4 Q F1(string)A F0 +(Refer to the most recent command starting with)9.33 E F1(string)2.5 E F0(.).22 +E F2(!?)108 242.4 Q F1(string)A F2([?])A F0 +(Refer to the most recent command containing)144 254.4 Q F1(string)2.5 E F0(.) +.22 E/F3 12/Times-Bold@0 SF(^)108 271.4 Q F1(string1)111.996 266.4 Q F3(^) +140.336 271.4 Q F1(string2)144.332 266.4 Q F3(^)172.672 271.4 Q F0 2.66 +(Quick substitution.)144 278.4 R 2.66(Repeat the last command, replacing)7.66 F +F1(string1)5.16 E F0(with)5.16 E F1(string2)5.16 E F0 7.66(.E).02 G(qui)490.34 +278.4 Q -.25(va)-.25 G 2.66(lent to).25 F -.74(``)144 290.4 S(!!:s/).74 E F1 +(string1)A F0(/)A F1(string2)A F0(/')A 2.5('\()-.74 G(see)240.02 290.4 Q F2 +(Modi\214ers)2.5 E F0(belo)2.5 E(w\).)-.25 E F2(!#)108 302.4 Q F0 +(The entire command line typed so f)144 302.4 Q(ar)-.1 E(.)-.55 E F2 -.75(Wo)87 +319.2 S(rd Designators).75 E F0(A)108 331.2 Q F2(:)3.654 E F0 1.154 +(separates the e)3.654 F -.15(ve)-.25 G 1.154(nt speci\214cation from the w).15 +F 1.154(ord designator)-.1 F 6.154(.I)-.55 G 3.654(tc)377.32 331.2 S 1.154 +(an be omitted if the w)388.194 331.2 R 1.155(ord designator)-.1 F(be)108 343.2 +Q .539(gins with a)-.15 F F2(^)3.039 E F0(,)A F2($)3.039 E F0(,)A F2(*)3.039 E +F0 3.039(,o)C(r)200.244 343.2 Q F2(%)3.039 E F0 5.539(.W)C .539 +(ords are numbered from the be)233.292 343.2 R .538 +(ginning of the line, with the \214rst w)-.15 F .538(ord being)-.1 F +(denoted by a 0 \(zero\).)108 355.2 Q F2 2.5(0\()108 372 S(zer)118.83 372 Q +(o\))-.18 E F0(The zeroth w)144 384 Q 2.5(ord. F)-.1 F +(or the shell, this is the command w)-.15 E(ord.)-.1 E F1(n)108 396 Q F0(The) +144 396 Q F1(n)2.5 E F0(th w)A(ord.)-.1 E F2(^)108 408 Q F0(The \214rst ar)144 +408 Q 2.5(gument. That)-.18 F(is, w)2.5 E(ord 1.)-.1 E F2($)108 420 Q F0 +(The last ar)144 420 Q(gument.)-.18 E F2(%)108 432 Q F0(The w)144 432 Q +(ord matched by the most recent `?)-.1 E F1(string)A F0(?' search.)A F1(x)108 +444 Q F2A F1(y)A F0 2.5(Ar)144 444 S(ange of w)157.05 444 Q(ords; `\255)-.1 +E F1(y)A F0 2.5('a)C(bbre)242.56 444 Q(viates `0\255)-.25 E F1(y)A F0('.)A F2 +(*)108 456 Q F0 .315(All of the w)144 456 R .315(ords b)-.1 F .315 +(ut the zeroth.)-.2 F .315(This is a synon)5.315 F .315(ym for `)-.15 F F1 +(1\255$)A F0 2.815('. It)B .315(is not an error to use)2.815 F F2(*)2.816 E F0 +.316(if there is)2.816 F(just one w)144 468 Q(ord in the e)-.1 E -.15(ve)-.25 G +(nt; the empty string is returned in that case.).15 E F2(x*)108 480 Q F0(Abbre) +144 480 Q(viates)-.25 E F1(x\255$)2.5 E F0(.)A F2<78ad>108 492 Q F0(Abbre)144 +492 Q(viates)-.25 E F1(x\255$)2.5 E F0(lik)2.5 E(e)-.1 E F2(x*)2.5 E F0 2.5(,b) +C(ut omits the last w)250.46 492 Q(ord.)-.1 E F2(Modi\214ers)87 508.8 Q F0 .158 +(After the optional w)108 520.8 R .158(ord designator)-.1 F 2.658(,y)-.4 G .158 +(ou can add a sequence of one or more of the follo)256.6 520.8 R .157 +(wing modi\214ers, each)-.25 F(preceded by a `:'.)108 532.8 Q F2(h)108 549.6 Q +F0(Remo)144 549.6 Q .3 -.15(ve a t)-.15 H(railing pathname component, lea).15 E +(ving only the head.)-.2 E F2(r)108 561.6 Q F0(Remo)144 561.6 Q .3 -.15(ve a t) +-.15 H(railing suf).15 E(\214x of the form)-.25 E F1(.xxx)2.5 E F0 2.5(,l)C(ea) +313.98 561.6 Q(ving the basename.)-.2 E F2(e)108 573.6 Q F0(Remo)144 573.6 Q .3 +-.15(ve a)-.15 H(ll b).15 E(ut the trailing suf)-.2 E(\214x.)-.25 E F2(t)108 +585.6 Q F0(Remo)144 585.6 Q .3 -.15(ve a)-.15 H +(ll leading pathname components, lea).15 E(ving the tail.)-.2 E F2(p)108 597.6 +Q F0(Print the ne)144 597.6 Q 2.5(wc)-.25 G(ommand b)204.02 597.6 Q +(ut do not e)-.2 E -.15(xe)-.15 G(cute it.).15 E F2(q)108 609.6 Q F0 +(Quote the substituted w)144 609.6 Q(ords, escaping further substitutions.)-.1 +E F2(x)108 621.6 Q F0(Quote the substituted w)144 621.6 Q(ords as with)-.1 E F2 +(q)2.5 E F0 2.5(,b)C(ut break into w)304.81 621.6 Q(ords at)-.1 E F2(blanks)2.5 +E F0(and ne)2.5 E(wlines.)-.25 E F2(s/)108 633.6 Q F1(old)A F2(/)A F1(ne)A(w) +-.15 E F2(/)A F0(Substitute)144 645.6 Q F1(ne)2.813 E(w)-.15 E F0 .314 +(for the \214rst occurrence of)2.813 F F1(old)2.814 E F0 .314(in the e)2.814 F +-.15(ve)-.25 G .314(nt line.).15 F(An)5.314 E 2.814(yd)-.15 G .314 +(elimiter can be used in place)424.29 645.6 R .617(of /.)144 657.6 R .617 +(The \214nal delimiter is optional if it is the last character of the e)5.617 F +-.15(ve)-.25 G .617(nt line.).15 F .616(The delimiter may)5.616 F .749 +(be quoted in)144 669.6 R F1(old)3.249 E F0(and)3.249 E F1(ne)3.249 E(w)-.15 E +F0 .749(with a single backslash.)3.249 F .75(If & appears in)5.749 F F1(ne)3.25 +E(w)-.15 E F0 3.25(,i).31 G 3.25(ti)444.66 669.6 S 3.25(sr)453.47 669.6 S .75 +(eplaced by)463.94 669.6 R F1(old)3.25 E F0 5.75(.A).77 G +(single backslash will quote the &.)144 681.6 Q F2(&)108 693.6 Q F0 +(Repeat the pre)144 693.6 Q(vious substitution.)-.25 E F2(g)108 705.6 Q F0 .398 +(Cause changes to be applied o)144 705.6 R -.15(ve)-.15 G 2.898(rt).15 G .398 +(he entire e)284.948 705.6 R -.15(ve)-.25 G .398(nt line.).15 F .397 +(This is used in conjunction with `)5.398 F F2(:s)A F0 2.897('\()C(e.g.,)523.06 +705.6 Q(`)144 717.6 Q F2(:gs/)A F1(old)A F2(/)A F1(ne)A(w)-.15 E F2(/)A F0 +1.218('\) or `)B F2(:&)A F0 3.718('. If)B 1.218(used with `)3.718 F F2(:s)A F0 +1.218(', an)B 3.718(yd)-.15 G 1.219 +(elimiter can be used in place of /, and the \214nal)343.124 717.6 R +(delimiter is optional if it is the last character of the e)144 729.6 Q -.15 +(ve)-.25 G(nt line.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(24)530 768 Q EP +%%Page: 25 25 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 9/Times-Bold@0 SF(ARITHMETIC EV)72 84 Q(ALU)-1.215 E -.855(AT)-.54 G(ION) +.855 E F0 1.478(The shell allo)108 96 R 1.477(ws arithmetic e)-.25 F 1.477 +(xpressions to be e)-.15 F -.25(va)-.25 G 1.477 +(luated, under certain circumstances \(see the).25 F/F2 10/Times-Bold@0 SF(let) +3.977 E F0 -.2(bu)3.977 G(iltin).2 E 1.232(command and)108 108 R F2 1.232 +(Arithmetic Expansion)3.732 F F0 3.732(\). Ev)B 1.232 +(aluation is done in long inte)-.25 F 1.232(gers with no check for o)-.15 F +-.15(ve)-.15 G(r\215o).15 E -.65(w,)-.25 G .279(though di)108 120 R .279 +(vision by 0 is trapped and \215agged as an error)-.25 F 5.278(.T)-.55 G .278 +(he follo)341.626 120 R .278(wing list of operators is grouped into le)-.25 F +(v-)-.25 E(els of equal-precedence operators.)108 132 Q(The le)5 E -.15(ve)-.25 +G(ls are listed in order of decreasing precedence.).15 E F2 2.5108 148.8 +S F0(unary minus and plus)144 148.8 Q F2 2.5(!~)108 160.8 S F0 +(logical and bitwise ne)144 160.8 Q -.05(ga)-.15 G(tion).05 E F2 2.5(*/%)108 +172.8 S F0(multiplication, di)144 172.8 Q(vision, remainder)-.25 E F2 2.5<2bad> +108 184.8 S F0(addition, subtraction)144 184.8 Q F2(<< >>)108 196.8 Q F0 +(left and right bitwise shifts)144 196.8 Q F2(<= >= < >)108 208.8 Q F0 +(comparison)144 220.8 Q F2(== !=)108 232.8 Q F0(equality and inequality)144 +232.8 Q F2(&)108 244.8 Q F0(bitwise AND)144 244.8 Q F2(^)108 256.8 Q F0 +(bitwise e)144 256.8 Q(xclusi)-.15 E .3 -.15(ve O)-.25 H(R).15 E F2(|)108 268.8 +Q F0(bitwise OR)144 268.8 Q F2(&&)108 280.8 Q F0(logical AND)144 280.8 Q F2(||) +108 292.8 Q F0(logical OR)144 292.8 Q F2 2.5(=*)108 304.8 S 2.5(=/)121.2 304.8 +S 2.5(=%)132.18 304.8 S 2.5(=+)150.38 304.8 S 2.5<3dad>164.28 304.8 S 2.5(=<) +178.18 304.8 S(<= >>= &= ^= |=)192.08 304.8 Q F0(assignment)144 316.8 Q .68 +(Shell v)108 333.6 R .68(ariables are allo)-.25 F .68 +(wed as operands; parameter e)-.25 F .68(xpansion is performed before the e) +-.15 F .68(xpression is e)-.15 F -.25(va)-.25 G(lu-).25 E 2.785(ated. The)108 +345.6 R -.25(va)2.785 G .284(lue of a parameter is coerced to a long inte).25 F +.284(ger within an e)-.15 F 2.784(xpression. A)-.15 F .284(shell v)2.784 F .284 +(ariable need not)-.25 F(ha)108 357.6 Q .3 -.15(ve i)-.2 H(ts inte).15 E +(ger attrib)-.15 E(ute turned on to be used in an e)-.2 E(xpression.)-.15 E +.049(Constants with a leading 0 are interpreted as octal numbers.)108 374.4 R +2.55(Al)5.049 G(eading)364.89 374.4 Q/F3 10/Times-Italic@0 SF(0x)2.55 E F0(or) +2.55 E F3(0X)2.55 E F0 .05(denotes he)2.55 F 2.55(xadecimal. Oth-)-.15 F .016 +(erwise, numbers tak)108 386.4 R 2.516(et)-.1 G .016(he form [)197.928 386.4 R +F3(base#)A F0 .015(]n, where)B F3(base)2.515 E F0 .015 +(is a decimal number between 2 and 36 representing the)2.515 F +(arithmetic base, and)108 398.4 Q F3(n)2.5 E F0(is a number in that base.)2.5 E +(If)5 E F3(base)2.5 E F0(is omitted, then base 10 is used.)2.5 E .234 +(Operators are e)108 415.2 R -.25(va)-.25 G .234 +(luated in order of precedence.).25 F(Sub-e)5.234 E .234 +(xpressions in parentheses are e)-.15 F -.25(va)-.25 G .235 +(luated \214rst and may).25 F -.15(ove)108 427.2 S +(rride the precedence rules abo).15 E -.15(ve)-.15 G(.).15 E F1(SHELL B)72 444 +Q(UIL)-.09 E(TIN COMMANDS)-.828 E F2(:)108 456 Q F0([)2.5 E F3(ar)A(guments) +-.37 E F0(])A .502(No ef)144 468 R .502(fect; the command does nothing be)-.25 +F .502(yond e)-.15 F(xpanding)-.15 E F3(ar)3.002 E(guments)-.37 E F0 .501 +(and performing an)3.001 F 3.001(ys)-.15 G(peci\214ed)508.34 468 Q 2.5 +(redirections. A)144 480 R(zero e)2.5 E(xit code is returned.)-.15 E F2(.)110.5 +496.8 Q F3(\214lename)6.666 E F0([)2.5 E F3(ar)A(guments)-.37 E F0(])A F2(sour) +108 508.8 Q(ce)-.18 E F3(\214lename)2.5 E F0([)2.5 E F3(ar)A(guments)-.37 E F0 +(])A 1.169(Read and e)144 520.8 R -.15(xe)-.15 G 1.169(cute commands from).15 F +F3(\214lename)3.669 E F0 1.169(in the current shell en)3.669 F 1.17 +(vironment and return the e)-.4 F(xit)-.15 E 1.302 +(status of the last command e)144 532.8 R -.15(xe)-.15 G 1.301(cuted from).15 F +F3(\214lename)3.801 E F0 6.301(.I).18 G(f)368.143 532.8 Q F3(\214lename)3.801 E +F0 1.301(does not contain a slash, path-)3.801 F .608(names in)144 544.8 R F1 +-.666(PA)3.108 G(TH)-.189 E F0 .608 +(are used to \214nd the directory containing)2.858 F F3(\214lename)3.108 E F0 +5.608(.T).18 G .608(he \214le searched for in)424.339 544.8 R F1 -.666(PA)3.108 +G(TH)-.189 E F0 .201(need not be e)144 556.8 R -.15(xe)-.15 G 2.701 +(cutable. The).15 F .201 +(current directory is searched if no \214le is found in)2.701 F F1 -.666(PA) +2.701 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .201(If an)4.701 F(y)-.15 E F3 +(ar)2.701 E(gu-)-.37 E(ments)144 568.8 Q F0 1.057(are supplied, the)3.557 F +3.557(yb)-.15 G 1.058(ecome the positional parameters when)252.228 568.8 R F3 +(\214le)3.558 E F0 1.058(is e)3.558 F -.15(xe)-.15 G 3.558(cuted. Otherwise).15 +F(the)3.558 E 1.079(positional parameters are unchanged.)144 580.8 R 1.078 +(The return status is the status of the last command e)6.079 F(xited)-.15 E +(within the script \(0 if no commands are e)144 592.8 Q -.15(xe)-.15 G +(cuted\), and f).15 E(alse if)-.1 E F3(\214lename)2.5 E F0(is not found.)2.5 E +F2(alias)108 609.6 Q F0([)2.5 E F3(name)A F0([=)A F3(value)A F0 2.5(].)C(..]) +193.9 609.6 Q F2(Alias)144 621.6 Q F0 1.667(with no ar)4.167 F 1.667 +(guments prints the list of aliases in the form)-.18 F F3(name)4.168 E F0(=)A +F3(value)A F0 1.668(on standard output.)4.168 F .607(When ar)144 633.6 R .607 +(guments are supplied, an alias is de\214ned for each)-.18 F F3(name)3.107 E F0 +(whose)3.107 E F3(value)3.107 E F0 .607(is gi)3.107 F -.15(ve)-.25 G 3.106 +(n. A).15 F(trailing)3.106 E 2.692(space in)144 645.6 R F3(value)5.192 E F0 +2.692(causes the ne)5.192 F 2.692(xt w)-.15 F 2.692(ord to be check)-.1 F 2.693 +(ed for alias substitution when the alias is)-.1 F -.15(ex)144 657.6 S 2.868 +(panded. F).15 F .367(or each)-.15 F F3(name)2.867 E F0 .367(in the ar)2.867 F +.367(gument list for which no)-.18 F F3(value)2.867 E F0 .367 +(is supplied, the name and v)2.867 F(alue)-.25 E 1.716 +(of the alias is printed.)144 669.6 R F2(Alias)6.716 E F0 1.717 +(returns true unless a)4.216 F F3(name)4.217 E F0 1.717(is gi)4.217 F -.15(ve) +-.25 G 4.217(nf).15 G 1.717(or which no alias has been)425.605 669.6 R +(de\214ned.)144 681.6 Q F2(bg)108 698.4 Q F0([)2.5 E F3(jobspec)A F0(])A(Place) +144 710.4 Q F3(jobspec)3.485 E F0 .985 +(in the background, as if it had been started with)3.485 F F2(&)3.485 E F0 +5.985(.I)C(f)425.645 710.4 Q F3(jobspec)3.485 E F0 .985(is not present, the) +3.485 F(shell')144 722.4 Q 4.166(sn)-.55 G 1.666(otion of the)178.726 722.4 R +F3(curr)4.166 E 1.666(ent job)-.37 F F0 1.666(is used.)4.166 F F2(bg)6.666 E F3 +(jobspec)4.166 E F0 1.667(returns 0 unless run when job control is)4.167 F +185.675(GNU 1995)72 768 R(May 5)2.5 E(25)530 768 Q EP +%%Page: 26 26 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +1.139(disabled or)144 84 R 3.639(,w)-.4 G 1.138 +(hen run with job control enabled, if)202.258 84 R/F1 10/Times-Italic@0 SF +(jobspec)3.638 E F0 -.1(wa)3.638 G 3.638(sn).1 G 1.138 +(ot found or started without job)412.37 84 R(control.)144 96 Q/F2 10 +/Times-Bold@0 SF(bind)108 112.8 Q F0([)2.5 E F2A F1 -.1(ke)2.5 G(ymap)-.2 +E F0 2.5(][)C F2(\255lvd)189.12 112.8 Q F0 2.5(][)C F2(-q)217.32 112.8 Q F1 +(name)2.5 E F0(])A F2(bind)108 124.8 Q F0([)2.5 E F2A F1 -.1(ke)2.5 G +(ymap)-.2 E F0(])A F2(-f)2.5 E F1(\214lename)2.5 E F2(bind)108 136.8 Q F0([)2.5 +E F2A F1 -.1(ke)2.5 G(ymap)-.2 E F0(])A F1 -.1(ke)2.5 G(yseq)-.2 E F0(:)A +F1(function-name)A F0 .238(Display current)144 148.8 R F2 -.18(re)2.738 G +(adline).18 E F0 -.1(ke)2.738 G 2.738(ya)-.05 G .239 +(nd function bindings, or bind a k)267.832 148.8 R .539 -.15(ey s)-.1 H .239 +(equence to a).15 F F2 -.18(re)2.739 G(adline).18 E F0(function)2.739 E .88 +(or macro.)144 160.8 R .88(The binding syntax accepted is identical to that of) +5.88 F F1(.inputr)3.38 E(c)-.37 E F0 3.38(,b).31 G .88(ut each binding must be) +440.93 160.8 R .38(passed as a separate ar)144 172.8 R .381 +(gument; e.g., '"\\C-x\\C-r": re\255read\255init\255\214le'.)-.18 F .381 +(Options, if supplied, ha)5.381 F .681 -.15(ve t)-.2 H(he).15 E(follo)144 184.8 +Q(wing meanings:)-.25 E F2144 196.8 Q F1 -.1(ke)2.5 G(ymap)-.2 E F0(Use) +180 208.8 Q F1 -.1(ke)5.175 G(ymap)-.2 E F0 2.674(as the k)5.175 F -.15(ey)-.1 +G 2.674(map to be af).15 F 2.674(fected by the subsequent bindings.)-.25 F +(Acceptable)7.674 E F1 -.1(ke)180 220.8 S(ymap)-.2 E F0 2.929(names are)5.428 F +F1 2.929(emacs, emacs-standar)5.429 F 2.929 +(d, emacs-meta, emacs-ctlx, vi, vi-mo)-.37 F(ve)-.1 E 5.429(,v)-.1 G(i-)533.89 +220.8 Q(command)180 232.8 Q F0 3.435(,a)C(nd)229.255 232.8 Q F1(vi-insert)3.435 +E F0(.).68 E F1(vi)5.934 E F0 .934(is equi)3.434 F -.25(va)-.25 G .934(lent to) +.25 F F1(vi-command)3.434 E F0(;)A F1(emacs)3.434 E F0 .934(is equi)3.434 F +-.25(va)-.25 G .934(lent to).25 F F1(emacs-)3.434 E(standar)180 244.8 Q(d)-.37 +E F0(.)A F2144 256.8 Q F0(List the names of all)180 256.8 Q F2 -.18(re) +2.5 G(adline).18 E F0(functions)2.5 E F2144 268.8 Q F0 +(List current function names and bindings)180 268.8 Q F2144 280.8 Q F0 +(Dump function names and bindings in such a w)180 280.8 Q(ay that the)-.1 E 2.5 +(yc)-.15 G(an be re-read)423.89 280.8 Q F2144 292.8 Q F1(\214lename)2.5 E +F0(Read k)180 304.8 Q .3 -.15(ey b)-.1 H(indings from).15 E F1(\214lename)2.5 E +F2144 316.8 Q F1(function)2.5 E F0(Query about which k)180 328.8 Q -.15 +(ey)-.1 G 2.5(si).15 G -1.9 -.4(nv o)282.51 328.8 T .2 -.1(ke t).4 H(he named) +.1 E F1(function)2.5 E F0(The return v)144 345.6 Q +(alue is 0 unless an unrecognized option is gi)-.25 E -.15(ve)-.25 G 2.5(no).15 +G 2.5(ra)391.37 345.6 S 2.5(ne)401.64 345.6 S(rror occurred.)413.58 345.6 Q F2 +(br)108 362.4 Q(eak)-.18 E F0([)2.5 E F1(n)A F0(])A .075(Exit from within a)144 +374.4 R F2 -.25(fo)2.575 G(r).25 E F0(,)A F2(while)2.575 E F0 2.575(,o)C(r) +270.86 374.4 Q F2(until)2.575 E F0 2.576(loop. If)2.575 F F1(n)2.576 E F0 .076 +(is speci\214ed, break)2.576 F F1(n)2.576 E F0(le)2.576 E -.15(ve)-.25 G(ls.) +.15 E F1(n)5.076 E F0 .076(must be)2.576 F/F3 10/Symbol SF2.576 E F0 2.576 +(1. If)2.576 F F1(n)2.576 E F0(is)2.576 E .838 +(greater than the number of enclosing loops, all enclosing loops are e)144 +386.4 R 3.338(xited. The)-.15 F .838(return v)3.338 F .838(alue is 0)-.25 F +(unless the shell is not e)144 398.4 Q -.15(xe)-.15 G(cuting a loop when).15 E +F2(br)2.5 E(eak)-.18 E F0(is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F2 -.2(bu)108 +415.2 S(iltin).2 E F1(shell\255b)2.5 E(uiltin)-.2 E F0([)2.5 E F1(ar)A(guments) +-.37 E F0(])A(Ex)144 427.2 Q .792(ecute the speci\214ed shell b)-.15 F .792 +(uiltin, passing it)-.2 F F1(ar)3.293 E(guments)-.37 E F0 3.293(,a).27 G .793 +(nd return its e)382.099 427.2 R .793(xit status.)-.15 F .793(This is useful) +5.793 F .603 +(when you wish to de\214ne a function whose name is the same as a shell b)144 +439.2 R .602(uiltin, b)-.2 F .602(ut need the func-)-.2 F .772 +(tionality of the b)144 451.2 R .772(uiltin within the function itself.)-.2 F +(The)5.773 E F2(cd)3.273 E F0 -.2(bu)3.273 G .773 +(iltin is commonly rede\214ned this w).2 F(ay)-.1 E(.)-.65 E +(The return status is f)144 463.2 Q(alse if)-.1 E F1(shell\255b)2.5 E(uiltin) +-.2 E F0(is not a shell b)2.5 E(uiltin command.)-.2 E F2(cd)108 480 Q F0([)2.5 +E F1(dir)A F0 5.17(]C)C .21(hange the current directory to)150.67 480 R F1(dir) +2.71 E F0 5.21(.T)C .21(he v)298.01 480 R(ariable)-.25 E/F4 9/Times-Bold@0 SF +(HOME)2.71 E F0 .21(is the def)2.46 F(ault)-.1 E F1(dir)2.71 E F0 5.21(.T).73 G +.21(he v)456.703 480 R(ariable)-.25 E F4(CDP)2.71 E -.855(AT)-.666 G(H).855 E +F0 .337(de\214nes the search path for the directory containing)144 492 R F1 +(dir)2.837 E F0 5.337(.A).73 G(lternati)379.662 492 Q .637 -.15(ve d)-.25 H +.337(irectory names are separated).15 F .31(by a colon \(:\).)144 504 R 2.809 +(An)5.309 G .309(ull directory name in)221.367 504 R F4(CDP)2.809 E -.855(AT) +-.666 G(H).855 E F0 .309(is the same as the current directory)2.559 F 2.809(,i) +-.65 G .309(.e., `)496.442 504 R(`)-.74 E F2(.)A F0 -.74('')C 5.309(.I).74 G(f) +536.67 504 Q F1(dir)144 516 Q F0(be)3.418 E .918(gins with a slash \(/\), then) +-.15 F F4(CDP)3.418 E -.855(AT)-.666 G(H).855 E F0 .918(is not used.)3.168 F +.919(An ar)5.919 F .919(gument of)-.18 F F23.419 E F0 .919(is equi)3.419 F +-.25(va)-.25 G .919(lent to).25 F F4($OLD-)3.419 E(PWD)144 528 Q/F5 9 +/Times-Roman@0 SF(.)A F0(The return v)4.5 E(alue is true if the directory w) +-.25 E(as successfully changed; f)-.1 E(alse otherwise.)-.1 E F2(command)108 +544.8 Q F0([)2.5 E F2(-pVv)A F0(])A F1(command)2.5 E F0([)2.5 E F1(ar)A(g)-.37 +E F0(...])2.5 E(Run)144 556.8 Q F1(command)2.878 E F0(with)2.878 E F1(ar)2.878 +E(gs)-.37 E F0 .378(suppressing the normal shell function lookup. Only b)2.878 +F .377(uiltin commands or)-.2 F .558(commands found in the)144 568.8 R F4 -.666 +(PA)3.058 G(TH)-.189 E F0 .559(are e)2.809 F -.15(xe)-.15 G 3.059(cuted. If).15 +F(the)3.059 E F23.059 E F0 .559(option is gi)3.059 F -.15(ve)-.25 G .559 +(n, the search for).15 F F1(command)3.059 E F0(is)3.059 E .232 +(performed using a def)144 580.8 R .231(ault v)-.1 F .231(alue for)-.25 F F2 +-.74(PA)2.731 G(TH)-.21 E F0 .231 +(that is guaranteed to \214nd all of the standard utilities.)2.731 F(If)5.231 E +.231(either the)144 592.8 R F22.731 E F0(or)2.731 E F22.731 E F0 +.232(option is supplied, a description of)2.732 F F1(command)2.732 E F0 .232 +(is printed.)2.732 F(The)5.232 E F22.732 E F0 .232(option causes)2.732 F +2.711(as)144 604.8 S .211(ingle w)155.041 604.8 R .211 +(ord indicating the command or pathname used to in)-.1 F -.2(vo)-.4 G -.1(ke).2 +G F1(command)2.81 E F0 .21(to be printed; the)2.71 F F22.71 E F0 .475 +(option produces a more v)144 616.8 R .476(erbose description.)-.15 F .476 +(An ar)5.476 F .476(gument of)-.18 F F22.976 E F0 .476 +(disables option checking for the)2.976 F 1.349(rest of the ar)144 628.8 R +3.849(guments. If)-.18 F(the)3.849 E F23.849 E F0(or)3.849 E F2 +3.849 E F0 1.348(option is supplied, the e)3.848 F 1.348(xit status is 0 if) +-.15 F F1(command)3.848 E F0 -.1(wa)3.848 G(s).1 E 1.305(found, and 1 if not.) +144 640.8 R 1.305(If neither option is supplied and an error occurred or)6.305 +F F1(command)3.806 E F0 1.306(cannot be)3.806 F .093(found, the e)144 652.8 R +.093(xit status is 127.)-.15 F .092(Otherwise, the e)5.092 F .092 +(xit status of the)-.15 F F2(command)2.592 E F0 -.2(bu)2.592 G .092 +(iltin is the e).2 F .092(xit status of)-.15 F F1(command)144 664.8 Q F0(.).77 +E F2(continue)108 681.6 Q F0([)2.5 E F1(n)A F0(])A .064(Resume the ne)144 693.6 +R .064(xt iteration of the enclosing)-.15 F F2 -.25(fo)2.564 G(r).25 E F0(,)A +F2(while)2.564 E F0 2.564(,o)C(r)366.096 693.6 Q F2(until)2.564 E F0 2.565 +(loop. If)2.565 F F1(n)2.565 E F0 .065(is speci\214ed, resume at the)2.565 F F1 +(n)144 705.6 Q F0 1.169(th enclosing loop.)B F1(n)6.169 E F0 1.169(must be) +3.669 F F33.669 E F0 3.669(1. If)3.669 F F1(n)3.669 E F0 1.169 +(is greater than the number of enclosing loops, the last)3.669 F 1.593 +(enclosing loop \(the `top\255le)144 717.6 R -.15(ve)-.25 G 1.593 +(l' loop\) is resumed.).15 F 1.593(The return v)6.593 F 1.593 +(alue is 0 unless the shell is not)-.25 F -.15(exe)144 729.6 S +(cuting a loop when).15 E F2(continue)2.5 E F0(is e)2.5 E -.15(xe)-.15 G +(cuted.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(26)530 768 Q EP +%%Page: 27 27 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(declar)108 84 Q(e)-.18 E F0([)2.5 E F1(\255frxi)A F0 2.5 +(][)C/F2 10/Times-Italic@0 SF(name)175.16 84 Q F0([=)A F2(value)A F0(]])A F1 +(typeset)108 96 Q F0([)2.5 E F1(\255frxi)A F0 2.5(][)C F2(name)174.23 96 Q F0 +([=)A F2(value)A F0(]])A 1.098(Declare v)144 108 R 1.098(ariables and/or gi) +-.25 F 1.398 -.15(ve t)-.25 H 1.098(hem attrib).15 F 3.598(utes. If)-.2 F(no) +3.598 E F2(name)3.598 E F0 3.598(sa)C 1.098(re gi)394.362 108 R -.15(ve)-.25 G +1.098(n, then display the v).15 F 1.098(alues of)-.25 F -.25(va)144 120 S 2.491 +(riables instead.).25 F 2.491(The options can be used to restrict output to v) +7.491 F 2.492(ariables with the speci\214ed)-.25 F(attrib)144 132 Q(ute.)-.2 E +F1144 144 Q F0(Use function names only)180 144 Q F1144 156 Q F0 +(Mak)180 156 Q(e)-.1 E F2(name)5.047 E F0 5.047(sr)C(eadonly)241.644 156 Q +7.547(.T)-.65 G 2.546(hese names cannot then be assigned v)288.811 156 R 2.546 +(alues by subsequent)-.25 F(assignment statements.)180 168 Q F1144 180 Q +F0(Mark)180 180 Q F2(name)2.5 E F0 2.5(sf)C(or e)235.54 180 Q +(xport to subsequent commands via the en)-.15 E(vironment.)-.4 E F1144 +192 Q F0 .557(The v)180 192 R .558(ariable is treated as an inte)-.25 F .558 +(ger; arithmetic e)-.15 F -.25(va)-.25 G .558(luation \(see).25 F/F3 9 +/Times-Bold@0 SF .558(ARITHMETIC EV)3.058 F(ALU)-1.215 E(A-)-.54 E(TION \))180 +204 Q F0(is performed when the v)2.25 E(ariable is assigned a v)-.25 E(alue.) +-.25 E 1.219(Using `+' instead of `\255' turns of)144 220.8 R 3.719(ft)-.25 G +1.219(he attrib)289.373 220.8 R 1.219(ute instead.)-.2 F 1.218 +(When used in a function, mak)6.219 F(es)-.1 E F2(name)3.718 E F0(s)A .235 +(local, as with the)144 232.8 R F1(local)2.735 E F0 2.735(command. The)2.735 F +.235(return v)2.735 F .235(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.736 +(lo).05 G .236(ption is encountered, an)443.752 232.8 R .435 +(attempt is made to de\214ne a function using "-f foo=bar", one of the)144 +244.8 R F2(names)2.935 E F0 .434(is not a le)2.935 F -.05(ga)-.15 G 2.934(ls) +.05 G .434(hell v)503.436 244.8 R(ari-)-.25 E .519 +(able name, an attempt is made to turn of)144 256.8 R 3.019(fr)-.25 G .52 +(eadonly status for a readonly v)318.391 256.8 R .52(ariable, or an attempt is) +-.25 F(made to display a non-e)144 268.8 Q(xistant function with -f.)-.15 E F1 +(dirs [-l] [+/\255n])108 285.6 Q F0 1.505 +(Display the list of currently remembered directories.)144 297.6 R 1.505 +(Directories are added to the list with the)6.505 F F1(pushd)144 309.6 Q F0 +(command; the)2.5 E F1(popd)2.5 E F0(command mo)2.5 E -.15(ve)-.15 G 2.5(sb).15 +G(ack up through the list.)331.5 309.6 Q F1(+n)144 321.6 Q F0 .13(displays the) +180 321.6 R F2(n)2.63 E F0 .13(th entry counting from the left of the list sho) +B .13(wn by)-.25 F F1(dirs)2.63 E F0 .13(when in)2.63 F -.2(vo)-.4 G -.1(ke).2 +G 2.63(dw).1 G(ith-)526.11 321.6 Q(out options, starting with zero.)180 333.6 Q +F1144 345.6 Q F0 1.342(displays the)180 345.6 R F2(n)3.842 E F0 1.342 +(th entry counting from the right of the list sho)B 1.342(wn by)-.25 F F1(dirs) +3.842 E F0 1.342(when in)3.842 F -.2(vo)-.4 G -.1(ke).2 G(d).1 E +(without options, starting with zero.)180 357.6 Q F1144 369.6 Q F0 .361 +(produces a longer listing; the def)180 369.6 R .361 +(ault listing format uses a tilde to denote the home direc-)-.1 F(tory)180 +381.6 Q(.)-.65 E .381(The return v)144 398.4 R .381(alue is 0 unless an ille) +-.25 F -.05(ga)-.15 G 2.881(lo).05 G .381(ption is supplied or)303.798 398.4 R +F2(n)2.88 E F0(inde)2.88 E -.15(xe)-.15 G 2.88(sb).15 G -.15(ey)430.78 398.4 S +.38(ond the end of the direc-).15 F(tory stack.)144 410.4 Q F1(echo)108 427.2 Q +F0([)2.5 E F1(\255neE)A F0 2.5(][)C F2(ar)164.8 427.2 Q(g)-.37 E F0(...])2.5 E +.266(Output the)144 439.2 R F2(ar)2.766 E(g)-.37 E F0 .266 +(s, separated by spaces.)B .266(The return status is al)5.266 F -.1(wa)-.1 G +.267(ys 0.).1 F(If)5.267 E F12.767 E F0 .267 +(is speci\214ed, the trailing)2.767 F(ne)144 451.2 Q .311(wline is suppressed.) +-.25 F .311(If the)5.311 F F12.811 E F0 .311(option is gi)2.811 F -.15 +(ve)-.25 G .311(n, interpretation of the follo).15 F .31 +(wing backslash-escaped)-.25 F .873(characters is enabled.)144 463.2 R(The) +5.874 E F13.374 E F0 .874 +(option disables the interpretation of these escape characters, e)3.374 F -.15 +(ve)-.25 G(n).15 E(on systems where the)144 475.2 Q 2.5(ya)-.15 G +(re interpreted by def)241.61 475.2 Q(ault.)-.1 E F1(\\a)144 487.2 Q F0 +(alert \(bell\))180 487.2 Q F1(\\b)144 499.2 Q F0(backspace)180 499.2 Q F1(\\c) +144 511.2 Q F0(suppress trailing ne)180 511.2 Q(wline)-.25 E F1(\\f)144 523.2 Q +F0(form feed)180 523.2 Q F1(\\n)144 535.2 Q F0(ne)180 535.2 Q 2.5(wl)-.25 G +(ine)201.69 535.2 Q F1(\\r)144 547.2 Q F0(carriage return)180 547.2 Q F1(\\t) +144 559.2 Q F0(horizontal tab)180 559.2 Q F1(\\v)144 571.2 Q F0 -.15(ve)180 +571.2 S(rtical tab).15 E F1(\\\\)144 583.2 Q F0(backslash)180 583.2 Q F1(\\nnn) +144 595.2 Q F0(the character whose ASCII code is)180 595.2 Q F2(nnn)2.5 E F0 +(\(octal\))2.5 E F1(enable)108 612 Q F0([)2.5 E F1A F0 2.5(][)C F1 +(\255all)162.03 612 Q F0 2.5(][)C F2(name)187.45 612 Q F0(...])2.5 E .683 +(Enable and disable b)144 624 R .683(uiltin shell commands.)-.2 F .683 +(This allo)5.683 F .683(ws the e)-.25 F -.15(xe)-.15 G .683 +(cution of a disk command which).15 F .324(has the same name as a shell b)144 +636 R .324(uiltin without specifying a full pathname.)-.2 F(If)5.324 E F1 +2.824 E F0 .324(is used, each)2.824 F F2(name)2.824 E F0 .181 +(is disabled; otherwise,)144 648 R F2(names)2.681 E F0 .181(are enabled.)2.681 +F -.15(Fo)5.181 G 2.681(re).15 G .181(xample, to use the)338.817 648 R F1(test) +2.68 E F0 .18(binary found via the)2.68 F F3 -.666(PA)2.68 G(TH)-.189 E F0 .748 +(instead of the shell b)144 660 R .748(uiltin v)-.2 F .748(ersion, type `)-.15 +F .748(`enable -n test')-.74 F 3.248('. If)-.74 F .748(no ar)3.248 F .749 +(guments are gi)-.18 F -.15(ve)-.25 G .749(n, a list of all).15 F .425 +(enabled shell b)144 672 R .425(uiltins is printed.)-.2 F .425(If only)5.425 F +F12.925 E F0 .424(is supplied, a list of all disabled b)2.925 F .424 +(uiltins is printed.)-.2 F(If)5.424 E(only)144 684 Q F1(\255all)2.546 E F0 .046 +(is supplied, the list printed includes all b)2.546 F .047 +(uiltins, with an indication of whether or not each)-.2 F .281(is enabled.)144 +696 R F1(enable)5.281 E F0(accepts)2.781 E F12.781 E F0 .281(as a synon) +2.781 F .281(ym for)-.15 F F1(\255all)2.781 E F0 5.281(.T)C .28(he return v) +370.81 696 R .28(alue is 0 unless a)-.25 F F2(name)2.78 E F0 .28(is not a)2.78 +F(shell b)144 708 Q(uiltin.)-.2 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(27)530 +768 Q EP +%%Page: 28 28 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF -2.3 -.15(ev a)108 84 T(l).15 E F0([)2.5 E/F2 10 +/Times-Italic@0 SF(ar)A(g)-.37 E F0(...])2.5 E(The)144 96 Q F2(ar)3.17 E(g)-.37 +E F0 3.17(sa)C .671(re read and concatenated together into a single command.) +187.74 96 R .671(This command is then read)5.671 F .165(and e)144 108 R -.15 +(xe)-.15 G .165(cuted by the shell, and its e).15 F .165 +(xit status is returned as the v)-.15 F .165(alue of the)-.25 F F1 -2.3 -.15 +(ev a)2.664 H(l).15 E F0 2.664(command. If)2.664 F(there)2.664 E(are no)144 120 +Q F2(ar)2.5 E(gs)-.37 E F0 2.5(,o).27 G 2.5(ro)198.89 120 S(nly null ar)209.72 +120 Q(guments,)-.18 E F1 -2.3 -.15(ev a)2.5 H(l).15 E F0(returns true.)2.5 E F1 +(exec)108 136.8 Q F0([[)2.5 E F1A F0(])A F2(command)2.5 E F0([)2.5 E F2(ar) +A(guments)-.37 E F0(]])A(If)144 148.8 Q F2(command)2.91 E F0 .41 +(is speci\214ed, it replaces the shell.)2.91 F .41(No ne)5.41 F 2.91(wp)-.25 G +.41(rocess is created.)371.42 148.8 R(The)5.41 E F2(ar)2.91 E(guments)-.37 E F0 +(become)2.91 E 1.239(the ar)144 160.8 R 1.239(guments to)-.18 F F2(command) +3.739 E F0 6.239(.I)C 3.739(ft)267.646 160.8 S 1.239(he \214rst ar)277.495 +160.8 R 1.238(gument is)-.18 F F13.738 E F0 3.738(,t)C 1.238 +(he shell places a dash in the zeroth ar)376.426 160.8 R(g)-.18 E 1.048 +(passed to)144 172.8 R F2(command)3.548 E F0 6.048(.T).77 G 1.048 +(his is what login does.)239.844 172.8 R 1.048(If the \214le cannot be e)6.048 +F -.15(xe)-.15 G 1.049(cuted for some reason, a).15 F(non-interacti)144 184.8 Q +.911 -.15(ve s)-.25 H .611(hell e).15 F .611(xits, unless the shell v)-.15 F +(ariable)-.25 E F1(no_exit_on_failed_exec)3.111 E F0 -.15(ex)3.111 G .611 +(ists, in which case).15 F .332(it returns f)144 196.8 R 2.832(ailure. An)-.1 F +(interacti)2.832 E .632 -.15(ve s)-.25 H .332(hell returns f).15 F .333 +(ailure if the \214le cannot be e)-.1 F -.15(xe)-.15 G 2.833(cuted. If).15 F F2 +(command)2.833 E F0(is)2.833 E(not speci\214ed, an)144 208.8 Q 2.5(yr)-.15 G +(edirections tak)219.95 208.8 Q 2.5(ee)-.1 G -.25(ff)289.83 208.8 S +(ect in the current shell, and the return status is 0.).25 E F1(exit)108 225.6 +Q F0([)2.5 E F2(n)A F0 6.29(]C)C .123(ause the shell to e)150.67 225.6 R .123 +(xit with a status of)-.15 F F2(n)2.623 E F0 5.123(.I)C(f)315.07 225.6 Q F2(n) +2.623 E F0 .123(is omitted, the e)2.623 F .122 +(xit status is that of the last command)-.15 F -.15(exe)144 237.6 S 2.5 +(cuted. A).15 F(trap on)2.5 E/F3 9/Times-Bold@0 SF(EXIT)2.5 E F0(is e)2.25 E +-.15(xe)-.15 G(cuted before the shell terminates.).15 E F1(export)108 254.4 Q +F0([)2.5 E F1(\255nf)A F0 2.5(][).833 G F2(name)166.183 254.4 Q F0([=)A F2(wor) +A(d)-.37 E F0(]] ...)A F1(export \255p)108 266.4 Q F0 .305(The supplied)144 +278.4 R F2(names)2.805 E F0 .305(are mark)2.805 F .305(ed for automatic e)-.1 F +.306(xport to the en)-.15 F .306(vironment of subsequently e)-.4 F -.15(xe)-.15 +G(cuted).15 E 2.694(commands. If)144 290.4 R(the)2.694 E F12.694 E F0 +.193(option is gi)2.693 F -.15(ve)-.25 G .193(n, the).15 F F2(names)2.693 E F0 +.193(refer to functions.)2.693 F .193(If no)5.193 F F2(names)2.693 E F0 .193 +(are gi)2.693 F -.15(ve)-.25 G .193(n, or if the).15 F F1144 302.4 Q F0 +.659(option is supplied, a list of all names that are e)3.159 F .66 +(xported in this shell is printed.)-.15 F(The)5.66 E F13.16 E F0(option) +3.16 E .538(causes the e)144 314.4 R .538(xport property to be remo)-.15 F -.15 +(ve)-.15 G 3.037(df).15 G .537(rom the named v)318.104 314.4 R 3.037 +(ariables. An)-.25 F(ar)3.037 E .537(gument of)-.18 F F13.037 E F0 +(disables)3.037 E .665(option checking for the rest of the ar)144 326.4 R +(guments.)-.18 E F1(export)5.665 E F0 .665(returns an e)3.165 F .666 +(xit status of 0 unless an ille)-.15 F -.05(ga)-.15 G(l).05 E .32 +(option is encountered, one of the)144 338.4 R F2(names)2.82 E F0 .32 +(is not a le)2.82 F -.05(ga)-.15 G 2.82(ls).05 G .32(hell v)366.18 338.4 R .32 +(ariable name, or)-.25 F F12.82 E F0 .32(is supplied with a)2.82 F F2 +(name)144 350.4 Q F0(that is not a function.)2.5 E F1(fc)108 367.2 Q F0([)2.5 E +F1A F2(ename)2.5 E F0 2.5(][)C F1(\255nlr)169.5 367.2 Q F0 2.5(][)C F2 +<8c72>197.14 367.2 Q(st)-.1 E F0 2.5(][)C F2(last)221.76 367.2 Q F0(])A F1 +(fc \255s)108 379.2 Q F0([)2.5 E F2(pat)A F0(=)A F2 -.37(re)C(p).37 E F0 2.5 +(][)C F2(cmd)174.23 379.2 Q F0(])A .664(Fix Command.)144 391.2 R .664 +(In the \214rst form, a range of commands from)5.664 F F2<8c72>3.165 E(st)-.1 E +F0(to)3.165 E F2(last)3.165 E F0 .665(is selected from the his-)3.165 F .968 +(tory list.)144 403.2 R F2 -.45(Fi)5.967 G -.1(rs).45 G(t).1 E F0(and)3.467 E +F2(last)3.467 E F0 .967 +(may be speci\214ed as a string \(to locate the last command be)3.467 F .967 +(ginning with)-.15 F .797(that string\) or as a number \(an inde)144 415.2 R +3.297(xi)-.15 G .797(nto the history list, where a ne)300.753 415.2 R -.05(ga) +-.15 G(ti).05 E 1.097 -.15(ve n)-.25 H .797(umber is used as an).15 F(of)144 +427.2 Q .322(fset from the current command number\).)-.25 F(If)5.322 E F2(last) +2.822 E F0 .322(is not speci\214ed it is set to the current command)2.822 F +.019(for listing \(so that)144 439.2 R F1 .019(fc \255l \25510)2.519 F F0 .019 +(prints the last 10 commands\) and to)2.519 F F2<8c72>2.519 E(st)-.1 E F0 2.519 +(otherwise. If)2.519 F F2<8c72>2.519 E(st)-.1 E F0 .019(is not spec-)2.519 F +(i\214ed it is set to the pre)144 451.2 Q +(vious command for editing and \25516 for listing.)-.25 E(The)144 475.2 Q F1 +2.921 E F0 .421(\215ag suppresses the command numbers when listing.)2.921 +F(The)5.421 E F12.921 E F0 .42(\215ag re)2.92 F -.15(ve)-.25 G .42 +(rses the order of the).15 F 3.642(commands. If)144 487.2 R(the)3.642 E F1 +3.642 E F0 1.142(\215ag is gi)3.642 F -.15(ve)-.25 G 1.142 +(n, the commands are listed on standard output.).15 F 1.142(Otherwise, the) +6.142 F .379(editor gi)144 499.2 R -.15(ve)-.25 G 2.879(nb).15 G(y)199.908 +499.2 Q F2(ename)2.879 E F0 .378(is in)2.879 F -.2(vo)-.4 G -.1(ke).2 G 2.878 +(do).1 G 2.878(na\214)285.712 499.2 S .378(le containing those commands.) +306.468 499.2 R(If)5.378 E F2(ename)2.878 E F0 .378(is not gi)2.878 F -.15(ve) +-.25 G .378(n, the).15 F -.25(va)144 511.2 S .804(lue of the).25 F F3(FCEDIT) +3.304 E F0 -.25(va)3.054 G .804(riable is used, and the v).25 F .805(alue of) +-.25 F F3(EDIT)3.305 E(OR)-.162 E F0(if)3.055 E F3(FCEDIT)3.305 E F0 .805 +(is not set.)3.055 F .805(If neither)5.805 F -.25(va)144 523.2 S 2.218 +(riable is set,).25 F F2(vi)6.384 E F0 2.217(is used.)6.383 F 2.217 +(When editing is complete, the edited commands are echoed and)7.217 F -.15(exe) +144 535.2 S(cuted.).15 E .039(In the second form,)144 559.2 R F2(command)2.539 +E F0 .039(is re-e)2.539 F -.15(xe)-.15 G .039(cuted after each instance of).15 +F F2(pat)2.54 E F0 .04(is replaced by)2.54 F F2 -.37(re)2.54 G(p).37 E F0 5.04 +(.A)C(useful)515.56 559.2 Q 1.009(alias to use with this is `)144 571.2 R 1.008 +(`r=fc \255s')-.74 F 1.008(', so that typing `)-.74 F 1.008(`r cc')-.74 F 3.508 +('r)-.74 G 1.008(uns the last command be)385.39 571.2 R 1.008(ginning with)-.15 +F -.74(``)144 583.2 S(cc').74 E 2.5('a)-.74 G(nd typing `)171.66 583.2 Q(`r') +-.74 E 2.5('r)-.74 G(e-e)233.22 583.2 Q -.15(xe)-.15 G(cutes the last command.) +.15 E .426(If the \214rst form is used, the return v)144 607.2 R .427 +(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.927(lo).05 G .427 +(ption is encountered or)399.768 607.2 R F2<8c72>2.927 E(st)-.1 E F0(or)2.927 E +F2(last)2.927 E F0 .455(specify history lines out of range.)144 619.2 R .454 +(If the)5.454 F F12.954 E F0 .454(option is supplied, the return v)2.954 +F .454(alue is the v)-.25 F .454(alue of the)-.25 F .787(last command e)144 +631.2 R -.15(xe)-.15 G .787(cuted or f).15 F .788 +(ailure if an error occurs with the temporary \214le of commands.)-.1 F .788 +(If the)5.788 F 1.196 +(second form is used, the return status is that of the command re-e)144 643.2 R +-.15(xe)-.15 G 1.196(cuted, unless).15 F F2(cmd)3.696 E F0 1.196(does not)3.696 +F(specify a v)144 655.2 Q(alid history line, in which case)-.25 E F1(fc)2.5 E +F0(returns f)2.5 E(ailure.)-.1 E F1(fg)108 672 Q F0([)2.5 E F2(jobspec)A F0(])A +(Place)144 684 Q F2(jobspec)3.041 E F0 .541(in the fore)3.041 F .542 +(ground, and mak)-.15 F 3.042(ei)-.1 G 3.042(tt)323.06 684 S .542 +(he current job)331.662 684 R 5.542(.I)-.4 G(f)399.258 684 Q F2(jobspec)3.042 E +F0 .542(is not present, the shell')3.042 F(s)-.55 E .958(notion of the)144 696 +R F2(curr)3.458 E .958(ent job)-.37 F F0 .957(is used.)3.457 F .957 +(The return v)5.957 F .957(alue is that of the command placed into the fore-) +-.25 F .194(ground, or f)144 708 R .194 +(ailure if run when job control is disabled or)-.1 F 2.695(,w)-.4 G .195 +(hen run with job control enabled, if)378.655 708 R F2(job-)2.695 E(spec)144 +720 Q F0(does not specify a v)2.5 E(alid job or)-.25 E F2(jobspec)2.5 E F0 +(speci\214es a job that w)2.5 E(as started without job control.)-.1 E 185.675 +(GNU 1995)72 768 R(May 5)2.5 E(28)530 768 Q EP +%%Page: 29 29 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(getopts)108 84 Q/F2 10/Times-Italic@0 SF(optstring name) +2.5 E F0([)2.5 E F2(ar)A(gs)-.37 E F0(])A F1(getopts)144 96 Q F0 .828 +(is used by shell procedures to parse positional parameters.)3.328 F F2 +(optstring)5.827 E F0 .827(contains the option)3.327 F .602 +(letters to be recognized; if a letter is follo)144 108 R .603 +(wed by a colon, the option is e)-.25 F .603(xpected to ha)-.15 F .903 -.15 +(ve a)-.2 H 3.103(na).15 G -.18(rg)523.52 108 S(u-).18 E .7 +(ment, which should be separated from it by white space.)144 120 R .7 +(Each time it is in)5.7 F -.2(vo)-.4 G -.1(ke).2 G(d,).1 E F1(getopts)3.2 E F0 +(places)3.2 E .008(the ne)144 132 R .008(xt option in the shell v)-.15 F +(ariable)-.25 E F2(name)2.508 E F0 2.508(,i).18 G(nitializing)316.884 132 Q F2 +(name)2.508 E F0 .009(if it does not e)2.508 F .009(xist, and the inde)-.15 F +2.509(xo)-.15 G 2.509(ft)521.941 132 S(he)530.56 132 Q(ne)144 144 Q .199(xt ar) +-.15 F .199(gument to be processed into the v)-.18 F(ariable)-.25 E/F3 9 +/Times-Bold@0 SF(OPTIND)2.699 E/F4 9/Times-Roman@0 SF(.)A F3(OPTIND)4.699 E F0 +.198(is initialized to 1 each time the)2.449 F .497 +(shell or a shell script is in)144 156 R -.2(vo)-.4 G -.1(ke).2 G 2.997 +(d. When).1 F .498(an option requires an ar)2.997 F(gument,)-.18 E F1(getopts) +2.998 E F0 .498(places that ar)2.998 F(gu-)-.18 E .028(ment into the v)144 168 +R(ariable)-.25 E F3(OPT)2.528 E(ARG)-.81 E F4(.)A F0 .028 +(The shell does not reset)4.528 F F3(OPTIND)2.528 E F0 .027 +(automatically; it must be manu-)2.278 F .161 +(ally reset between multiple calls to)144 180 R F1(getopts)2.661 E F0 .161 +(within the same shell in)2.661 F -.2(vo)-.4 G .161(cation if a ne).2 F 2.662 +(ws)-.25 G .162(et of param-)490.806 180 R(eters is to be used.)144 192 Q F1 +(getopts)144 216 Q F0 1.252(can report errors in tw)3.752 F 3.752(ow)-.1 G +3.752(ays. If)287.942 216 R 1.252(the \214rst character of)3.752 F F2 +(optstring)3.752 E F0 1.251(is a colon,)3.752 F F2(silent)3.751 E F0(error) +3.751 E 1.442(reporting is used.)144 228 R 1.442 +(In normal operation diagnostic messages are printed when ille)6.442 F -.05(ga) +-.15 G 3.943(lo).05 G 1.443(ptions or)503.277 228 R .654(missing option ar)144 +240 R .653(guments are encountered.)-.18 F .653(If the v)5.653 F(ariable)-.25 E +F3(OPTERR)3.153 E F0 .653(is set to 0, no error message)2.903 F +(will be displayed, e)144 252 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)241.09 252 S +(he \214rst character of)249.7 252 Q F2(optstring)2.5 E F0(is not a colon.)2.5 +E .826(If an ille)144 276 R -.05(ga)-.15 G 3.326(lo).05 G .826(ption is seen,) +199.878 276 R F1(getopts)3.326 E F0 .826(places ? into)3.326 F F2(name)3.326 E +F0 .826(and, if not silent, prints an error message)3.326 F .4(and unsets)144 +288 R F3(OPT)2.9 E(ARG)-.81 E F4(.)A F0(If)4.899 E F1(getopts)2.899 E F0 .399 +(is silent, the option character found is placed in)2.899 F F3(OPT)2.899 E(ARG) +-.81 E F0 .399(and no)2.649 F(diagnostic message is printed.)144 300 Q 1.241 +(If a required ar)144 324 R 1.241(gument is not found, and)-.18 F F1(getopts) +3.741 E F0 1.241(is not silent, a question mark \()3.741 F F1(?).833 E F0 3.742 +(\)i).833 G 3.742(sp)494.746 324 S 1.242(laced in)507.378 324 R F2(name)144 336 +Q F0(,).18 E F1(OPT)3.357 E(ARG)-.9 E F0 .856 +(is unset, and a diagnostic message is printed.)3.357 F(If)5.856 E F1(getopts) +3.356 E F0 .856(is silent, then a colon)3.356 F(\()144 348 Q F1(:).833 E F0 2.5 +(\)i).833 G 2.5(sp)160.936 348 S(laced in)172.326 348 Q F2(name)2.5 E F0(and) +2.5 E F3(OPT)2.5 E(ARG)-.81 E F0(is set to the option character found.)2.25 E +F1(getopts)144 372 Q F0 2.392(normally parses the positional parameters, b) +4.892 F 2.392(ut if more ar)-.2 F 2.393(guments are gi)-.18 F -.15(ve)-.25 G +4.893(ni).15 G(n)509.927 372 Q F2(ar)4.893 E(gs)-.37 E F0(,).27 E F1(getopts) +144 384 Q F0 .651(parses those instead.)3.151 F F1(getopts)5.651 E F0 .651 +(returns true if an option, speci\214ed or unspeci\214ed, is found.)3.151 F +(It returns f)144 396 Q +(alse if the end of options is encountered or an error occurs.)-.1 E F1(hash) +108 412.8 Q F0([)2.5 E F1A F0 2.5(][)C F2(name)153.14 412.8 Q F0(])A -.15 +(Fo)144 424.8 S 2.819(re).15 G(ach)164.999 424.8 Q F2(name)2.819 E F0 2.819(,t) +.18 G .319(he full pathname of the command is determined and remembered.) +211.637 424.8 R(The)5.32 E F12.82 E F0(option)2.82 E .508 +(causes the shell to for)144 436.8 R .508(get all remembered locations.)-.18 F +.508(If no ar)5.508 F .508(guments are gi)-.18 F -.15(ve)-.25 G .507 +(n, information about).15 F .193(remembered commands is printed.)144 448.8 R +.193(An ar)5.193 F .193(gument of)-.18 F F12.693 E F0 .194 +(disables option checking for the rest of the)2.693 F(ar)144 460.8 Q 2.5 +(guments. The)-.18 F(return status is true unless a)2.5 E F2(name)2.5 E F0 +(is not found or an ille)2.5 E -.05(ga)-.15 G 2.5(lo).05 G(ption is supplied.) +453.86 460.8 Q F1(help)108 477.6 Q F0([)2.5 E F2(pattern)A F0(])A .991 +(Display helpful information about b)144 489.6 R .991(uiltin commands.)-.2 F +(If)5.991 E F2(pattern)3.491 E F0 .991(is speci\214ed,)3.491 F F1(help)3.491 E +F0(gi)3.49 E -.15(ve)-.25 G 3.49(sd).15 G(etailed)513.34 489.6 Q .408 +(help on all commands matching)144 501.6 R F2(pattern)2.909 E F0 2.909(;o).24 G +.409(therwise a list of the b)316.13 501.6 R .409(uiltins is printed.)-.2 F +.409(The return sta-)5.409 F(tus is 0 unless no command matches)144 513.6 Q F2 +(pattern)2.5 E F0(.).24 E F1(history)108 530.4 Q F0([)2.5 E F2(n)A F0(])A F1 +(history \255rwan)108 542.4 Q F0([)2.5 E F2(\214lename)A F0(])A -.4(Wi)144 +554.4 S .752 +(th no options, display the command history list with line numbers.).4 F .752 +(Lines listed with a)5.752 F F1(*)3.251 E F0(ha)3.251 E -.15(ve)-.2 G .375 +(been modi\214ed.)144 566.4 R .375(An ar)5.375 F .375(gument of)-.18 F F2(n) +2.875 E F0 .375(lists only the last)2.875 F F2(n)2.875 E F0 2.875(lines. If) +2.875 F 2.876(an)2.876 G .376(on-option ar)411.832 566.4 R .376 +(gument is supplied,)-.18 F .811 +(it is used as the name of the history \214le; if not, the v)144 578.4 R .811 +(alue of)-.25 F F3(HISTFILE)3.311 E F0 .811(is used.)3.061 F .811 +(Options, if sup-)5.811 F(plied, ha)144 590.4 Q .3 -.15(ve t)-.2 H(he follo).15 +E(wing meanings:)-.25 E F1144 602.4 Q F0 .598(Append the `)180 602.4 R +(`ne)-.74 E(w')-.25 E 3.098('h)-.74 G .598 +(istory lines \(history lines entered since the be)266.424 602.4 R .599 +(ginning of the current)-.15 F F1(bash)180 614.4 Q F0 +(session\) to the history \214le)2.5 E F1144 626.4 Q F0 .854(Read the hi\ +story lines not already read from the history \214le into the current history \ +list.)180 626.4 R .772 +(These are lines appended to the history \214le since the be)180 638.4 R .773 +(ginning of the current)-.15 F F1(bash)3.273 E F0(ses-)3.273 E(sion.)180 650.4 +Q F1144 662.4 Q F0 +(Read the contents of the history \214le and use them as the current history) +180 662.4 Q F1144 674.4 Q F0 +(Write the current history to the history \214le, o)180 674.4 Q -.15(ve)-.15 G +(rwriting the history \214le').15 E 2.5(sc)-.55 G(ontents.)474.4 674.4 Q .989 +(The return v)144 691.2 R .989(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G +3.489(lo).05 G .989(ption is encountered or an error occurs while reading or) +308.662 691.2 R(writing the history \214le.)144 703.2 Q 185.675(GNU 1995)72 768 +R(May 5)2.5 E(29)530 768 Q EP +%%Page: 30 30 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(jobs)108 84 Q F0([)2.5 E F1(\255lnp)A F0 2.5(][)C/F2 10 +/Times-Italic@0 SF(jobspec)A F0(... ])2.5 E F1(jobs \255x)108 96 Q F2(command) +2.5 E F0([)2.5 E F2(ar)2.5 E(gs)-.37 E F0(... ])2.5 E .297 +(The \214rst form lists the acti)144 108 R .598 -.15(ve j)-.25 H 2.798 +(obs. The).15 F F12.798 E F0 .298 +(option lists process IDs in addition to the normal infor)2.798 F(-)-.2 E .746 +(mation; the)144 120 R F13.246 E F0 .745 +(option lists only the process ID of the job')3.246 F 3.245(sp)-.55 G .745 +(rocess group leader)394.205 120 R 5.745(.T)-.55 G(he)487.25 120 Q F1 +3.245 E F0(option)3.245 E 2.08(displays only jobs that ha)144 132 R 2.38 -.15 +(ve c)-.2 H 2.081(hanged status since last noti\214ed.).15 F(If)7.081 E F2 +(jobspec)4.581 E F0 2.081(is gi)4.581 F -.15(ve)-.25 G 2.081(n, output is).15 F +.727(restricted to information about that job)144 144 R 5.727(.T)-.4 G .727 +(he return status is 0 unless an ille)316.282 144 R -.05(ga)-.15 G 3.227(lo).05 +G .726(ption is encoun-)474.108 144 R(tered or an ille)144 156 Q -.05(ga)-.15 G +(l).05 E F2(jobspec)2.5 E F0(is supplied.)2.5 E .607(If the)144 180 R F1 +3.107 E F0 .607(option is supplied,)3.107 F F1(jobs)3.107 E F0 .607 +(replaces an)3.107 F(y)-.15 E F2(jobspec)3.107 E F0 .607(found in)3.107 F F2 +(command)3.107 E F0(or)3.107 E F2(ar)3.107 E(gs)-.37 E F0 .607(with the corre-) +3.107 F(sponding process group ID, and e)144 192 Q -.15(xe)-.15 G(cutes).15 E +F2(command)2.5 E F0(passing it)2.5 E F2(ar)2.5 E(gs)-.37 E F0 2.5(,r).27 G +(eturning its e)418.56 192 Q(xit status.)-.15 E F1(kill)108 208.8 Q F0([)2.5 E +F1(-s sigspec)A F0(|)2.5 E F1(\255sigspec)2.5 E F0 2.5(][)C F2(pid)219.31 208.8 +Q F0(|)2.5 E F2(jobspec)2.5 E F0 2.5(].)C(..)277.97 208.8 Q F1(kill \255l)108 +220.8 Q F0([)2.5 E F2(signum)A F0(])A .943(Send the signal named by)144 232.8 R +F2(sigspec)3.443 E F0 .942(to the processes named by)3.443 F F2(pid)3.442 E F0 +(or)3.442 E F2(jobspec)3.442 E F0(.).31 E F2(sigspec)5.942 E F0 .942 +(is either a)3.442 F .908(signal name such as)144 244.8 R/F3 9/Times-Bold@0 SF +(SIGKILL)3.408 E F0 .908(or a signal number)3.158 F 5.908(.I)-.55 G(f)359.638 +244.8 Q F2(sigspec)3.408 E F0 .908(is a signal name, the name is case)3.408 F +(insensiti)144 256.8 Q 2.43 -.15(ve a)-.25 H 2.13(nd may be gi).15 F -.15(ve) +-.25 G 4.63(nw).15 G 2.13(ith or without the)279.67 256.8 R F3(SIG)4.63 E F0 +4.629(pre\214x. If)4.379 F F2(sigspec)4.629 E F0 2.129(is not present, then) +4.629 F F3(SIGTERM)144 268.8 Q F0 .813(is assumed.)3.063 F .813(An ar)5.813 F +.813(gument of)-.18 F F13.313 E F0 .814(lists the signal names.)3.313 F +.814(If an)5.814 F 3.314(ya)-.15 G -.18(rg)450.232 268.8 S .814 +(uments are supplied).18 F(when)144 280.8 Q F12.827 E F0 .327(is gi)2.827 +F -.15(ve)-.25 G .327(n, the names of the speci\214ed signals are listed, and \ +the return status is 0.).15 F .326(An ar)5.326 F(gu-)-.18 E .484(ment of)144 +292.8 R F12.984 E F0 .484 +(disables option checking for the rest of the ar)2.984 F(guments.)-.18 E F1 +(kill)5.485 E F0 .485(returns true if at least one)2.985 F(signal w)144 304.8 Q +(as successfully sent, or f)-.1 E(alse if an error occurs or an ille)-.1 E -.05 +(ga)-.15 G 2.5(lo).05 G(ption is encountered.)419.09 304.8 Q F1(let)108 321.6 Q +F2(ar)2.5 E(g)-.37 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Each)144 333.6 Q +F2(ar)3.677 E(g)-.37 E F0 1.177(is an arithmetic e)3.677 F 1.177 +(xpression to be e)-.15 F -.25(va)-.25 G 1.177(luated \(see).25 F F3 1.176 +(ARITHMETIC EV)3.677 F(ALU)-1.215 E -.855(AT)-.54 G(ION).855 E/F4 9 +/Times-Roman@0 SF(\).)A F0 1.176(If the)5.676 F(last)144 345.6 Q F2(ar)2.5 E(g) +-.37 E F0 -.25(eva)2.5 G(luates to 0,).25 E F1(let)2.5 E F0 +(returns 1; 0 is returned otherwise.)2.5 E F1(local)108 362.4 Q F0([)2.5 E F2 +(name)A F0([=)A F2(value)A F0 2.5(].)C(..])194.45 362.4 Q -.15(Fo)144 374.4 S +3.276(re).15 G .776(ach ar)165.456 374.4 R .776(gument, create a local v)-.18 F +.776(ariable named)-.25 F F2(name)3.276 E F0 3.276(,a).18 G .776(nd assign it) +380.784 374.4 R F2(value)3.276 E F0 5.777(.W).18 G(hen)470.729 374.4 Q F1 +(local)3.277 E F0 .777(is used)3.277 F .131(within a function, it causes the v) +144 386.4 R(ariable)-.25 E F2(name)2.631 E F0 .131(to ha)2.631 F .431 -.15 +(ve a v)-.2 H .13(isible scope restricted to that function and).15 F .232 +(its children.)144 398.4 R -.4(Wi)5.232 G .232(th no operands,).4 F F1(local) +2.733 E F0 .233(writes a list of local v)2.733 F .233 +(ariables to the standard output.)-.25 F .233(It is an)5.233 F .42 +(error to use)144 410.4 R F1(local)2.92 E F0 .42(when not within a function.) +2.92 F .42(The return status is 0 unless)5.42 F F1(local)2.92 E F0 .42 +(is used outside a)2.92 F(function, or an ille)144 422.4 Q -.05(ga)-.15 G(l).05 +E F2(name)2.5 E F0(is supplied.)2.5 E F1(logout)108 439.2 Q F0 +(Exit a login shell.)9.33 E F1(popd)108 456 Q F0([)2.5 E F1(+/\255n)A F0(])A +(Remo)144 468 Q -.15(ve)-.15 G 2.799(se).15 G .299 +(ntries from the directory stack.)188.159 468 R -.4(Wi)5.299 G .299(th no ar).4 +F .299(guments, remo)-.18 F -.15(ve)-.15 G 2.799(st).15 G .3 +(he top directory from the)438.82 468 R(stack, and performs a)144 480 Q F1(cd) +2.5 E F0(to the ne)2.5 E 2.5(wt)-.25 G(op directory)291.22 480 Q(.)-.65 E F1 +(+n)144 492 Q F0(remo)180 492 Q -.15(ve)-.15 G 2.849(st).15 G(he)219.209 492 Q +F2(n)2.849 E F0 .349(th entry counting from the left of the list sho)B .349 +(wn by)-.25 F F1(dirs)2.848 E F0 2.848(,s)C .348(tarting with zero.)470.704 492 +R -.15(Fo)180 504 S 2.5(re).15 G(xample: `)200.53 504 Q(`popd +0')-.74 E 2.5 +('r)-.74 G(emo)286.06 504 Q -.15(ve)-.15 G 2.5(st).15 G(he \214rst directory) +321.59 504 Q 2.5(,`)-.65 G(`popd +1')394.63 504 Q 2.5('t)-.74 G(he second.) +442.3 504 Q F1144 516 Q F0(remo)180 516 Q -.15(ve)-.15 G 2.501(st).15 G +(he)218.861 516 Q F2(n)2.501 E F0 .001 +(th entry counting from the right of the list sho)B .001(wn by)-.25 F F1(dirs) +2.502 E F0 2.502(,s)C .002(tarting with zero.)471.396 516 R -.15(Fo)180 528 S +2.5(re).15 G(xample: `)200.53 528 Q(`popd -0')-.74 E 2.5('r)-.74 G(emo)283.75 +528 Q -.15(ve)-.15 G 2.5(st).15 G(he last directory)319.28 528 Q 2.5(,`)-.65 G +(`popd -1')390.65 528 Q 2.5('t)-.74 G(he ne)436.01 528 Q(xt to last.)-.15 E +.644(If the)144 544.8 R F1(popd)3.144 E F0 .644(command is successful, a)3.144 +F F1(dirs)3.143 E F0 .643(is performed as well, and the return status is 0.) +3.143 F F1(popd)5.643 E F0 .57(returns f)144 556.8 R .57(alse if an ille)-.1 F +-.05(ga)-.15 G 3.07(lo).05 G .571 +(ption is encountered, the directory stack is empty)251.25 556.8 R 3.071(,an) +-.65 G(on-e)469.319 556.8 Q .571(xistent direc-)-.15 F +(tory stack entry is speci\214ed, or the directory change f)144 568.8 Q(ails.) +-.1 E F1(pushd)108 585.6 Q F0([)2.5 E F2(dir)A F0(])A F1(pushd +/\255n)108 +597.6 Q F0 .64(Adds a directory to the top of the directory stack, or rotates \ +the stack, making the ne)144 609.6 R 3.139(wt)-.25 G .639(op of the)503.172 +609.6 R 1.315(stack the current w)144 621.6 R 1.315(orking directory)-.1 F +6.315(.W)-.65 G 1.315(ith no ar)306.885 621.6 R 1.315(guments, e)-.18 F 1.316 +(xchanges the top tw)-.15 F 3.816(od)-.1 G 1.316(irectories and)484.534 621.6 R +(returns 0, unless the directory stack is empty)144 633.6 Q(.)-.65 E F1(+n)144 +645.6 Q F0 1.268(Rotates the stack so that the)180 645.6 R F2(n)3.768 E F0 +1.267(th directory \(counting from the left of the list sho)B 1.267(wn by)-.25 +F F1(dirs)180 657.6 Q F0 2.5(\)i)C 2.5(sa)205.28 657.6 S 2.5(tt)216.11 657.6 S +(he top.)224.17 657.6 Q F1144 669.6 Q F0(Rotates the stack so that the) +180 669.6 Q F2(n)2.5 E F0 +(th directory \(counting from the right\) is at the top.)A F1(dir)144 681.6 Q +F0(adds)180 681.6 Q F2(dir)2.5 E F0 +(to the directory stack at the top, making it the ne)2.5 E 2.5(wc)-.25 G +(urrent w)422.5 681.6 Q(orking directory)-.1 E(.)-.65 E .488(If the)144 698.4 R +F1(pushd)2.988 E F0 .488(command is successful, a)2.988 F F1(dirs)2.988 E F0 +.488(is performed as well.)2.988 F .489(If the \214rst form is used,)5.488 F F1 +(pushd)2.989 E F0 1.103(returns 0 unless the cd to)144 710.4 R F2(dir)3.603 E +F0 -.1(fa)3.603 G 3.603(ils. W).1 F 1.103(ith the second form,)-.4 F F1(pushd) +3.603 E F0 1.103(returns 0 unless the directory)3.603 F .846(stack is empty)144 +722.4 R 3.346(,an)-.65 G(on-e)220.894 722.4 Q .847(xistant directory stack ele\ +ment is speci\214ed, or the directory change to the)-.15 F 185.675(GNU 1995)72 +768 R(May 5)2.5 E(30)530 768 Q EP +%%Page: 31 31 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(speci\214ed ne)144 84 Q 2.5(wc)-.25 G(urrent directory f)205.4 84 Q(ails.)-.1 +E/F1 10/Times-Bold@0 SF(pwd)108 100.8 Q F0 .725 +(Print the absolute pathname of the current w)144 100.8 R .724 +(orking directory)-.1 F 5.724(.T)-.65 G .724(he path printed contains no sym-) +405.56 100.8 R .521(bolic links if the)144 112.8 R F13.021 E F0 .521 +(option to the)3.021 F F1(set)3.021 E F0 -.2(bu)3.021 G .521 +(iltin command is set.).2 F .521(See also the description of)5.521 F F1 +(nolinks)3.022 E F0(under)144 124.8 Q F1 .074(Shell V)2.574 F(ariables)-.92 E +F0(abo)2.574 E -.15(ve)-.15 G 2.574(\). The).15 F .074 +(return status is 0 unless an error occurs while reading the path-)2.574 F +(name of the current directory)144 136.8 Q(.)-.65 E F1 -.18(re)108 153.6 S(ad) +.18 E F0([)2.5 E F1A F0 2.5(][)C/F2 10/Times-Italic@0 SF(name)152.39 +153.6 Q F0(...])2.5 E .036 +(One line is read from the standard input, and the \214rst w)144 165.6 R .037 +(ord is assigned to the \214rst)-.1 F F2(name)2.537 E F0 2.537(,t).18 G .037 +(he second)500.253 165.6 R -.1(wo)144 177.6 S .109(rd to the second).1 F F2 +(name)2.609 E F0 2.609(,a).18 G .109(nd so on, with lefto)254.045 177.6 R -.15 +(ve)-.15 G 2.609(rw).15 G .109(ords assigned to the last)354.18 177.6 R F2 +(name)2.609 E F0 5.109(.O).18 G .108(nly the char)489.444 177.6 R(-)-.2 E .143 +(acters in)144 189.6 R/F3 9/Times-Bold@0 SF(IFS)2.643 E F0 .143 +(are recognized as w)2.393 F .143(ord delimiters.)-.1 F .143(If no)5.143 F F2 +(names)2.643 E F0 .144(are supplied, the line read is assigned)2.643 F .194 +(to the v)144 201.6 R(ariable)-.25 E F3(REPL)2.694 E(Y)-.828 E/F4 9 +/Times-Roman@0 SF(.)A F0 .194 +(The return code is zero, unless end-of-\214le is encountered.)4.694 F .193 +(If the)5.193 F F12.693 E F0(option)2.693 E .444(is gi)144 213.6 R -.15 +(ve)-.25 G .444(n, a backslash-ne).15 F .444 +(wline pair is not ignored, and the backslash is considered to be part of the) +-.25 F(line.)144 225.6 Q F1 -.18(re)108 242.4 S(adonly).18 E F0([)2.5 E F1 +A F0 2.5(][)C F2(name)169.62 242.4 Q F0(...])2.5 E F1 -.18(re)108 254.4 S +(adonly -p).18 E F0 .419(The gi)144 266.4 R -.15(ve)-.25 G(n).15 E F2(names) +2.919 E F0 .419(are mark)2.919 F .419(ed readonly and the v)-.1 F .419 +(alues of these)-.25 F F2(names)2.919 E F0 .418(may not be changed by sub-) +2.919 F .541(sequent assignment.)144 278.4 R .541(If the)5.541 F F13.041 +E F0 .541(option is supplied, the functions corresponding to the)3.041 F F2 +(names)3.042 E F0 .542(are so)3.042 F(mark)144 290.4 Q 3.037(ed. If)-.1 F .537 +(no ar)3.037 F .537(guments are gi)-.18 F -.15(ve)-.25 G .536(n, or if the).15 +F F13.036 E F0 .536(option is supplied, a list of all readonly names is) +3.036 F 2.501(printed. An)144 302.4 R(ar)2.501 E .002(gument of)-.18 F F1 +2.502 E F0 .002(disables option checking for the rest of the ar)2.502 F 2.502 +(guments. The)-.18 F .002(return sta-)2.502 F .192(tus is 0 unless an ille)144 +314.4 R -.05(ga)-.15 G 2.692(lo).05 G .192(ption is encountered, one of the) +247.732 314.4 R F2(names)2.691 E F0 .191(is not a le)2.691 F -.05(ga)-.15 G +2.691(ls).05 G .191(hell v)463.498 314.4 R .191(ariable name,)-.25 F(or)144 +326.4 Q F12.5 E F0(is supplied with a)2.5 E F2(name)2.5 E F0 +(that is not a function.)2.5 E F1 -.18(re)108 343.2 S(tur).18 E(n)-.15 E F0([) +2.5 E F2(n)A F0(])A .618(Causes a function to e)144 355.2 R .618 +(xit with the return v)-.15 F .618(alue speci\214ed by)-.25 F F2(n)3.118 E F0 +5.619(.I).24 G(f)404.557 355.2 Q F2(n)3.119 E F0 .619 +(is omitted, the return status is)3.119 F 1.335(that of the last command e)144 +367.2 R -.15(xe)-.15 G 1.335(cuted in the function body).15 F 6.335(.I)-.65 G +3.835(fu)387.48 367.2 S 1.335(sed outside a function, b)399.645 367.2 R 1.335 +(ut during)-.2 F -.15(exe)144 379.2 S .794(cution of a script by the).15 F F1 +(.)3.294 E F0(\()5.794 E F1(sour)A(ce)-.18 E F0 3.294(\)c)C .794 +(ommand, it causes the shell to stop e)309.832 379.2 R -.15(xe)-.15 G .795 +(cuting that script).15 F .278(and return either)144 391.2 R F2(n)2.778 E F0 +.278(or the e)2.778 F .277(xit status of the last command e)-.15 F -.15(xe)-.15 +G .277(cuted within the script as the e).15 F .277(xit sta-)-.15 F .081 +(tus of the script.)144 403.2 R .082 +(If used outside a function and not during e)5.082 F -.15(xe)-.15 G .082 +(cution of a script by).15 F F1(.)2.582 E F0 2.582(,t).833 G .082 +(he return sta-)487.076 403.2 R(tus is f)144 415.2 Q(alse.)-.1 E F1(set)108 432 +Q F0([)2.5 E F1(\255\255abefhkmnptuvxldCHP)A F0 2.5(][)C F1(-o)243.29 432 Q F2 +(option)2.5 E F0 2.5(][)C F2(ar)288.84 432 Q(g)-.37 E F0(...])2.5 E F1144 +444 Q F0 1.036(Automatically mark v)184 444 R 1.036 +(ariables which are modi\214ed or created for e)-.25 F 1.035(xport to the en) +-.15 F(viron-)-.4 E(ment of subsequent commands.)184 456 Q F1144 468 Q F0 +.721(Cause the status of terminated background jobs to be reported immediately) +184 468 R 3.221(,r)-.65 G .721(ather than)499.569 468 R(before the ne)184 480 Q +(xt primary prompt.)-.15 E(\(Also see)5 E F1(notify)2.5 E F0(under)2.5 E F1 +(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1 +144 492 Q F0 1.772(Exit immediately if a)184 492 R F2(simple-command)4.272 E F0 +(\(see)4.272 E F3 1.772(SHELL GRAMMAR)4.272 F F0(abo)4.022 E -.15(ve)-.15 G +4.271(\)e).15 G 1.771(xits with a)494.788 492 R .642(non\255zero status.)184 +504 R .642(The shell does not e)5.642 F .642(xit if the command that f)-.15 F +.643(ails is part of an)-.1 F F2(until)3.143 E F0(or)3.143 E F2(while)184 516 Q +F0 .728(loop, part of an)3.228 F F2(if)3.228 E F0 .728(statement, part of a) +3.228 F F1(&&)3.228 E F0(or)3.228 E/F5 10/Symbol SF 1.6663.228 G F0 .728 +(list, or if the command')1.562 F 3.228(sr)-.55 G(eturn)519.45 516 Q -.25(va) +184 528 S(lue is being in).25 E -.15(ve)-.4 G(rted via).15 E F1(!)2.5 E F0(.)A +F1144 540 Q F0(Disable pathname e)184 540 Q(xpansion.)-.15 E F1144 +552 Q F0 .106 +(Locate and remember function commands as functions are de\214ned.)184 552 R +.106(Function commands)5.106 F(are normally look)184 564 Q +(ed up when the function is e)-.1 E -.15(xe)-.15 G(cuted.).15 E F1144 576 +Q F0 .162(All k)184 576 R -.15(ey)-.1 G -.1(wo).15 G .162(rd ar).1 F .162 +(guments are placed in the en)-.18 F .161 +(vironment for a command, not just those that)-.4 F(precede the command name.) +184 588 Q F1144 600 Q F0 .009(Monitor mode.)184 600 R .009 +(Job control is enabled.)5.009 F .009(This \215ag is on by def)5.009 F .01 +(ault for interacti)-.1 F .31 -.15(ve s)-.25 H .01(hells on).15 F .124 +(systems that support it \(see)184 612 R F3 .124(JOB CONTR)2.624 F(OL)-.27 E F0 +(abo)2.374 E -.15(ve)-.15 G 2.624(\). Background).15 F .124 +(processes run in a sep-)2.624 F .72 +(arate process group and a line containing their e)184 624 R .721 +(xit status is printed upon their comple-)-.15 F(tion.)184 636 Q F1144 +648 Q F0 .653(Read commands b)184 648 R .653(ut do not e)-.2 F -.15(xe)-.15 G +.653(cute them.).15 F .652(This may be used to check a shell script for)5.653 F +(syntax errors.)184 660 Q(This is ignored for interacti)5 E .3 -.15(ve s)-.25 H +(hells.).15 E F1144 672 Q F2(option-name)2.5 E F0(The)184 684 Q F2 +(option-name)2.5 E F0(can be one of the follo)2.5 E(wing:)-.25 E F1(allexport) +184 696 Q F0(Same as)224 708 Q F12.5 E F0(.)A 185.675(GNU 1995)72 768 R +(May 5)2.5 E(31)530 768 Q EP +%%Page: 32 32 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF(braceexpand)184 84 Q F0 .312(The shell performs brace e) +224 96 R .313(xpansion \(see)-.15 F F1 .313(Brace Expansion)2.813 F F0(abo) +2.813 E -.15(ve)-.15 G 2.813(\). This).15 F .313(is on)2.813 F(by def)224 108 Q +(ault.)-.1 E F1(emacs)184 120 Q F0 .089 +(Use an emacs-style command line editing interf)224 120 R 2.589(ace. This)-.1 F +.089(is enabled by def)2.589 F(ault)-.1 E .128(when the shell is interacti)224 +132 R -.15(ve)-.25 G 2.628(,u).15 G .128(nless the shell is started with the) +345.89 132 R F1(\255nolineediting)2.629 E F0(option.)224 144 Q F1(err)184 156 Q +(exit)-.18 E F0(Same as)224 156 Q F12.5 E F0(.)A F1(histexpand)184 168 Q +F0(Same as)224 180 Q F12.5 E F0(.)A F1(ignor)184 192 Q(eeof)-.18 E F0 +1.024(The ef)224 204 R 1.024 +(fect is as if the shell command `IGNOREEOF=10' had been e)-.25 F -.15(xe)-.15 +G(cuted).15 E(\(see)224 216 Q F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E +-.15(ve)-.15 G(\).).15 E F1(interacti)184 228 Q -.1(ve)-.1 G(\255comments).1 E +F0(Allo)224 240 Q 2.52(waw)-.25 G .02(ord be)265.35 240 R .021(ginning with) +-.15 F F1(#)2.521 E F0 .021(to cause that w)2.521 F .021 +(ord and all remaining characters)-.1 F +(on that line to be ignored in an interacti)224 252 Q .3 -.15(ve s)-.25 H +(hell \(see).15 E/F2 9/Times-Bold@0 SF(COMMENTS)2.5 E F0(abo)2.25 E -.15(ve) +-.15 G(\).).15 E F1(monitor)184 264 Q F0(Same as)5.56 E F12.5 E F0(.)A F1 +(noclob)184 276 Q(ber)-.1 E F0(Same as)224 288 Q F12.5 E F0(.)A F1 +(noexec)184 300 Q F0(Same as)224 300 Q F12.5 E F0(.)A F1(noglob)184 312 Q +F0(Same as)224 312 Q F12.5 E F0(.)A F1(nohash)184 324 Q F0(Same as)9.43 E +F12.5 E F0(.)A F1(notify)184 336 Q F0(Same as)224 336 Q F12.5 E F0 +(.)A F1(nounset)184 348 Q F0(Same as)6.66 E F12.5 E F0(.)A F1(ph)184 360 +Q(ysical)-.15 E F0(Same as)5.14 E F12.5 E F0(.)A F1(posix)184 372 Q F0 +2.244(Change the beha)224 372 R 2.244(vior of bash where the def)-.2 F 2.243 +(ault operation dif)-.1 F 2.243(fers from the)-.25 F +(Posix 1003.2 standard to match the standard.)224 384 Q F1(pri)184 396 Q +(vileged)-.1 E F0(Same as)224 408 Q F12.5 E F0(.)A F1 -.1(ve)184 420 S +(rbose).1 E F0(Same as)7.33 E F12.5 E F0(.)A F1(vi)184 432 Q F0 +(Use a vi-style command line editing interf)224 432 Q(ace.)-.1 E F1(xtrace)184 +444 Q F0(Same as)224 444 Q F12.5 E F0(.)A(If no)184 456 Q/F3 10 +/Times-Italic@0 SF(option-name)2.5 E F0(is supplied, the v)2.5 E +(alues of the current options are printed.)-.25 E F1144 468 Q F0 -.45(Tu) +184 468 S .521(rn on).45 F F3(privile)3.021 E -.1(ge)-.4 G(d).1 E F0 3.021 +(mode. In)3.021 F .521(this mode, the)3.021 F F1($ENV)3.021 E F0 .522 +(\214le is not processed, and shell func-)3.021 F .26 +(tions are not inherited from the en)184 480 R 2.76(vironment. This)-.4 F .26 +(is enabled automatically on startup if)2.76 F .481(the ef)184 492 R(fecti)-.25 +E .781 -.15(ve u)-.25 H .482 +(ser \(group\) id is not equal to the real user \(group\) id.).15 F -.45(Tu) +5.482 G .482(rning this option).45 F(of)184 504 Q 2.5(fc)-.25 G(auses the ef) +202.35 504 Q(fecti)-.25 E .3 -.15(ve u)-.25 H +(ser and group ids to be set to the real user and group ids.).15 E F1144 +516 Q F0(Exit after reading and e)184 516 Q -.15(xe)-.15 G(cuting one command.) +.15 E F1144 528 Q F0 -.35(Tr)184 528 S .445(eat unset v).35 F .444 +(ariables as an error when performing parameter e)-.25 F 2.944(xpansion. If) +-.15 F -.15(ex)2.944 G .444(pansion is).15 F .519(attempted on an unset v)184 +540 R .519(ariable, the shell prints an error message, and, if not interacti) +-.25 F -.15(ve)-.25 G(,).15 E -.15(ex)184 552 S(its with a non\255zero status.) +.15 E F1144 564 Q F0(Print shell input lines as the)184 564 Q 2.5(ya)-.15 +G(re read.)306.63 564 Q F1144 576 Q F0 1.057(After e)184 576 R 1.056 +(xpanding each)-.15 F F3(simple-command)3.556 E F0(,).77 E F1(bash)3.556 E F0 +1.056(displays the e)3.556 F 1.056(xpanded v)-.15 F 1.056(alue of)-.25 F F2 +(PS4)3.556 E/F4 9/Times-Roman@0 SF(,)A F0(fol-)3.306 E(lo)184 588 Q +(wed by the command and its e)-.25 E(xpanded ar)-.15 E(guments.)-.18 E F1 +144 600 Q F0(Sa)184 600 Q 1.398 -.15(ve a)-.2 H 1.098 +(nd restore the binding of).15 F F3(name)3.598 E F0 1.098(in a)3.598 F F1 -.25 +(fo)3.598 G(r).25 E F3(name)3.598 E F0([in)3.599 E F1 -.1(wo)3.599 G(rd).1 E F0 +3.599(]c)C 1.099(ommand \(see)451.687 600 R F2(SHELL)3.599 E(GRAMMAR)184 612 Q +F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1144 624 Q F0 1.68 +(Disable the hashing of commands that are look)184 624 R 1.68(ed up for e)-.1 F +-.15(xe)-.15 G 4.18(cution. Normally).15 F 4.18(,c)-.65 G(om-)523.89 624 Q +1.275(mands are remembered in a hash table, and once found, do not ha)184 636 R +1.576 -.15(ve t)-.2 H 3.776(ob).15 G 3.776(el)490.888 636 S(ook)501.884 636 Q +1.276(ed up)-.1 F(ag)184 648 Q(ain.)-.05 E F1144 660 Q F0 .812(The ef)184 +660 R .812(fect is as if the shell command `noclobber=' had been e)-.25 F -.15 +(xe)-.15 G .811(cuted \(see).15 F F1 .811(Shell V)3.311 F(ari-)-.92 E(ables)184 +672 Q F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1144 684 Q F0(Enable)184 684 +Q F1(!)3.13 E F0 .63(style history substitution.)5.63 F .63 +(This \215ag is on by def)5.63 F .63(ault when the shell is interac-)-.1 F(ti) +184 696 Q -.15(ve)-.25 G(.).15 E F1144 708 Q F0 2.107 +(If set, do not follo)184 708 R 4.607(ws)-.25 G 2.107 +(ymbolic links when performing commands such as)279.835 708 R F1(cd)4.607 E F0 +(which)4.606 E(change the current directory)184 720 Q 5(.T)-.65 G(he ph)309.42 +720 Q(ysical directory is used instead.)-.05 E 185.675(GNU 1995)72 768 R(May 5) +2.5 E(32)530 768 Q EP +%%Page: 33 33 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF144 84 Q F0 .05(If no ar)184 84 R .05 +(guments follo)-.18 F 2.55(wt)-.25 G .05 +(his \215ag, then the positional parameters are unset.)280.98 84 R .05 +(Otherwise, the)5.05 F(positional parameters are set to the)184 96 Q/F2 10 +/Times-Italic@0 SF(ar)2.5 E(g)-.37 E F0(s, e)A -.15(ve)-.25 G 2.5(ni).15 G 2.5 +(fs)371.81 96 S(ome of them be)381.53 96 Q(gin with a)-.15 E F12.5 E F0(.)A +F1144 108 Q F0 1.945(Signal the end of options, cause all remaining)184 108 +R F2(ar)4.444 E(g)-.37 E F0 4.444(st)C 4.444(ob)409.45 108 S 4.444(ea)423.894 +108 S 1.944(ssigned to the positional)437.218 108 R 3.445(parameters. The)184 +120 R F13.445 E F0(and)3.445 E F13.445 E F0 .945 +(options are turned of)3.445 F 3.445(f. If)-.25 F .946(there are no)3.445 F F2 +(ar)3.446 E(g)-.37 E F0 .946(s, the positional)B(parameters remain unchanged.) +184 132 Q .317(The \215ags are of)144 148.8 R 2.817(fb)-.25 G 2.817(yd)218.328 +148.8 S(ef)231.145 148.8 Q .317(ault unless otherwise noted.)-.1 F .316 +(Using + rather than \255 causes these \215ags to be)5.317 F .198(turned of)144 +160.8 R 2.698(f. The)-.25 F .199 +(\215ags can also be speci\214ed as options to an in)2.699 F -.2(vo)-.4 G .199 +(cation of the shell.).2 F .199(The current set)5.199 F .643 +(of \215ags may be found in)144 172.8 R F1<24ad>3.143 E F0 5.642(.A)C .642 +(fter the option ar)273.91 172.8 R .642(guments are processed, the remaining) +-.18 F F2 3.142(na)3.142 G -.37(rg)512.238 172.8 S F0 3.142(sa).37 G(re)532.23 +172.8 Q .775(treated as v)144 184.8 R .775 +(alues for the positional parameters and are assigned, in order)-.25 F 3.275 +(,t)-.4 G(o)448.69 184.8 Q F1($1)3.275 E F0(,)A F1($2)3.275 E F0(,)A F1 3.275 +(... $)3.275 F F2(n)A F0 5.775(.I)C 3.275(fn)523.395 184.8 S(o)535 184.8 Q .309 +(options or)144 196.8 R F2(ar)2.809 E(g)-.37 E F0 2.808(sa)C .308 +(re supplied, all shell v)212.056 196.8 R .308(ariables are printed.)-.25 F +.308(The return status is al)5.308 F -.1(wa)-.1 G .308(ys true unless).1 F +(an ille)144 208.8 Q -.05(ga)-.15 G 2.5(lo).05 G(ption is encountered.)188.24 +208.8 Q F1(shift)108 225.6 Q F0([)2.5 E F2(n)A F0(])A .428 +(The positional parameters from)144 237.6 R F2(n)2.928 E F0 .429 +(+1 ... are renamed to)B F1 .429($1 ....)2.929 F F0 -.15(Pa)5.429 G .429 +(rameters represented by the num-).15 F(bers)144 249.6 Q F1($#)3.434 E F0(do) +3.434 E .934(wn to)-.25 F F1($#)3.434 E F0A F2(n)A F0 .934(+1 are unset.)B +(If)5.934 E F2(n)3.433 E F0 .933(is 0, no parameters are changed.)3.433 F(If) +5.933 E F2(n)3.433 E F0 .933(is not gi)3.433 F -.15(ve)-.25 G .933(n, it is).15 +F .026(assumed to be 1.)144 261.6 R F2(n)5.026 E F0 .026(must be a non-ne)2.526 +F -.05(ga)-.15 G(ti).05 E .326 -.15(ve n)-.25 H .026 +(umber less than or equal to).15 F F1($#)2.526 E F0 5.026(.I)C(f)454.886 261.6 +Q F2(n)2.526 E F0 .027(is greater than)2.527 F F1($#)2.527 E F0(,)A .03 +(the positional parameters are not changed.)144 273.6 R .029 +(The return status is greater than 0 if)5.03 F F2(n)2.529 E F0 .029 +(is greater than)2.529 F F1($#)2.529 E F0(or less than 0; otherwise 0.)144 +285.6 Q F1(suspend)108 302.4 Q F0([)2.5 E F1A F0(])A .492(Suspend the e) +144 314.4 R -.15(xe)-.15 G .492(cution of this shell until it recei).15 F -.15 +(ve)-.25 G 2.992(sa).15 G/F3 9/Times-Bold@0 SF(SIGCONT).001 E F0 2.993 +(signal. The)2.743 F F12.993 E F0 .493(option says not to)2.993 F .759 +(complain if this is a login shell; just suspend an)144 326.4 R(yw)-.15 E(ay) +-.1 E 5.758(.T)-.65 G .758(he return status is 0 unless the shell is a)375.688 +326.4 R(login shell and)144 338.4 Q F12.5 E F0 +(is not supplied, or if job control is not enabled.)2.5 E F1(test)108 355.2 Q +F2 -.2(ex)2.5 G(pr).2 E F1([)108 367.2 Q F2 -.2(ex)2.5 G(pr).2 E F1(])2.5 E F0 +.877(Return a status of 0 \(true\) or 1 \(f)6.77 F .878 +(alse\) depending on the e)-.1 F -.25(va)-.25 G .878 +(luation of the conditional e).25 F(xpression)-.15 E F2 -.2(ex)144 379.2 S(pr) +.2 E F0 5.008(.E).73 G .008(xpressions may be unary or binary)175.918 379.2 R +5.007(.U)-.65 G .007(nary e)328.064 379.2 R .007 +(xpressions are often used to e)-.15 F .007(xamine the status)-.15 F .203 +(of a \214le.)144 391.2 R .203 +(There are string operators and numeric comparison operators as well.)5.203 F +.204(Each operator and)5.204 F 1.592(operand must be a separate ar)144 403.2 R +4.091(gument. If)-.18 F F2(\214le)4.091 E F0 1.591(is of the form /de)4.091 F +(v/fd/)-.25 E F2(n)A F0 4.091(,t)C 1.591(hen \214le descriptor)444.756 403.2 R +F2(n)4.091 E F0(is)4.091 E(check)144 415.2 Q(ed.)-.1 E F1144 427.2 Q F2 +(\214le)2.5 E F0 -.35(Tr)180 427.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 +G(ists and is block special.).15 E F1144 439.2 Q F2(\214le)2.5 E F0 -.35 +(Tr)180 439.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is character special.).15 E F1144 451.2 Q F2(\214le)2.5 E F0 +-.35(Tr)180 451.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a directory).15 E(.)-.65 E F1144 463.2 Q F2(\214le)2.5 E F0 +-.35(Tr)180 463.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists.).15 E F1 +144 475.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 475.2 S(ue if).35 E F2(\214le) +2.5 E F0 -.15(ex)2.5 G(ists and is a re).15 E(gular \214le.)-.15 E F1144 +487.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 487.2 S(ue if).35 E F2(\214le)2.5 E F0 +-.15(ex)2.5 G(ists and is set-group-id.).15 E F1144 499.2 Q F2(\214le)2.5 +E F0 -.35(Tr)180 499.2 S(ue if).35 E F2(\214le)2.5 E F0(has its `)2.5 E(`stick) +-.74 E(y')-.15 E 2.5('b)-.74 G(it set.)295.22 499.2 Q F1144 511.2 Q F2 +(\214le)2.5 E F0 -.35(Tr)8.91 G(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a symbolic link.).15 E F1144 523.2 Q F2(\214le)2.5 E F0 -.35 +(Tr)180 523.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a named pipe.).15 E F1144 535.2 Q F2(\214le)2.5 E F0 -.35 +(Tr)180 535.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is readable.).15 E F1144 547.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 +547.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and has a size greater than zero.).15 E F1144 559.2 Q F2(\214le)2.5 +E F0 -.35(Tr)180 559.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a sock).15 E(et.)-.1 E F1144 571.2 Q F2(fd)2.5 E F0 -.35(Tr) +180 571.2 S(ue if).35 E F2(fd)2.5 E F0(is opened on a terminal.)2.5 E F1 +144 583.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 583.2 S(ue if).35 E F2(\214le)2.5 E +F0 -.15(ex)2.5 G(ists and its set-user).15 E(-id bit is set.)-.2 E F1144 +595.2 Q F2(\214le)2.5 E F0 -.35(Tr)8.36 G(ue if).35 E F2(\214le)2.5 E F0 -.15 +(ex)2.5 G(ists and is writable.).15 E F1144 607.2 Q F2(\214le)2.5 E F0 +-.35(Tr)180 607.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is e) +.15 E -.15(xe)-.15 G(cutable.).15 E F1144 619.2 Q F2(\214le)2.5 E F0 -.35 +(Tr)7.8 G(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is o).15 E +(wned by the ef)-.25 E(fecti)-.25 E .3 -.15(ve u)-.25 H(ser id.).15 E F1 +144 631.2 Q F2(\214le)2.5 E F0 -.35(Tr)7.8 G(ue if).35 E F2(\214le)2.5 E F0 +-.15(ex)2.5 G(ists and is o).15 E(wned by the ef)-.25 E(fecti)-.25 E .3 -.15 +(ve g)-.25 H(roup id.).15 E F2(\214le1)144 643.2 Q F02.5 E F1(nt)A F2 +(\214le2)2.5 E F0 -.35(Tr)180 655.2 S(ue if).35 E F2(\214le1)2.5 E F0(is ne)2.5 +E(wer \(according to modi\214cation date\) than)-.25 E F2(\214le2)2.5 E F0(.)A +F2(\214le1)144 667.2 Q F02.5 E F1(ot)A F2(\214le2)2.5 E F0 -.35(Tr)180 +679.2 S(ue if).35 E F2(\214le1)2.5 E F0(is older than \214le2.)2.5 E F2 +(\214le1)144 691.2 Q F1(\255ef)2.5 E F2(\214le)2.5 E F0 -.35(Tr)180 703.2 S +(ue if).35 E F2(\214le1)2.5 E F0(and)2.5 E F2(\214le2)2.5 E F0(ha)2.5 E .3 -.15 +(ve t)-.2 H(he same de).15 E(vice and inode numbers.)-.25 E 185.675(GNU 1995)72 +768 R(May 5)2.5 E(33)530 768 Q EP +%%Page: 34 34 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF144 84 Q/F2 10/Times-Italic@0 SF(string)2.5 E F0 +-.35(Tr)180 96 S(ue if the length of).35 E F2(string)2.5 E F0(is zero.)2.5 E F1 +144 108 Q F2(string)2.5 E(string)144 120 Q F0 -.35(Tr)180 120 S +(ue if the length of).35 E F2(string)2.5 E F0(is non\255zero.)2.5 E F2(string1) +144 132 Q F1(=)2.5 E F2(string2)2.5 E F0 -.35(Tr)180 144 S +(ue if the strings are equal.).35 E F2(string1)144 156 Q F1(!=)2.5 E F2 +(string2)2.5 E F0 -.35(Tr)180 168 S(ue if the strings are not equal.).35 E F1 +(!)144 180 Q F2 -.2(ex)2.5 G(pr).2 E F0 -.35(Tr)180 180 S(ue if).35 E F2 -.2 +(ex)2.5 G(pr).2 E F0(is f)2.5 E(alse.)-.1 E F2 -.2(ex)144 192 S(pr1).2 E F0 +2.5 E F1(a)A F2 -.2(ex)2.5 G(pr2).2 E F0 -.35(Tr)180 204 S(ue if both).35 E F2 +-.2(ex)2.5 G(pr1).2 E F0(AND)2.5 E F2 -.2(ex)2.5 G(pr2).2 E F0(are true.)2.5 E +F2 -.2(ex)144 216 S(pr1).2 E F02.5 E F1(o)A F2 -.2(ex)2.5 G(pr2).2 E F0 +-.35(Tr)180 228 S(ue if either).35 E F2 -.2(ex)2.5 G(pr1).2 E F0(OR)2.5 E F2 +-.2(ex)2.5 G(pr2).2 E F0(is true.)2.5 E F2(ar)144 240 Q(g1)-.37 E F1(OP)2.5 E +F2(ar)2.5 E(g2)-.37 E/F3 9/Times-Bold@0 SF(OP)180 252 Q F0 .035(is one of)2.284 +F F1(\255eq)2.535 E F0(,)A F1(\255ne)2.535 E F0(,)A F1(\255lt)2.535 E F0(,)A F1 +(\255le)2.535 E F0(,)A F1(\255gt)2.535 E F0 2.535(,o)C(r)332.165 252 Q F1 +(\255ge)2.535 E F0 5.035(.T)C .035 +(hese arithmetic binary operators return true)366.815 252 R(if)180 264 Q F2(ar) +3.32 E(g1)-.37 E F0 .82(is equal, not-equal, less-than, less-than-or)3.32 F .82 +(-equal, greater)-.2 F .82(-than, or greater)-.2 F(-than-or)-.2 E(-)-.2 E .5 +(equal than)180 276 R F2(ar)3 E(g2)-.37 E F0 3.001(,r)C(especti)252.231 276 Q +-.15(ve)-.25 G(ly).15 E(.)-.65 E F2(Ar)5.501 E(g1)-.37 E F0(and)3.001 E F2(ar) +3.001 E(g2)-.37 E F0 .501(may be positi)3.001 F .801 -.15(ve i)-.25 H(nte).15 E +.501(gers, ne)-.15 F -.05(ga)-.15 G(ti).05 E .801 -.15(ve i)-.25 H(nte).15 E +(gers,)-.15 E(or the special e)180 288 Q(xpression)-.15 E F12.5 E F2 +(string)2.5 E F0 2.5(,w)C(hich e)327.48 288 Q -.25(va)-.25 G +(luates to the length of).25 E F2(string)2.5 E F0(.).22 E F1(times)108 304.8 Q +F0 1.229(Print the accumulated user and system times for the shell and for pro\ +cesses run from the shell.)144 304.8 R(The return status is 0.)144 316.8 Q F1 +(trap)108 333.6 Q F0([)2.5 E F1A F0 2.5(][)C F2(ar)149.8 333.6 Q(g)-.37 E +F0 2.5(][)C F2(sigspec)172.48 333.6 Q F0(])A .767(The command)144 345.6 R F2 +(ar)3.267 E(g)-.37 E F0 .767(is to be read and e)3.267 F -.15(xe)-.15 G .767 +(cuted when the shell recei).15 F -.15(ve)-.25 G 3.267(ss).15 G(ignal\(s\)) +434.781 345.6 Q F2(sigspec)3.267 E F0 5.767(.I).31 G(f)509.945 345.6 Q F2(ar) +3.267 E(g)-.37 E F0(is)3.268 E 2.164(absent or)144 357.6 R F14.664 E F0 +4.664(,a)C 2.164(ll speci\214ed signals are reset to their original v)204.512 +357.6 R 2.164(alues \(the v)-.25 F 2.163(alues the)-.25 F 4.663(yh)-.15 G 2.163 +(ad upon)505.897 357.6 R .681(entrance to the shell\).)144 369.6 R(If)5.681 E +F2(ar)3.181 E(g)-.37 E F0 .681 +(is the null string this signal is ignored by the shell and by the com-)3.181 F +1.174(mands it in)144 381.6 R -.2(vo)-.4 G -.1(ke).2 G(s.).1 E F2(sigspec)6.174 +E F0 1.174(is either a signal name de\214ned in <)3.674 F F2(signal.h)A F0 +1.173(>, or a signal number)B 6.173(.I)-.55 G(f)536.67 381.6 Q F2(sigspec)144 +393.6 Q F0(is)2.769 E F3(EXIT)2.769 E F0 .269(\(0\) the command)2.519 F F2(ar) +2.769 E(g)-.37 E F0 .269(is e)2.769 F -.15(xe)-.15 G .269(cuted on e).15 F .269 +(xit from the shell.)-.15 F -.4(Wi)5.269 G .269(th no ar).4 F(guments,)-.18 E +F1(trap)2.77 E F0 .403 +(prints the list of commands associated with each signal number)144 405.6 R +5.402(.T)-.55 G(he)414.118 405.6 Q F12.902 E F0 .402 +(option causes the shell to)2.902 F .562 +(print a list of signal names and their corresponding numbers.)144 417.6 R .562 +(An ar)5.562 F .562(gument of)-.18 F F13.062 E F0 .562(disables option) +3.062 F .564(checking for the rest of the ar)144 429.6 R 3.064 +(guments. Signals)-.18 F .564 +(ignored upon entry to the shell cannot be trapped)3.064 F 1.144(or reset.)144 +441.6 R -.35(Tr)6.144 G 1.145(apped signals are reset to their original v).35 F +1.145(alues in a child process when it is created.)-.25 F +(The return status is f)144 453.6 Q +(alse if either the trap name or number is in)-.1 E -.25(va)-.4 G +(lid; otherwise).25 E F1(trap)2.5 E F0(returns true.)2.5 E F1(type)108 470.4 Q +F0([)2.5 E F1(\255all)A F0 2.5(][)C F1(\255type)157.58 470.4 Q F0(|)2.5 E F1 +(\255path)2.5 E F0(])A F2(name)2.5 E F0([)2.5 E F2(name)A F0(...])2.5 E -.4(Wi) +144 482.4 S .206(th no options, indicate ho).4 F 2.706(we)-.25 G(ach)272.15 +482.4 Q F2(name)2.705 E F0 -.1(wo)2.705 G .205 +(uld be interpreted if used as a command name.).1 F .205(If the)5.205 F F1 +(\255type)144 494.4 Q F0 .527(\215ag is used,)3.027 F F1(type)3.027 E F0 .528 +(prints a phrase which is one of)3.028 F F2(alias)3.028 E F0(,).27 E F2 -.1(ke) +3.028 G(ywor)-.2 E(d)-.37 E F0(,).77 E F2(function)3.028 E F0(,).24 E F2 -.2 +(bu)3.028 G(iltin).2 E F0 3.028(,o).24 G(r)512.284 494.4 Q F2(\214le)3.028 E F0 +(if)3.028 E F2(name)144 506.4 Q F0 .297(is an alias, shell reserv)2.798 F .297 +(ed w)-.15 F .297(ord, function, b)-.1 F .297(uiltin, or disk \214le, respecti) +-.2 F -.15(ve)-.25 G(ly).15 E 2.797(.I)-.65 G 2.797(ft)472.152 506.4 S .297 +(he name is not)481.059 506.4 R 1.097(found, then nothing is printed, and an e) +144 518.4 R 1.097(xit status of f)-.15 F 1.097(alse is returned.)-.1 F 1.097 +(If the)6.097 F F1(\255path)3.598 E F0 1.098(\215ag is used,)3.598 F F1(type) +144 530.4 Q F0 1.009(either returns the name of the disk \214le that w)3.509 F +1.008(ould be e)-.1 F -.15(xe)-.15 G 1.008(cuted if).15 F F2(name)3.508 E F0 +1.008(were speci\214ed as a)3.508 F .562(command name, or nothing if)144 542.4 +R F1(\255type)3.062 E F0 -.1(wo)3.062 G .562(uld not return).1 F F2(\214le) +3.063 E F0 5.563(.I).18 G 3.063(fac)389.542 542.4 S .563(ommand is hashed,) +407.878 542.4 R F1(\255path)3.063 E F0(prints)3.063 E .684(the hashed v)144 +554.4 R .684(alue, not necessarily the \214le that appears \214rst in)-.25 F F3 +-.666(PA)3.184 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .684(If the)5.184 F F1 +(\255all)3.184 E F0 .683(\215ag is used,)3.184 F F1(type)3.183 E F0 1.135 +(prints all of the places that contain an e)144 566.4 R -.15(xe)-.15 G 1.135 +(cutable named).15 F F2(name)3.635 E F0 6.136(.T).18 G 1.136 +(his includes aliases and func-)418.256 566.4 R 1.011 +(tions, if and only if the)144 578.4 R F1(\255path)3.511 E F0 1.011 +(\215ag is not also used.)3.511 F 1.011 +(The table of hashed commands is not con-)6.011 F .786(sulted when using)144 +590.4 R F1(\255all)3.286 E F0(.)A F1(type)5.786 E F0(accepts)3.286 E F1 +3.286 E F0(,)A F13.286 E F0 3.286(,a)C(nd)335.698 590.4 Q F13.286 E +F0 .787(in place of)3.287 F F1(\255all)3.287 E F0(,)A F1(\255type)3.287 E F0 +3.287(,a)C(nd)466.906 590.4 Q F1(\255path)3.287 E F0 3.287(,r)C(espec-)514.46 +590.4 Q(ti)144 602.4 Q -.15(ve)-.25 G(ly).15 E 6.127(.A)-.65 G 3.627(na)181.577 +602.4 S -.18(rg)194.644 602.4 S 1.127(ument of).18 F F13.627 E F0 1.127 +(disables option checking for the rest of the ar)3.627 F(guments.)-.18 E F1 +(type)6.126 E F0(returns)3.626 E(true if an)144 614.4 Q 2.5(yo)-.15 G 2.5(ft) +192.45 614.4 S(he ar)201.06 614.4 Q(guments are found, f)-.18 E +(alse if none are found.)-.1 E F1(ulimit)108 631.2 Q F0([)2.5 E F1 +(\255SHacdfmstpnuv)A F0([)2.5 E F2(limit)A F0(]])A F1(Ulimit)144 643.2 Q F0 +(pro)3.056 E .556(vides control o)-.15 F -.15(ve)-.15 G 3.057(rt).15 G .557 +(he resources a)266.316 643.2 R -.25(va)-.2 G .557 +(ilable to the shell and to processes started by it, on).25 F .765 +(systems that allo)144 655.2 R 3.265(ws)-.25 G .765(uch control.)226.325 655.2 +R .765(The v)5.765 F .765(alue of)-.25 F F2(limit)3.265 E F0 .765 +(can be a number in the unit speci\214ed for the)3.265 F .301 +(resource, or the v)144 667.2 R(alue)-.25 E F1(unlimited)2.801 E F0 5.301(.T)C +(he)288.565 667.2 Q F1(H)2.801 E F0(and)2.801 E F1(S)2.801 E F0 .302 +(options specify that the hard or soft limit is set for)2.802 F .005(the gi)144 +679.2 R -.15(ve)-.25 G 2.505(nr).15 G 2.505(esource. A)186.38 679.2 R .004(har\ +d limit cannot be increased once it is set; a soft limit may be increased up) +2.505 F .008(to the v)144 691.2 R .008(alue of the hard limit.)-.25 F .008 +(If neither)5.008 F F1(H)2.508 E F0(nor)2.508 E F1(S)2.508 E F0 .008 +(is speci\214ed, the command applies to the soft limit.)2.508 F(If)144 703.2 Q +F2(limit)2.758 E F0 .258(is omitted, the current v)2.758 F .257 +(alue of the soft limit of the resource is printed, unless the)-.25 F F1(H) +2.757 E F0(option)2.757 E .575(is gi)144 715.2 R -.15(ve)-.25 G 3.075(n. When) +.15 F .576(more than one resource is speci\214ed, the limit name and unit is p\ +rinted before the)3.076 F -.25(va)144 727.2 S 2.5(lue. Other).25 F +(options are interpreted as follo)2.5 E(ws:)-.25 E 185.675(GNU 1995)72 768 R +(May 5)2.5 E(34)530 768 Q EP +%%Page: 35 35 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +/F1 10/Times-Bold@0 SF144 84 Q F0(all current limits are reported)180 84 +Q F1144 96 Q F0(the maximum size of core \214les created)180 96 Q F1 +144 108 Q F0(the maximum size of a process')180 108 Q 2.5(sd)-.55 G +(ata se)317.76 108 Q(gment)-.15 E F1144 120 Q F0 +(the maximum size of \214les created by the shell)180 120 Q F1144 132 Q +F0(the maximum resident set size)180 132 Q F1144 144 Q F0 +(the maximum stack size)180 144 Q F1144 156 Q F0 +(the maximum amount of cpu time in seconds)180 156 Q F1144 168 Q F0 +(the pipe size in 512-byte blocks \(this may not be set\))180 168 Q F1144 +180 Q F0 .164 +(the maximum number of open \214le descriptors \(most systems do not allo)180 +180 R 2.664(wt)-.25 G .164(his v)481.708 180 R .164(alue to be)-.25 F +(set, only displayed\))180 192 Q F1144 204 Q F0 +(the maximum number of processes a)180 204 Q -.25(va)-.2 G +(ilable to a single user).25 E F1144 216 Q F0 +(The maximum amount of virtual memory a)180 216 Q -.25(va)-.2 G +(ilable to the shell).25 E .778(An ar)144 232.8 R .778(gument of)-.18 F F1 +3.278 E F0 .778(disables option checking for the rest of the ar)3.278 F +3.279(guments. If)-.18 F/F2 10/Times-Italic@0 SF(limit)3.279 E F0 .779(is gi) +3.279 F -.15(ve)-.25 G .779(n, it is).15 F .394(the ne)144 244.8 R 2.894(wv) +-.25 G .394(alue of the speci\214ed resource \(the)183.168 244.8 R F1 +2.893 E F0 .393(option is display only\).)2.893 F .393(If no option is gi)5.393 +F -.15(ve)-.25 G .393(n, then).15 F F1144 256.8 Q F0 .43(is assumed.)2.93 +F -1.11(Va)5.43 G .43(lues are in 1024-byte increments, e)1.11 F .431 +(xcept for)-.15 F F12.931 E F0 2.931(,w)C .431(hich is in seconds,) +421.315 256.8 R F12.931 E F0 2.931(,w)C(hich)522.78 256.8 Q .828 +(is in units of 512-byte blocks, and)144 268.8 R F13.327 E F0(and)3.327 E +F13.327 E F0 3.327(,w)C .827(hich are unscaled v)344.784 268.8 R 3.327 +(alues. The)-.25 F .827(return status is 0)3.327 F .621(unless an ille)144 +280.8 R -.05(ga)-.15 G 3.121(lo).05 G .621 +(ption is encountered, a non-numeric ar)217.603 280.8 R .622(gument other than) +-.18 F F1(unlimited)3.122 E F0 .622(is supplied)3.122 F(as)144 292.8 Q F2 +(limit)2.5 E F0 2.5(,o)C 2.5(ra)183.17 292.8 S 2.5(ne)193.44 292.8 S +(rror occurs while setting a ne)205.38 292.8 Q 2.5(wl)-.25 G(imit.)333.99 292.8 +Q F1(umask)108 309.6 Q F0([)2.5 E F1A F0 2.5(][)C F2(mode)162.59 309.6 Q +F0(])A .23(The user \214le-creation mask is set to)144 321.6 R F2(mode)2.73 E +F0 5.23(.I).18 G(f)323.21 321.6 Q F2(mode)2.73 E F0(be)2.729 E .229 +(gins with a digit, it is interpreted as an octal)-.15 F .066(number; otherwis\ +e it is interpreted as a symbolic mode mask similar to that accepted by)144 +333.6 R F2 -.15(ch)2.566 G(mod).15 E F0(\(1\).).77 E(If)144 345.6 Q F2(mode) +2.55 E F0 .05(is omitted, or if the)2.55 F F12.55 E F0 .049 +(option is supplied, the current v)2.55 F .049(alue of the mask is printed.) +-.25 F(The)5.049 E F12.549 E F0 .475 +(option causes the mask to be printed in symbolic form; the def)144 357.6 R +.475(ault output is an octal number)-.1 F 5.475(.A)-.55 G(n)535 357.6 Q(ar)144 +369.6 Q .125(gument of)-.18 F F12.625 E F0 .125 +(disables option checking for the rest of the ar)2.625 F 2.624(guments. The) +-.18 F .124(return status is 0 if the)2.624 F(mode w)144 381.6 Q +(as successfully changed or if no)-.1 E F2(mode)2.5 E F0(ar)2.5 E(gument w)-.18 +E(as supplied, and f)-.1 E(alse otherwise.)-.1 E F1(unalias)108 398.4 Q F0 +<5bad>2.5 E F1(a)A F0 2.5(][)C F2(name)164.2 398.4 Q F0(...])2.5 E(Remo)144 +410.4 Q -.15(ve)-.15 G F2(name)2.882 E F0 2.732(sf)C .232 +(rom the list of de\214ned aliases.)211.374 410.4 R(If)5.232 E F12.733 E +F0 .233(is supplied, all alias de\214nitions are remo)2.733 F -.15(ve)-.15 G +(d.).15 E(The return v)144 422.4 Q(alue is true unless a supplied)-.25 E F2 +(name)2.5 E F0(is not a de\214ned alias.)2.5 E F1(unset)108 439.2 Q F0<5bad>2.5 +E F1(fv)A F0 2.5(][)C F2(name)159.74 439.2 Q F0(...])2.5 E -.15(Fo)144 451.2 S +2.773(re).15 G(ach)164.953 451.2 Q F2(name)2.773 E F0 2.773(,r).18 G(emo) +212.049 451.2 Q .573 -.15(ve t)-.15 H .273(he corresponding v).15 F .273 +(ariable or)-.25 F 2.773(,g)-.4 G -2.15 -.25(iv e)369.094 451.2 T 2.773(nt).25 +G(he)391.467 451.2 Q F12.773 E F0 .273(option, function.)2.773 F .272 +(An ar)5.272 F(gument)-.18 E(of)144 463.2 Q F12.58 E F0 .08 +(disables option checking for the rest of the ar)2.58 F 2.58(guments. Note)-.18 +F(that)2.58 E/F3 9/Times-Bold@0 SF -.666(PA)2.58 G(TH)-.189 E/F4 9 +/Times-Roman@0 SF(,)A F3(IFS)2.33 E F4(,)A F3(PPID)2.33 E F4(,)A F3(PS1)2.331 E +F4(,)A F3(PS2)2.331 E F4(,)A F3(UID)144 475.2 Q F4(,)A F0(and)4.074 E F3(EUID) +4.324 E F0 1.824(cannot be unset.)4.074 F 1.824(If an)6.824 F 4.323(yo)-.15 G +(f)321.938 475.2 Q F3(RANDOM)4.323 E F4(,)A F3(SECONDS)4.073 E F4(,)A F3 +(LINENO)4.073 E F4(,)A F0(or)4.073 E F3(HISTCMD)4.323 E F0(are)4.073 E .328 +(unset, the)144 487.2 R 2.828(yl)-.15 G .328(ose their special properties, e) +193.116 487.2 R -.15(ve)-.25 G 2.828(ni).15 G 2.828(ft)330.436 487.2 S(he) +339.374 487.2 Q 2.828(ya)-.15 G .328(re subsequently reset.)360.932 487.2 R +.328(The e)5.328 F .329(xit status is true)-.15 F(unless a)144 499.2 Q F2(name) +2.5 E F0(does not e)2.5 E(xist or is non-unsettable.)-.15 E F1(wait)108 516 Q +F0([)2.5 E F2(n)A F0(])A -.8(Wa)144 528 S 1.061 +(it for the speci\214ed process and return its termination status.).8 F F2(n) +6.061 E F0 1.06(may be a process ID or a job)3.56 F .753 +(speci\214cation; if a job spec is gi)144 540 R -.15(ve)-.25 G .754 +(n, all processes in that job').15 F 3.254(sp)-.55 G .754(ipeline are w)404.012 +540 R .754(aited for)-.1 F 5.754(.I)-.55 G(f)502.458 540 Q F2(n)3.254 E F0 .754 +(is not)3.254 F(gi)144 552 Q -.15(ve)-.25 G .027(n, all currently acti).15 F +.327 -.15(ve c)-.25 H .027(hild processes are w).15 F .027(aited for)-.1 F +2.526(,a)-.4 G .026(nd the return status is zero.)375.932 552 R(If)5.026 E F2 +(n)2.526 E F0(speci\214es)2.526 E 2.595(an)144 564 S(on-e)156.035 564 Q .095 +(xistant process or job, the return status is 127.)-.15 F .096 +(Otherwise, the return status is the e)5.095 F .096(xit status)-.15 F +(of the last process or job w)144 576 Q(aited for)-.1 E(.)-.55 E F3(INV)72 +592.8 Q(OCA)-.405 E(TION)-.855 E F0(A)108 604.8 Q F2(lo)2.5 E(gin shell)-.1 E +F0(is one whose \214rst character of ar)2.5 E(gument zero is a)-.18 E F12.5 +E F0 2.5(,o)C 2.5(ro)375.87 604.8 S(ne started with the)386.7 604.8 Q F1 +(\255login)2.5 E F0(\215ag.)2.5 E(An)108 621.6 Q F2(inter)2.812 E(active)-.15 E +F0 .312(shell is one whose standard input and output are both connected to ter\ +minals \(as determined)2.812 F(by)108 633.6 Q F2(isatty)2.57 E F0 .07 +(\(3\)\), or one started with the).32 F F12.57 E F0(option.)2.57 E F3 +(PS1)5.07 E F0 .07(is set and)2.32 F F1<24ad>2.57 E F0(includes)2.57 E F1(i) +2.571 E F0(if)2.571 E F1(bash)2.571 E F0 .071(is interacti)2.571 F -.15(ve)-.25 +G 2.571(,a).15 G(llo)502.679 633.6 Q .071(wing a)-.25 F +(shell script or a startup \214le to test this state.)108 645.6 Q +(Login shells:)108 662.4 Q(On login \(subject to the)113 674.4 Q F1(\255nopr) +2.5 E(o\214le)-.18 E F0(option\):)2.5 E(if)128 686.4 Q F2(/etc/pr)2.5 E +(o\214le)-.45 E F0 -.15(ex)2.5 G(ists, source it.).15 E(if)128 710.4 Q F2 +(~/.bash_pr)2.5 E(o\214le)-.45 E F0 -.15(ex)2.5 G(ists, source it,).15 E +(else if)133 722.4 Q F2(~/.bash_lo)2.5 E(gin)-.1 E F0 -.15(ex)2.5 G +(ists, source it,).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(35)530 768 Q EP +%%Page: 36 36 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +(else if)138 84 Q/F1 10/Times-Italic@0 SF(~/.pr)2.5 E(o\214le)-.45 E F0 -.15 +(ex)2.5 G(ists, source it.).15 E(On e)113 108 Q(xit:)-.15 E(if)128 120 Q F1 +(~/.bash_lo)2.5 E(gout)-.1 E F0 -.15(ex)2.5 G(ists, source it.).15 E +(Non-login interacti)108 144 Q .3 -.15(ve s)-.25 H(hells:).15 E +(On startup \(subject to the)113 156 Q/F2 10/Times-Bold@0 SF(\255nor)2.5 E(c) +-.18 E F0(and)2.5 E F22.5 E(c\214le)-.18 E F0(options\):)2.5 E(if)128 168 +Q F1(~/.bashr)2.5 E(c)-.37 E F0 -.15(ex)2.5 G(ists, source it.).15 E +(Non-interacti)108 192 Q .3 -.15(ve s)-.25 H(hells:).15 E(On startup:)113 204 Q +(if the en)128 216 Q(vironment v)-.4 E(ariable)-.25 E F2(ENV)2.5 E F0 +(is non-null, e)2.5 E(xpand)-.15 E +(it and source the \214le it names, as if the command)128 228 Q +(if [ "$ENV" ]; then . $ENV)148 240 Q 2.5<3b8c>-.74 G(had been e)128 252 Q -.15 +(xe)-.15 G(cuted, b).15 E(ut do not use)-.2 E F2 -.74(PA)2.5 G(TH)-.21 E F0 +(to search)2.5 E(for the pathname.)128 264 Q +(When not started in Posix mode, bash)5 E(looks for)128 276 Q F2 -.3(BA)2.5 G +(SH_ENV).3 E F0(before)2.5 E F2(ENV)2.5 E F0(.)A 1.023(If Bash is in)108 297.6 +R -.2(vo)-.4 G -.1(ke).2 G 3.523(da).1 G(s)191.382 297.6 Q F2(sh)3.523 E F0 +3.523(,i)C 3.523(tt)217.048 297.6 S 1.023(ries to mimic the beha)226.131 297.6 +R 1.023(vior of)-.2 F F2(sh)3.523 E F0 1.023(as closely as possible.)3.523 F +-.15(Fo)6.022 G 3.522(ral).15 G 1.022(ogin shell, it)488.226 297.6 R .505 +(attempts to source only)108 309.6 R F1(/etc/pr)3.006 E(o\214le)-.45 E F0(and) +3.006 E F1(~/.pr)3.006 E(o\214le)-.45 E F0 3.006(,i).18 G 3.006(nt)311.64 309.6 +S .506(hat order)322.426 309.6 R 5.506(.T)-.55 G(he)372.318 309.6 Q F2 +(\255nopr)3.006 E(o\214le)-.18 E F0 .506(option may still be used to)3.006 F +(disable this beha)108 321.6 Q(vior)-.2 E 5(.A)-.55 G(shell in)207.24 321.6 Q +-.2(vo)-.4 G -.1(ke).2 G 2.5(da).1 G(s)267.09 321.6 Q F2(sh)2.5 E F0 +(does not attempt to source an)2.5 E 2.5(yo)-.15 G(ther startup \214les.)414.71 +321.6 Q(When)108 338.4 Q F2(bash)2.71 E F0 .21(is started in)2.71 F F1(posix) +2.71 E F0 .21(mode, as with the)2.71 F F2(\255posix)2.709 E F0 .209 +(command line option, it follo)2.709 F .209(ws the Posix standard)-.25 F .187 +(for startup \214les.)108 350.4 R .188(In this mode, the)5.188 F F2(ENV)2.688 E +F0 -.25(va)2.688 G .188(riable is e).25 F .188 +(xpanded and that \214le sourced; no other startup \214les are)-.15 F(read.)108 +362.4 Q/F3 9/Times-Bold@0 SF(SEE ALSO)72 379.2 Q F1(Bash F)108 391.2 Q(eatur) +-.75 E(es)-.37 E F0 2.5(,B)C(rian F)176.6 391.2 Q(ox and Chet Rame)-.15 E(y) +-.15 E F1(The Gnu Readline Libr)108 403.2 Q(ary)-.15 E F0 2.5(,B)C(rian F) +225.35 403.2 Q(ox and Chet Rame)-.15 E(y)-.15 E F1(The Gnu History Libr)108 +415.2 Q(ary)-.15 E F0 2.5(,B)C(rian F)219.8 415.2 Q(ox and Chet Rame)-.15 E(y) +-.15 E F1 2.5(AS)108 427.2 S(ystem V Compatible Implementation of 4.2)121.61 +427.2 Q/F4 9/Times-Italic@0 SF(BSD)A F1 -.25(Jo)2.5 G 2.5(bC).25 G(ontr)335.067 +427.2 Q(ol)-.45 E F0 2.5(,D)C -.2(av)371.287 427.2 S(id Lennert).2 E F1 -.8(Po) +108 439.2 S(rtable Oper).8 E(ating System Interface \(POSIX\) P)-.15 E +(art 2: Shell and Utilities)-.8 E F0 2.5(,I)C(EEE)404.83 439.2 Q F1(sh)108 +451.2 Q F0(\(1\),)A F1(ksh)2.5 E F0(\(1\),)A F1(csh)2.5 E F0(\(1\))A F1(emacs) +108 463.2 Q F0(\(1\),)A F1(vi)2.5 E F0(\(1\))A F1 -.37(re)108 475.2 S(adline) +.37 E F0(\(3\))A F3(FILES)72 492 Q F1(/bin/bash)109.666 504 Q F0(The)144 516 Q +F2(bash)2.5 E F0 -.15(exe)2.5 G(cutable).15 E F1(/etc/pr)109.666 528 Q(o\214le) +-.45 E F0(The systemwide initialization \214le, e)144 540 Q -.15(xe)-.15 G +(cuted for login shells).15 E F1(~/.bash_pr)109.666 552 Q(o\214le)-.45 E F0 +(The personal initialization \214le, e)144 564 Q -.15(xe)-.15 G +(cuted for login shells).15 E F1(~/.bashr)109.666 576 Q(c)-.37 E F0(The indi) +144 588 Q(vidual per)-.25 E(-interacti)-.2 E -.15(ve)-.25 G +(-shell startup \214le).15 E F1(~/.inputr)109.666 600 Q(c)-.37 E F0(Indi)144 +612 Q(vidual)-.25 E F1 -.37(re)2.5 G(adline).37 E F0(initialization \214le)2.5 +E F3 -.45(AU)72 628.8 S(THORS).45 E F0(Brian F)144 640.8 Q(ox, Free Softw)-.15 +E(are F)-.1 E(oundation \(primary author\))-.15 E(bfox@ai.MIT)144 652.8 Q(.Edu) +-.74 E(Chet Rame)144 669.6 Q 1.3 -.65(y, C)-.15 H(ase W).65 E(estern Reserv)-.8 +E 2.5(eU)-.15 G(ni)296.66 669.6 Q -.15(ve)-.25 G(rsity).15 E(chet@ins.CWR)144 +681.6 Q(U.Edu)-.4 E F3 -.09(BU)72 698.4 S 2.25(GR).09 G(EPOR)100.161 698.4 Q +(TS)-.36 E F0 .568(If you \214nd a b)108 710.4 R .568(ug in)-.2 F F2(bash,) +3.068 E F0 .568(you should report it.)3.068 F .568(But \214rst, you should mak) +5.568 F 3.068(es)-.1 G .568(ure that it really is a b)419.578 710.4 R .567 +(ug, and)-.2 F(that it appears in the latest v)108 722.4 Q(ersion of)-.15 E F2 +(bash)2.5 E F0(that you ha)2.5 E -.15(ve)-.2 G(.).15 E 185.675(GNU 1995)72 768 +R(May 5)2.5 E(36)530 768 Q EP +%%Page: 37 37 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E +.437(Once you ha)108 84 R .737 -.15(ve d)-.2 H .438(etermined that a b).15 F +.438(ug actually e)-.2 F .438(xists, use the)-.15 F/F1 10/Times-Italic@0 SF +(bashb)2.938 E(ug)-.2 E F0 .438(command to submit a b)2.938 F .438(ug report.) +-.2 F(If)5.438 E .454(you ha)108 96 R .754 -.15(ve a \214)-.2 H .453 +(x, you are welcome to mail that as well!).15 F .453 +(Suggestions and `philosophical' b)5.453 F .453(ug reports may be)-.2 F +(mailed to)108 108 Q F1 -.2(bu)2.5 G(g-bash).2 E F0(@)A F1(pr)A(ep.ai.MIT)-.37 +E(.Edu)-.74 E F0(or posted to the Usenet ne)2.5 E(wsgroup)-.25 E/F2 10 +/Times-Bold@0 SF(gnu.bash.b)2.5 E(ug)-.2 E F0(.)A(ALL b)108 124.8 Q +(ug reports should include:)-.2 E(The v)108 141.6 Q(ersion number of)-.15 E F2 +(bash)2.5 E F0(The hardw)108 153.6 Q(are and operating system)-.1 E +(The compiler used to compile)108 165.6 Q 2.5(Ad)108 177.6 S +(escription of the b)122.72 177.6 Q(ug beha)-.2 E(viour)-.2 E 2.5(As)108 189.6 +S(hort script or `recipe' which e)121.61 189.6 Q -.15(xe)-.15 G(rcises the b) +.15 E(ug)-.2 E F1(bashb)108 206.4 Q(ug)-.2 E F0 +(inserts the \214rst three items automatically into the template it pro)2.5 E +(vides for \214ling a b)-.15 E(ug report.)-.2 E(Comments and b)108 223.2 Q +(ug reports concerning this manual page should be directed to)-.2 E F1 -.15(ch) +2.5 G(et@ins.CWR).15 E -.25(U.)-.4 G(Edu).25 E F0(.).25 E/F3 9/Times-Bold@0 SF +-.09(BU)72 240 S(GS).09 E F0(It')108 252 Q 2.5(st)-.55 G(oo big and too slo) +126.06 252 Q -.65(w.)-.25 G 1.868(There are some subtle dif)108 268.8 R 1.868 +(ferences between)-.25 F F2(bash)4.369 E F0 1.869(and traditional v)4.369 F +1.869(ersions of)-.15 F F2(sh)4.369 E F0 4.369(,m)C 1.869(ostly because of the) +455.243 268.8 R F3(POSIX)108 280.8 Q F0(speci\214cation.)2.25 E +(Aliases are confusing in some uses.)108 297.6 Q 185.675(GNU 1995)72 768 R +(May 5)2.5 E(37)530 768 Q EP +%%Trailer +end +%%EOF diff --git a/documentation/bash.txt b/documentation/bash.txt 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: + || & && ; ;; ( ) | + + + + +GNU Last change: 1995 May 5 2 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + +RESERVED WORDS + _R_e_s_e_r_v_e_d _w_o_r_d_s are words that have a special meaning to the + shell. The following words are recognized as reserved when + unquoted and either the first word of a simple command (see + SHELL GRAMMAR below) or the third word of a case or for com- + mand: + + ! case do done elif else esac fi for function if in select + then until while { } + +SHELL GRAMMAR + Simple Commands + A _s_i_m_p_l_e _c_o_m_m_a_n_d is a sequence of optional variable assign- + ments followed by _b_l_a_n_k-separated words and redirections, + and terminated by a _c_o_n_t_r_o_l _o_p_e_r_a_t_o_r. The first word speci- + fies the command to be executed. The remaining words are + passed as arguments to the invoked command. + + The return value of a _s_i_m_p_l_e _c_o_m_m_a_n_d is its exit status, or + 128+_n if the command is terminated by signal _n. + + Pipelines + A _p_i_p_e_l_i_n_e is a sequence of one or more commands separated + by the character |. The format for a pipeline is: + + [ ! ] _c_o_m_m_a_n_d [ | _c_o_m_m_a_n_d_2 ... ] + + The standard output of _c_o_m_m_a_n_d is connected to the standard + input of _c_o_m_m_a_n_d_2. This connection is performed before any + redirections specified by the command (see REDIRECTION + below). + + If the reserved word ! precedes a pipeline, the exit status + of that pipeline is the logical NOT of the exit status of + the last command. Otherwise, the status of the pipeline is + the exit status of the last command. The shell waits for + all commands in the pipeline to terminate before returning a + value. + + Each command in a pipeline is executed as a separate process + (i.e., in a subshell). + + Lists + A _l_i_s_t is a sequence of one or more pipelines separated by + one of the operators ;, &, &&, or ||, and terminated by one + of ;, &, or . + + Of these list operators, && and || have equal precedence, + followed by ; and &, which have equal precedence. + + If a command is terminated by the control operator &, the + shell executes the command in the _b_a_c_k_g_r_o_u_n_d in a subshell. + + + +GNU Last change: 1995 May 5 3 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + The shell does not wait for the command to finish, and the + return status is 0. Commands separated by a ; are executed + sequentially; the shell waits for each command to terminate + in turn. The return status is the exit status of the last + command executed. + + The control operators && and || denote AND lists and OR + lists, respectively. An AND list has the form + + _c_o_m_m_a_n_d && _c_o_m_m_a_n_d_2 + + _c_o_m_m_a_n_d_2 is executed if, and only if, _c_o_m_m_a_n_d returns an + exit status of zero. + + An OR list has the form + + _c_o_m_m_a_n_d || _c_o_m_m_a_n_d_2 + + _c_o_m_m_a_n_d_2 is executed if and only if _c_o_m_m_a_n_d returns a + non-zero exit status. The return status of AND and OR lists + is the exit status of the last command executed in the list. + + Compound Commands + A _c_o_m_p_o_u_n_d _c_o_m_m_a_n_d is one of the following: + + (_l_i_s_t) + _l_i_s_t is executed in a subshell. Variable assignments + and builtin commands that affect the shell's environ- + ment do not remain in effect after the command com- + pletes. The return status is the exit status of _l_i_s_t. + + { _l_i_s_t; } + _l_i_s_t is simply executed in the current shell environ- + ment. This is known as a _g_r_o_u_p _c_o_m_m_a_n_d. The return + status is the exit status of _l_i_s_t. + + for _n_a_m_e [ in _w_o_r_d; ] do _l_i_s_t ; done + The list of words following in is expanded, generating + a list of items. The variable _n_a_m_e is set to each ele- + ment of this list in turn, and _l_i_s_t is executed each + time. If the in _w_o_r_d is omitted, the for command exe- + cutes _l_i_s_t once for each positional parameter that is + set (see PARAMETERS below). + + select _n_a_m_e [ in _w_o_r_d; ] do _l_i_s_t ; done + The list of words following in is expanded, generating + a list of items. The set of expanded words is printed + on the standard error, each preceded by a number. If + the in _w_o_r_d is omitted, the positional parameters are + printed (see PARAMETERS below). The PS3 prompt is then + displayed and a line read from the standard input. If + the line consists of the number corresponding to one of + + + +GNU Last change: 1995 May 5 4 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + the displayed words, then the value of _n_a_m_e is set to + that word. If the line is empty, the words and prompt + are displayed again. If EOF is read, the command com- + pletes. Any other value read causes _n_a_m_e to be set to + null. The line read is saved in the variable REPLY. + The _l_i_s_t is executed after each selection until a break + or return command is executed. The exit status of + select is the exit status of the last command executed + in _l_i_s_t, or zero if no commands were executed. + + case _w_o_r_d in [ _p_a_t_t_e_r_n [ | _p_a_t_t_e_r_n ] ... ) _l_i_s_t ;; ] ... esac + A case command first expands _w_o_r_d, and tries to match + it against each _p_a_t_t_e_r_n in turn, using the same match- + ing rules as for pathname expansion (see Pathname + Expansion below). When a match is found, the + corresponding _l_i_s_t is executed. After the first match, + no subsequent matches are attempted. The exit status + is zero if no patterns are matches. Otherwise, it is + the exit status of the last command executed in _l_i_s_t. + + if _l_i_s_t then _l_i_s_t [ elif _l_i_s_t then _l_i_s_t ] ... [ else _l_i_s_t ] fi + The if _l_i_s_t is executed. If its exit status is zero, + the then _l_i_s_t is executed. Otherwise, each elif _l_i_s_t + is executed in turn, and if its exit status is zero, + the corresponding then _l_i_s_t is executed and the command + completes. Otherwise, the else _l_i_s_t is executed, if + present. The exit status is the exit status of the + last command executed, or zero if no condition tested + true. + + while _l_i_s_t do _l_i_s_t done + until _l_i_s_t do _l_i_s_t done + The while command continuously executes the do _l_i_s_t as + long as the last command in _l_i_s_t returns an exit status + of zero. The until command is identical to the while + command, except that the test is negated; the do _l_i_s_t + is executed as long as the last command in _l_i_s_t returns + a non-zero exit status. The exit status of the while + and until commands is the exit status of the last do + _l_i_s_t command executed, or zero if none was executed. + + [ function ] _n_a_m_e () { _l_i_s_t; } + This defines a function named _n_a_m_e. The _b_o_d_y of the + function is the _l_i_s_t of commands between { and }. This + list is executed whenever _n_a_m_e is specified as the name + of a simple command. The exit status of a function is + the exit status of the last command executed in the + body. (See FUNCTIONS below.) + +COMMENTS + In a non-interactive shell, or an interactive shell in which + the -o interactive-comments option to the set builtin is + + + +GNU Last change: 1995 May 5 5 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + enabled, a word beginning with # causes that word and all + remaining characters on that line to be ignored. An + interactive shell without the -o interactive-comments option + enabled does not allow comments. + +QUOTING + _Q_u_o_t_i_n_g is used to remove the special meaning of certain + characters or words to the shell. Quoting can be used to + disable special treatment for special characters, to prevent + reserved words from being recognized as such, and to prevent + parameter expansion. + + Each of the _m_e_t_a_c_h_a_r_a_c_t_e_r_s listed above under DEFINITIONS + has special meaning to the shell and must be quoted if they + are to represent themselves. There are three quoting + mechanisms: the _e_s_c_a_p_e _c_h_a_r_a_c_t_e_r, single quotes, and double + quotes. + + A non-quoted backslash (\) is the _e_s_c_a_p_e _c_h_a_r_a_c_t_e_r. It + preserves the literal value of the next character that fol- + lows, with the exception of . If a \ pair + appears, and the backslash is not quoted, the \ is + treated as a line continuation (that is, it is effectively + ignored). + + Enclosing characters in single quotes preserves the literal + value of each character within the quotes. A single quote + may not occur between single quotes, even when preceded by a + backslash. + + Enclosing characters in double quotes preserves the literal + value of all characters within the quotes, with the excep- + tion of $, `, and \. The characters $ and ` retain their + special meaning within double quotes. The backslash retains + its special meaning only when followed by one of the follow- + ing characters: $, `, ", \, or . A double quote + may be quoted within double quotes by preceding it with a + backslash. + + The special parameters * and @ have special meaning when in + double quotes (see PARAMETERS below). + +PARAMETERS + A _p_a_r_a_m_e_t_e_r is an entity that stores values, somewhat like a + variable in a conventional programming language. It can be + a _n_a_m_e, a number, or one of the special characters listed + below under Special Parameters. For the shell's purposes, a + _v_a_r_i_a_b_l_e is a parameter denoted by a _n_a_m_e. + + A parameter is set if it has been assigned a value. The + null string is a valid value. Once a variable is set, it + may be unset only by using the unset builtin command (see + + + +GNU Last change: 1995 May 5 6 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + SHELL BUILTIN COMMANDS below). + + A _v_a_r_i_a_b_l_e may be assigned to by a statement of the form + + _n_a_m_e=[_v_a_l_u_e] + + If _v_a_l_u_e is not given, the variable is assigned the null + string. All _v_a_l_u_e_s undergo tilde expansion, parameter and + variable expansion, command substitution, arithmetic expan- + sion, and quote removal. If the variable has its -i attri- + bute set (see declare below in SHELL BUILTIN COMMANDS) then + _v_a_l_u_e is subject to arithmetic expansion even if the $[...] + syntax does not appear. Word splitting is not performed, + with the exception of "$@" as explained below under Special + Parameters. Pathname expansion is not performed. + + Positional Parameters + A _p_o_s_i_t_i_o_n_a_l _p_a_r_a_m_e_t_e_r is a parameter denoted by one or more + digits, other than the single digit 0. Positional parame- + ters are assigned from the shell's arguments when it is + invoked, and may be reassigned using the set builtin com- + mand. Positional parameters may not be assigned to with + assignment statements. The positional parameters are tem- + porarily replaced when a shell function is executed (see + FUNCTIONS below). + + When a positional parameter consisting of more than a single + digit is expanded, it must be enclosed in braces (see EXPAN- + SION below). + + Special Parameters + The shell treats several parameters specially. These param- + eters may only be referenced; assignment to them is not + allowed. + * Expands to the positional parameters, starting from + one. When the expansion occurs within double quotes, + it expands to a single word with the value of each + parameter separated by the first character of the IFS + special variable. That is, ``$*'' is equivalent to + ``$1_c$2_c...'', where _c is the first character of the + value of the IFS variable. If IFS is null or unset, + the parameters are separated by spaces. + @ Expands to the positional parameters, starting from + one. When the expansion occurs within double quotes, + each parameter expands as a separate word. That is, `` + $@'' is equivalent to ``$1'' ``$2'' ... When there are + no positional parameters, ``$@'' and $@ expand to noth- + ing (i.e., they are removed). + # Expands to the number of positional parameters in + decimal. + ? Expands to the status of the most recently executed + foreground pipeline. + + + +GNU Last change: 1995 May 5 7 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + - Expands to the current option flags as specified upon + invocation, by the set builtin command, or those set by + the shell itself (such as the -i flag). + $ Expands to the process ID of the shell. In a () sub- + shell, it expands to the process ID of the current + shell, not the subshell. + ! Expands to the process ID of the most recently executed + background (asynchronous) command. + 0 Expands to the name of the shell or shell script. This + is set at shell initialization. If bash is invoked + with a file of commands, $0 is set to the name of that + file. If bash is started with the -c option, then $0 + is set to the first argument after the string to be + executed, if one is present. Otherwise, it is set to + the pathname used to invoke bash, as given by argument + zero. + _ Expands to the last argument to the previous command, + after expansion. Also set to the full pathname of each + command executed and placed in the environment exported + to that command. + + Shell Variables + The following variables are set by the shell: + + PPID The process ID of the shell's parent. + PWD The current working directory as set by the cd command. + OLDPWD + The previous working directory as set by the cd com- + mand. + REPLY + Set to the line of input read by the read builtin com- + mand when no arguments are supplied. + UID Expands to the user ID of the current user, initialized + at shell startup. + EUID Expands to the effective user ID of the current user, + initialized at shell startup. + BASH Expands to the full pathname used to invoke this + instance of bash. + BASH_VERSION + Expands to the version number of this instance of bash. + SHLVL + Incremented by one each time an instance of bash is + started. + RANDOM + Each time this parameter is referenced, a random + integer is generated. The sequence of random numbers + may be initialized by assigning a value to RANDOM. If + RANDOM is unset, it loses its special properties, even + if it is subsequently reset. + SECONDS + Each time this parameter is referenced, the number of + seconds since shell invocation is returned. If a value + + + +GNU Last change: 1995 May 5 8 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + is assigned to SECONDS, the value returned upon subse- + quent references is the number of seconds since the + assignment plus the value assigned. If SECONDS is + unset, it loses its special properties, even if it is + subsequently reset. + LINENO + Each time this parameter is referenced, the shell sub- + stitutes a decimal number representing the current + sequential line number (starting with 1) within a + script or function. When not in a script or function, + the value substituted is not guaranteed to be meaning- + ful. When in a function, the value is not the number + of the source line that the command appears on (that + information has been lost by the time the function is + executed), but is an approximation of the number of + _s_i_m_p_l_e _c_o_m_m_a_n_d_s executed in the current function. If + LINENO is unset, it loses its special properties, even + if it is subsequently reset. + HISTCMD + The history number, or index in the history list, of + the current command. If HISTCMD is unset, it loses its + special properties, even if it is subsequently reset. + OPTARG + The value of the last option argument processed by the + getopts builtin command (see SHELL BUILTIN COMMANDS + below). + OPTIND + The index of the next argument to be processed by the + getopts builtin command (see SHELL BUILTIN COMMANDS + below). + HOSTTYPE + Automatically set to a string that uniquely describes + the type of machine on which bash is executing. The + default is system-dependent. + OSTYPE + Automatically set to a string that describes the + operating system on which bash is executing. The + default is system-dependent. + + The following variables are used by the shell. In some + cases, bash assigns a default value to a variable; these + cases are noted below. + + IFS The _I_n_t_e_r_n_a_l _F_i_e_l_d _S_e_p_a_r_a_t_o_r that is used for word + splitting after expansion and to split lines into words + with the read builtin command. The default value is + ``''. + PATH The search path for commands. It is a colon-separated + list of directories in which the shell looks for com- + mands (see COMMAND EXECUTION below). The default path + is system-dependent, and is set by the administrator + who installs bash. A common value is + + + +GNU Last change: 1995 May 5 9 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''. + HOME The home directory of the current user; the default + argument for the cd builtin command. + CDPATH + The search path for the cd command. This is a colon- + separated list of directories in which the shell looks + for destination directories specified by the cd com- + mand. A sample value is ``.:~:/usr''. + ENV If this parameter is set when bash is executing a shell + script, its value is interpreted as a filename contain- + ing commands to initialize the shell, as in ._b_a_s_h_r_c. + The value of ENV is subjected to parameter expansion, + command substitution, and arithmetic expansion before + being interpreted as a pathname. PATH is not used to + search for the resultant pathname. + MAIL If this parameter is set to a filename and the MAILPATH + variable is not set, bash informs the user of the + arrival of mail in the specified file. + MAILCHECK + Specifies how often (in seconds) bash checks for mail. + The default is 60 seconds. When it is time to check + for mail, the shell does so before prompting. If this + variable is unset, the shell disables mail checking. + MAILPATH + A colon-separated list of pathnames to be checked for + mail. The message to be printed may be specified by + separating the pathname from the message with a `?'. + $_ stands for the name of the current mailfile. Exam- + ple: + MAILPATH='/usr/spool/mail/bfox?"You have + mail":~/shell-mail?"$_ has mail!"' + Bash supplies a default value for this variable, but + the location of the user mail files that it uses is + system dependent (e.g., /usr/spool/mail/$USER). + MAIL_WARNING + If set, and a file that bash is checking for mail has + been accessed since the last time it was checked, the + message ``The mail in _m_a_i_l_f_i_l_e has been read'' is + printed. + PS1 The value of this parameter is expanded (see PROMPTING + below) and used as the primary prompt string. The + default value is ``bash\$ ''. + PS2 The value of this parameter is expanded and used as the + secondary prompt string. The default is ``> ''. + PS3 The value of this parameter is used as the prompt for + the _s_e_l_e_c_t command (see SHELL GRAMMAR above). + PS4 The value of this parameter is expanded and the value + is printed before each command bash displays during an + execution trace. The first character of PS4 is repli- + cated multiple times, as necessary, to indicate multi- + ple levels of indirection. The default is ``+ ''. + HISTSIZE + + + +GNU Last change: 1995 May 5 10 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + The number of commands to remember in the command his- + tory (see HISTORY below). The default value is 500. + HISTFILE + The name of the file in which command history is saved. + (See HISTORY below.) The default value is + ~/._b_a_s_h__h_i_s_t_o_r_y. If unset, the command history is not + saved when an interactive shell exits. + HISTFILESIZE + The maximum number of lines contained in the history + file. When this variable is assigned a value, the his- + tory file is truncated, if necessary, to contain no + more than that number of lines. The default value is + 500. + OPTERR + If set to the value 1, bash displays error messages + generated by the getopts builtin command (see SHELL + BUILTIN COMMANDS below). OPTERR is initialized to 1 + each time the shell is invoked or a shell script is + executed. + PROMPT_COMMAND + If set, the value is executed as a command prior to + issuing each primary prompt. + IGNOREEOF + Controls the action of the shell on receipt of an EOF + character as the sole input. If set, the value is the + number of consecutive EOF characters typed as the first + characters on an input line before bash exits. If the + variable exists but does not have a numeric value, or + has no value, the default value is 10. If it does not + exist, EOF signifies the end of input to the shell. + This is only in effect for interactive shells. + TMOUT + If set to a value greater than zero, the value is + interpreted as the number of seconds to wait for input + after issuing the primary prompt. Bash terminates + after waiting for that number of seconds if input does + not arrive. + FCEDIT + The default editor for the fc builtin command. + FIGNORE + A colon-separated list of suffixes to ignore when per- + forming filename completion (see READLINE below). A + filename whose suffix matches one of the entries in + FIGNORE is excluded from the list of matched filenames. + A sample value is ``.o:~''. + INPUTRC + The filename for the readline startup file, overriding + the default of ~/._i_n_p_u_t_r_c (see READLINE below). + notify + If set, bash reports terminated background jobs immedi- + ately, rather than waiting until before printing the + next primary prompt (see also the -b option to the set + + + +GNU Last change: 1995 May 5 11 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + builtin command). + history_control + HISTCONTROL + If set to a value of _i_g_n_o_r_e_s_p_a_c_e, lines which begin + with a space character are not entered on the history + list. If set to a value of _i_g_n_o_r_e_d_u_p_s, lines matching + the last history line are not entered. A value of + _i_g_n_o_r_e_b_o_t_h combines the two options. If unset, or if + set to any other value than those above, all lines read + by the parser are saved on the history list. + + command_oriented_history + If set, bash attempts to save all lines of a + multiple-line command in the same history entry. This + allows easy re-editing of multi-line commands. + + glob_dot_filenames + If set, bash includes filenames beginning with a `.' in + the results of pathname expansion. + + allow_null_glob_expansion + If set, bash allows pathname patterns which match no + files (see Pathname Expansion below) to expand to a + null string, rather than themselves. + + histchars + The two or three characters which control history + expansion and tokenization (see HISTORY EXPANSION + below). The first character is the _h_i_s_t_o_r_y _e_x_p_a_n_s_i_o_n + _c_h_a_r_a_c_t_e_r, that is, the character which signals the + start of a history expansion, normally `!'. The second + character is the _q_u_i_c_k _s_u_b_s_t_i_t_u_t_i_o_n character, which is + used as shorthand for re-running the previous command + entered, substituting one string for another in the + command. The default is `^'. The optional third char- + acter is the character which signifies that the + remainder of the line is a comment, when found as the + first character of a word, normally `#'. The history + comment character causes history substitution to be + skipped for the remaining words on the line. It does + not necessarily cause the shell parser to treat the + rest of the line as a comment. + + nolinks + If set, the shell does not follow symbolic links when + executing commands that change the current working + directory. It uses the physical directory structure + instead. By default, bash follows the logical chain of + directories when performing commands which change the + current directory, such as cd. See also the descrip- + tion of the -P option to the set builtin ( SHELL BUIL- + TIN COMMANDS below). + + + +GNU Last change: 1995 May 5 12 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + hostname_completion_file + HOSTFILE + Contains the name of a file in the same format as + /_e_t_c/_h_o_s_t_s that should be read when the shell needs to + complete a hostname. The file may be changed interac- + tively; the next time hostname completion is attempted + bash adds the contents of the new file to the already + existing database. + + noclobber + If set, bash does not overwrite an existing file with + the >, >&, and <> redirection operators. This variable + may be overridden when creating output files by using + the redirection operator >| instead of > (see also the + -C option to the set builtin command). + + auto_resume + This variable controls how the shell interacts with the + user and job control. If this variable is set, single + word simple commands without redirections are treated + as candidates for resumption of an existing stopped + job. There is no ambiguity allowed; if there is more + than one job beginning with the string typed, the job + most recently accessed is selected. The _n_a_m_e of a + stopped job, in this context, is the command line used + to start it. If set to the value _e_x_a_c_t, the string + supplied must match the name of a stopped job exactly; + if set to _s_u_b_s_t_r_i_n_g, the string supplied needs to match + a substring of the name of a stopped job. The _s_u_b_- + _s_t_r_i_n_g value provides functionality analogous to the %? + job id (see JOB CONTROL below). If set to any other + value, the supplied string must be a prefix of a + stopped job's name; this provides functionality analo- + gous to the % job id. + + no_exit_on_failed_exec + If this variable exists, a non-interactive shell will + not exit if it cannot execute the file specified in the + exec builtin command. An interactive shell does not + exit if exec fails. + + cdable_vars + If this is set, an argument to the cd builtin command + that is not a directory is assumed to be the name of a + variable whose value is the directory to change to. + +EXPANSION + Expansion is performed on the command line after it has been + split into words. There are seven kinds of expansion per- + formed: _b_r_a_c_e _e_x_p_a_n_s_i_o_n, _t_i_l_d_e _e_x_p_a_n_s_i_o_n, _p_a_r_a_m_e_t_e_r _a_n_d + _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n, _c_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n, _a_r_i_t_h_m_e_t_i_c _e_x_p_a_n_- + _s_i_o_n, _w_o_r_d _s_p_l_i_t_t_i_n_g, and _p_a_t_h_n_a_m_e _e_x_p_a_n_s_i_o_n. + + + +GNU Last change: 1995 May 5 13 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + The order of expansions is: brace expansion, tilde expan- + sion, parameter, variable, command, and arithmetic substitu- + tion (done in a left-to-right fashion), word splitting, and + pathname expansion. + + On systems that can support it, there is an additional + expansion available: _p_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n. + + Only brace expansion, word splitting, and pathname expansion + can change the number of words of the expansion; other + expansions expand a single word to a single word. The sin- + gle exception to this is the expansion of ``$@'' as + explained above (see PARAMETERS). + + Brace Expansion + _B_r_a_c_e _e_x_p_a_n_s_i_o_n is a mechanism by which arbitrary strings + may be generated. This mechanism is similar to _p_a_t_h_n_a_m_e + _e_x_p_a_n_s_i_o_n, but the filenames generated need not exist. Pat- + terns to be brace expanded take the form of an optional + _p_r_e_a_m_b_l_e, followed by a series of comma-separated strings + between a pair of braces, followed by an optional _p_o_s_t_a_m_b_l_e. + The preamble is prepended to each string contained within + the braces, and the postamble is then appended to each + resulting string, expanding left to right. + + Brace expansions may be nested. The results of each + expanded string are not sorted; left to right order is + preserved. For example, a{d,c,b}e expands into `ade ace + abe'. + + Brace expansion is performed before any other expansions, + and any characters special to other expansions are preserved + in the result. It is strictly textual. Bash does not apply + any syntactic interpretation to the context of the expansion + or the text between the braces. + + A correctly-formed brace expansion must contain unquoted + opening and closing braces, and at least one unquoted comma. + Any incorrectly formed brace expansion is left unchanged. + + This construct is typically used as shorthand when the com- + mon prefix of the strings to be generated is longer than in + the above example: + + mkdir /usr/local/src/bash/{old,new,dist,bugs} + or + chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} + + Brace expansion introduces a slight incompatibility with + traditional versions of sh, the Bourne shell. sh does not + treat opening or closing braces specially when they appear + as part of a word, and preserves them in the output. Bash + + + +GNU Last change: 1995 May 5 14 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + removes braces from words as a consequence of brace expan- + sion. For example, a word entered to sh as _f_i_l_e{_1,_2} + appears identically in the output. The same word is output + as _f_i_l_e_1 _f_i_l_e_2 after expansion by bash. If strict compati- + bility with sh is desired, start bash with the -nobraceex- + pansion flag (see OPTIONS above) or disable brace expansion + with the +o braceexpand option to the set command (see SHELL + BUILTIN COMMANDS below). + + Tilde Expansion + If a word begins with a tilde character (`~'), all of the + characters preceding the first slash (or all characters, if + there is no slash) are treated as a possible _l_o_g_i_n _n_a_m_e. If + this _l_o_g_i_n _n_a_m_e is the null string, the tilde is replaced + with the value of the parameter HOME. If HOME is unset, the + home directory of the user executing the shell is substi- + tuted instead. + + If a `+' follows the tilde, the value of PWD replaces the + tilde and `+'. If a `-' follows, the value of OLDPWD is + substituted. If the value following the tilde is a valid + _l_o_g_i_n _n_a_m_e, the tilde and _l_o_g_i_n _n_a_m_e are replaced with the + home directory associated with that name. If the name is + invalid, or the tilde expansion fails, the word is + unchanged. + + Each variable assignment is checked for unquoted instances + of tildes following a : or =. In these cases, tilde substi- + tution is also performed. Consequently, one may use path- + names with tildes in assignments to PATH, MAILPATH, and + CDPATH, and the shell assigns the expanded value. + + Parameter Expansion + The `$' character introduces parameter expansion, command + substitution, or arithmetic expansion. The parameter name + or symbol to be expanded may be enclosed in braces, which + are optional but serve to protect the variable to be + expanded from characters immediately following it which + could be interpreted as part of the name. + + ${_p_a_r_a_m_e_t_e_r} + The value of _p_a_r_a_m_e_t_e_r is substituted. The braces are + required when _p_a_r_a_m_e_t_e_r is a positional parameter with + more than one digit, or when _p_a_r_a_m_e_t_e_r is followed by a + character which is not to be interpreted as part of its + name. + + In each of the cases below, _w_o_r_d is subject to tilde expan- + sion, parameter expansion, command substitution, and arith- + metic expansion. Bash tests for a parameter that is unset + or null; omitting the colon results in a test only for a + parameter that is unset. + + + +GNU Last change: 1995 May 5 15 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + ${_p_a_r_a_m_e_t_e_r:-_w_o_r_d} + Use Default Values. If _p_a_r_a_m_e_t_e_r is unset or null, the + expansion of _w_o_r_d is substituted. Otherwise, the value + of _p_a_r_a_m_e_t_e_r is substituted. + ${_p_a_r_a_m_e_t_e_r:=_w_o_r_d} + Assign Default Values. If _p_a_r_a_m_e_t_e_r is unset or null, + the expansion of _w_o_r_d is assigned to _p_a_r_a_m_e_t_e_r. The + value of _p_a_r_a_m_e_t_e_r is then substituted. Positional + parameters and special parameters may not be assigned + to in this way. + ${_p_a_r_a_m_e_t_e_r:?_w_o_r_d} + Display Error if Null or Unset. If _p_a_r_a_m_e_t_e_r is null + or unset, the expansion of _w_o_r_d (or a message to that + effect if _w_o_r_d is not present) is written to the stan- + dard error and the shell, if it is not interactive, + exits. Otherwise, the value of _p_a_r_a_m_e_t_e_r is substi- + tuted. + ${_p_a_r_a_m_e_t_e_r:+_w_o_r_d} + Use Alternate Value. If _p_a_r_a_m_e_t_e_r is null or unset, + nothing is substituted, otherwise the expansion of _w_o_r_d + is substituted. + ${#_p_a_r_a_m_e_t_e_r} + The length in characters of the value of _p_a_r_a_m_e_t_e_r is + substituted. If _p_a_r_a_m_e_t_e_r is * or @, the length sub- + stituted is the length of * expanded within double + quotes. + ${_p_a_r_a_m_e_t_e_r#_w_o_r_d} + ${_p_a_r_a_m_e_t_e_r##_w_o_r_d} + The _w_o_r_d is expanded to produce a pattern just as in + pathname expansion. If the pattern matches the begin- + ning of the value of _p_a_r_a_m_e_t_e_r, then the expansion is + the value of _p_a_r_a_m_e_t_e_r with the shortest matching pat- + tern deleted (the ``#'' case) or the longest matching + pattern deleted (the ``##'' case). + + ${_p_a_r_a_m_e_t_e_r%_w_o_r_d} + ${_p_a_r_a_m_e_t_e_r%%_w_o_r_d} + The _w_o_r_d is expanded to produce a pattern just as in + pathname expansion. If the pattern matches a trailing + portion of the value of _p_a_r_a_m_e_t_e_r, then the expansion + is the value of _p_a_r_a_m_e_t_e_r with the shortest matching + pattern deleted (the ``%'' case) or the longest match- + ing pattern deleted (the ``%%'' case). + + Command Substitution + _C_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n allows the output of a command to + replace the command name. There are two forms: + + $(_c_o_m_m_a_n_d) + or + `_c_o_m_m_a_n_d` + + + + +GNU Last change: 1995 May 5 16 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + Bash performs the expansion by executing _c_o_m_m_a_n_d and replac- + ing the command substitution with the standard output of the + command, with any trailing newlines deleted. + + When the old-style backquote form of substitution is used, + backslash retains its literal meaning except when followed + by $, `, or \. When using the $(_c_o_m_m_a_n_d) form, all charac- + ters between the parentheses make up the command; none are + treated specially. + + Command substitutions may be nested. To nest when using the + old form, escape the inner backquotes with backslashes. + + If the substitution appears within double quotes, word + splitting and pathname expansion are not performed on the + results. + + Arithmetic Expansion + Arithmetic expansion allows the evaluation of an arithmetic + expression and the substitution of the result. There are + two formats for arithmetic expansion: + + $[_e_x_p_r_e_s_s_i_o_n] + + $((_e_x_p_r_e_s_s_i_o_n)) + + The _e_x_p_r_e_s_s_i_o_n is treated as if it were within double + quotes, but a double quote inside the braces or parentheses + is not treated specially. All tokens in the expression + undergo parameter expansion, command substitution, and quote + removal. Arithmetic substitutions may be nested. + + The evaluation is performed according to the rules listed + below under ARITHMETIC EVALUATION. If _e_x_p_r_e_s_s_i_o_n is + invalid, bash prints a message indicating failure and no + substitution occurs. + + Process Substitution + _P_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n is supported on systems that support + named pipes (_F_I_F_O_s) or the /dev/fd method of naming open + files. It takes the form of <(_l_i_s_t) or >(_l_i_s_t). The pro- + cess _l_i_s_t is run with its input or output connected to a + _F_I_F_O or some file in /dev/fd. The name of this file is + passed as an argument to the current command as the result + of the expansion. If the >(_l_i_s_t) form is used, writing to + the file will provide input for _l_i_s_t. If the <(_l_i_s_t) form + is used, the file passed as an argument should be read to + obtain the output of _l_i_s_t. + + On systems that support it, _p_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n is per- + formed simultaneously with _p_a_r_a_m_e_t_e_r _a_n_d _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n, + _c_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n, and _a_r_i_t_h_m_e_t_i_c _e_x_p_a_n_s_i_o_n. + + + +GNU Last change: 1995 May 5 17 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + Word Splitting + The shell scans the results of parameter expansion, command + substitution, and arithmetic expansion that did not occur + within double quotes for _w_o_r_d _s_p_l_i_t_t_i_n_g. + + The shell treats each character of IFS as a delimiter, and + splits the results of the other expansions into words on + these characters. If the value of IFS is exactly + , the default, then any sequence of IFS + characters serves to delimit words. If IFS has a value + other than the default, then sequences of the whitespace + characters space and tab are ignored at the beginning and + end of the word, as long as the whitespace character is in + the value of IFS (an IFS whitespace character). Any charac- + ter in IFS that is not IFS whitespace, along with any adja- + cent IFS whitespace characters, delimits a field. A + sequence of IFS whitespace characters is also treated as a + delimiter. If the value of IFS is null, no word splitting + occurs. IFS cannot be unset. + + Explicit null arguments ("" or '') are retained. Implicit + null arguments, resulting from the expansion of _p_a_r_a_m_e_t_e_r_s + that have no values, are removed. + + Note that if no expansion occurs, no splitting is performed. + + Pathname Expansion + After word splitting, unless the -f option has been set, + bash scans each _w_o_r_d for the characters *, ?, and [. If one + of these characters appears, then the word is regarded as a + _p_a_t_t_e_r_n, and replaced with an alphabetically sorted list of + pathnames matching the pattern. If no matching pathnames + are found, and the shell variable allow_null_glob_expansion + is unset, the word is left unchanged. If the variable is + set, and no matches are found, the word is removed. When a + pattern is used for pathname generation, the character ``.'' + at the start of a name or immediately following a slash must + be matched explicitly, unless the shell variable + glob_dot_filenames is set. The slash character must always + be matched explicitly. In other cases, the ``.'' character + is not treated specially. + + The special pattern characters have the following meanings: + + * Matches any string, including the null string. + ? Matches any single character. + [...] + Matches any one of the enclosed characters. A pair of + characters separated by a minus sign denotes a _r_a_n_g_e; + any character lexically between those two characters, + inclusive, is matched. If the first character follow- + ing the [ is a ! or a ^ then any character not enclosed + + + +GNU Last change: 1995 May 5 18 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + is matched. A - or ] may be matched by including it as + the first or last character in the set. + + Quote Removal + After the preceding expansions, all unquoted occurrences of + the characters \, `, and " are removed. + +REDIRECTION + Before a command is executed, its input and output may be + _r_e_d_i_r_e_c_t_e_d using a special notation interpreted by the + shell. Redirection may also be used to open and close files + for the current shell execution environment. The following + redirection operators may precede or appear anywhere within + a _s_i_m_p_l_e _c_o_m_m_a_n_d or may follow a _c_o_m_m_a_n_d. Redirections are + processed in the order they appear, from left to right. + + In the following descriptions, if the file descriptor number + is omitted, and the first character of the redirection + operator is <, the redirection refers to the standard input + (file descriptor 0). If the first character of the redirec- + tion operator is >, the redirection refers to the standard + output (file descriptor 1). + + The word that follows the redirection operator in the fol- + lowing descriptions is subjected to brace expansion, tilde + expansion, parameter expansion, command substitution, arith- + metic expansion, quote removal, and pathname expansion. If + it expands to more than one word, bash reports an error. + + Note that the order of redirections is significant. For + example, the command + + ls > dirlist 2>&1 + + directs both standard output and standard error to the file + _d_i_r_l_i_s_t, while the command + + ls 2>&1 > dirlist + + directs only the standard output to file _d_i_r_l_i_s_t, because + the standard error was duplicated as standard output before + the standard output was redirected to _d_i_r_l_i_s_t. + + Redirecting Input + Redirection of input causes the file whose name results from + the expansion of _w_o_r_d to be opened for reading on file + descriptor _n, or the standard input (file descriptor 0) if _n + is not specified. + + The general format for redirecting input is: + + + + + +GNU Last change: 1995 May 5 19 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + [_n]<_w_o_r_d + + Redirecting Output + Redirection of output causes the file whose name results + from the expansion of _w_o_r_d to be opened for writing on file + descriptor _n, or the standard output (file descriptor 1) if + _n is not specified. If the file does not exist it is + created; if it does exist it is truncated to zero size. + + The general format for redirecting output is: + + [_n]>_w_o_r_d + + If the redirection operator is >|, then the value of the -C + option to the set builtin command is not tested, and file + creation is attempted. (See also the description of + noclobber under Shell Variables above.) + + Appending Redirected Output + Redirection of output in this fashion causes the file whose + name results from the expansion of _w_o_r_d to be opened for + appending on file descriptor _n, or the standard output (file + descriptor 1) if _n is not specified. If the file does not + exist it is created. + + The general format for appending output is: + + [_n]>>_w_o_r_d + + Redirecting Standard Output and Standard Error + Bash allows both the standard output (file descriptor 1) and + the standard error output (file descriptor 2) to be + redirected to the file whose name is the expansion of _w_o_r_d + with this construct. + + There are two formats for redirecting standard output and + standard error: + + &>_w_o_r_d + and + >&_w_o_r_d + + Of the two forms, the first is preferred. This is semanti- + cally equivalent to + + >_w_o_r_d 2>&1 + + Here Documents + This type of redirection instructs the shell to read input + from the current source until a line containing only _w_o_r_d + (with no trailing blanks) is seen. All of the lines read up + to that point are then used as the standard input for a + + + +GNU Last change: 1995 May 5 20 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + command. + + The format of here-documents is as follows: + + <<[-]_w_o_r_d + _h_e_r_e-_d_o_c_u_m_e_n_t + _d_e_l_i_m_i_t_e_r + + No parameter expansion, command substitution, pathname + expansion, or arithmetic expansion is performed on _w_o_r_d. If + any characters in _w_o_r_d are quoted, the _d_e_l_i_m_i_t_e_r is the + result of quote removal on _w_o_r_d, and the lines in the here- + document are not expanded. Otherwise, all lines of the + here-document are subjected to parameter expansion, command + substitution, and arithmetic expansion. In the latter case, + the pair \ is ignored, and \ must be used to quote + the characters \, $, and `. + + If the redirection operator is <<-, then all leading tab + characters are stripped from input lines and the line con- + taining _d_e_l_i_m_i_t_e_r. This allows here-documents within shell + scripts to be indented in a natural fashion. + + Duplicating File Descriptors + The redirection operator + + [_n]<&_w_o_r_d + + is used to duplicate input file descriptors. If _w_o_r_d + expands to one or more digits, the file descriptor denoted + by _n is made to be a copy of that file descriptor. If _w_o_r_d + evaluates to -, file descriptor _n is closed. If _n is not + specified, the standard input (file descriptor 0) is used. + + The operator + + [_n]>&_w_o_r_d + + is used similarly to duplicate output file descriptors. If + _n is not specified, the standard output (file descriptor 1) + is used. As a special case, if _n is omitted, and _w_o_r_d does + not expand to one or more digits, the standard output and + standard error are redirected as described previously. + + Opening File Descriptors for Reading and Writing + The redirection operator + + [_n]<>_w_o_r_d + + causes the file whose name is the expansion of _w_o_r_d to be + opened for both reading and writing on file descriptor _n, or + as the standard input and standard output if _n is not + + + +GNU Last change: 1995 May 5 21 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + specified. If the file does not exist, it is created. + +FUNCTIONS + A shell function, defined as described above under SHELL + GRAMMAR, stores a series of commands for later execution. + Functions are executed in the context of the current shell; + no new process is created to interpret them (contrast this + with the execution of a shell script). When a function is + executed, the arguments to the function become the posi- + tional parameters during its execution. The special parame- + ter # is updated to reflect the change. Positional parame- + ter 0 is unchanged. + + Variables local to the function may be declared with the + local builtin command. Ordinarily, variables and their + values are shared between the function and its caller. + + If the builtin command return is executed in a function, the + function completes and execution resumes with the next com- + mand after the function call. When a function completes, + the values of the positional parameters and the special + parameter # are restored to the values they had prior to + function execution. + + Function names and definitions may be listed with the -f + option to the declare or typeset builtin commands. Func- + tions may be exported so that subshells automatically have + them defined with the -f option to the export builtin. + + Functions may be recursive. No limit is imposed on the + number of recursive calls. + +ALIASES + The shell maintains a list of _a_l_i_a_s_e_s that may be set and + unset with the alias and unalias builtin commands (see SHELL + BUILTIN COMMANDS below). The first word of each command, if + unquoted, is checked to see if it has an alias. If so, that + word is replaced by the text of the alias. The alias name + and the replacement text may contain any valid shell input, + including the _m_e_t_a_c_h_a_r_a_c_t_e_r_s listed above, with the excep- + tion that the alias name may not contain =. The first word + of the replacement text is tested for aliases, but a word + that is identical to an alias being expanded is not expanded + a second time. This means that one may alias ls to ls -F, + for instance, and bash does not try to recursively expand + the replacement text. If the last character of the alias + value is a _b_l_a_n_k, then the next command word following the + alias is also checked for alias expansion. + + Aliases are created and listed with the alias command, and + removed with the unalias command. + + + + +GNU Last change: 1995 May 5 22 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + There is no mechanism for using arguments in the replacement + text, as in csh. If arguments are needed, a shell function + should be used. + + Aliases are not expanded when the shell is not interactive. + + The rules concerning the definition and use of aliases are + somewhat confusing. Bash always reads at least one complete + line of input before executing any of the commands on that + line. Aliases are expanded when a command is read, not when + it is executed. Therefore, an alias definition appearing on + the same line as another command does not take effect until + the next line of input is read. This means that the com- + mands following the alias definition on that line are not + affected by the new alias. This behavior is also an issue + when functions are executed. Aliases are expanded when the + function definition is read, not when the function is exe- + cuted, because a function definition is itself a compound + command. As a consequence, aliases defined in a function + are not available until after that function is executed. To + be safe, always put alias definitions on a separate line, + and do not use alias in compound commands. + + Note that for almost every purpose, aliases are superseded + by shell functions. + +JOB CONTROL + _J_o_b _c_o_n_t_r_o_l refers to the ability to selectively stop + (_s_u_s_p_e_n_d) the execution of processes and continue (_r_e_s_u_m_e) + their execution at a later point. A user typically employs + this facility via an interactive interface supplied jointly + by the system's terminal driver and bash. + + The shell associates a _j_o_b with each pipeline. It keeps a + table of currently executing jobs, which may be listed with + the jobs command. When bash starts a job asynchronously (in + the _b_a_c_k_g_r_o_u_n_d), it prints a line that looks like: + + [1] 25647 + + indicating that this job is job number 1 and that the pro- + cess ID of the last process in the pipeline associated with + this job is 25647. All of the processes in a single pipe- + line are members of the same job. Bash uses the _j_o_b + abstraction as the basis for job control. + + To facilitate the implementation of the user interface to + job control, the system maintains the notion of a _c_u_r_r_e_n_t + _t_e_r_m_i_n_a_l _p_r_o_c_e_s_s _g_r_o_u_p _I_D. Members of this process group + (processes whose process group ID is equal to the current + terminal process group ID) receive keyboard-generated sig- + nals such as SIGINT. These processes are said to be in the + + + +GNU Last change: 1995 May 5 23 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + _f_o_r_e_g_r_o_u_n_d. _B_a_c_k_g_r_o_u_n_d processes are those whose process + group ID differs from the terminal's; such processes are + immune to keyboard-generated signals. Only foreground + processes are allowed to read from or write to the terminal. + Background processes which attempt to read from (write to) + the terminal are sent a SIGTTIN (SIGTTOU) signal by the ter- + minal driver, which, unless caught, suspends the process. + + If the operating system on which bash is running supports + job control, bash allows you to use it. Typing the _s_u_s_p_e_n_d + character (typically ^Z, Control-Z) while a process is run- + ning causes that process to be stopped and returns you to + bash. Typing the _d_e_l_a_y_e_d _s_u_s_p_e_n_d character (typically ^Y, + Control-Y) causes the process to be stopped when it attempts + to read input from the terminal, and control to be returned + to bash. You may then manipulate the state of this job, + using the bg command to continue it in the background, the + fg command to continue it in the foreground, or the kill + command to kill it. A ^Z takes effect immediately, and has + the additional side effect of causing pending output and + typeahead to be discarded. + + There are a number of ways to refer to a job in the shell. + The character % introduces a job name. Job number _n may be + referred to as %n. A job may also be referred to using a + prefix of the name used to start it, or using a substring + that appears in its command line. For example, %ce refers + to a stopped ce job. If a prefix matches more than one job, + bash reports an error. Using %?ce, on the other hand, + refers to any job containing the string ce in its command + line. If the substring matches more than one job, bash + reports an error. The symbols %% and %+ refer to the + shell's notion of the _c_u_r_r_e_n_t _j_o_b, which is the last job + stopped while it was in the foreground. The _p_r_e_v_i_o_u_s _j_o_b + may be referenced using %-. In output pertaining to jobs + (e.g., the output of the jobs command), the current job is + always flagged with a +, and the previous job with a -. + + Simply naming a job can be used to bring it into the fore- + ground: %1 is a synonym for ``fg %1'', bringing job 1 from + the background into the foreground. Similarly, ``%1 &'' + resumes job 1 in the background, equivalent to ``bg %1''. + + The shell learns immediately whenever a job changes state. + Normally, bash waits until it is about to print a prompt + before reporting changes in a job's status so as to not + interrupt any other output. If the -b option to the set + builtin command is set, bash reports such changes immedi- + ately. (See also the description of notify variable under + Shell Variables above.) + + + + + +GNU Last change: 1995 May 5 24 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + If you attempt to exit bash while jobs are stopped, the + shell prints a message warning you. You may then use the + jobs command to inspect their status. If you do this, or + try to exit again immediately, you are not warned again, and + the stopped jobs are terminated. + +SIGNALS + When bash is interactive, it ignores SIGTERM (so that kill 0 + does not kill an interactive shell), and SIGINT is caught + and handled (so that the wait builtin is interruptible). In + all cases, bash ignores SIGQUIT. If job control is in + effect, bash ignores SIGTTIN, SIGTTOU, and SIGTSTP. + + Synchronous jobs started by bash have signals set to the + values inherited by the shell from its parent. When job + control is not in effect, background jobs (jobs started with + &) ignore SIGINT and SIGQUIT. Commands run as a result of + command substitution ignore the keyboard-generated job con- + trol signals SIGTTIN, SIGTTOU, and SIGTSTP. + +COMMAND EXECUTION + After a command has been split into words, if it results in + a simple command and an optional list of arguments, the fol- + lowing actions are taken. + + If the command name contains no slashes, the shell attempts + to locate it. If there exists a shell function by that + name, that function is invoked as described above in FUNC- + TIONS. If the name does not match a function, the shell + searches for it in the list of shell builtins. If a match + is found, that builtin is invoked. + + If the name is neither a shell function nor a builtin, and + contains no slashes, bash searches each element of the PATH + for a directory containing an executable file by that name. + If the search is unsuccessful, the shell prints an error + message and returns a nonzero exit status. + + If the search is successful, or if the command name contains + one or more slashes, the shell executes the named program. + Argument 0 is set to the name given, and the remaining argu- + ments to the command are set to the arguments given, if any. + + If this execution fails because the file is not in execut- + able format, and the file is not a directory, it is assumed + to be a _s_h_e_l_l _s_c_r_i_p_t, a file containing shell commands. A + subshell is spawned to execute it. This subshell reinitial- + izes itself, so that the effect is as if a new shell had + been invoked to handle the script, with the exception that + the locations of commands remembered by the parent (see hash + below under SHELL BUILTIN COMMANDS) are retained by the + child. + + + +GNU Last change: 1995 May 5 25 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + If the program is a file beginning with #!, the remainder of + the first line specifies an interpreter for the program. + The shell executes the specified interpreter on operating + systems that do not handle this executable format them- + selves. The arguments to the interpreter consist of a sin- + gle optional argument following the interpreter name on the + first line of the program, followed by the name of the pro- + gram, followed by the command arguments, if any. + +ENVIRONMENT + When a program is invoked it is given an array of strings + called the _e_n_v_i_r_o_n_m_e_n_t. This is a list of _n_a_m_e-_v_a_l_u_e pairs, + of the form _n_a_m_e=_v_a_l_u_e. + + The shell allows you to manipulate the environment in + several ways. On invocation, the shell scans its own + environment and creates a parameter for each name found, + automatically marking it for _e_x_p_o_r_t to child processes. + Executed commands inherit the environment. The export and + declare -x commands allow parameters and functions to be + added to and deleted from the environment. If the value of + a parameter in the environment is modified, the new value + becomes part of the environment, replacing the old. The + environment inherited by any executed command consists of + the shell's initial environment, whose values may be modi- + fied in the shell, less any pairs removed by the unset com- + mand, plus any additions via the export and declare -x com- + mands. + + The environment for any _s_i_m_p_l_e _c_o_m_m_a_n_d or function may be + augmented temporarily by prefixing it with parameter assign- + ments, as described above in PARAMETERS. These assignment + statements affect only the environment seen by that command. + + If the -k flag is set (see the set builtin command below), + then _a_l_l parameter assignments are placed in the environment + for a command, not just those that precede the command name. + + When bash invokes an external command, the variable _ is set + to the full path name of the command and passed to that com- + mand in its environment. + +EXIT STATUS + For the purposes of the shell, a command which exits with a + zero exit status has succeeded. An exit status of zero + indicates success. A non-zero exit status indicates + failure. When a command terminates on a fatal signal, bash + uses the value of 128+signal as the exit status. + + If a command is not found, the child process created to exe- + cute it returns a status of 127. If a command is found but + is not executable, the return status is 126. + + + +GNU Last change: 1995 May 5 26 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + Bash itself returns the exit status of the last command exe- + cuted, unless a syntax error occurs, in which case it exits + with a non-zero value. See also the exit builtin command + below. + +PROMPTING + When executing interactively, bash displays the primary + prompt PS1 when it is ready to read a command, and the + secondary prompt PS2 when it needs more input to complete a + command. Bash allows these prompt strings to be customized + by inserting a number of backslash-escaped special charac- + ters that are decoded as follows: + \t the current time in HH:MM:SS format + \d the date in "Weekday Month Date" format (e.g., + "Tue May 26") + \n newline + \s the name of the shell, the basename of $0 (the + portion following the final slash) + \w the current working directory + \W the basename of the current working directory + \u the username of the current user + \h the hostname + \# the command number of this command + \! the history number of this command + \$ if the effective UID is 0, a #, otherwise a $ + \nnn the character corresponding to the octal number + nnn + \\ a backslash + \[ begin a sequence of non-printing characters, which + could be used to embed a terminal control sequence + into the prompt + \] end a sequence of non-printing characters + + The command number and the history number are usually dif- + ferent: the history number of a command is its position in + the history list, which may include commands restored from + the history file (see HISTORY below), while the command + number is the position in the sequence of commands executed + during the current shell session. After the string is + decoded, it is expanded via parameter expansion, command + substitution, arithmetic expansion, and word splitting. + +READLINE + This is the library that handles reading input when using an + interactive shell, unless the -nolineediting option is + given. By default, the line editing commands are similar to + those of emacs. A vi-style line editing interface is also + available. + + In this section, the emacs-style notation is used to denote + keystrokes. Control keys are denoted by C-_k_e_y, e.g., C-n + means Control-N. Similarly, _m_e_t_a keys are denoted by M-_k_e_y, + + + +GNU Last change: 1995 May 5 27 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + so M-x means Meta-X. (On keyboards without a _m_e_t_a key, M-_x + means ESC _x, i.e., press the Escape key then the _x key. + This makes ESC the _m_e_t_a _p_r_e_f_i_x. The combination M-C-_x means + ESC-Control-_x, or press the Escape key then hold the Control + key while pressing the _x key.) + + The default key-bindings may be changed with an ~/._i_n_p_u_t_r_c + file. The value of the shell variable INPUTRC, if set, is + used instead of ~/._i_n_p_u_t_r_c. Other programs that use this + library may add their own commands and bindings. + + For example, placing + + M-Control-u: universal-argument + or + C-Meta-u: universal-argument + into the ~/._i_n_p_u_t_r_c would make M-C-u execute the readline + command _u_n_i_v_e_r_s_a_l-_a_r_g_u_m_e_n_t. + + The following symbolic character names are recognized: + _R_U_B_O_U_T, _D_E_L, _E_S_C, _L_F_D, _N_E_W_L_I_N_E, _R_E_T, _R_E_T_U_R_N, _S_P_C, _S_P_A_C_E, and + _T_A_B. In addition to command names, readline allows keys to + be bound to a string that is inserted when the key is + pressed (a _m_a_c_r_o). + + Readline is customized by putting commands in an initializa- + tion file. The name of this file is taken from the value of + the INPUTRC variable. If that variable is unset, the + default is ~/._i_n_p_u_t_r_c. When a program which uses the read- + line library starts up, the init file is read, and the key + bindings and variables are set. There are only a few basic + constructs allowed in the readline init file. Blank lines + are ignored. Lines beginning with a # are comments. Lines + beginning with a $ indicate conditional constructs. Other + lines denote key bindings and variable settings. + + The syntax for controlling key bindings in the ~/._i_n_p_u_t_r_c + file is simple. All that is required is the name of the + command or the text of a macro and a key sequence to which + it should be bound. The name may be specified in one of two + ways: as a symbolic key name, possibly with _M_e_t_a- or + _C_o_n_t_r_o_l- prefixes, or as a key sequence. When using the + form keyname:_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, _k_e_y_n_a_m_e is the name of + a key spelled out in English. For example: + + Control-u: universal-argument + Meta-Rubout: backward-kill-word + Control-o: ">&output" + + In the above example, _C-_u is bound to the function + universal-argument, _M-_D_E_L is bound to the function + backward-kill-word, and _C-_o is bound to run the macro + + + +GNU Last change: 1995 May 5 28 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + expressed on the right hand side (that is, to insert the + text >&_o_u_t_p_u_t into the line). + + In the second form, "keyseq":_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, keyseq + differs from keyname above in that strings denoting an + entire key sequence may be specified by placing the sequence + within double quotes. Some GNU Emacs style key escapes can + be used, as in the following example. + + "\C-u": universal-argument + "\C-x\C-r": re-read-init-file + "\e[11~": "Function Key 1" + + In this example, _C-_u is again bound to the function + universal-argument. _C-_x _C-_r is bound to the function + re-read-init-file, and _E_S_C [ _1 _1 ~ is bound to insert the + text Function Key 1. The full set of escape sequences is + + \C- control prefix + + \M- meta prefix + + \e an escape character + + \\ backslash + + " \" literal " + + \' literal ' + + When entering the text of a macro, single or double quotes + should be used to indicate a macro definition. Unquoted + text is assumed to be a function name. Backslash will quote + any character in the macro text, including " and '. + + Bash allows the current readline key bindings to be + displayed or modified with the bind builtin command. The + editing mode may be switched during interactive use by using + the -o option to the set builtin command (see SHELL BUILTIN + COMMANDS below). + + Readline has variables that can be used to further customize + its behavior. A variable may be set in the _i_n_p_u_t_r_c file + with a statement of the form + + set _v_a_r_i_a_b_l_e-_n_a_m_e _v_a_l_u_e + + Except where noted, readline variables can take the values + On or Off. The variables and their default values are: + + horizontal-scroll-mode (Off) + When set to On, makes readline use a single line for + + + +GNU Last change: 1995 May 5 29 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + display, scrolling the input horizontally on a single + screen line when it becomes longer than the screen + width rather than wrapping to a new line. + editing-mode (emacs) + Controls whether readline begins with a set of key + bindings similar to _e_m_a_c_s or _v_i. editing-mode can be + set to either emacs or vi. + mark-modified-lines (Off) + If set to On, history lines that have been modified are + displayed with a preceding asterisk (*). + bell-style (audible) + Controls what happens when readline wants to ring the + terminal bell. If set to none, readline never rings + the bell. If set to visible, readline uses a visible + bell if one is available. If set to audible, readline + attempts to ring the terminal's bell. + comment-begin (``#'') + The string that is inserted in vi mode when the + vi-comment command is executed. + meta-flag (Off) + If set to On, readline will enable eight-bit input + (that is, it will not strip the high bit from the char- + acters it reads), regardless of what the terminal + claims it can support. + convert-meta (On) + If set to On, readline will convert characters with the + eighth bit set to an ASCII key sequence by stripping + the eighth bit and prepending an escape character (in + effect, using escape as the _m_e_t_a _p_r_e_f_i_x). + output-meta (Off) + If set to On, readline will display characters with the + eighth bit set directly rather than as a meta-prefixed + escape sequence. + completion-query-items (100) + This determines when the user is queried about viewing + the number of possible completions generated by the + possible-completions command. It may be set to any + integer value greater than or equal to zero. If the + number of possible completions is greater than or equal + to the value of this variable, the user is asked + whether or not he wishes to view them; otherwise they + are simply listed on the terminal. + keymap (emacs) + Set the current readline keymap. The set of legal key- + map names is _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s- + _c_t_l_x, _v_i, _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is + equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to + _e_m_a_c_s-_s_t_a_n_d_a_r_d. The default value is _e_m_a_c_s; the value + of editing-mode also affects the default keymap. + show-all-if-ambiguous (Off) + This alters the default behavior of the completion + functions. If set to on, words which have more than + + + +GNU Last change: 1995 May 5 30 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + one possible completion cause the matches to be listed + immediately instead of ringing the bell. + expand-tilde (Off) + If set to on, tilde expansion is performed when read- + line attempts word completion. + + Readline implements a facility similar in spirit to the con- + ditional compilation features of the C preprocessor which + allows key bindings and variable settings to be performed as + the result of tests. There are three parser directives + used. + + $if The $if construct allows bindings to be made based on + the editing mode, the terminal being used, or the + application using readline. The text of the test + extends to the end of the line; no characters are + required to isolate it. + + mode The mode= form of the $if directive is used to + test whether readline is in emacs or vi mode. + This may be used in conjunction with the set key- + map command, for instance, to set bindings in the + _e_m_a_c_s-_s_t_a_n_d_a_r_d and _e_m_a_c_s-_c_t_l_x keymaps only if + readline is starting out in emacs mode. + + term The term= form may be used to include terminal- + specific key bindings, perhaps to bind the key + sequences output by the terminal's function keys. + The word on the right side of the = is tested + against the full name of the terminal and the por- + tion of the terminal name before the first -. + This allows _s_u_n to match both _s_u_n and _s_u_n-_c_m_d, for + instance. + + application + The application construct is used to include + application-specific settings. Each program using + the readline library sets the _a_p_p_l_i_c_a_t_i_o_n _n_a_m_e, + and an initialization file can test for a particu- + lar value. This could be used to bind key + sequences to functions useful for a specific pro- + gram. For instance, the following command adds a + key sequence that quotes the current or previous + word in Bash: + $if Bash + # Quote the current or previous word + "\C-xq": "\eb\"\ef\"" + $endif + + $endif + This command, as you saw in the previous example, ter- + minates an $if command. + + + +GNU Last change: 1995 May 5 31 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + $else + Commands in this branch of the $if directive are exe- + cuted if the test fails. + + Readline commands may be given numeric _a_r_g_u_m_e_n_t_s, which nor- + mally act as a repeat count. Sometimes, however, it is the + sign of the argument that is significant. Passing a nega- + tive argument to a command that acts in the forward direc- + tion (e.g., kill-line) causes that command to act in a back- + ward direction. Commands whose behavior with arguments + deviates from this are noted. + + When a command is described as _k_i_l_l_i_n_g text, the text + deleted is saved for possible future retrieval (_y_a_n_k_i_n_g). + The killed text is saved in a _k_i_l_l-_r_i_n_g. Consecutive kills + cause the text to be accumulated into one unit, which can be + yanked all at once. Commands which do not kill text separate + the chunks of text on the kill-ring. + + The following is a list of the names of the commands and the + default key sequences to which they are bound. + + Commands for Moving + beginning-of-line (C-a) + Move to the start of the current line. + end-of-line (C-e) + Move to the end of the line. + forward-char (C-f) + Move forward a character. + backward-char (C-b) + Move back a character. + forward-word (M-f) + Move forward to the end of the next word. Words are + composed of alphanumeric characters (letters and + digits). + backward-word (M-b) + Move back to the start of this, or the previous, word. + Words are composed of alphanumeric characters (letters + and digits). + clear-screen (C-l) + Clear the screen leaving the current line at the top of + the screen. With an argument, refresh the current line + without clearing the screen. + redraw-current-line + Refresh the current line. By default, this is unbound. + + Commands for Manipulating the History + accept-line (Newline, Return) + Accept the line regardless of where the cursor is. If + this line is non-empty, add it to the history list + according to the state of the HISTCONTROL variable. If + the line is a modified history line, then restore the + + + +GNU Last change: 1995 May 5 32 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + history line to its original state. + previous-history (C-p) + Fetch the previous command from the history list, mov- + ing back in the list. + next-history (C-n) + Fetch the next command from the history list, moving + forward in the list. + beginning-of-history (M-<) + Move to the first line in the history. + end-of-history (M->) + Move to the end of the input history, i.e., the line + currently being entered. + reverse-search-history (C-r) + Search backward starting at the current line and moving + `up' through the history as necessary. This is an + incremental search. + forward-search-history (C-s) + Search forward starting at the current line and moving + `down' through the history as necessary. This is an + incremental search. + non-incremental-reverse-search-history (M-p) + Search backward through the history starting at the + current line using a non-incremental search for a + string supplied by the user. + non-incremental-forward-search-history (M-n) + Search forward through the history using a + non-incremental search for a string supplied by the + user. + history-search-forward + Search forward through the history for the string of + characters between the start of the current line and + the current point. This is a non-incremental search. + By default, this command is unbound. + history-search-backward + Search backward through the history for the string of + characters between the start of the current line and + the current point. This is a non-incremental search. + By default, this command is unbound. + yank-nth-arg (M-C-y) + Insert the first argument to the previous command (usu- + ally the second word on the previous line) at point + (the current cursor position). With an argument _n, + insert the _nth word from the previous command (the + words in the previous command begin with word 0). A + negative argument inserts the _nth word from the end of + the previous command. + yank-last-arg (M-., M-_) + Insert the last argument to the previous command (the + last word on the previous line). With an argument, + behave exactly like yank-nth-arg. + shell-expand-line (M-C-e) + Expand the line the way the shell does when it reads + + + +GNU Last change: 1995 May 5 33 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + it. This performs alias and history expansion as well + as all of the shell word expansions. See HISTORY + EXPANSION below for a description of history expansion. + history-expand-line (M-^) + Perform history expansion on the current line. See + HISTORY EXPANSION below for a description of history + expansion. + insert-last-argument (M-., M-_) + A synonym for yank-last-arg. + operate-and-get-next (C-o) + Accept the current line for execution and fetch the + next line relative to the current line from the history + for editing. Any argument is ignored. + + Commands for Changing Text + delete-char (C-d) + Delete the character under the cursor. If point is at + the beginning of the line, there are no characters in + the line, and the last character typed was not C-d, + then return EOF. + backward-delete-char (Rubout) + Delete the character behind the cursor. When given a + numeric argument, save the deleted text on the + kill-ring. + quoted-insert (C-q, C-v) + Add the next character that you type to the line verba- + tim. This is how to insert characters like C-q, for + example. + tab-insert (C-v TAB) + Insert a tab character. + self-insert (a, b, A, 1, !, ...) + Insert the character typed. + transpose-chars (C-t) + Drag the character before point forward over the char- + acter at point. Point moves forward as well. If point + is at the end of the line, then transpose the two char- + acters before point. Negative arguments don't work. + transpose-words (M-t) + Drag the word behind the cursor past the word in front + of the cursor moving the cursor over that word as well. + upcase-word (M-u) + Uppercase the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + downcase-word (M-l) + Lowercase the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + capitalize-word (M-c) + Capitalize the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + + + +GNU Last change: 1995 May 5 34 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + Killing and Yanking + kill-line (C-k) + Kill the text from the current cursor position to the + end of the line. + backward-kill-line (C-x C-Rubout) + Kill backward to the beginning of the line. + unix-line-discard (C-u) + Kill backward from point to the beginning of the line. + kill-whole-line + Kill all characters on the current line, no matter + where the cursor is. By default, this is unbound. + kill-word (M-d) + Kill from the cursor to the end of the current word, or + if between words, to the end of the next word. Word + boundaries are the same as those used by forward-word. + backward-kill-word (M-Rubout) + Kill the word behind the cursor. Word boundaries are + the same as those used by backward-word. + unix-word-rubout (C-w) + Kill the word behind the cursor, using white space as a + word boundary. The word boundaries are different from + backward-kill-word. + delete-horizontal-space + Delete all spaces and tabs around point. By default, + this is unbound. + yank (C-y) + Yank the top of the kill ring into the buffer at the + cursor. + yank-pop (M-y) + Rotate the kill-ring, and yank the new top. Only works + following yank or yank-pop. + + Numeric Arguments + digit-argument (M-0, M-1, ..., M--) + Add this digit to the argument already accumulating, or + start a new argument. M-- starts a negative argument. + universal-argument + Each time this is executed, the argument count is mul- + tiplied by four. The argument count is initially one, + so executing this function the first time makes the + argument count four. By default, this is not bound to + a key. + + Completing + complete (TAB) + Attempt to perform completion on the text before point. + Bash attempts completion treating the text as a vari- + able (if the text begins with $), username (if the text + begins with ~), hostname (if the text begins with @), + or command (including aliases and functions) in turn. + If none of these produces a match, filename completion + is attempted. + + + +GNU Last change: 1995 May 5 35 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + possible-completions (M-?) + List the possible completions of the text before point. + insert-completions + Insert all completions of the text before point that + would have been generated by possible-completions. By + default, this is not bound to a key. + complete-filename (M-/) + Attempt filename completion on the text before point. + possible-filename-completions (C-x /) + List the possible completions of the text before point, + treating it as a filename. + complete-username (M-~) + Attempt completion on the text before point, treating + it as a username. + possible-username-completions (C-x ~) + List the possible completions of the text before point, + treating it as a username. + complete-variable (M-$) + Attempt completion on the text before point, treating + it as a shell variable. + possible-variable-completions (C-x $) + List the possible completions of the text before point, + treating it as a shell variable. + complete-hostname (M-@) + Attempt completion on the text before point, treating + it as a hostname. + possible-hostname-completions (C-x @) + List the possible completions of the text before point, + treating it as a hostname. + complete-command (M-!) + Attempt completion on the text before point, treating + it as a command name. Command completion attempts to + match the text against aliases, reserved words, shell + functions, builtins, and finally executable filenames, + in that order. + possible-command-completions (C-x !) + List the possible completions of the text before point, + treating it as a command name. + dynamic-complete-history (M-TAB) + Attempt completion on the text before point, comparing + the text against lines from the history list for possi- + ble completion matches. + complete-into-braces (M-{) + Perform filename completion and return the list of pos- + sible completions enclosed within braces so the list is + available to the shell (see Brace Expansion above). + + Keyboard Macros + start-kbd-macro (C-x () + Begin saving the characters typed into the current key- + board macro. + end-kbd-macro (C-x )) + + + +GNU Last change: 1995 May 5 36 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + Stop saving the characters typed into the current key- + board macro and save the definition. + call-last-kbd-macro (C-x e) + Re-execute the last keyboard macro defined, by making + the characters in the macro appear as if typed at the + keyboard. + + Miscellaneous + re-read-init-file (C-x C-r) + Read in the contents of your init file, and incorporate + any bindings or variable assignments found there. + abort (C-g) + Abort the current editing command and ring the + terminal's bell (subject to the setting of bell-style). + do-uppercase-version (M-a, M-b, ...) + Run the command that is bound to the corresponding + uppercase character. + prefix-meta (ESC) + Metafy the next character typed. ESC f is equivalent + to Meta-f. + undo (C-_, C-x C-u) + Incremental undo, separately remembered for each line. + revert-line (M-r) + Undo all changes made to this line. This is like typ- + ing the undo command enough times to return the line to + its initial state. + tilde-expand (M-~) + Perform tilde expansion on the current word. + dump-functions + Print all of the functions and their key bindings to + the readline output stream. If a numeric argument is + supplied, the output is formatted in such a way that it + can be made part of an _i_n_p_u_t_r_c file. + display-shell-version (C-x C-v) + Display version information about the current instance + of bash. + +HISTORY + When interactive, the shell provides access to the _c_o_m_m_a_n_d + _h_i_s_t_o_r_y, the list of commands previously typed. The text of + the last HISTSIZE commands (default 500) is saved in a his- + tory list. The shell stores each command in the history + list prior to parameter and variable expansion (see EXPAN- + SION above) but after history expansion is performed, sub- + ject to the values of the shell variables + command_oriented_history and HISTCONTROL. On startup, the + history is initialized from the file named by the variable + HISTFILE (default ~/._b_a_s_h__h_i_s_t_o_r_y). HISTFILE is truncated, + if necessary, to contain no more than HISTFILESIZE lines. + The builtin command fc (see SHELL BUILTIN COMMANDS below) + may be used to list or edit and re-execute a portion of the + history list. The history builtin can be used to display + + + +GNU Last change: 1995 May 5 37 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + the history list and manipulate the history file. When + using the command-line editing, search commands are avail- + able in each editing mode that provide access to the history + list. When an interactive shell exits, the last HISTSIZE + lines are copied from the history list to HISTFILE. If + HISTFILE is unset, or if the history file is unwritable, the + history is not saved. + +HISTORY EXPANSION + The shell supports a history expansion feature that is simi- + lar to the history expansion in csh. This section describes + what syntax features are available. This feature is enabled + by default for interactive shells, and can be disabled using + the +H option to the set builtin command (see SHELL BUILTIN + COMMANDS below). Non-interactive shells do not perform his- + tory expansion. + + History expansion is performed immediately after a complete + line is read, before the shell breaks it into words. It + takes place in two parts. The first is to determine which + line from the previous history to use during substitution. + The second is to select portions of that line for inclusion + into the current one. The line selected from the previous + history is the _e_v_e_n_t, and the portions of that line that are + acted upon are _w_o_r_d_s. The line is broken into words in the + same fashion as when reading input, so that several + _m_e_t_a_c_h_a_r_a_c_t_e_r-separated words surrounded by quotes are con- + sidered as one word. Only backslash (\) and single quotes + can quote the history escape character, which is ! by + default. + + The shell allows control of the various characters used by + the history expansion mechanism (see the description of + histchars above under Shell Variables). + + Event Designators + An event designator is a reference to a command line entry + in the history list. + + ! Start a history substitution, except when followed by a + blank, newline, = or (. + !! Refer to the previous command. This is a synonym for + `!-1'. + !_n Refer to command line _n. + !-_n Refer to the current command line minus _n. + !_s_t_r_i_n_g + Refer to the most recent command starting with _s_t_r_i_n_g. + !?_s_t_r_i_n_g[?] + Refer to the most recent command containing _s_t_r_i_n_g. +9 ^8_s_t_r_i_n_g_19^8_s_t_r_i_n_g_29^ +8 Quick substitution. Repeat the last command, replacing + _s_t_r_i_n_g_1 with _s_t_r_i_n_g_2. Equivalent to + + + +GNU Last change: 1995 May 5 38 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + ``!!:s/_s_t_r_i_n_g_1/_s_t_r_i_n_g_2/'' (see Modifiers below). + !# The entire command line typed so far. + + Word Designators + A : separates the event specification from the word designa- + tor. It can be omitted if the word designator begins with a + ^, $, *, or %. Words are numbered from the beginning of the + line, with the first word being denoted by a 0 (zero). + + 0 (zero) + The zeroth word. For the shell, this is the command + word. + _n The _nth word. + ^ The first argument. That is, word 1. + $ The last argument. + % The word matched by the most recent `?_s_t_r_i_n_g?' search. + _x-_y A range of words; `-_y' abbreviates `0-_y'. + * All of the words but the zeroth. This is a synonym for + `_1-$'. It is not an error to use * if there is just + one word in the event; the empty string is returned in + that case. + x* Abbreviates _x-$. + x- Abbreviates _x-$ like x*, but omits the last word. + + Modifiers + After the optional word designator, you can add a sequence + of one or more of the following modifiers, each preceded by + a `:'. + + h Remove a trailing pathname component, leaving only the + head. + r Remove a trailing suffix of the form ._x_x_x, leaving the + basename. + e Remove all but the trailing suffix. + t Remove all leading pathname components, leaving the + tail. + p Print the new command but do not execute it. + q Quote the substituted words, escaping further substitu- + tions. + x Quote the substituted words as with q, but break into + words at blanks and newlines. + s/_o_l_d/_n_e_w/ + Substitute _n_e_w for the first occurrence of _o_l_d in the + event line. Any delimiter can be used in place of /. + The final delimiter is optional if it is the last char- + acter of the event line. The delimiter may be quoted + in _o_l_d and _n_e_w with a single backslash. If & appears + in _n_e_w, it is replaced by _o_l_d. A single backslash will + quote the &. + & Repeat the previous substitution. + g Cause changes to be applied over the entire event line. + This is used in conjunction with `:s' (e.g., + + + +GNU Last change: 1995 May 5 39 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + `:gs/_o_l_d/_n_e_w/') or `:&'. If used with `:s', any delim- + iter can be used in place of /, and the final delimiter + is optional if it is the last character of the event + line. + +ARITHMETIC EVALUATION + The shell allows arithmetic expressions to be evaluated, + under certain circumstances (see the let builtin command and + Arithmetic Expansion). Evaluation is done in long integers + with no check for overflow, though division by 0 is trapped + and flagged as an error. The following list of operators is + grouped into levels of equal-precedence operators. The lev- + els are listed in order of decreasing precedence. + + - + unary minus and plus + ! ~ logical and bitwise negation + * / % + multiplication, division, remainder + + - addition, subtraction + << >> + left and right bitwise shifts + <= >= < > + comparison + == != + equality and inequality + & bitwise AND + ^ bitwise exclusive OR + | bitwise OR + && logical AND + || logical OR + = *= /= %= += -= + assignment + + Shell variables are allowed as operands; parameter expansion + is performed before the expression is evaluated. The value + of a parameter is coerced to a long integer within an + expression. A shell variable need not have its integer + attribute turned on to be used in an expression. + + Constants with a leading 0 are interpreted as octal numbers. + A leading _0_x or _0_X denotes hexadecimal. Otherwise, numbers + take the form [_b_a_s_e#]n, where _b_a_s_e is a decimal number + between 2 and 36 representing the arithmetic base, and _n is + a number in that base. If _b_a_s_e is omitted, then base 10 is + used. + + Operators are evaluated in order of precedence. Sub- + expressions in parentheses are evaluated first and may over- + ride the precedence rules above. + +SHELL BUILTIN COMMANDS + : [_a_r_g_u_m_e_n_t_s] + + + +GNU Last change: 1995 May 5 40 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + No effect; the command does nothing beyond expanding + _a_r_g_u_m_e_n_t_s and performing any specified redirections. A + zero exit code is returned. + + . _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] + source _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] + Read and execute commands from _f_i_l_e_n_a_m_e in the current + shell environment and return the exit status of the + last command executed from _f_i_l_e_n_a_m_e. If _f_i_l_e_n_a_m_e does + not contain a slash, pathnames in PATH are used to find + the directory containing _f_i_l_e_n_a_m_e. The file searched + for in PATH need not be executable. The current direc- + tory is searched if no file is found in PATH. If any + _a_r_g_u_m_e_n_t_s are supplied, they become the positional + parameters when _f_i_l_e is executed. Otherwise the posi- + tional parameters are unchanged. The return status is + the status of the last command exited within the script + (0 if no commands are executed), and false if _f_i_l_e_n_a_m_e + is not found. + + alias [_n_a_m_e[=_v_a_l_u_e] ...] + Alias with no arguments prints the list of aliases in + the form _n_a_m_e=_v_a_l_u_e on standard output. When arguments + are supplied, an alias is defined for each _n_a_m_e whose + _v_a_l_u_e is given. A trailing space in _v_a_l_u_e causes the + next word to be checked for alias substitution when the + alias is expanded. For each _n_a_m_e in the argument list + for which no _v_a_l_u_e is supplied, the name and value of + the alias is printed. Alias returns true unless a _n_a_m_e + is given for which no alias has been defined. + + bg [_j_o_b_s_p_e_c] + Place _j_o_b_s_p_e_c in the background, as if it had been + started with &. If _j_o_b_s_p_e_c is not present, the shell's + notion of the _c_u_r_r_e_n_t _j_o_b is used. bg _j_o_b_s_p_e_c returns + 0 unless run when job control is disabled or, when run + with job control enabled, if _j_o_b_s_p_e_c was not found or + started without job control. + + bind [-m _k_e_y_m_a_p] [-lvd] [-q _n_a_m_e] + bind [-m _k_e_y_m_a_p] -f _f_i_l_e_n_a_m_e + bind [-m _k_e_y_m_a_p] _k_e_y_s_e_q:_f_u_n_c_t_i_o_n-_n_a_m_e + Display current readline key and function bindings, or + bind a key sequence to a readline function or macro. + The binding syntax accepted is identical to that of + ._i_n_p_u_t_r_c, but each binding must be passed as a separate + argument; e.g., '"\C-x\C-r": re-read-init-file'. + Options, if supplied, have the following meanings: + -m _k_e_y_m_a_p + Use _k_e_y_m_a_p as the keymap to be affected by the + subsequent bindings. Acceptable _k_e_y_m_a_p names are + _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s-_c_t_l_x, _v_i, + + + +GNU Last change: 1995 May 5 41 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is + equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to + _e_m_a_c_s-_s_t_a_n_d_a_r_d. + -l List the names of all readline functions + -v List current function names and bindings + -d Dump function names and bindings in such a way + that they can be re-read + -f _f_i_l_e_n_a_m_e + Read key bindings from _f_i_l_e_n_a_m_e + -q _f_u_n_c_t_i_o_n + Query about which keys invoke the named _f_u_n_c_t_i_o_n + + The return value is 0 unless an unrecognized option is + given or an error occurred. + + break [_n] + Exit from within a for, while, or until loop. If _n is + specified, break _n levels. _n must be >_ 1. If _n is + greater than the number of enclosing loops, all enclos- + ing loops are exited. The return value is 0 unless the + shell is not executing a loop when break is executed. + + builtin _s_h_e_l_l-_b_u_i_l_t_i_n [_a_r_g_u_m_e_n_t_s] + Execute the specified shell builtin, passing it _a_r_g_u_- + _m_e_n_t_s, and return its exit status. This is useful when + you wish to define a function whose name is the same as + a shell builtin, but need the functionality of the + builtin within the function itself. The cd builtin is + commonly redefined this way. The return status is + false if _s_h_e_l_l-_b_u_i_l_t_i_n is not a shell builtin command. + + cd [_d_i_r] + Change the current directory to _d_i_r. The variable HOME + is the default _d_i_r. The variable CDPATH defines the + search path for the directory containing _d_i_r. Alterna- + tive directory names are separated by a colon (:). A + null directory name in CDPATH is the same as the + current directory, i.e., ``.''. If _d_i_r begins with a + slash (/), then CDPATH is not used. An argument of - + is equivalent to $OLDPWD. The return value is true if + the directory was successfully changed; false other- + wise. + + command [-pVv] _c_o_m_m_a_n_d [_a_r_g ...] + Run _c_o_m_m_a_n_d with _a_r_g_s suppressing the normal shell + function lookup. Only builtin commands or commands + found in the PATH are executed. If the -p option is + given, the search for _c_o_m_m_a_n_d is performed using a + default value for PATH that is guaranteed to find all + of the standard utilities. If either the -V or -v + option is supplied, a description of _c_o_m_m_a_n_d is + printed. The -v option causes a single word indicating + + + +GNU Last change: 1995 May 5 42 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + the command or pathname used to invoke _c_o_m_m_a_n_d to be + printed; the -V option produces a more verbose descrip- + tion. An argument of -- disables option checking for + the rest of the arguments. If the -V or -v option is + supplied, the exit status is 0 if _c_o_m_m_a_n_d was found, + and 1 if not. If neither option is supplied and an + error occurred or _c_o_m_m_a_n_d cannot be found, the exit + status is 127. Otherwise, the exit status of the com- + mand builtin is the exit status of _c_o_m_m_a_n_d. + + continue [_n] + Resume the next iteration of the enclosing for, while, + or until loop. If _n is specified, resume at the _nth + enclosing loop. _n must be >_ 1. If _n is greater than + the number of enclosing loops, the last enclosing loop + (the `top-level' loop) is resumed. The return value is + 0 unless the shell is not executing a loop when con- + tinue is executed. + + declare [-frxi] [_n_a_m_e[=_v_a_l_u_e]] + typeset [-frxi] [_n_a_m_e[=_v_a_l_u_e]] + Declare variables and/or give them attributes. If no + _n_a_m_es are given, then display the values of variables + instead. The options can be used to restrict output to + variables with the specified attribute. + -f Use function names only + -r Make _n_a_m_es readonly. These names cannot then be + assigned values by subsequent assignment state- + ments. + -x Mark _n_a_m_es for export to subsequent commands via + the environment. + -i The variable is treated as an integer; arithmetic + evaluation (see ARITHMETIC EVALUATION ) is per- + formed when the variable is assigned a value. + + Using `+' instead of `-' turns off the attribute + instead. When used in a function, makes _n_a_m_es local, + as with the local command. The return value is 0 + unless an illegal option is encountered, an attempt is + made to define a function using "-f foo=bar", one of + the _n_a_m_e_s is not a legal shell variable name, an + attempt is made to turn off readonly status for a + readonly variable, or an attempt is made to display a + non-existant function with -f. + + dirs [-l] [+/-n] + Display the list of currently remembered directories. + Directories are added to the list with the pushd com- + mand; the popd command moves back up through the list. + +n displays the _nth entry counting from the left of + the list shown by dirs when invoked without + options, starting with zero. + + + +GNU Last change: 1995 May 5 43 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + -n displays the _nth entry counting from the right of + the list shown by dirs when invoked without + options, starting with zero. + -l produces a longer listing; the default listing + format uses a tilde to denote the home directory. + + The return value is 0 unless an illegal option is sup- + plied or _n indexes beyond the end of the directory + stack. + + echo [-neE] [_a_r_g ...] + Output the _a_r_gs, separated by spaces. The return + status is always 0. If -n is specified, the trailing + newline is suppressed. If the -e option is given, + interpretation of the following backslash-escaped char- + acters is enabled. The -E option disables the + interpretation of these escape characters, even on sys- + tems where they are interpreted by default. + \a alert (bell) + \b backspace + \c suppress trailing newline + \f form feed + \n new line + \r carriage return + \t horizontal tab + \v vertical tab + \\ backslash + \nnn the character whose ASCII code is _n_n_n (octal) + + enable [-n] [-all] [_n_a_m_e ...] + Enable and disable builtin shell commands. This allows + the execution of a disk command which has the same name + as a shell builtin without specifying a full pathname. + If -n is used, each _n_a_m_e is disabled; otherwise, _n_a_m_e_s + are enabled. For example, to use the test binary found + via the PATH instead of the shell builtin version, type + ``enable -n test''. If no arguments are given, a list + of all enabled shell builtins is printed. If only -n + is supplied, a list of all disabled builtins is + printed. If only -all is supplied, the list printed + includes all builtins, with an indication of whether or + not each is enabled. enable accepts -a as a synonym + for -all. The return value is 0 unless a _n_a_m_e is not a + shell builtin. + + eval [_a_r_g ...] + The _a_r_gs are read and concatenated together into a sin- + gle command. This command is then read and executed by + the shell, and its exit status is returned as the value + of the eval command. If there are no _a_r_g_s, or only + null arguments, eval returns true. + + + + +GNU Last change: 1995 May 5 44 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + exec [[-] _c_o_m_m_a_n_d [_a_r_g_u_m_e_n_t_s]] + If _c_o_m_m_a_n_d is specified, it replaces the shell. No new + process is created. The _a_r_g_u_m_e_n_t_s become the arguments + to _c_o_m_m_a_n_d. If the first argument is -, the shell + places a dash in the zeroth arg passed to _c_o_m_m_a_n_d. + This is what login does. If the file cannot be exe- + cuted for some reason, a non-interactive shell exits, + unless the shell variable no_exit_on_failed_exec + exists, in which case it returns failure. An interac- + tive shell returns failure if the file cannot be exe- + cuted. If _c_o_m_m_a_n_d is not specified, any redirections + take effect in the current shell, and the return status + is 0. + + exit [_n] + Cause the shell to exit with a status of _n. If _n is + omitted, the exit status is that of the last command + executed. A trap on EXIT is executed before the shell + terminates. + + export [-nf] [_n_a_m_e[=_w_o_r_d]] ... + export -p + The supplied _n_a_m_e_s are marked for automatic export to + the environment of subsequently executed commands. If + the -f option is given, the _n_a_m_e_s refer to functions. + If no _n_a_m_e_s are given, or if the -p option is supplied, + a list of all names that are exported in this shell is + printed. The -n option causes the export property to + be removed from the named variables. An argument of -- + disables option checking for the rest of the arguments. + export returns an exit status of 0 unless an illegal + option is encountered, one of the _n_a_m_e_s is not a legal + shell variable name, or -f is supplied with a _n_a_m_e that + is not a function. + + fc [-e _e_n_a_m_e] [-nlr] [_f_i_r_s_t] [_l_a_s_t] + fc -s [_p_a_t=_r_e_p] [_c_m_d] + Fix Command. In the first form, a range of commands + from _f_i_r_s_t to _l_a_s_t is selected from the history list. + _F_i_r_s_t and _l_a_s_t may be specified as a string (to locate + the last command beginning with that string) or as a + number (an index into the history list, where a nega- + tive number is used as an offset from the current com- + mand number). If _l_a_s_t is not specified it is set to + the current command for listing (so that fc -l -10 + prints the last 10 commands) and to _f_i_r_s_t otherwise. + If _f_i_r_s_t is not specified it is set to the previous + command for editing and -16 for listing. + + The -n flag suppresses the command numbers when list- + ing. The -r flag reverses the order of the commands. + If the -l flag is given, the commands are listed on + + + +GNU Last change: 1995 May 5 45 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + standard output. Otherwise, the editor given by _e_n_a_m_e + is invoked on a file containing those commands. If + _e_n_a_m_e is not given, the value of the FCEDIT variable is + used, and the value of EDITOR if FCEDIT is not set. If + neither variable is set, _v_i is used. When editing is + complete, the edited commands are echoed and executed. + + In the second form, _c_o_m_m_a_n_d is re-executed after each + instance of _p_a_t is replaced by _r_e_p. A useful alias to + use with this is ``r=fc -s'', so that typing ``r cc'' + runs the last command beginning with ``cc'' and typing + ``r'' re-executes the last command. + + If the first form is used, the return value is 0 unless + an illegal option is encountered or _f_i_r_s_t or _l_a_s_t + specify history lines out of range. If the -e option + is supplied, the return value is the value of the last + command executed or failure if an error occurs with the + temporary file of commands. If the second form is + used, the return status is that of the command re- + executed, unless _c_m_d does not specify a valid history + line, in which case fc returns failure. + + fg [_j_o_b_s_p_e_c] + Place _j_o_b_s_p_e_c in the foreground, and make it the + current job. If _j_o_b_s_p_e_c is not present, the shell's + notion of the _c_u_r_r_e_n_t _j_o_b is used. The return value is + that of the command placed into the foreground, or + failure if run when job control is disabled or, when + run with job control enabled, if _j_o_b_s_p_e_c does not + specify a valid job or _j_o_b_s_p_e_c specifies a job that was + started without job control. + + getopts _o_p_t_s_t_r_i_n_g _n_a_m_e [_a_r_g_s] + getopts is used by shell procedures to parse positional + parameters. _o_p_t_s_t_r_i_n_g contains the option letters to + be recognized; if a letter is followed by a colon, the + option is expected to have an argument, which should be + separated from it by white space. Each time it is + invoked, getopts places the next option in the shell + variable _n_a_m_e, initializing _n_a_m_e if it does not exist, + and the index of the next argument to be processed into + the variable OPTIND. OPTIND is initialized to 1 each + time the shell or a shell script is invoked. When an + option requires an argument, getopts places that argu- + ment into the variable OPTARG. The shell does not + reset OPTIND automatically; it must be manually reset + between multiple calls to getopts within the same shell + invocation if a new set of parameters is to be used. + + getopts can report errors in two ways. If the first + character of _o_p_t_s_t_r_i_n_g is a colon, _s_i_l_e_n_t error + + + +GNU Last change: 1995 May 5 46 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + reporting is used. In normal operation diagnostic mes- + sages are printed when illegal options or missing + option arguments are encountered. If the variable + OPTERR is set to 0, no error message will be displayed, + even if the first character of _o_p_t_s_t_r_i_n_g is not a + colon. + + If an illegal option is seen, getopts places ? into + _n_a_m_e and, if not silent, prints an error message and + unsets OPTARG. If getopts is silent, the option char- + acter found is placed in OPTARG and no diagnostic mes- + sage is printed. + + If a required argument is not found, and getopts is not + silent, a question mark (?) is placed in _n_a_m_e, OPTARG + is unset, and a diagnostic message is printed. If + getopts is silent, then a colon (:) is placed in _n_a_m_e + and OPTARG is set to the option character found. + + getopts normally parses the positional parameters, but + if more arguments are given in _a_r_g_s, getopts parses + those instead. getopts returns true if an option, + specified or unspecified, is found. It returns false + if the end of options is encountered or an error + occurs. + + hash [-r] [_n_a_m_e] + For each _n_a_m_e, the full pathname of the command is + determined and remembered. The -r option causes the + shell to forget all remembered locations. If no argu- + ments are given, information about remembered commands + is printed. An argument of -- disables option checking + for the rest of the arguments. The return status is + true unless a _n_a_m_e is not found or an illegal option is + supplied. + + help [_p_a_t_t_e_r_n] + Display helpful information about builtin commands. If + _p_a_t_t_e_r_n is specified, help gives detailed help on all + commands matching _p_a_t_t_e_r_n; otherwise a list of the + builtins is printed. The return status is 0 unless no + command matches _p_a_t_t_e_r_n. + + history [_n] + history -rwan [_f_i_l_e_n_a_m_e] + With no options, display the command history list with + line numbers. Lines listed with a * have been modi- + fied. An argument of _n lists only the last _n lines. + If a non-option argument is supplied, it is used as the + name of the history file; if not, the value of HISTFILE + is used. Options, if supplied, have the following + meanings: + + + +GNU Last change: 1995 May 5 47 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + -a Append the ``new'' history lines (history lines + entered since the beginning of the current bash + session) to the history file + -n Read the history lines not already read from the + history file into the current history list. These + are lines appended to the history file since the + beginning of the current bash session. + -r Read the contents of the history file and use them + as the current history + -w Write the current history to the history file, + overwriting the history file's contents. + + The return value is 0 unless an illegal option is + encountered or an error occurs while reading or writing + the history file. + + jobs [-lnp] [ _j_o_b_s_p_e_c ... ] + jobs -x _c_o_m_m_a_n_d [ _a_r_g_s ... ] + The first form lists the active jobs. The -l option + lists process IDs in addition to the normal informa- + tion; the -p option lists only the process ID of the + job's process group leader. The -n option displays + only jobs that have changed status since last notified. + If _j_o_b_s_p_e_c is given, output is restricted to informa- + tion about that job. The return status is 0 unless an + illegal option is encountered or an illegal _j_o_b_s_p_e_c is + supplied. + + If the -x option is supplied, jobs replaces any _j_o_b_s_p_e_c + found in _c_o_m_m_a_n_d or _a_r_g_s with the corresponding process + group ID, and executes _c_o_m_m_a_n_d passing it _a_r_g_s, return- + ing its exit status. + + kill [-s sigspec | -sigspec] [_p_i_d | _j_o_b_s_p_e_c] ... + kill -l [_s_i_g_n_u_m] + Send the signal named by _s_i_g_s_p_e_c to the processes named + by _p_i_d or _j_o_b_s_p_e_c. _s_i_g_s_p_e_c is either a signal name + such as SIGKILL or a signal number. If _s_i_g_s_p_e_c is a + signal name, the name is case insensitive and may be + given with or without the SIG prefix. If _s_i_g_s_p_e_c is + not present, then SIGTERM is assumed. An argument of + -l lists the signal names. If any arguments are sup- + plied when -l is given, the names of the specified sig- + nals are listed, and the return status is 0. An argu- + ment of -- disables option checking for the rest of the + arguments. kill returns true if at least one signal + was successfully sent, or false if an error occurs or + an illegal option is encountered. + + let _a_r_g [_a_r_g ...] + Each _a_r_g is an arithmetic expression to be evaluated + (see ARITHMETIC EVALUATION). If the last _a_r_g evaluates + + + +GNU Last change: 1995 May 5 48 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + to 0, let returns 1; 0 is returned otherwise. + + local [_n_a_m_e[=_v_a_l_u_e] ...] + For each argument, create a local variable named _n_a_m_e, + and assign it _v_a_l_u_e. When local is used within a func- + tion, it causes the variable _n_a_m_e to have a visible + scope restricted to that function and its children. + With no operands, local writes a list of local vari- + ables to the standard output. It is an error to use + local when not within a function. The return status is + 0 unless local is used outside a function, or an ille- + gal _n_a_m_e is supplied. + + logout + Exit a login shell. + + popd [+/-n] + Removes entries from the directory stack. With no + arguments, removes the top directory from the stack, + and performs a cd to the new top directory. + +n removes the _nth entry counting from the left of + the list shown by dirs, starting with zero. For + example: ``popd +0'' removes the first directory, + ``popd +1'' the second. + -n removes the _nth entry counting from the right of + the list shown by dirs, starting with zero. For + example: ``popd -0'' removes the last directory, + ``popd -1'' the next to last. + + If the popd command is successful, a dirs is performed + as well, and the return status is 0. popd returns + false if an illegal option is encountered, the direc- + tory stack is empty, a non-existent directory stack + entry is specified, or the directory change fails. + + pushd [_d_i_r] + pushd +/-n + Adds a directory to the top of the directory stack, or + rotates the stack, making the new top of the stack the + current working directory. With no arguments, + exchanges the top two directories and returns 0, unless + the directory stack is empty. + +n Rotates the stack so that the _nth directory + (counting from the left of the list shown by dirs) + is at the top. + -n Rotates the stack so that the _nth directory + (counting from the right) is at the top. + dir adds _d_i_r to the directory stack at the top, making + it the new current working directory. + + If the pushd command is successful, a dirs is performed + as well. If the first form is used, pushd returns 0 + + + +GNU Last change: 1995 May 5 49 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + unless the cd to _d_i_r fails. With the second form, + pushd returns 0 unless the directory stack is empty, a + non-existant directory stack element is specified, or + the directory change to the specified new current + directory fails. + + pwd Print the absolute pathname of the current working + directory. The path printed contains no symbolic links + if the -P option to the set builtin command is set. + See also the description of nolinks under Shell Vari- + ables above). The return status is 0 unless an error + occurs while reading the pathname of the current direc- + tory. + + read [-r] [_n_a_m_e ...] + One line is read from the standard input, and the first + word is assigned to the first _n_a_m_e, the second word to + the second _n_a_m_e, and so on, with leftover words + assigned to the last _n_a_m_e. Only the characters in IFS + are recognized as word delimiters. If no _n_a_m_e_s are + supplied, the line read is assigned to the variable + REPLY. The return code is zero, unless end-of-file is + encountered. If the -r option is given, a backslash- + newline pair is not ignored, and the backslash is con- + sidered to be part of the line. + + readonly [-f] [_n_a_m_e ...] + readonly -p + The given _n_a_m_e_s are marked readonly and the values of + these _n_a_m_e_s may not be changed by subsequent assign- + ment. If the -f option is supplied, the functions + corresponding to the _n_a_m_e_s are so marked. If no argu- + ments are given, or if the -p option is supplied, a + list of all readonly names is printed. An argument of + -- disables option checking for the rest of the argu- + ments. The return status is 0 unless an illegal option + is encountered, one of the _n_a_m_e_s is not a legal shell + variable name, or -f is supplied with a _n_a_m_e that is + not a function. + + return [_n] + Causes a function to exit with the return value speci- + fied by _n. If _n is omitted, the return status is that + of the last command executed in the function body. If + used outside a function, but during execution of a + script by the . (source) command, it causes the shell + to stop executing that script and return either _n or + the exit status of the last command executed within the + script as the exit status of the script. If used out- + side a function and not during execution of a script by + ., the return status is false. + + + + +GNU Last change: 1995 May 5 50 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + set [--abefhkmnptuvxldCHP] [-o _o_p_t_i_o_n] [_a_r_g ...] + -a Automatically mark variables which are modified + or created for export to the environment of + subsequent commands. + -b Cause the status of terminated background jobs + to be reported immediately, rather than before + the next primary prompt. (Also see notify + under Shell Variables above). + -e Exit immediately if a _s_i_m_p_l_e-_c_o_m_m_a_n_d (see SHELL + GRAMMAR above) exits with a non-zero status. + The shell does not exit if the command that + fails is part of an _u_n_t_i_l or _w_h_i_l_e loop, part + of an _i_f statement, part of a && or || list, or + if the command's return value is being inverted + via !. + -f Disable pathname expansion. + -h Locate and remember function commands as func- + tions are defined. Function commands are nor- + mally looked up when the function is executed. + -k All keyword arguments are placed in the + environment for a command, not just those that + precede the command name. + -m Monitor mode. Job control is enabled. This + flag is on by default for interactive shells on + systems that support it (see JOB CONTROL + above). Background processes run in a separate + process group and a line containing their exit + status is printed upon their completion. + -n Read commands but do not execute them. This + may be used to check a shell script for syntax + errors. This is ignored for interactive + shells. + -o _o_p_t_i_o_n-_n_a_m_e + The _o_p_t_i_o_n-_n_a_m_e can be one of the following: + allexport + Same as -a. + braceexpand + The shell performs brace expansion (see + Brace Expansion above). This is on by + default. + emacs Use an emacs-style command line editing + interface. This is enabled by default + when the shell is interactive, unless + the shell is started with the -nol- + ineediting option. + errexit Same as -e. + histexpand + Same as -H. + ignoreeof + The effect is as if the shell command + `IGNOREEOF=10' had been executed (see + Shell Variables above). + + + +GNU Last change: 1995 May 5 51 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + interactive-comments + Allow a word beginning with # to cause + that word and all remaining characters + on that line to be ignored in an + interactive shell (see COMMENTS above). + monitor Same as -m. + noclobber + Same as -C. + noexec Same as -n. + noglob Same as -f. + nohash Same as -d. + notify Same as -b. + nounset Same as -u. + physical + Same as -P. + posix Change the behavior of bash where the + default operation differs from the + Posix 1003.2 standard to match the + standard. + privileged + Same as -p. + verbose Same as -v. + vi Use a vi-style command line editing + interface. + xtrace Same as -x. + If no _o_p_t_i_o_n-_n_a_m_e is supplied, the values of + the current options are printed. + -p Turn on _p_r_i_v_i_l_e_g_e_d mode. In this mode, the + $ENV file is not processed, and shell functions + are not inherited from the environment. This + is enabled automatically on startup if the + effective user (group) id is not equal to the + real user (group) id. Turning this option off + causes the effective user and group ids to be + set to the real user and group ids. + -t Exit after reading and executing one command. + -u Treat unset variables as an error when perform- + ing parameter expansion. If expansion is + attempted on an unset variable, the shell + prints an error message, and, if not interac- + tive, exits with a non-zero status. + -v Print shell input lines as they are read. + -x After expanding each _s_i_m_p_l_e-_c_o_m_m_a_n_d, bash + displays the expanded value of PS4, followed by + the command and its expanded arguments. + -l Save and restore the binding of _n_a_m_e in a for + _n_a_m_e [in word] command (see SHELL GRAMMAR + above). + -d Disable the hashing of commands that are looked + up for execution. Normally, commands are + remembered in a hash table, and once found, do + not have to be looked up again. + + + +GNU Last change: 1995 May 5 52 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + -C The effect is as if the shell command + `noclobber=' had been executed (see Shell Vari- + ables above). + -H Enable ! style history substitution. This flag + is on by default when the shell is interactive. + -P If set, do not follow symbolic links when per- + forming commands such as cd which change the + current directory. The physical directory is + used instead. + -- If no arguments follow this flag, then the + positional parameters are unset. Otherwise, + the positional parameters are set to the _a_r_gs, + even if some of them begin with a -. + - Signal the end of options, cause all remaining + _a_r_gs to be assigned to the positional parame- + ters. The -x and -v options are turned off. + If there are no _a_r_gs, the positional parameters + remain unchanged. + + The flags are off by default unless otherwise noted. + Using + rather than - causes these flags to be turned + off. The flags can also be specified as options to an + invocation of the shell. The current set of flags may + be found in $-. After the option arguments are pro- + cessed, the remaining _n _a_r_gs are treated as values for + the positional parameters and are assigned, in order, + to $1, $2, ... $_n. If no options or _a_r_gs are supplied, + all shell variables are printed. The return status is + always true unless an illegal option is encountered. + + shift [_n] + The positional parameters from _n+1 ... are renamed to + $1 .... Parameters represented by the numbers $# down + to $#-_n+1 are unset. If _n is 0, no parameters are + changed. If _n is not given, it is assumed to be 1. _n + must be a non-negative number less than or equal to $#. + If _n is greater than $#, the positional parameters are + not changed. The return status is greater than 0 if _n + is greater than $# or less than 0; otherwise 0. + + suspend [-f] + Suspend the execution of this shell until it receives a + SIGCONT signal. The -f option says not to complain if + this is a login shell; just suspend anyway. The return + status is 0 unless the shell is a login shell and -f is + not supplied, or if job control is not enabled. + + test _e_x_p_r + [ _e_x_p_r ] + Return a status of 0 (true) or 1 (false) depending on + the evaluation of the conditional expression _e_x_p_r. + Expressions may be unary or binary. Unary expressions + + + +GNU Last change: 1995 May 5 53 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + are often used to examine the status of a file. There + are string operators and numeric comparison operators + as well. Each operator and operand must be a separate + argument. If _f_i_l_e is of the form /dev/fd/_n, then file + descriptor _n is checked. + -b _f_i_l_e + True if _f_i_l_e exists and is block special. + -c _f_i_l_e + True if _f_i_l_e exists and is character special. + -d _f_i_l_e + True if _f_i_l_e exists and is a directory. + -e _f_i_l_e + True if _f_i_l_e exists. + -f _f_i_l_e + True if _f_i_l_e exists and is a regular file. + -g _f_i_l_e + True if _f_i_l_e exists and is set-group-id. + -k _f_i_l_e + True if _f_i_l_e has its ``sticky'' bit set. + -L _f_i_l_e + True if _f_i_l_e exists and is a symbolic link. + -p _f_i_l_e + True if _f_i_l_e exists and is a named pipe. + -r _f_i_l_e + True if _f_i_l_e exists and is readable. + -s _f_i_l_e + True if _f_i_l_e exists and has a size greater than + zero. + -S _f_i_l_e + True if _f_i_l_e exists and is a socket. + -t _f_d + True if _f_d is opened on a terminal. + -u _f_i_l_e + True if _f_i_l_e exists and its set-user-id bit is + set. + -w _f_i_l_e + True if _f_i_l_e exists and is writable. + -x _f_i_l_e + True if _f_i_l_e exists and is executable. + -O _f_i_l_e + True if _f_i_l_e exists and is owned by the effective + user id. + -G _f_i_l_e + True if _f_i_l_e exists and is owned by the effective + group id. + _f_i_l_e_1 -nt _f_i_l_e_2 + True if _f_i_l_e_1 is newer (according to modification + date) than _f_i_l_e_2. + _f_i_l_e_1 -ot _f_i_l_e_2 + True if _f_i_l_e_1 is older than file2. + _f_i_l_e_1 -ef _f_i_l_e + True if _f_i_l_e_1 and _f_i_l_e_2 have the same device and + + + +GNU Last change: 1995 May 5 54 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + inode numbers. + -z _s_t_r_i_n_g + True if the length of _s_t_r_i_n_g is zero. + -n _s_t_r_i_n_g + _s_t_r_i_n_g + True if the length of _s_t_r_i_n_g is non-zero. + _s_t_r_i_n_g_1 = _s_t_r_i_n_g_2 + True if the strings are equal. + _s_t_r_i_n_g_1 != _s_t_r_i_n_g_2 + True if the strings are not equal. + ! _e_x_p_r + True if _e_x_p_r is false. + _e_x_p_r_1 -a _e_x_p_r_2 + True if both _e_x_p_r_1 AND _e_x_p_r_2 are true. + _e_x_p_r_1 -o _e_x_p_r_2 + True if either _e_x_p_r_1 OR _e_x_p_r_2 is true. + _a_r_g_1 OP _a_r_g_2 + OP is one of -eq, -ne, -lt, -le, -gt, or -ge. + These arithmetic binary operators return true if + _a_r_g_1 is equal, not-equal, less-than, less-than- + or-equal, greater-than, or greater-than-or-equal + than _a_r_g_2, respectively. _A_r_g_1 and _a_r_g_2 may be + positive integers, negative integers, or the spe- + cial expression -l _s_t_r_i_n_g, which evaluates to the + length of _s_t_r_i_n_g. + + times + Print the accumulated user and system times for the + shell and for processes run from the shell. The return + status is 0. + + trap [-l] [_a_r_g] [_s_i_g_s_p_e_c] + The command _a_r_g is to be read and executed when the + shell receives signal(s) _s_i_g_s_p_e_c. If _a_r_g is absent or + -, all specified signals are reset to their original + values (the values they had upon entrance to the + shell). If _a_r_g is the null string this signal is + ignored by the shell and by the commands it invokes. + _s_i_g_s_p_e_c is either a signal name defined in <_s_i_g_n_a_l._h>, + or a signal number. If _s_i_g_s_p_e_c is EXIT (0) the command + _a_r_g is executed on exit from the shell. With no argu- + ments, trap prints the list of commands associated with + each signal number. The -l option causes the shell to + print a list of signal names and their corresponding + numbers. An argument of -- disables option checking + for the rest of the arguments. Signals ignored upon + entry to the shell cannot be trapped or reset. Trapped + signals are reset to their original values in a child + process when it is created. The return status is false + if either the trap name or number is invalid; otherwise + trap returns true. + + + + +GNU Last change: 1995 May 5 55 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + type [-all] [-type | -path] _n_a_m_e [_n_a_m_e ...] + With no options, indicate how each _n_a_m_e would be inter- + preted if used as a command name. If the -type flag is + used, type prints a phrase which is one of _a_l_i_a_s, _k_e_y_- + _w_o_r_d, _f_u_n_c_t_i_o_n, _b_u_i_l_t_i_n, or _f_i_l_e if _n_a_m_e is an alias, + shell reserved word, function, builtin, or disk file, + respectively. If the name is not found, then nothing is + printed, and an exit status of false is returned. If + the -path flag is used, type either returns the name of + the disk file that would be executed if _n_a_m_e were + specified as a command name, or nothing if -type would + not return _f_i_l_e. If a command is hashed, -path prints + the hashed value, not necessarily the file that appears + first in PATH. If the -all flag is used, type prints + all of the places that contain an executable named + _n_a_m_e. This includes aliases and functions, if and only + if the -path flag is not also used. The table of + hashed commands is not consulted when using -all. type + accepts -a, -t, and -p in place of -all, -type, and + -path, respectively. An argument of -- disables option + checking for the rest of the arguments. type returns + true if any of the arguments are found, false if none + are found. + + ulimit [-SHacdfmstpnuv [_l_i_m_i_t]] + Ulimit provides control over the resources available to + the shell and to processes started by it, on systems + that allow such control. The value of _l_i_m_i_t can be a + number in the unit specified for the resource, or the + value unlimited. The H and S options specify that the + hard or soft limit is set for the given resource. A + hard limit cannot be increased once it is set; a soft + limit may be increased up to the value of the hard + limit. If neither H nor S is specified, the command + applies to the soft limit. If _l_i_m_i_t is omitted, the + current value of the soft limit of the resource is + printed, unless the H option is given. When more than + one resource is specified, the limit name and unit is + printed before the value. Other options are inter- + preted as follows: + -a all current limits are reported + -c the maximum size of core files created + -d the maximum size of a process's data segment + -f the maximum size of files created by the shell + -m the maximum resident set size + -s the maximum stack size + -t the maximum amount of cpu time in seconds + -p the pipe size in 512-byte blocks (this may not be + set) + -n the maximum number of open file descriptors (most + systems do not allow this value to be set, only + displayed) + + + +GNU Last change: 1995 May 5 56 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + -u the maximum number of processes available to a + single user + -v The maximum amount of virtual memory available to + the shell + + An argument of -- disables option checking for the rest + of the arguments. If _l_i_m_i_t is given, it is the new + value of the specified resource (the -a option is + display only). If no option is given, then -f is + assumed. Values are in 1024-byte increments, except + for -t, which is in seconds, -p, which is in units of + 512-byte blocks, and -n and -u, which are unscaled + values. The return status is 0 unless an illegal + option is encountered, a non-numeric argument other + than unlimited is supplied as _l_i_m_i_t, or an error occurs + while setting a new limit. + + umask [-S] [_m_o_d_e] + The user file-creation mask is set to _m_o_d_e. If _m_o_d_e + begins with a digit, it is interpreted as an octal + number; otherwise it is interpreted as a symbolic mode + mask similar to that accepted by _c_h_m_o_d(1). If _m_o_d_e is + omitted, or if the -S option is supplied, the current + value of the mask is printed. The -S option causes the + mask to be printed in symbolic form; the default output + is an octal number. An argument of -- disables option + checking for the rest of the arguments. The return + status is 0 if the mode was successfully changed or if + no _m_o_d_e argument was supplied, and false otherwise. + + unalias [-a] [_n_a_m_e ...] + Remove _n_a_m_es from the list of defined aliases. If -a + is supplied, all alias definitions are removed. The + return value is true unless a supplied _n_a_m_e is not a + defined alias. + + unset [-fv] [_n_a_m_e ...] + For each _n_a_m_e, remove the corresponding variable or, + given the -f option, function. An argument of -- dis- + ables option checking for the rest of the arguments. + Note that PATH, IFS, PPID, PS1, PS2, UID, and EUID can- + not be unset. If any of RANDOM, SECONDS, LINENO, or + HISTCMD are unset, they lose their special properties, + even if they are subsequently reset. The exit status + is true unless a _n_a_m_e does not exist or is non- + unsettable. + + wait [_n] + Wait for the specified process and return its termina- + tion status. _n may be a process ID or a job specifica- + tion; if a job spec is given, all processes in that + job's pipeline are waited for. If _n is not given, all + + + +GNU Last change: 1995 May 5 57 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + currently active child processes are waited for, and + the return status is zero. If _n specifies a non- + existant process or job, the return status is 127. + Otherwise, the return status is the exit status of the + last process or job waited for. + +INVOCATION + A _l_o_g_i_n _s_h_e_l_l is one whose first character of argument zero + is a -, or one started with the -login flag. + + An _i_n_t_e_r_a_c_t_i_v_e shell is one whose standard input and output + are both connected to terminals (as determined by + _i_s_a_t_t_y(3)), or one started with the -i option. PS1 is set + and $- includes i if bash is interactive, allowing a shell + script or a startup file to test this state. + + Login shells: + On login (subject to the -noprofile option): + if /_e_t_c/_p_r_o_f_i_l_e exists, source it. + + if ~/._b_a_s_h__p_r_o_f_i_l_e exists, source it, + else if ~/._b_a_s_h__l_o_g_i_n exists, source it, + else if ~/._p_r_o_f_i_l_e exists, source it. + + On exit: + if ~/._b_a_s_h__l_o_g_o_u_t exists, source it. + + Non-login interactive shells: + On startup (subject to the -norc and -rcfile options): + if ~/._b_a_s_h_r_c exists, source it. + + Non-interactive shells: + On startup: + if the environment variable ENV is non-null, expand + it and source the file it names, as if the command + if [ "$ENV" ]; then . $ENV; fi + had been executed, but do not use PATH to search + for the pathname. When not started in Posix mode, bash + looks for BASH_ENV before ENV. + + If Bash is invoked as sh, it tries to mimic the behavior of + sh as closely as possible. For a login shell, it attempts + to source only /_e_t_c/_p_r_o_f_i_l_e and ~/._p_r_o_f_i_l_e, in that order. + The -noprofile option may still be used to disable this + behavior. A shell invoked as sh does not attempt to source + any other startup files. + + When bash is started in _p_o_s_i_x mode, as with the -posix com- + mand line option, it follows the Posix standard for startup + files. In this mode, the ENV variable is expanded and that + file sourced; no other startup files are read. + + + + +GNU Last change: 1995 May 5 58 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + +SEE ALSO + _B_a_s_h _F_e_a_t_u_r_e_s, Brian Fox and Chet Ramey + _T_h_e _G_n_u _R_e_a_d_l_i_n_e _L_i_b_r_a_r_y, Brian Fox and Chet Ramey + _T_h_e _G_n_u _H_i_s_t_o_r_y _L_i_b_r_a_r_y, Brian Fox and Chet Ramey +Lennert + _A _S_y_s_t_e_m _V _C_o_m_p_a_t_i_b_l_e _I_m_p_l_e_m_e_n_t_a_t_i_o_n _o_f _4._2_B_S_D _J_o_b _C_o_n_t_r_o_l, David +_U_t_i_l_i_t_i_e_s, IEEE + _P_o_r_t_a_b_l_e _O_p_e_r_a_t_i_n_g _S_y_s_t_e_m _I_n_t_e_r_f_a_c_e (_P_O_S_I_X) _P_a_r_t _2: _S_h_e_l_l _a_n_d + _s_h(1), _k_s_h(1), _c_s_h(1) + _e_m_a_c_s(1), _v_i(1) + _r_e_a_d_l_i_n_e(3) + +FILES + /_b_i_n/_b_a_s_h + The bash executable + /_e_t_c/_p_r_o_f_i_l_e + The systemwide initialization file, executed for login + shells + ~/._b_a_s_h__p_r_o_f_i_l_e + The personal initialization file, executed for login + shells + ~/._b_a_s_h_r_c + The individual per-interactive-shell startup file + ~/._i_n_p_u_t_r_c + Individual _r_e_a_d_l_i_n_e initialization file + +AUTHORS + Brian Fox, Free Software Foundation (primary author) + bfox@ai.MIT.Edu + + Chet Ramey, Case Western Reserve University + chet@ins.CWRU.Edu + +BUG REPORTS + If you find a bug in bash, you should report it. But first, + you should make sure that it really is a bug, and that it + appears in the latest version of bash that you have. + + Once you have determined that a bug actually exists, use the + _b_a_s_h_b_u_g command to submit a bug report. If you have a fix, + you are welcome to mail that as well! Suggestions and `phi- + losophical' bug reports may be mailed to _b_u_g- + _b_a_s_h@_p_r_e_p._a_i._M_I_T._E_d_u or posted to the Usenet newsgroup + gnu.bash.bug. + + ALL bug reports should include: + + The version number of bash + The hardware and operating system + The compiler used to compile + A description of the bug behaviour + A short script or `recipe' which exercises the bug + + + +GNU Last change: 1995 May 5 59 + + + + + + +BASH(1) USER COMMANDS BASH(1) + + + + _b_a_s_h_b_u_g inserts the first three items automatically into the + template it provides for filing a bug report. + + Comments and bug reports concerning this manual page should + be directed to _c_h_e_t@_i_n_s._C_W_R_U._E_d_u. + +BUGS + It's too big and too slow. + + There are some subtle differences between bash and tradi- + tional versions of sh, mostly because of the POSIX specifi- + cation. + + Aliases are confusing in some uses. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GNU Last change: 1995 May 5 60 + + + diff --git a/documentation/builtins.1 b/documentation/builtins.1 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 F2A F3 -.1(ke)2.5 +G(ymap)-.2 E F0 2.5(][)C F2(\255lvd)189.12 468 Q F0 2.5(][)C F2(-q)217.32 468 Q +F3(name)2.5 E F0(])A F2(bind)108 480 Q F0([)2.5 E F2A F3 -.1(ke)2.5 G +(ymap)-.2 E F0(])A F2(-f)2.5 E F3(\214lename)2.5 E F2(bind)108 492 Q F0([)2.5 E +F2A F3 -.1(ke)2.5 G(ymap)-.2 E F0(])A F3 -.1(ke)2.5 G(yseq)-.2 E F0(:)A +F3(function-name)A F0 .239(Display current)144 504 R F2 -.18(re)2.739 G(adline) +.18 E F0 -.1(ke)2.739 G 2.739(ya)-.05 G .239(nd function bindings, or bind a k) +267.836 504 R .538 -.15(ey s)-.1 H .238(equence to a).15 F F2 -.18(re)2.738 G +(adline).18 E F0(function)2.738 E .88(or macro.)144 516 R .88 +(The binding syntax accepted is identical to that of)5.88 F F3(.inputr)3.38 E +(c)-.37 E F0 3.38(,b).31 G .88(ut each binding must be)440.93 516 R .381 +(passed as a separate ar)144 528 R .381 +(gument; e.g., '"\\C-x\\C-r": re\255read\255init\255\214le'.)-.18 F .381 +(Options, if supplied, ha)5.381 F .68 -.15(ve t)-.2 H(he).15 E(follo)144 540 Q +(wing meanings:)-.25 E F2144 552 Q F3 -.1(ke)2.5 G(ymap)-.2 E F0(Use)180 +564 Q F3 -.1(ke)5.174 G(ymap)-.2 E F0 2.674(as the k)5.174 F -.15(ey)-.1 G +2.674(map to be af).15 F 2.674(fected by the subsequent bindings.)-.25 F +(Acceptable)7.675 E F3 -.1(ke)180 576 S(ymap)-.2 E F0 2.929(names are)5.429 F +F3 2.929(emacs, emacs-standar)5.429 F 2.929 +(d, emacs-meta, emacs-ctlx, vi, vi-mo)-.37 F(ve)-.1 E 5.428(,v)-.1 G(i-)533.89 +576 Q(command)180 588 Q F0 3.434(,a)C(nd)229.254 588 Q F3(vi-insert)3.434 E F0 +(.).68 E F3(vi)5.934 E F0 .934(is equi)3.434 F -.25(va)-.25 G .934(lent to).25 +F F3(vi-command)3.434 E F0(;)A F3(emacs)3.434 E F0 .934(is equi)3.434 F -.25 +(va)-.25 G .935(lent to).25 F F3(emacs-)3.435 E(standar)180 600 Q(d)-.37 E F0 +(.)A F2144 612 Q F0(List the names of all)180 612 Q F2 -.18(re)2.5 G +(adline).18 E F0(functions)2.5 E F2144 624 Q F0 +(List current function names and bindings)180 624 Q F2144 636 Q F0 +(Dump function names and bindings in such a w)180 636 Q(ay that the)-.1 E 2.5 +(yc)-.15 G(an be re-read)423.89 636 Q F2144 648 Q F3(\214lename)2.5 E F0 +(Read k)180 660 Q .3 -.15(ey b)-.1 H(indings from).15 E F3(\214lename)2.5 E F2 +144 672 Q F3(function)2.5 E F0(Query about which k)180 684 Q -.15(ey)-.1 +G 2.5(si).15 G -1.9 -.4(nv o)282.51 684 T .2 -.1(ke t).4 H(he named).1 E F3 +(function)2.5 E F0(The return v)144 700.8 Q +(alue is 0 unless an unrecognized option is gi)-.25 E -.15(ve)-.25 G 2.5(no).15 +G 2.5(ra)391.37 700.8 S 2.5(ne)401.64 700.8 S(rror occurred.)413.58 700.8 Q +170.955(GNU 1993)72 768 R(September 16)2.5 E(1)535 768 Q EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF(br)108 84 Q(eak)-.18 E F0([)2.5 E/F2 10/Times-Italic@0 SF(n)A F0(])A .076 +(Exit from within a)144 96 R F1 -.25(fo)2.576 G(r).25 E F0(,)A F1(while)2.576 E +F0 2.576(,o)C(r)270.866 96 Q F1(until)2.576 E F0 2.576(loop. If)2.576 F F2(n) +2.576 E F0 .076(is speci\214ed, break)2.576 F F2(n)2.576 E F0(le)2.576 E -.15 +(ve)-.25 G(ls.).15 E F2(n)5.075 E F0 .075(must be)2.575 F/F3 10/Symbol SF +2.575 E F0 2.575(1. If)2.575 F F2(n)2.575 E F0(is)2.575 E .838 +(greater than the number of enclosing loops, all enclosing loops are e)144 108 +R 3.338(xited. The)-.15 F .838(return v)3.338 F .839(alue is 0)-.25 F +(unless the shell is not e)144 120 Q -.15(xe)-.15 G(cuting a loop when).15 E F1 +(br)2.5 E(eak)-.18 E F0(is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 -.2(bu)108 +136.8 S(iltin).2 E F2(shell\255b)2.5 E(uiltin)-.2 E F0([)2.5 E F2(ar)A(guments) +-.37 E F0(])A(Ex)144 148.8 Q .793(ecute the speci\214ed shell b)-.15 F .793 +(uiltin, passing it)-.2 F F2(ar)3.293 E(guments)-.37 E F0 3.293(,a).27 G .793 +(nd return its e)382.104 148.8 R .792(xit status.)-.15 F .792(This is useful) +5.792 F .603 +(when you wish to de\214ne a function whose name is the same as a shell b)144 +160.8 R .603(uiltin, b)-.2 F .603(ut need the func-)-.2 F .773 +(tionality of the b)144 172.8 R .773(uiltin within the function itself.)-.2 F +(The)5.773 E F1(cd)3.273 E F0 -.2(bu)3.273 G .772 +(iltin is commonly rede\214ned this w).2 F(ay)-.1 E(.)-.65 E +(The return status is f)144 184.8 Q(alse if)-.1 E F2(shell\255b)2.5 E(uiltin) +-.2 E F0(is not a shell b)2.5 E(uiltin command.)-.2 E F1(cd)108 201.6 Q F0([) +2.5 E F2(dir)A F0 5.17(]C)C .21(hange the current directory to)150.67 201.6 R +F2(dir)2.71 E F0 5.21(.T)C .21(he v)298.01 201.6 R(ariable)-.25 E/F4 9 +/Times-Bold@0 SF(HOME)2.71 E F0 .21(is the def)2.46 F(ault)-.1 E F2(dir)2.71 E +F0 5.21(.T).73 G .21(he v)456.703 201.6 R(ariable)-.25 E F4(CDP)2.71 E -.855 +(AT)-.666 G(H).855 E F0 .337 +(de\214nes the search path for the directory containing)144 213.6 R F2(dir) +2.837 E F0 5.337(.A).73 G(lternati)379.663 213.6 Q .637 -.15(ve d)-.25 H .337 +(irectory names are separated).15 F .309(by a colon \(:\).)144 225.6 R 2.809 +(An)5.309 G .309(ull directory name in)221.365 225.6 R F4(CDP)2.809 E -.855(AT) +-.666 G(H).855 E F0 .309(is the same as the current directory)2.559 F 2.809(,i) +-.65 G .31(.e., `)496.44 225.6 R(`)-.74 E F1(.)A F0 -.74('')C 5.31(.I).74 G(f) +536.67 225.6 Q F2(dir)144 237.6 Q F0(be)3.419 E .919 +(gins with a slash \(/\), then)-.15 F F4(CDP)3.419 E -.855(AT)-.666 G(H).855 E +F0 .919(is not used.)3.169 F .918(An ar)5.918 F .918(gument of)-.18 F F1 +3.418 E F0 .918(is equi)3.418 F -.25(va)-.25 G .918(lent to).25 F F4($OLD-) +3.418 E(PWD)144 249.6 Q/F5 9/Times-Roman@0 SF(.)A F0(The return v)4.5 E +(alue is true if the directory w)-.25 E(as successfully changed; f)-.1 E +(alse otherwise.)-.1 E F1(command)108 266.4 Q F0([)2.5 E F1(-pVv)A F0(])A F2 +(command)2.5 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Run)144 278.4 Q F2 +(command)2.877 E F0(with)2.877 E F2(ar)2.877 E(gs)-.37 E F0 .378 +(suppressing the normal shell function lookup. Only b)2.877 F .378 +(uiltin commands or)-.2 F .559(commands found in the)144 290.4 R F4 -.666(PA) +3.059 G(TH)-.189 E F0 .559(are e)2.809 F -.15(xe)-.15 G 3.059(cuted. If).15 F +(the)3.059 E F13.059 E F0 .559(option is gi)3.059 F -.15(ve)-.25 G .558 +(n, the search for).15 F F2(command)3.058 E F0(is)3.058 E .231 +(performed using a def)144 302.4 R .231(ault v)-.1 F .231(alue for)-.25 F F1 +-.74(PA)2.731 G(TH)-.21 E F0 .231 +(that is guaranteed to \214nd all of the standard utilities.)2.731 F(If)5.232 E +.232(either the)144 314.4 R F12.732 E F0(or)2.732 E F12.732 E F0 +.232(option is supplied, a description of)2.732 F F2(command)2.732 E F0 .232 +(is printed.)2.732 F(The)5.231 E F12.731 E F0 .231(option causes)2.731 F +2.71(as)144 326.4 S .21(ingle w)155.04 326.4 R .21 +(ord indicating the command or pathname used to in)-.1 F -.2(vo)-.4 G -.1(ke).2 +G F2(command)2.811 E F0 .211(to be printed; the)2.711 F F12.711 E F0 .476 +(option produces a more v)144 338.4 R .476(erbose description.)-.15 F .476 +(An ar)5.476 F .476(gument of)-.18 F F12.976 E F0 .475 +(disables option checking for the)2.976 F 1.348(rest of the ar)144 350.4 R +3.848(guments. If)-.18 F(the)3.848 E F13.848 E F0(or)3.848 E F1 +3.848 E F0 1.348(option is supplied, the e)3.848 F 1.349(xit status is 0 if) +-.15 F F2(command)3.849 E F0 -.1(wa)3.849 G(s).1 E 1.306(found, and 1 if not.) +144 362.4 R 1.305(If neither option is supplied and an error occurred or)6.306 +F F2(command)3.805 E F0 1.305(cannot be)3.805 F .092(found, the e)144 374.4 R +.092(xit status is 127.)-.15 F .092(Otherwise, the e)5.092 F .092 +(xit status of the)-.15 F F1(command)2.592 E F0 -.2(bu)2.592 G .093 +(iltin is the e).2 F .093(xit status of)-.15 F F2(command)144 386.4 Q F0(.).77 +E F1(continue)108 403.2 Q F0([)2.5 E F2(n)A F0(])A .065(Resume the ne)144 415.2 +R .065(xt iteration of the enclosing)-.15 F F1 -.25(fo)2.565 G(r).25 E F0(,)A +F1(while)2.565 E F0 2.564(,o)C(r)366.104 415.2 Q F1(until)2.564 E F0 2.564 +(loop. If)2.564 F F2(n)2.564 E F0 .064(is speci\214ed, resume at the)2.564 F F2 +(n)144 427.2 Q F0 1.168(th enclosing loop.)B F2(n)6.169 E F0 1.169(must be) +3.669 F F33.669 E F0 3.669(1. If)3.669 F F2(n)3.669 E F0 1.169 +(is greater than the number of enclosing loops, the last)3.669 F 1.594 +(enclosing loop \(the `top\255le)144 439.2 R -.15(ve)-.25 G 1.593 +(l' loop\) is resumed.).15 F 1.593(The return v)6.593 F 1.593 +(alue is 0 unless the shell is not)-.25 F -.15(exe)144 451.2 S +(cuting a loop when).15 E F1(continue)2.5 E F0(is e)2.5 E -.15(xe)-.15 G +(cuted.).15 E F1(declar)108 468 Q(e)-.18 E F0([)2.5 E F1(\255frxi)A F0 2.5(][)C +F2(name)175.16 468 Q F0([=)A F2(value)A F0(]])A F1(typeset)108 480 Q F0([)2.5 E +F1(\255frxi)A F0 2.5(][)C F2(name)174.23 480 Q F0([=)A F2(value)A F0(]])A 1.098 +(Declare v)144 492 R 1.098(ariables and/or gi)-.25 F 1.398 -.15(ve t)-.25 H +1.098(hem attrib).15 F 3.598(utes. If)-.2 F(no)3.598 E F2(name)3.598 E F0 3.598 +(sa)C 1.098(re gi)394.362 492 R -.15(ve)-.25 G 1.098(n, then display the v).15 +F 1.098(alues of)-.25 F -.25(va)144 504 S 2.492(riables instead.).25 F 2.491 +(The options can be used to restrict output to v)7.492 F 2.491 +(ariables with the speci\214ed)-.25 F(attrib)144 516 Q(ute.)-.2 E F1144 +528 Q F0(Use function names only)180 528 Q F1144 540 Q F0(Mak)180 540 Q +(e)-.1 E F2(name)5.046 E F0 5.046(sr)C(eadonly)241.642 540 Q 7.546(.T)-.65 G +2.546(hese names cannot then be assigned v)288.808 540 R 2.547 +(alues by subsequent)-.25 F(assignment statements.)180 552 Q F1144 564 Q +F0(Mark)180 564 Q F2(name)2.5 E F0 2.5(sf)C(or e)235.54 564 Q +(xport to subsequent commands via the en)-.15 E(vironment.)-.4 E F1144 +576 Q F0 .558(The v)180 576 R .558(ariable is treated as an inte)-.25 F .558 +(ger; arithmetic e)-.15 F -.25(va)-.25 G .558(luation \(see).25 F F4 .557 +(ARITHMETIC EV)3.058 F(ALU)-1.215 E(A-)-.54 E(TION \))180 588 Q F0 +(is performed when the v)2.25 E(ariable is assigned a v)-.25 E(alue.)-.25 E +1.218(Using `+' instead of `\255' turns of)144 604.8 R 3.719(ft)-.25 G 1.219 +(he attrib)289.369 604.8 R 1.219(ute instead.)-.2 F 1.219 +(When used in a function, mak)6.219 F(es)-.1 E F2(name)3.719 E F0(s)A .236 +(local, as with the)144 616.8 R F1(local)2.736 E F0 2.735(command. The)2.736 F +.235(return v)2.735 F .235(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.735 +(lo).05 G .235(ption is encountered, an)443.755 616.8 R .435 +(attempt is made to de\214ne a function using "-f foo=bar", one of the)144 +628.8 R F2(names)2.935 E F0 .435(is not a le)2.935 F -.05(ga)-.15 G 2.935(ls) +.05 G .435(hell v)503.435 628.8 R(ari-)-.25 E .52 +(able name, an attempt is made to turn of)144 640.8 R 3.019(fr)-.25 G .519 +(eadonly status for a readonly v)318.399 640.8 R .519 +(ariable, or an attempt is)-.25 F(made to display a non-e)144 652.8 Q +(xistant function with -f.)-.15 E F1(dirs [-l] [+/\255n])108 669.6 Q F0 1.505 +(Display the list of currently remembered directories.)144 681.6 R 1.505 +(Directories are added to the list with the)6.505 F F1(pushd)144 693.6 Q F0 +(command; the)2.5 E F1(popd)2.5 E F0(command mo)2.5 E -.15(ve)-.15 G 2.5(sb).15 +G(ack up through the list.)331.5 693.6 Q F1(+n)144 705.6 Q F0 .13(displays the) +180 705.6 R F2(n)2.63 E F0 .13(th entry counting from the left of the list sho) +B .13(wn by)-.25 F F1(dirs)2.63 E F0 .13(when in)2.63 F -.2(vo)-.4 G -.1(ke).2 +G 2.63(dw).1 G(ith-)526.11 705.6 Q(out options, starting with zero.)180 717.6 Q +170.955(GNU 1993)72 768 R(September 16)2.5 E(2)535 768 Q EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF144 84 Q F0 1.342(displays the)180 84 R/F2 10/Times-Italic@0 SF(n)3.842 +E F0 1.342(th entry counting from the right of the list sho)B 1.342(wn by)-.25 +F F1(dirs)3.842 E F0 1.342(when in)3.842 F -.2(vo)-.4 G -.1(ke).2 G(d).1 E +(without options, starting with zero.)180 96 Q F1144 108 Q F0 .362 +(produces a longer listing; the def)180 108 R .361 +(ault listing format uses a tilde to denote the home direc-)-.1 F(tory)180 120 +Q(.)-.65 E .38(The return v)144 136.8 R .38(alue is 0 unless an ille)-.25 F +-.05(ga)-.15 G 2.88(lo).05 G .381(ption is supplied or)303.79 136.8 R F2(n) +2.881 E F0(inde)2.881 E -.15(xe)-.15 G 2.881(sb).15 G -.15(ey)430.775 136.8 S +.381(ond the end of the direc-).15 F(tory stack.)144 148.8 Q F1(echo)108 165.6 +Q F0([)2.5 E F1(\255neE)A F0 2.5(][)C F2(ar)164.8 165.6 Q(g)-.37 E F0(...])2.5 +E .267(Output the)144 177.6 R F2(ar)2.767 E(g)-.37 E F0 .267 +(s, separated by spaces.)B .267(The return status is al)5.267 F -.1(wa)-.1 G +.266(ys 0.).1 F(If)5.266 E F12.766 E F0 .266 +(is speci\214ed, the trailing)2.766 F(ne)144 189.6 Q .31(wline is suppressed.) +-.25 F .311(If the)5.31 F F12.811 E F0 .311(option is gi)2.811 F -.15(ve) +-.25 G .311(n, interpretation of the follo).15 F .311(wing backslash-escaped) +-.25 F .874(characters is enabled.)144 201.6 R(The)5.874 E F13.374 E F0 +.874(option disables the interpretation of these escape characters, e)3.374 F +-.15(ve)-.25 G(n).15 E(on systems where the)144 213.6 Q 2.5(ya)-.15 G +(re interpreted by def)241.61 213.6 Q(ault.)-.1 E F1(\\a)144 225.6 Q F0 +(alert \(bell\))180 225.6 Q F1(\\b)144 237.6 Q F0(backspace)180 237.6 Q F1(\\c) +144 249.6 Q F0(suppress trailing ne)180 249.6 Q(wline)-.25 E F1(\\f)144 261.6 Q +F0(form feed)180 261.6 Q F1(\\n)144 273.6 Q F0(ne)180 273.6 Q 2.5(wl)-.25 G +(ine)201.69 273.6 Q F1(\\r)144 285.6 Q F0(carriage return)180 285.6 Q F1(\\t) +144 297.6 Q F0(horizontal tab)180 297.6 Q F1(\\v)144 309.6 Q F0 -.15(ve)180 +309.6 S(rtical tab).15 E F1(\\\\)144 321.6 Q F0(backslash)180 321.6 Q F1(\\nnn) +144 333.6 Q F0(the character whose ASCII code is)180 333.6 Q F2(nnn)2.5 E F0 +(\(octal\))2.5 E F1(enable)108 350.4 Q F0([)2.5 E F1A F0 2.5(][)C F1 +(\255all)162.03 350.4 Q F0 2.5(][)C F2(name)187.45 350.4 Q F0(...])2.5 E .682 +(Enable and disable b)144 362.4 R .683(uiltin shell commands.)-.2 F .683 +(This allo)5.683 F .683(ws the e)-.25 F -.15(xe)-.15 G .683 +(cution of a disk command which).15 F .324(has the same name as a shell b)144 +374.4 R .324(uiltin without specifying a full pathname.)-.2 F(If)5.324 E F1 +2.824 E F0 .324(is used, each)2.824 F F2(name)2.823 E F0 .18 +(is disabled; otherwise,)144 386.4 R F2(names)2.68 E F0 .18(are enabled.)2.68 F +-.15(Fo)5.18 G 2.68(re).15 G .181(xample, to use the)338.81 386.4 R F1(test) +2.681 E F0 .181(binary found via the)2.681 F/F3 9/Times-Bold@0 SF -.666(PA) +2.681 G(TH)-.189 E F0 .749(instead of the shell b)144 398.4 R .749(uiltin v)-.2 +F .749(ersion, type `)-.15 F .748(`enable -n test')-.74 F 3.248('. If)-.74 F +.748(no ar)3.248 F .748(guments are gi)-.18 F -.15(ve)-.25 G .748 +(n, a list of all).15 F .424(enabled shell b)144 410.4 R .424 +(uiltins is printed.)-.2 F .424(If only)5.424 F F12.924 E F0 .425 +(is supplied, a list of all disabled b)2.924 F .425(uiltins is printed.)-.2 F +(If)5.425 E(only)144 422.4 Q F1(\255all)2.547 E F0 .047 +(is supplied, the list printed includes all b)2.547 F .046 +(uiltins, with an indication of whether or not each)-.2 F .28(is enabled.)144 +434.4 R F1(enable)5.28 E F0(accepts)2.78 E F12.78 E F0 .28(as a synon) +2.78 F .28(ym for)-.15 F F1(\255all)2.78 E F0 5.28(.T)C .281(he return v)370.8 +434.4 R .281(alue is 0 unless a)-.25 F F2(name)2.781 E F0 .281(is not a)2.781 F +(shell b)144 446.4 Q(uiltin.)-.2 E F1 -2.3 -.15(ev a)108 463.2 T(l).15 E F0([) +2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(The)144 475.2 Q F2(ar)3.171 E(g)-.37 E F0 +3.171(sa)C .671(re read and concatenated together into a single command.) +187.742 475.2 R .67(This command is then read)5.67 F .164(and e)144 487.2 R +-.15(xe)-.15 G .164(cuted by the shell, and its e).15 F .165 +(xit status is returned as the v)-.15 F .165(alue of the)-.25 F F1 -2.3 -.15 +(ev a)2.665 H(l).15 E F0 2.665(command. If)2.665 F(there)2.665 E(are no)144 +499.2 Q F2(ar)2.5 E(gs)-.37 E F0 2.5(,o).27 G 2.5(ro)198.89 499.2 S +(nly null ar)209.72 499.2 Q(guments,)-.18 E F1 -2.3 -.15(ev a)2.5 H(l).15 E F0 +(returns true.)2.5 E F1(exec)108 516 Q F0([[)2.5 E F1A F0(])A F2(command) +2.5 E F0([)2.5 E F2(ar)A(guments)-.37 E F0(]])A(If)144 528 Q F2(command)2.91 E +F0 .41(is speci\214ed, it replaces the shell.)2.91 F .41(No ne)5.41 F 2.91(wp) +-.25 G .41(rocess is created.)371.42 528 R(The)5.41 E F2(ar)2.91 E(guments)-.37 +E F0(become)2.91 E 1.238(the ar)144 540 R 1.238(guments to)-.18 F F2(command) +3.738 E F0 6.238(.I)C 3.738(ft)267.642 540 S 1.238(he \214rst ar)277.49 540 R +1.238(gument is)-.18 F F13.738 E F0 3.738(,t)C 1.239 +(he shell places a dash in the zeroth ar)376.42 540 R(g)-.18 E 1.049(passed to) +144 552 R F2(command)3.549 E F0 6.049(.T).77 G 1.048(his is what login does.) +239.847 552 R 1.048(If the \214le cannot be e)6.048 F -.15(xe)-.15 G 1.048 +(cuted for some reason, a).15 F(non-interacti)144 564 Q .91 -.15(ve s)-.25 H +.611(hell e).15 F .611(xits, unless the shell v)-.15 F(ariable)-.25 E F1 +(no_exit_on_failed_exec)3.111 E F0 -.15(ex)3.111 G .611(ists, in which case).15 +F .333(it returns f)144 576 R 2.833(ailure. An)-.1 F(interacti)2.833 E .633 +-.15(ve s)-.25 H .333(hell returns f).15 F .332 +(ailure if the \214le cannot be e)-.1 F -.15(xe)-.15 G 2.832(cuted. If).15 F F2 +(command)2.832 E F0(is)2.832 E(not speci\214ed, an)144 588 Q 2.5(yr)-.15 G +(edirections tak)219.95 588 Q 2.5(ee)-.1 G -.25(ff)289.83 588 S +(ect in the current shell, and the return status is 0.).25 E F1(exit)108 604.8 +Q F0([)2.5 E F2(n)A F0 6.29(]C)C .122(ause the shell to e)150.67 604.8 R .122 +(xit with a status of)-.15 F F2(n)2.623 E F0 5.123(.I)C(f)315.064 604.8 Q F2(n) +2.623 E F0 .123(is omitted, the e)2.623 F .123 +(xit status is that of the last command)-.15 F -.15(exe)144 616.8 S 2.5 +(cuted. A).15 F(trap on)2.5 E F3(EXIT)2.5 E F0(is e)2.25 E -.15(xe)-.15 G +(cuted before the shell terminates.).15 E F1(export)108 633.6 Q F0([)2.5 E F1 +(\255nf)A F0 2.5(][).833 G F2(name)166.183 633.6 Q F0([=)A F2(wor)A(d)-.37 E F0 +(]] ...)A F1(export \255p)108 645.6 Q F0 .306(The supplied)144 657.6 R F2 +(names)2.806 E F0 .306(are mark)2.806 F .305(ed for automatic e)-.1 F .305 +(xport to the en)-.15 F .305(vironment of subsequently e)-.4 F -.15(xe)-.15 G +(cuted).15 E 2.693(commands. If)144 669.6 R(the)2.693 E F12.693 E F0 .193 +(option is gi)2.693 F -.15(ve)-.25 G .193(n, the).15 F F2(names)2.693 E F0 .193 +(refer to functions.)2.693 F .193(If no)5.193 F F2(names)2.693 E F0 .193 +(are gi)2.693 F -.15(ve)-.25 G .194(n, or if the).15 F F1144 681.6 Q F0 +.66(option is supplied, a list of all names that are e)3.16 F .659 +(xported in this shell is printed.)-.15 F(The)5.659 E F13.159 E F0 +(option)3.159 E .537(causes the e)144 693.6 R .537(xport property to be remo) +-.15 F -.15(ve)-.15 G 3.037(df).15 G .537(rom the named v)318.099 693.6 R 3.038 +(ariables. An)-.25 F(ar)3.038 E .538(gument of)-.18 F F13.038 E F0 +(disables)3.038 E .666(option checking for the rest of the ar)144 705.6 R +(guments.)-.18 E F1(export)5.665 E F0 .665(returns an e)3.165 F .665 +(xit status of 0 unless an ille)-.15 F -.05(ga)-.15 G(l).05 E .32 +(option is encountered, one of the)144 717.6 R F2(names)2.82 E F0 .32 +(is not a le)2.82 F -.05(ga)-.15 G 2.82(ls).05 G .32(hell v)366.18 717.6 R .32 +(ariable name, or)-.25 F F12.82 E F0 .32(is supplied with a)2.82 F F2 +(name)144 729.6 Q F0(that is not a function.)2.5 E 170.955(GNU 1993)72 768 R +(September 16)2.5 E(3)535 768 Q EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF(fc)108 84 Q F0([)2.5 E F1A/F2 10/Times-Italic@0 SF(ename)2.5 E F0 2.5 +(][)C F1(\255nlr)169.5 84 Q F0 2.5(][)C F2<8c72>197.14 84 Q(st)-.1 E F0 2.5(][) +C F2(last)221.76 84 Q F0(])A F1(fc \255s)108 96 Q F0([)2.5 E F2(pat)A F0(=)A F2 +-.37(re)C(p).37 E F0 2.5(][)C F2(cmd)174.23 96 Q F0(])A .665(Fix Command.)144 +108 R .665(In the \214rst form, a range of commands from)5.665 F F2<8c72>3.164 +E(st)-.1 E F0(to)3.164 E F2(last)3.164 E F0 .664(is selected from the his-) +3.164 F .967(tory list.)144 120 R F2 -.45(Fi)5.967 G -.1(rs).45 G(t).1 E F0 +(and)3.467 E F2(last)3.467 E F0 .967 +(may be speci\214ed as a string \(to locate the last command be)3.467 F .968 +(ginning with)-.15 F .797(that string\) or as a number \(an inde)144 132 R +3.297(xi)-.15 G .797(nto the history list, where a ne)300.756 132 R -.05(ga) +-.15 G(ti).05 E 1.097 -.15(ve n)-.25 H .796(umber is used as an).15 F(of)144 +144 Q .321(fset from the current command number\).)-.25 F(If)5.322 E F2(last) +2.822 E F0 .322(is not speci\214ed it is set to the current command)2.822 F +.019(for listing \(so that)144 156 R F1 .019(fc \255l \25510)2.519 F F0 .019 +(prints the last 10 commands\) and to)2.519 F F2<8c72>2.519 E(st)-.1 E F0 2.519 +(otherwise. If)2.519 F F2<8c72>2.519 E(st)-.1 E F0 .019(is not spec-)2.519 F +(i\214ed it is set to the pre)144 168 Q +(vious command for editing and \25516 for listing.)-.25 E(The)144 192 Q F1 +2.92 E F0 .42(\215ag suppresses the command numbers when listing.)2.92 F +(The)5.421 E F12.921 E F0 .421(\215ag re)2.921 F -.15(ve)-.25 G .421 +(rses the order of the).15 F 3.642(commands. If)144 204 R(the)3.642 E F1 +3.642 E F0 1.142(\215ag is gi)3.642 F -.15(ve)-.25 G 1.142 +(n, the commands are listed on standard output.).15 F 1.142(Otherwise, the) +6.142 F .378(editor gi)144 216 R -.15(ve)-.25 G 2.878(nb).15 G(y)199.906 216 Q +F2(ename)2.878 E F0 .378(is in)2.878 F -.2(vo)-.4 G -.1(ke).2 G 2.878(do).1 G +2.878(na\214)285.708 216 S .378(le containing those commands.)306.464 216 R(If) +5.378 E F2(ename)2.878 E F0 .379(is not gi)2.879 F -.15(ve)-.25 G .379(n, the) +.15 F -.25(va)144 228 S .805(lue of the).25 F/F3 9/Times-Bold@0 SF(FCEDIT)3.305 +E F0 -.25(va)3.055 G .805(riable is used, and the v).25 F .805(alue of)-.25 F +F3(EDIT)3.305 E(OR)-.162 E F0(if)3.054 E F3(FCEDIT)3.304 E F0 .804(is not set.) +3.054 F .804(If neither)5.804 F -.25(va)144 240 S(riable is set, is used.).25 E +(When editing is complete, the edited commands are echoed and e)5 E -.15(xe) +-.15 G(cuted.).15 E .039(In the second form,)144 264 R F2(command)2.539 E F0 +.039(is re-e)2.539 F -.15(xe)-.15 G .039(cuted after each instance of).15 F F2 +(pat)2.54 E F0 .04(is replaced by)2.54 F F2 -.37(re)2.54 G(p).37 E F0 5.04(.A)C +(useful)515.56 264 Q 1.009(alias to use with this is `)144 276 R 1.008 +(`r=fc \255s')-.74 F 1.008(', so that typing `)-.74 F 1.008(`r cc')-.74 F 3.508 +('r)-.74 G 1.008(uns the last command be)385.39 276 R 1.008(ginning with)-.15 F +-.74(``)144 288 S(cc').74 E 2.5('a)-.74 G(nd typing `)171.66 288 Q(`r')-.74 E +2.5('r)-.74 G(e-e)233.22 288 Q -.15(xe)-.15 G(cutes the last command.).15 E +.426(If the \214rst form is used, the return v)144 312 R .427 +(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.927(lo).05 G .427 +(ption is encountered or)399.768 312 R F2<8c72>2.927 E(st)-.1 E F0(or)2.927 E +F2(last)2.927 E F0 .455(specify history lines out of range.)144 324 R .454 +(If the)5.454 F F12.954 E F0 .454(option is supplied, the return v)2.954 +F .454(alue is the v)-.25 F .454(alue of the)-.25 F .787(last command e)144 336 +R -.15(xe)-.15 G .787(cuted or f).15 F .788 +(ailure if an error occurs with the temporary \214le of commands.)-.1 F .788 +(If the)5.788 F 1.196 +(second form is used, the return status is that of the command re-e)144 348 R +-.15(xe)-.15 G 1.196(cuted, unless).15 F F2(cmd)3.696 E F0 1.196(does not)3.696 +F(specify a v)144 360 Q(alid history line, in which case)-.25 E F1(fc)2.5 E F0 +(returns f)2.5 E(ailure.)-.1 E F1(fg)108 376.8 Q F0([)2.5 E F2(jobspec)A F0(])A +(Place)144 388.8 Q F2(jobspec)3.041 E F0 .541(in the fore)3.041 F .542 +(ground, and mak)-.15 F 3.042(ei)-.1 G 3.042(tt)323.06 388.8 S .542 +(he current job)331.662 388.8 R 5.542(.I)-.4 G(f)399.258 388.8 Q F2(jobspec) +3.042 E F0 .542(is not present, the shell')3.042 F(s)-.55 E .958(notion of the) +144 400.8 R F2(curr)3.458 E .958(ent job)-.37 F F0 .957(is used.)3.457 F .957 +(The return v)5.957 F .957(alue is that of the command placed into the fore-) +-.25 F .194(ground, or f)144 412.8 R .194 +(ailure if run when job control is disabled or)-.1 F 2.695(,w)-.4 G .195 +(hen run with job control enabled, if)378.655 412.8 R F2(job-)2.695 E(spec)144 +424.8 Q F0(does not specify a v)2.5 E(alid job or)-.25 E F2(jobspec)2.5 E F0 +(speci\214es a job that w)2.5 E(as started without job control.)-.1 E F1 +(getopts)108 441.6 Q F2(optstring name)2.5 E F0([)2.5 E F2(ar)A(gs)-.37 E F0(]) +A F1(getopts)144 453.6 Q F0 .828 +(is used by shell procedures to parse positional parameters.)3.328 F F2 +(optstring)5.827 E F0 .827(contains the option)3.327 F .602 +(letters to be recognized; if a letter is follo)144 465.6 R .603 +(wed by a colon, the option is e)-.25 F .603(xpected to ha)-.15 F .903 -.15 +(ve a)-.2 H 3.103(na).15 G -.18(rg)523.52 465.6 S(u-).18 E .7 +(ment, which should be separated from it by white space.)144 477.6 R .7 +(Each time it is in)5.7 F -.2(vo)-.4 G -.1(ke).2 G(d,).1 E F1(getopts)3.2 E F0 +(places)3.2 E .008(the ne)144 489.6 R .008(xt option in the shell v)-.15 F +(ariable)-.25 E F2(name)2.508 E F0 2.508(,i).18 G(nitializing)316.884 489.6 Q +F2(name)2.508 E F0 .009(if it does not e)2.508 F .009(xist, and the inde)-.15 F +2.509(xo)-.15 G 2.509(ft)521.941 489.6 S(he)530.56 489.6 Q(ne)144 501.6 Q .199 +(xt ar)-.15 F .199(gument to be processed into the v)-.18 F(ariable)-.25 E F3 +(OPTIND)2.699 E/F4 9/Times-Roman@0 SF(.)A F3(OPTIND)4.699 E F0 .198 +(is initialized to 1 each time the)2.449 F .497(shell or a shell script is in) +144 513.6 R -.2(vo)-.4 G -.1(ke).2 G 2.997(d. When).1 F .498 +(an option requires an ar)2.997 F(gument,)-.18 E F1(getopts)2.998 E F0 .498 +(places that ar)2.998 F(gu-)-.18 E .028(ment into the v)144 525.6 R(ariable) +-.25 E F3(OPT)2.528 E(ARG)-.81 E F4(.)A F0 .028(The shell does not reset)4.528 +F F3(OPTIND)2.528 E F0 .027(automatically; it must be manu-)2.278 F .161 +(ally reset between multiple calls to)144 537.6 R F1(getopts)2.661 E F0 .161 +(within the same shell in)2.661 F -.2(vo)-.4 G .161(cation if a ne).2 F 2.662 +(ws)-.25 G .162(et of param-)490.806 537.6 R(eters is to be used.)144 549.6 Q +F1(getopts)144 573.6 Q F0 1.252(can report errors in tw)3.752 F 3.752(ow)-.1 G +3.752(ays. If)287.942 573.6 R 1.252(the \214rst character of)3.752 F F2 +(optstring)3.752 E F0 1.251(is a colon,)3.752 F F2(silent)3.751 E F0(error) +3.751 E 1.442(reporting is used.)144 585.6 R 1.442 +(In normal operation diagnostic messages are printed when ille)6.442 F -.05(ga) +-.15 G 3.943(lo).05 G 1.443(ptions or)503.277 585.6 R .654(missing option ar) +144 597.6 R .653(guments are encountered.)-.18 F .653(If the v)5.653 F(ariable) +-.25 E F3(OPTERR)3.153 E F0 .653(is set to 0, no error message)2.903 F +(will be displayed, e)144 609.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)241.09 +609.6 S(he \214rst character of)249.7 609.6 Q F2(optstring)2.5 E F0 +(is not a colon.)2.5 E .826(If an ille)144 633.6 R -.05(ga)-.15 G 3.326(lo).05 +G .826(ption is seen,)199.878 633.6 R F1(getopts)3.326 E F0 .826(places ? into) +3.326 F F2(name)3.326 E F0 .826(and, if not silent, prints an error message) +3.326 F .4(and unsets)144 645.6 R F3(OPT)2.9 E(ARG)-.81 E F4(.)A F0(If)4.899 E +F1(getopts)2.899 E F0 .399(is silent, the option character found is placed in) +2.899 F F3(OPT)2.899 E(ARG)-.81 E F0 .399(and no)2.649 F +(diagnostic message is printed.)144 657.6 Q 1.241(If a required ar)144 681.6 R +1.241(gument is not found, and)-.18 F F1(getopts)3.741 E F0 1.241 +(is not silent, a question mark \()3.741 F F1(?).833 E F0 3.742(\)i).833 G +3.742(sp)494.746 681.6 S 1.242(laced in)507.378 681.6 R F2(name)144 693.6 Q F0 +(,).18 E F1(OPT)3.357 E(ARG)-.9 E F0 .856 +(is unset, and a diagnostic message is printed.)3.357 F(If)5.856 E F1(getopts) +3.356 E F0 .856(is silent, then a colon)3.356 F(\()144 705.6 Q F1(:).833 E F0 +2.5(\)i).833 G 2.5(sp)160.936 705.6 S(laced in)172.326 705.6 Q F2(name)2.5 E F0 +(and)2.5 E F3(OPT)2.5 E(ARG)-.81 E F0(is set to the option character found.) +2.25 E F1(getopts)144 729.6 Q F0 2.392 +(normally parses the positional parameters, b)4.892 F 2.392(ut if more ar)-.2 F +2.393(guments are gi)-.18 F -.15(ve)-.25 G 4.893(ni).15 G(n)509.927 729.6 Q F2 +(ar)4.893 E(gs)-.37 E F0(,).27 E 170.955(GNU 1993)72 768 R(September 16)2.5 E +(4)535 768 Q EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF(getopts)144 84 Q F0 .651(parses those instead.)3.151 F F1(getopts)5.651 E F0 +.651(returns true if an option, speci\214ed or unspeci\214ed, is found.)3.151 F +(It returns f)144 96 Q +(alse if the end of options is encountered or an error occurs.)-.1 E F1(hash) +108 112.8 Q F0([)2.5 E F1A F0 2.5(][)C/F2 10/Times-Italic@0 SF(name) +153.14 112.8 Q F0(])A -.15(Fo)144 124.8 S 2.819(re).15 G(ach)164.999 124.8 Q F2 +(name)2.819 E F0 2.819(,t).18 G .319 +(he full pathname of the command is determined and remembered.)211.637 124.8 R +(The)5.32 E F12.82 E F0(option)2.82 E .508(causes the shell to for)144 +136.8 R .508(get all remembered locations.)-.18 F .508(If no ar)5.508 F .508 +(guments are gi)-.18 F -.15(ve)-.25 G .507(n, information about).15 F .193 +(remembered commands is printed.)144 148.8 R .193(An ar)5.193 F .193(gument of) +-.18 F F12.693 E F0 .194(disables option checking for the rest of the) +2.693 F(ar)144 160.8 Q 2.5(guments. The)-.18 F(return status is true unless a) +2.5 E F2(name)2.5 E F0(is not found or an ille)2.5 E -.05(ga)-.15 G 2.5(lo).05 +G(ption is supplied.)453.86 160.8 Q F1(help)108 177.6 Q F0([)2.5 E F2(pattern)A +F0(])A .991(Display helpful information about b)144 189.6 R .991 +(uiltin commands.)-.2 F(If)5.991 E F2(pattern)3.491 E F0 .991(is speci\214ed,) +3.491 F F1(help)3.491 E F0(gi)3.49 E -.15(ve)-.25 G 3.49(sd).15 G(etailed) +513.34 189.6 Q .408(help on all commands matching)144 201.6 R F2(pattern)2.909 +E F0 2.909(;o).24 G .409(therwise a list of the b)316.13 201.6 R .409 +(uiltins is printed.)-.2 F .409(The return sta-)5.409 F +(tus is 0 unless no command matches)144 213.6 Q F2(pattern)2.5 E F0(.).24 E F1 +(history)108 230.4 Q F0([)2.5 E F2(n)A F0(])A F1(history \255rwan)108 242.4 Q +F0([)2.5 E F2(\214lename)A F0(])A -.4(Wi)144 254.4 S .752 +(th no options, display the command history list with line numbers.).4 F .752 +(Lines listed with a)5.752 F F1(*)3.251 E F0(ha)3.251 E -.15(ve)-.2 G .375 +(been modi\214ed.)144 266.4 R .375(An ar)5.375 F .375(gument of)-.18 F F2(n) +2.875 E F0 .375(lists only the last)2.875 F F2(n)2.875 E F0 2.875(lines. If) +2.875 F 2.876(an)2.876 G .376(on-option ar)411.832 266.4 R .376 +(gument is supplied,)-.18 F .811 +(it is used as the name of the history \214le; if not, the v)144 278.4 R .811 +(alue of)-.25 F/F3 9/Times-Bold@0 SF(HISTFILE)3.311 E F0 .811(is used.)3.061 F +.811(Options, if sup-)5.811 F(plied, ha)144 290.4 Q .3 -.15(ve t)-.2 H +(he follo).15 E(wing meanings:)-.25 E F1144 302.4 Q F0 .598(Append the `) +180 302.4 R(`ne)-.74 E(w')-.25 E 3.098('h)-.74 G .598 +(istory lines \(history lines entered since the be)266.424 302.4 R .599 +(ginning of the current)-.15 F F1(bash)180 314.4 Q F0 +(session\) to the history \214le)2.5 E F1144 326.4 Q F0 .854(Read the hi\ +story lines not already read from the history \214le into the current history \ +list.)180 326.4 R .772 +(These are lines appended to the history \214le since the be)180 338.4 R .773 +(ginning of the current)-.15 F F1(bash)3.273 E F0(ses-)3.273 E(sion.)180 350.4 +Q F1144 362.4 Q F0 +(Read the contents of the history \214le and use them as the current history) +180 362.4 Q F1144 374.4 Q F0 +(Write the current history to the history \214le, o)180 374.4 Q -.15(ve)-.15 G +(rwriting the history \214le').15 E 2.5(sc)-.55 G(ontents.)474.4 374.4 Q .989 +(The return v)144 391.2 R .989(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G +3.489(lo).05 G .989(ption is encountered or an error occurs while reading or) +308.662 391.2 R(writing the history \214le.)144 403.2 Q F1(jobs)108 420 Q F0([) +2.5 E F1(\255lnp)A F0 2.5(][)C F2(jobspec)A F0(... ])2.5 E F1(jobs \255x)108 +432 Q F2(command)2.5 E F0([)2.5 E F2(ar)2.5 E(gs)-.37 E F0(... ])2.5 E .297 +(The \214rst form lists the acti)144 444 R .598 -.15(ve j)-.25 H 2.798 +(obs. The).15 F F12.798 E F0 .298 +(option lists process IDs in addition to the normal infor)2.798 F(-)-.2 E .746 +(mation; the)144 456 R F13.246 E F0 .745 +(option lists only the process ID of the job')3.246 F 3.245(sp)-.55 G .745 +(rocess group leader)394.205 456 R 5.745(.T)-.55 G(he)487.25 456 Q F1 +3.245 E F0(option)3.245 E 2.08(displays only jobs that ha)144 468 R 2.38 -.15 +(ve c)-.2 H 2.081(hanged status since last noti\214ed.).15 F(If)7.081 E F2 +(jobspec)4.581 E F0 2.081(is gi)4.581 F -.15(ve)-.25 G 2.081(n, output is).15 F +.727(restricted to information about that job)144 480 R 5.727(.T)-.4 G .727 +(he return status is 0 unless an ille)316.282 480 R -.05(ga)-.15 G 3.227(lo).05 +G .726(ption is encoun-)474.108 480 R(tered or an ille)144 492 Q -.05(ga)-.15 G +(l).05 E F2(jobspec)2.5 E F0(is supplied.)2.5 E .607(If the)144 516 R F1 +3.107 E F0 .607(option is supplied,)3.107 F F1(jobs)3.107 E F0 .607 +(replaces an)3.107 F(y)-.15 E F2(jobspec)3.107 E F0 .607(found in)3.107 F F2 +(command)3.107 E F0(or)3.107 E F2(ar)3.107 E(gs)-.37 E F0 .607(with the corre-) +3.107 F(sponding process group ID, and e)144 528 Q -.15(xe)-.15 G(cutes).15 E +F2(command)2.5 E F0(passing it)2.5 E F2(ar)2.5 E(gs)-.37 E F0 2.5(,r).27 G +(eturning its e)418.56 528 Q(xit status.)-.15 E F1(kill)108 544.8 Q F0([)2.5 E +F1(-s sigspec)A F0(|)2.5 E F1(\255sigspec)2.5 E F0 2.5(][)C F2(pid)219.31 544.8 +Q F0(|)2.5 E F2(jobspec)2.5 E F0 2.5(].)C(..)277.97 544.8 Q F1(kill \255l)108 +556.8 Q F0([)2.5 E F2(signum)A F0(])A .943(Send the signal named by)144 568.8 R +F2(sigspec)3.443 E F0 .942(to the processes named by)3.443 F F2(pid)3.442 E F0 +(or)3.442 E F2(jobspec)3.442 E F0(.).31 E F2(sigspec)5.942 E F0 .942 +(is either a)3.442 F .908(signal name such as)144 580.8 R F3(SIGKILL)3.408 E F0 +.908(or a signal number)3.158 F 5.908(.I)-.55 G(f)359.638 580.8 Q F2(sigspec) +3.408 E F0 .908(is a signal name, the name is case)3.408 F(insensiti)144 592.8 +Q 2.43 -.15(ve a)-.25 H 2.13(nd may be gi).15 F -.15(ve)-.25 G 4.63(nw).15 G +2.13(ith or without the)279.67 592.8 R F3(SIG)4.63 E F0 4.629(pre\214x. If) +4.379 F F2(sigspec)4.629 E F0 2.129(is not present, then)4.629 F F3(SIGTERM)144 +604.8 Q F0 .813(is assumed.)3.063 F .813(An ar)5.813 F .813(gument of)-.18 F F1 +3.313 E F0 .814(lists the signal names.)3.313 F .814(If an)5.814 F 3.314 +(ya)-.15 G -.18(rg)450.232 604.8 S .814(uments are supplied).18 F(when)144 +616.8 Q F12.827 E F0 .327(is gi)2.827 F -.15(ve)-.25 G .327(n, the names\ + of the speci\214ed signals are listed, and the return status is 0.).15 F .326 +(An ar)5.326 F(gu-)-.18 E .484(ment of)144 628.8 R F12.984 E F0 .484 +(disables option checking for the rest of the ar)2.984 F(guments.)-.18 E F1 +(kill)5.485 E F0 .485(returns true if at least one)2.985 F(signal w)144 640.8 Q +(as successfully sent, or f)-.1 E(alse if an error occurs or an ille)-.1 E -.05 +(ga)-.15 G 2.5(lo).05 G(ption is encountered.)419.09 640.8 Q F1(let)108 657.6 Q +F2(ar)2.5 E(g)-.37 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Each)144 669.6 Q +F2(ar)3.677 E(g)-.37 E F0 1.177(is an arithmetic e)3.677 F 1.177 +(xpression to be e)-.15 F -.25(va)-.25 G 1.177(luated \(see).25 F F3 1.176 +(ARITHMETIC EV)3.677 F(ALU)-1.215 E -.855(AT)-.54 G(ION).855 E/F4 9 +/Times-Roman@0 SF(\).)A F0 1.176(If the)5.676 F(last)144 681.6 Q F2(ar)2.5 E(g) +-.37 E F0 -.25(eva)2.5 G(luates to 0,).25 E F1(let)2.5 E F0 +(returns 1; 0 is returned otherwise.)2.5 E F1(local)108 698.4 Q F0([)2.5 E F2 +(name)A F0([=)A F2(value)A F0 2.5(].)C(..])194.45 698.4 Q -.15(Fo)144 710.4 S +3.276(re).15 G .776(ach ar)165.456 710.4 R .776(gument, create a local v)-.18 F +.776(ariable named)-.25 F F2(name)3.276 E F0 3.276(,a).18 G .776(nd assign it) +380.784 710.4 R F2(value)3.276 E F0 5.777(.W).18 G(hen)470.729 710.4 Q F1 +(local)3.277 E F0 .777(is used)3.277 F .131(within a function, it causes the v) +144 722.4 R(ariable)-.25 E F2(name)2.631 E F0 .131(to ha)2.631 F .431 -.15 +(ve a v)-.2 H .13(isible scope restricted to that function and).15 F 170.955 +(GNU 1993)72 768 R(September 16)2.5 E(5)535 768 Q EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .232(its children.) +144 84 R -.4(Wi)5.232 G .232(th no operands,).4 F/F1 10/Times-Bold@0 SF(local) +2.733 E F0 .233(writes a list of local v)2.733 F .233 +(ariables to the standard output.)-.25 F .233(It is an)5.233 F .42 +(error to use)144 96 R F1(local)2.92 E F0 .42(when not within a function.)2.92 +F .42(The return status is 0 unless)5.42 F F1(local)2.92 E F0 .42 +(is used outside a)2.92 F(function, or an ille)144 108 Q -.05(ga)-.15 G(l).05 E +/F2 10/Times-Italic@0 SF(name)2.5 E F0(is supplied.)2.5 E F1(logout)108 124.8 Q +F0(Exit a login shell.)9.33 E F1(popd)108 141.6 Q F0([)2.5 E F1(+/\255n)A F0(]) +A(Remo)144 153.6 Q -.15(ve)-.15 G 2.799(se).15 G .299 +(ntries from the directory stack.)188.159 153.6 R -.4(Wi)5.299 G .299(th no ar) +.4 F .299(guments, remo)-.18 F -.15(ve)-.15 G 2.799(st).15 G .3 +(he top directory from the)438.82 153.6 R(stack, and performs a)144 165.6 Q F1 +(cd)2.5 E F0(to the ne)2.5 E 2.5(wt)-.25 G(op directory)291.22 165.6 Q(.)-.65 E +F1(+n)144 177.6 Q F0(remo)180 177.6 Q -.15(ve)-.15 G 2.849(st).15 G(he)219.209 +177.6 Q F2(n)2.849 E F0 .349(th entry counting from the left of the list sho)B +.349(wn by)-.25 F F1(dirs)2.848 E F0 2.848(,s)C .348(tarting with zero.)470.704 +177.6 R -.15(Fo)180 189.6 S 2.5(re).15 G(xample: `)200.53 189.6 Q(`popd +0') +-.74 E 2.5('r)-.74 G(emo)286.06 189.6 Q -.15(ve)-.15 G 2.5(st).15 G +(he \214rst directory)321.59 189.6 Q 2.5(,`)-.65 G(`popd +1')394.63 189.6 Q 2.5 +('t)-.74 G(he second.)442.3 189.6 Q F1144 201.6 Q F0(remo)180 201.6 Q +-.15(ve)-.15 G 2.501(st).15 G(he)218.861 201.6 Q F2(n)2.501 E F0 .001 +(th entry counting from the right of the list sho)B .001(wn by)-.25 F F1(dirs) +2.502 E F0 2.502(,s)C .002(tarting with zero.)471.396 201.6 R -.15(Fo)180 213.6 +S 2.5(re).15 G(xample: `)200.53 213.6 Q(`popd -0')-.74 E 2.5('r)-.74 G(emo) +283.75 213.6 Q -.15(ve)-.15 G 2.5(st).15 G(he last directory)319.28 213.6 Q 2.5 +(,`)-.65 G(`popd -1')390.65 213.6 Q 2.5('t)-.74 G(he ne)436.01 213.6 Q +(xt to last.)-.15 E .644(If the)144 230.4 R F1(popd)3.144 E F0 .644 +(command is successful, a)3.144 F F1(dirs)3.143 E F0 .643 +(is performed as well, and the return status is 0.)3.143 F F1(popd)5.643 E F0 +.57(returns f)144 242.4 R .57(alse if an ille)-.1 F -.05(ga)-.15 G 3.07(lo).05 +G .571(ption is encountered, the directory stack is empty)251.25 242.4 R 3.071 +(,an)-.65 G(on-e)469.319 242.4 Q .571(xistent direc-)-.15 F +(tory stack entry is speci\214ed, or the directory change f)144 254.4 Q(ails.) +-.1 E F1(pushd)108 271.2 Q F0([)2.5 E F2(dir)A F0(])A F1(pushd +/\255n)108 +283.2 Q F0 .64(Adds a directory to the top of the directory stack, or rotates \ +the stack, making the ne)144 295.2 R 3.139(wt)-.25 G .639(op of the)503.172 +295.2 R 1.315(stack the current w)144 307.2 R 1.315(orking directory)-.1 F +6.315(.W)-.65 G 1.315(ith no ar)306.885 307.2 R 1.315(guments, e)-.18 F 1.316 +(xchanges the top tw)-.15 F 3.816(od)-.1 G 1.316(irectories and)484.534 307.2 R +(returns 0, unless the directory stack is empty)144 319.2 Q(.)-.65 E F1(+n)144 +331.2 Q F0 1.268(Rotates the stack so that the)180 331.2 R F2(n)3.768 E F0 +1.267(th directory \(counting from the left of the list sho)B 1.267(wn by)-.25 +F F1(dirs)180 343.2 Q F0 2.5(\)i)C 2.5(sa)205.28 343.2 S 2.5(tt)216.11 343.2 S +(he top.)224.17 343.2 Q F1144 355.2 Q F0(Rotates the stack so that the) +180 355.2 Q F2(n)2.5 E F0 +(th directory \(counting from the right\) is at the top.)A F1(dir)144 367.2 Q +F0(adds)180 367.2 Q F2(dir)2.5 E F0 +(to the directory stack at the top, making it the ne)2.5 E 2.5(wc)-.25 G +(urrent w)422.5 367.2 Q(orking directory)-.1 E(.)-.65 E .488(If the)144 384 R +F1(pushd)2.988 E F0 .488(command is successful, a)2.988 F F1(dirs)2.988 E F0 +.488(is performed as well.)2.988 F .489(If the \214rst form is used,)5.488 F F1 +(pushd)2.989 E F0 1.103(returns 0 unless the cd to)144 396 R F2(dir)3.603 E F0 +-.1(fa)3.603 G 3.603(ils. W).1 F 1.103(ith the second form,)-.4 F F1(pushd) +3.603 E F0 1.103(returns 0 unless the directory)3.603 F .846(stack is empty)144 +408 R 3.346(,an)-.65 G(on-e)220.894 408 Q .847(xistant directory stack element\ + is speci\214ed, or the directory change to the)-.15 F(speci\214ed ne)144 420 Q +2.5(wc)-.25 G(urrent directory f)205.4 420 Q(ails.)-.1 E F1(pwd)108 436.8 Q F0 +.725(Print the absolute pathname of the current w)144 436.8 R .724 +(orking directory)-.1 F 5.724(.T)-.65 G .724(he path printed contains no sym-) +405.56 436.8 R .521(bolic links if the)144 448.8 R F13.021 E F0 .521 +(option to the)3.021 F F1(set)3.021 E F0 -.2(bu)3.021 G .521 +(iltin command is set.).2 F .521(See also the description of)5.521 F F1 +(nolinks)3.022 E F0(under)144 460.8 Q F1 .074(Shell V)2.574 F(ariables)-.92 E +F0(abo)2.574 E -.15(ve)-.15 G 2.574(\). The).15 F .074 +(return status is 0 unless an error occurs while reading the path-)2.574 F +(name of the current directory)144 472.8 Q(.)-.65 E F1 -.18(re)108 489.6 S(ad) +.18 E F0([)2.5 E F1A F0 2.5(][)C F2(name)152.39 489.6 Q F0(...])2.5 E +.036(One line is read from the standard input, and the \214rst w)144 501.6 R +.037(ord is assigned to the \214rst)-.1 F F2(name)2.537 E F0 2.537(,t).18 G +.037(he second)500.253 501.6 R -.1(wo)144 513.6 S .109(rd to the second).1 F F2 +(name)2.609 E F0 2.609(,a).18 G .109(nd so on, with lefto)254.045 513.6 R -.15 +(ve)-.15 G 2.609(rw).15 G .109(ords assigned to the last)354.18 513.6 R F2 +(name)2.609 E F0 5.109(.O).18 G .108(nly the char)489.444 513.6 R(-)-.2 E .143 +(acters in)144 525.6 R/F3 9/Times-Bold@0 SF(IFS)2.643 E F0 .143 +(are recognized as w)2.393 F .143(ord delimiters.)-.1 F .143(If no)5.143 F F2 +(names)2.643 E F0 .144(are supplied, the line read is assigned)2.643 F .194 +(to the v)144 537.6 R(ariable)-.25 E F3(REPL)2.694 E(Y)-.828 E/F4 9 +/Times-Roman@0 SF(.)A F0 .194 +(The return code is zero, unless end-of-\214le is encountered.)4.694 F .193 +(If the)5.193 F F12.693 E F0(option)2.693 E .444(is gi)144 549.6 R -.15 +(ve)-.25 G .444(n, a backslash-ne).15 F .444 +(wline pair is not ignored, and the backslash is considered to be part of the) +-.25 F(line.)144 561.6 Q F1 -.18(re)108 578.4 S(adonly).18 E F0([)2.5 E F1 +A F0 2.5(][)C F2(name)169.62 578.4 Q F0(...])2.5 E F1 -.18(re)108 590.4 S +(adonly -p).18 E F0 .419(The gi)144 602.4 R -.15(ve)-.25 G(n).15 E F2(names) +2.919 E F0 .419(are mark)2.919 F .419(ed readonly and the v)-.1 F .419 +(alues of these)-.25 F F2(names)2.919 E F0 .418(may not be changed by sub-) +2.919 F .541(sequent assignment.)144 614.4 R .541(If the)5.541 F F13.041 +E F0 .541(option is supplied, the functions corresponding to the)3.041 F F2 +(names)3.042 E F0 .542(are so)3.042 F(mark)144 626.4 Q 3.037(ed. If)-.1 F .537 +(no ar)3.037 F .537(guments are gi)-.18 F -.15(ve)-.25 G .536(n, or if the).15 +F F13.036 E F0 .536(option is supplied, a list of all readonly names is) +3.036 F 2.501(printed. An)144 638.4 R(ar)2.501 E .002(gument of)-.18 F F1 +2.502 E F0 .002(disables option checking for the rest of the ar)2.502 F 2.502 +(guments. The)-.18 F .002(return sta-)2.502 F .192(tus is 0 unless an ille)144 +650.4 R -.05(ga)-.15 G 2.692(lo).05 G .192(ption is encountered, one of the) +247.732 650.4 R F2(names)2.691 E F0 .191(is not a le)2.691 F -.05(ga)-.15 G +2.691(ls).05 G .191(hell v)463.498 650.4 R .191(ariable name,)-.25 F(or)144 +662.4 Q F12.5 E F0(is supplied with a)2.5 E F2(name)2.5 E F0 +(that is not a function.)2.5 E F1 -.18(re)108 679.2 S(tur).18 E(n)-.15 E F0([) +2.5 E F2(n)A F0(])A .618(Causes a function to e)144 691.2 R .618 +(xit with the return v)-.15 F .618(alue speci\214ed by)-.25 F F2(n)3.118 E F0 +5.619(.I).24 G(f)404.557 691.2 Q F2(n)3.119 E F0 .619 +(is omitted, the return status is)3.119 F 1.335(that of the last command e)144 +703.2 R -.15(xe)-.15 G 1.335(cuted in the function body).15 F 6.335(.I)-.65 G +3.835(fu)387.48 703.2 S 1.335(sed outside a function, b)399.645 703.2 R 1.335 +(ut during)-.2 F -.15(exe)144 715.2 S .794(cution of a script by the).15 F F1 +(.)3.294 E F0(\()5.794 E F1(sour)A(ce)-.18 E F0 3.294(\)c)C .794 +(ommand, it causes the shell to stop e)309.832 715.2 R -.15(xe)-.15 G .795 +(cuting that script).15 F 1.234(and return either)144 727.2 R F2(n)3.734 E F0 +1.234(or the e)3.734 F 1.234(xit status of the last command e)-.15 F -.15(xe) +-.15 G 1.234(cuted within the script as the e).15 F(xit)-.15 E 170.955 +(GNU 1993)72 768 R(September 16)2.5 E(6)535 768 Q EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .393 +(status of the script.)144 84 R .393 +(If used outside a function and not during e)5.393 F -.15(xe)-.15 G .393 +(cution of a script by).15 F/F1 10/Times-Bold@0 SF(.)2.893 E F0 2.893(,t).833 G +.393(he return)503.787 84 R(status is f)144 96 Q(alse.)-.1 E F1(set)108 112.8 Q +F0([)2.5 E F1(\255\255abefhkmnptuvxldCHP)A F0 2.5(][)C F1(-o)243.29 112.8 Q/F2 +10/Times-Italic@0 SF(option)2.5 E F0 2.5(][)C F2(ar)288.84 112.8 Q(g)-.37 E F0 +(...])2.5 E F1144 124.8 Q F0 1.036(Automatically mark v)184 124.8 R 1.036 +(ariables which are modi\214ed or created for e)-.25 F 1.035(xport to the en) +-.15 F(viron-)-.4 E(ment of subsequent commands.)184 136.8 Q F1144 148.8 +Q F0 .721 +(Cause the status of terminated background jobs to be reported immediately)184 +148.8 R 3.221(,r)-.65 G .721(ather than)499.569 148.8 R(before the ne)184 160.8 +Q(xt primary prompt.)-.15 E(\(Also see)5 E F1(notify)2.5 E F0(under)2.5 E F1 +(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1 +144 172.8 Q F0 1.772(Exit immediately if a)184 172.8 R F2(simple-command)4.272 +E F0(\(see)4.272 E/F3 9/Times-Bold@0 SF 1.772(SHELL GRAMMAR)4.272 F F0(abo) +4.022 E -.15(ve)-.15 G 4.271(\)e).15 G 1.771(xits with a)494.788 172.8 R .642 +(non\255zero status.)184 184.8 R .642(The shell does not e)5.642 F .642 +(xit if the command that f)-.15 F .643(ails is part of an)-.1 F F2(until)3.143 +E F0(or)3.143 E F2(while)184 196.8 Q F0 .728(loop, part of an)3.228 F F2(if) +3.228 E F0 .728(statement, part of a)3.228 F F1(&&)3.228 E F0(or)3.228 E/F4 10 +/Symbol SF 1.6663.228 G F0 .728(list, or if the command')1.562 F 3.228 +(sr)-.55 G(eturn)519.45 196.8 Q -.25(va)184 208.8 S(lue is being in).25 E -.15 +(ve)-.4 G(rted via).15 E F1(!)2.5 E F0(.)A F1144 220.8 Q F0 +(Disable pathname e)184 220.8 Q(xpansion.)-.15 E F1144 232.8 Q F0 .106 +(Locate and remember function commands as functions are de\214ned.)184 232.8 R +.106(Function commands)5.106 F(are normally look)184 244.8 Q +(ed up when the function is e)-.1 E -.15(xe)-.15 G(cuted.).15 E F1144 +256.8 Q F0 .162(All k)184 256.8 R -.15(ey)-.1 G -.1(wo).15 G .162(rd ar).1 F +.162(guments are placed in the en)-.18 F .161 +(vironment for a command, not just those that)-.4 F(precede the command name.) +184 268.8 Q F1144 280.8 Q F0 .009(Monitor mode.)184 280.8 R .009 +(Job control is enabled.)5.009 F .009(This \215ag is on by def)5.009 F .01 +(ault for interacti)-.1 F .31 -.15(ve s)-.25 H .01(hells on).15 F .124 +(systems that support it \(see)184 292.8 R F3 .124(JOB CONTR)2.624 F(OL)-.27 E +F0(abo)2.374 E -.15(ve)-.15 G 2.624(\). Background).15 F .124 +(processes run in a sep-)2.624 F .72 +(arate process group and a line containing their e)184 304.8 R .721 +(xit status is printed upon their comple-)-.15 F(tion.)184 316.8 Q F1144 +328.8 Q F0 .653(Read commands b)184 328.8 R .653(ut do not e)-.2 F -.15(xe)-.15 +G .653(cute them.).15 F .652(This may be used to check a shell script for)5.653 +F(syntax errors.)184 340.8 Q(This is ignored for interacti)5 E .3 -.15(ve s) +-.25 H(hells.).15 E F1144 352.8 Q F2(option-name)2.5 E F0(The)184 364.8 Q +F2(option-name)2.5 E F0(can be one of the follo)2.5 E(wing:)-.25 E F1 +(allexport)184 376.8 Q F0(Same as)224 388.8 Q F12.5 E F0(.)A F1 +(braceexpand)184 400.8 Q F0 .312(The shell performs brace e)224 412.8 R .313 +(xpansion \(see)-.15 F F1 .313(Brace Expansion)2.813 F F0(abo)2.813 E -.15(ve) +-.15 G 2.813(\). This).15 F .313(is on)2.813 F(by def)224 424.8 Q(ault.)-.1 E +F1(emacs)184 436.8 Q F0 .089(Use an emacs-style command line editing interf)224 +436.8 R 2.589(ace. This)-.1 F .089(is enabled by def)2.589 F(ault)-.1 E .128 +(when the shell is interacti)224 448.8 R -.15(ve)-.25 G 2.628(,u).15 G .128 +(nless the shell is started with the)345.89 448.8 R F1(\255nolineediting)2.629 +E F0(option.)224 460.8 Q F1(err)184 472.8 Q(exit)-.18 E F0(Same as)224 472.8 Q +F12.5 E F0(.)A F1(histexpand)184 484.8 Q F0(Same as)224 496.8 Q F1 +2.5 E F0(.)A F1(ignor)184 508.8 Q(eeof)-.18 E F0 1.024(The ef)224 520.8 R 1.024 +(fect is as if the shell command `IGNOREEOF=10' had been e)-.25 F -.15(xe)-.15 +G(cuted).15 E(\(see)224 532.8 Q F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E +-.15(ve)-.15 G(\).).15 E F1(interacti)184 544.8 Q -.1(ve)-.1 G(\255comments).1 +E F0(Allo)224 556.8 Q 2.52(waw)-.25 G .02(ord be)265.35 556.8 R .021 +(ginning with)-.15 F F1(#)2.521 E F0 .021(to cause that w)2.521 F .021 +(ord and all remaining characters)-.1 F +(on that line to be ignored in an interacti)224 568.8 Q .3 -.15(ve s)-.25 H +(hell \(see).15 E F3(COMMENTS)2.5 E F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1 +(monitor)184 580.8 Q F0(Same as)5.56 E F12.5 E F0(.)A F1(noclob)184 592.8 +Q(ber)-.1 E F0(Same as)224 604.8 Q F12.5 E F0(.)A F1(noexec)184 616.8 Q +F0(Same as)224 616.8 Q F12.5 E F0(.)A F1(noglob)184 628.8 Q F0(Same as) +224 628.8 Q F12.5 E F0(.)A F1(nohash)184 640.8 Q F0(Same as)9.43 E F1 +2.5 E F0(.)A F1(notify)184 652.8 Q F0(Same as)224 652.8 Q F12.5 E +F0(.)A F1(nounset)184 664.8 Q F0(Same as)6.66 E F12.5 E F0(.)A F1(ph)184 +676.8 Q(ysical)-.15 E F0(Same as)5.14 E F12.5 E F0(.)A F1(posix)184 688.8 +Q F0 2.244(Change the beha)224 688.8 R 2.244(vior of bash where the def)-.2 F +2.243(ault operation dif)-.1 F 2.243(fers from the)-.25 F +(Posix 1003.2 standard to match the standard.)224 700.8 Q 170.955(GNU 1993)72 +768 R(September 16)2.5 E(7)535 768 Q EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF(pri)184 84 Q(vileged)-.1 E F0(Same as)224 96 Q F12.5 E F0(.)A F1 -.1 +(ve)184 108 S(rbose).1 E F0(Same as)7.33 E F12.5 E F0(.)A F1(vi)184 120 Q +F0(Use a vi-style command line editing interf)224 120 Q(ace.)-.1 E F1(xtrace) +184 132 Q F0(Same as)224 132 Q F12.5 E F0(.)A(If no)184 144 Q/F2 10 +/Times-Italic@0 SF(option-name)2.5 E F0(is supplied, the v)2.5 E +(alues of the current options are printed.)-.25 E F1144 156 Q F0 -.45(Tu) +184 156 S .521(rn on).45 F F2(privile)3.021 E -.1(ge)-.4 G(d).1 E F0 3.021 +(mode. In)3.021 F .521(this mode, the)3.021 F F1($ENV)3.021 E F0 .522 +(\214le is not processed, and shell func-)3.021 F .26 +(tions are not inherited from the en)184 168 R 2.76(vironment. This)-.4 F .26 +(is enabled automatically on startup if)2.76 F .481(the ef)184 180 R(fecti)-.25 +E .781 -.15(ve u)-.25 H .482 +(ser \(group\) id is not equal to the real user \(group\) id.).15 F -.45(Tu) +5.482 G .482(rning this option).45 F(of)184 192 Q 2.5(fc)-.25 G(auses the ef) +202.35 192 Q(fecti)-.25 E .3 -.15(ve u)-.25 H +(ser and group ids to be set to the real user and group ids.).15 E F1144 +204 Q F0(Exit after reading and e)184 204 Q -.15(xe)-.15 G(cuting one command.) +.15 E F1144 216 Q F0 -.35(Tr)184 216 S .445(eat unset v).35 F .444 +(ariables as an error when performing parameter e)-.25 F 2.944(xpansion. If) +-.15 F -.15(ex)2.944 G .444(pansion is).15 F .519(attempted on an unset v)184 +228 R .519(ariable, the shell prints an error message, and, if not interacti) +-.25 F -.15(ve)-.25 G(,).15 E -.15(ex)184 240 S(its with a non\255zero status.) +.15 E F1144 252 Q F0(Print shell input lines as the)184 252 Q 2.5(ya)-.15 +G(re read.)306.63 252 Q F1144 264 Q F0 1.057(After e)184 264 R 1.056 +(xpanding each)-.15 F F2(simple-command)3.556 E F0(,).77 E F1(bash)3.556 E F0 +1.056(displays the e)3.556 F 1.056(xpanded v)-.15 F 1.056(alue of)-.25 F/F3 9 +/Times-Bold@0 SF(PS4)3.556 E/F4 9/Times-Roman@0 SF(,)A F0(fol-)3.306 E(lo)184 +276 Q(wed by the command and its e)-.25 E(xpanded ar)-.15 E(guments.)-.18 E F1 +144 288 Q F0(Sa)184 288 Q 1.398 -.15(ve a)-.2 H 1.098 +(nd restore the binding of).15 F F2(name)3.598 E F0 1.098(in a)3.598 F F1 -.25 +(fo)3.598 G(r).25 E F2(name)3.598 E F0([in)3.599 E F1 -.1(wo)3.599 G(rd).1 E F0 +3.599(]c)C 1.099(ommand \(see)451.687 288 R F3(SHELL)3.599 E(GRAMMAR)184 300 Q +F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1144 312 Q F0 1.68 +(Disable the hashing of commands that are look)184 312 R 1.68(ed up for e)-.1 F +-.15(xe)-.15 G 4.18(cution. Normally).15 F 4.18(,c)-.65 G(om-)523.89 312 Q +1.275(mands are remembered in a hash table, and once found, do not ha)184 324 R +1.576 -.15(ve t)-.2 H 3.776(ob).15 G 3.776(el)490.888 324 S(ook)501.884 324 Q +1.276(ed up)-.1 F(ag)184 336 Q(ain.)-.05 E F1144 348 Q F0 .812(The ef)184 +348 R .812(fect is as if the shell command `noclobber=' had been e)-.25 F -.15 +(xe)-.15 G .811(cuted \(see).15 F F1 .811(Shell V)3.311 F(ari-)-.92 E(ables)184 +360 Q F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1144 372 Q F0(Enable)184 372 +Q F1(!)3.13 E F0 .63(style history substitution.)5.63 F .63 +(This \215ag is on by def)5.63 F .63(ault when the shell is interac-)-.1 F(ti) +184 384 Q -.15(ve)-.25 G(.).15 E F1144 396 Q F0 2.107 +(If set, do not follo)184 396 R 4.607(ws)-.25 G 2.107 +(ymbolic links when performing commands such as)279.835 396 R F1(cd)4.607 E F0 +(which)4.606 E(change the current directory)184 408 Q 5(.T)-.65 G(he ph)309.42 +408 Q(ysical directory is used instead.)-.05 E F1144 420 Q F0 .05 +(If no ar)184 420 R .05(guments follo)-.18 F 2.55(wt)-.25 G .05 +(his \215ag, then the positional parameters are unset.)280.98 420 R .05 +(Otherwise, the)5.05 F(positional parameters are set to the)184 432 Q F2(ar)2.5 +E(g)-.37 E F0(s, e)A -.15(ve)-.25 G 2.5(ni).15 G 2.5(fs)371.81 432 S +(ome of them be)381.53 432 Q(gin with a)-.15 E F12.5 E F0(.)A F1144 444 +Q F0 1.945(Signal the end of options, cause all remaining)184 444 R F2(ar)4.444 +E(g)-.37 E F0 4.444(st)C 4.444(ob)409.45 444 S 4.444(ea)423.894 444 S 1.944 +(ssigned to the positional)437.218 444 R 3.445(parameters. The)184 456 R F1 +3.445 E F0(and)3.445 E F13.445 E F0 .945(options are turned of) +3.445 F 3.445(f. If)-.25 F .946(there are no)3.445 F F2(ar)3.446 E(g)-.37 E F0 +.946(s, the positional)B(parameters remain unchanged.)184 468 Q .317 +(The \215ags are of)144 484.8 R 2.817(fb)-.25 G 2.817(yd)218.328 484.8 S(ef) +231.145 484.8 Q .317(ault unless otherwise noted.)-.1 F .316 +(Using + rather than \255 causes these \215ags to be)5.317 F .198(turned of)144 +496.8 R 2.698(f. The)-.25 F .199 +(\215ags can also be speci\214ed as options to an in)2.699 F -.2(vo)-.4 G .199 +(cation of the shell.).2 F .199(The current set)5.199 F .643 +(of \215ags may be found in)144 508.8 R F1<24ad>3.143 E F0 5.642(.A)C .642 +(fter the option ar)273.91 508.8 R .642(guments are processed, the remaining) +-.18 F F2 3.142(na)3.142 G -.37(rg)512.238 508.8 S F0 3.142(sa).37 G(re)532.23 +508.8 Q .775(treated as v)144 520.8 R .775 +(alues for the positional parameters and are assigned, in order)-.25 F 3.275 +(,t)-.4 G(o)448.69 520.8 Q F1($1)3.275 E F0(,)A F1($2)3.275 E F0(,)A F1 3.275 +(... $)3.275 F F2(n)A F0 5.775(.I)C 3.275(fn)523.395 520.8 S(o)535 520.8 Q .309 +(options or)144 532.8 R F2(ar)2.809 E(g)-.37 E F0 2.808(sa)C .308 +(re supplied, all shell v)212.056 532.8 R .308(ariables are printed.)-.25 F +.308(The return status is al)5.308 F -.1(wa)-.1 G .308(ys true unless).1 F +(an ille)144 544.8 Q -.05(ga)-.15 G 2.5(lo).05 G(ption is encountered.)188.24 +544.8 Q F1(shift)108 561.6 Q F0([)2.5 E F2(n)A F0(])A .428 +(The positional parameters from)144 573.6 R F2(n)2.928 E F0 .429 +(+1 ... are renamed to)B F1 .429($1 ....)2.929 F F0 -.15(Pa)5.429 G .429 +(rameters represented by the num-).15 F(bers)144 585.6 Q F1($#)3.434 E F0(do) +3.434 E .934(wn to)-.25 F F1($#)3.434 E F0A F2(n)A F0 .934(+1 are unset.)B +(If)5.934 E F2(n)3.433 E F0 .933(is 0, no parameters are changed.)3.433 F(If) +5.933 E F2(n)3.433 E F0 .933(is not gi)3.433 F -.15(ve)-.25 G .933(n, it is).15 +F .026(assumed to be 1.)144 597.6 R F2(n)5.026 E F0 .026(must be a non-ne)2.526 +F -.05(ga)-.15 G(ti).05 E .326 -.15(ve n)-.25 H .026 +(umber less than or equal to).15 F F1($#)2.526 E F0 5.026(.I)C(f)454.886 597.6 +Q F2(n)2.526 E F0 .027(is greater than)2.527 F F1($#)2.527 E F0(,)A .03 +(the positional parameters are not changed.)144 609.6 R .029 +(The return status is greater than 0 if)5.03 F F2(n)2.529 E F0 .029 +(is greater than)2.529 F F1($#)2.529 E F0(or less than 0; otherwise 0.)144 +621.6 Q F1(suspend)108 638.4 Q F0([)2.5 E F1A F0(])A .492(Suspend the e) +144 650.4 R -.15(xe)-.15 G .492(cution of this shell until it recei).15 F -.15 +(ve)-.25 G 2.992(sa).15 G F3(SIGCONT).001 E F0 2.993(signal. The)2.743 F F1 +2.993 E F0 .493(option says not to)2.993 F .759 +(complain if this is a login shell; just suspend an)144 662.4 R(yw)-.15 E(ay) +-.1 E 5.758(.T)-.65 G .758(he return status is 0 unless the shell is a)375.688 +662.4 R(login shell and)144 674.4 Q F12.5 E F0 +(is not supplied, or if job control is not enabled.)2.5 E F1(test)108 691.2 Q +F2 -.2(ex)2.5 G(pr).2 E F1([)108 703.2 Q F2 -.2(ex)2.5 G(pr).2 E F1(])2.5 E F0 +.877(Return a status of 0 \(true\) or 1 \(f)6.77 F .878 +(alse\) depending on the e)-.1 F -.25(va)-.25 G .878 +(luation of the conditional e).25 F(xpression)-.15 E F2 -.2(ex)144 715.2 S(pr) +.2 E F0 5.008(.E).73 G .008(xpressions may be unary or binary)175.918 715.2 R +5.007(.U)-.65 G .007(nary e)328.064 715.2 R .007 +(xpressions are often used to e)-.15 F .007(xamine the status)-.15 F .203 +(of a \214le.)144 727.2 R .203 +(There are string operators and numeric comparison operators as well.)5.203 F +.204(Each operator and)5.204 F 170.955(GNU 1993)72 768 R(September 16)2.5 E(8) +535 768 Q EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E 1.592 +(operand must be a separate ar)144 84 R 4.091(gument. If)-.18 F/F1 10 +/Times-Italic@0 SF(\214le)4.091 E F0 1.591(is of the form /de)4.091 F(v/fd/) +-.25 E F1(n)A F0 4.091(,t)C 1.591(hen \214le descriptor)444.756 84 R F1(n)4.091 +E F0(is)4.091 E(check)144 96 Q(ed.)-.1 E/F2 10/Times-Bold@0 SF144 108 Q +F1(\214le)2.5 E F0 -.35(Tr)180 108 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 +G(ists and is block special.).15 E F2144 120 Q F1(\214le)2.5 E F0 -.35 +(Tr)180 120 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is character special.).15 E F2144 132 Q F1(\214le)2.5 E F0 -.35 +(Tr)180 132 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a directory).15 E(.)-.65 E F2144 144 Q F1(\214le)2.5 E F0 +-.35(Tr)180 144 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists.).15 E F2 +144 156 Q F1(\214le)2.5 E F0 -.35(Tr)180 156 S(ue if).35 E F1(\214le)2.5 +E F0 -.15(ex)2.5 G(ists and is a re).15 E(gular \214le.)-.15 E F2144 168 +Q F1(\214le)2.5 E F0 -.35(Tr)180 168 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex) +2.5 G(ists and is set-group-id.).15 E F2144 180 Q F1(\214le)2.5 E F0 -.35 +(Tr)180 180 S(ue if).35 E F1(\214le)2.5 E F0(has its `)2.5 E(`stick)-.74 E(y') +-.15 E 2.5('b)-.74 G(it set.)295.22 180 Q F2144 192 Q F1(\214le)2.5 E F0 +-.35(Tr)8.91 G(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a symbolic link.).15 E F2144 204 Q F1(\214le)2.5 E F0 -.35 +(Tr)180 204 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is a named pipe.).15 E F2144 216 Q F1(\214le)2.5 E F0 -.35(Tr) +180 216 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is readable.) +.15 E F2144 228 Q F1(\214le)2.5 E F0 -.35(Tr)180 228 S(ue if).35 E F1 +(\214le)2.5 E F0 -.15(ex)2.5 G(ists and has a size greater than zero.).15 E F2 +144 240 Q F1(\214le)2.5 E F0 -.35(Tr)180 240 S(ue if).35 E F1(\214le)2.5 +E F0 -.15(ex)2.5 G(ists and is a sock).15 E(et.)-.1 E F2144 252 Q F1(fd) +2.5 E F0 -.35(Tr)180 252 S(ue if).35 E F1(fd)2.5 E F0(is opened on a terminal.) +2.5 E F2144 264 Q F1(\214le)2.5 E F0 -.35(Tr)180 264 S(ue if).35 E F1 +(\214le)2.5 E F0 -.15(ex)2.5 G(ists and its set-user).15 E(-id bit is set.)-.2 +E F2144 276 Q F1(\214le)2.5 E F0 -.35(Tr)8.36 G(ue if).35 E F1(\214le)2.5 +E F0 -.15(ex)2.5 G(ists and is writable.).15 E F2144 288 Q F1(\214le)2.5 +E F0 -.35(Tr)180 288 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is e).15 E -.15(xe)-.15 G(cutable.).15 E F2144 300 Q F1(\214le) +2.5 E F0 -.35(Tr)7.8 G(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G +(ists and is o).15 E(wned by the ef)-.25 E(fecti)-.25 E .3 -.15(ve u)-.25 H +(ser id.).15 E F2144 312 Q F1(\214le)2.5 E F0 -.35(Tr)7.8 G(ue if).35 E +F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is o).15 E(wned by the ef)-.25 E +(fecti)-.25 E .3 -.15(ve g)-.25 H(roup id.).15 E F1(\214le1)144 324 Q F02.5 +E F2(nt)A F1(\214le2)2.5 E F0 -.35(Tr)180 336 S(ue if).35 E F1(\214le1)2.5 E F0 +(is ne)2.5 E(wer \(according to modi\214cation date\) than)-.25 E F1(\214le2) +2.5 E F0(.)A F1(\214le1)144 348 Q F02.5 E F2(ot)A F1(\214le2)2.5 E F0 -.35 +(Tr)180 360 S(ue if).35 E F1(\214le1)2.5 E F0(is older than \214le2.)2.5 E F1 +(\214le1)144 372 Q F2(\255ef)2.5 E F1(\214le)2.5 E F0 -.35(Tr)180 384 S(ue if) +.35 E F1(\214le1)2.5 E F0(and)2.5 E F1(\214le2)2.5 E F0(ha)2.5 E .3 -.15(ve t) +-.2 H(he same de).15 E(vice and inode numbers.)-.25 E F2144 396 Q F1 +(string)2.5 E F0 -.35(Tr)180 408 S(ue if the length of).35 E F1(string)2.5 E F0 +(is zero.)2.5 E F2144 420 Q F1(string)2.5 E(string)144 432 Q F0 -.35(Tr) +180 432 S(ue if the length of).35 E F1(string)2.5 E F0(is non\255zero.)2.5 E F1 +(string1)144 444 Q F2(=)2.5 E F1(string2)2.5 E F0 -.35(Tr)180 456 S +(ue if the strings are equal.).35 E F1(string1)144 468 Q F2(!=)2.5 E F1 +(string2)2.5 E F0 -.35(Tr)180 480 S(ue if the strings are not equal.).35 E F2 +(!)144 492 Q F1 -.2(ex)2.5 G(pr).2 E F0 -.35(Tr)180 492 S(ue if).35 E F1 -.2 +(ex)2.5 G(pr).2 E F0(is f)2.5 E(alse.)-.1 E F1 -.2(ex)144 504 S(pr1).2 E F0 +2.5 E F2(a)A F1 -.2(ex)2.5 G(pr2).2 E F0 -.35(Tr)180 516 S(ue if both).35 E F1 +-.2(ex)2.5 G(pr1).2 E F0(AND)2.5 E F1 -.2(ex)2.5 G(pr2).2 E F0(are true.)2.5 E +F1 -.2(ex)144 528 S(pr1).2 E F02.5 E F2(o)A F1 -.2(ex)2.5 G(pr2).2 E F0 +-.35(Tr)180 540 S(ue if either).35 E F1 -.2(ex)2.5 G(pr1).2 E F0(OR)2.5 E F1 +-.2(ex)2.5 G(pr2).2 E F0(is true.)2.5 E F1(ar)144 552 Q(g1)-.37 E F2(OP)2.5 E +F1(ar)2.5 E(g2)-.37 E/F3 9/Times-Bold@0 SF(OP)180 564 Q F0 .035(is one of)2.284 +F F2(\255eq)2.535 E F0(,)A F2(\255ne)2.535 E F0(,)A F2(\255lt)2.535 E F0(,)A F2 +(\255le)2.535 E F0(,)A F2(\255gt)2.535 E F0 2.535(,o)C(r)332.165 564 Q F2 +(\255ge)2.535 E F0 5.035(.T)C .035 +(hese arithmetic binary operators return true)366.815 564 R(if)180 576 Q F1(ar) +3.32 E(g1)-.37 E F0 .82(is equal, not-equal, less-than, less-than-or)3.32 F .82 +(-equal, greater)-.2 F .82(-than, or greater)-.2 F(-than-or)-.2 E(-)-.2 E .5 +(equal than)180 588 R F1(ar)3 E(g2)-.37 E F0 3.001(,r)C(especti)252.231 588 Q +-.15(ve)-.25 G(ly).15 E(.)-.65 E F1(Ar)5.501 E(g1)-.37 E F0(and)3.001 E F1(ar) +3.001 E(g2)-.37 E F0 .501(may be positi)3.001 F .801 -.15(ve i)-.25 H(nte).15 E +.501(gers, ne)-.15 F -.05(ga)-.15 G(ti).05 E .801 -.15(ve i)-.25 H(nte).15 E +(gers,)-.15 E(or the special e)180 600 Q(xpression)-.15 E F22.5 E F1 +(string)2.5 E F0 2.5(,w)C(hich e)327.48 600 Q -.25(va)-.25 G +(luates to the length of).25 E F1(string)2.5 E F0(.).22 E F2(times)108 616.8 Q +F0 1.229(Print the accumulated user and system times for the shell and for pro\ +cesses run from the shell.)144 616.8 R(The return status is 0.)144 628.8 Q F2 +(trap)108 645.6 Q F0([)2.5 E F2A F0 2.5(][)C F1(ar)149.8 645.6 Q(g)-.37 E +F0 2.5(][)C F1(sigspec)172.48 645.6 Q F0(])A .767(The command)144 657.6 R F1 +(ar)3.267 E(g)-.37 E F0 .767(is to be read and e)3.267 F -.15(xe)-.15 G .767 +(cuted when the shell recei).15 F -.15(ve)-.25 G 3.267(ss).15 G(ignal\(s\)) +434.781 657.6 Q F1(sigspec)3.267 E F0 5.767(.I).31 G(f)509.945 657.6 Q F1(ar) +3.267 E(g)-.37 E F0(is)3.268 E 2.164(absent or)144 669.6 R F24.664 E F0 +4.664(,a)C 2.164(ll speci\214ed signals are reset to their original v)204.512 +669.6 R 2.164(alues \(the v)-.25 F 2.163(alues the)-.25 F 4.663(yh)-.15 G 2.163 +(ad upon)505.897 669.6 R .681(entrance to the shell\).)144 681.6 R(If)5.681 E +F1(ar)3.181 E(g)-.37 E F0 .681 +(is the null string this signal is ignored by the shell and by the com-)3.181 F +1.174(mands it in)144 693.6 R -.2(vo)-.4 G -.1(ke).2 G(s.).1 E F1(sigspec)6.174 +E F0 1.174(is either a signal name de\214ned in <)3.674 F F1(signal.h)A F0 +1.173(>, or a signal number)B 6.173(.I)-.55 G(f)536.67 693.6 Q F1(sigspec)144 +705.6 Q F0(is)2.769 E F3(EXIT)2.769 E F0 .269(\(0\) the command)2.519 F F1(ar) +2.769 E(g)-.37 E F0 .269(is e)2.769 F -.15(xe)-.15 G .269(cuted on e).15 F .269 +(xit from the shell.)-.15 F -.4(Wi)5.269 G .269(th no ar).4 F(guments,)-.18 E +F2(trap)2.77 E F0 .403 +(prints the list of commands associated with each signal number)144 717.6 R +5.402(.T)-.55 G(he)414.118 717.6 Q F22.902 E F0 .402 +(option causes the shell to)2.902 F .562 +(print a list of signal names and their corresponding numbers.)144 729.6 R .562 +(An ar)5.562 F .562(gument of)-.18 F F23.062 E F0 .562(disables option) +3.062 F 170.955(GNU 1993)72 768 R(September 16)2.5 E(9)535 768 Q EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .564 +(checking for the rest of the ar)144 84 R 3.064(guments. Signals)-.18 F .564 +(ignored upon entry to the shell cannot be trapped)3.064 F 1.144(or reset.)144 +96 R -.35(Tr)6.144 G 1.145(apped signals are reset to their original v).35 F +1.145(alues in a child process when it is created.)-.25 F +(The return status is f)144 108 Q(alse if either the trap name or number is in) +-.1 E -.25(va)-.4 G(lid; otherwise).25 E/F1 10/Times-Bold@0 SF(trap)2.5 E F0 +(returns true.)2.5 E F1(type)108 124.8 Q F0([)2.5 E F1(\255all)A F0 2.5(][)C F1 +(\255type)157.58 124.8 Q F0(|)2.5 E F1(\255path)2.5 E F0(])A/F2 10 +/Times-Italic@0 SF(name)2.5 E F0([)2.5 E F2(name)A F0(...])2.5 E -.4(Wi)144 +136.8 S .206(th no options, indicate ho).4 F 2.706(we)-.25 G(ach)272.15 136.8 Q +F2(name)2.705 E F0 -.1(wo)2.705 G .205 +(uld be interpreted if used as a command name.).1 F .205(If the)5.205 F F1 +(\255type)144 148.8 Q F0 .527(\215ag is used,)3.027 F F1(type)3.027 E F0 .528 +(prints a phrase which is one of)3.028 F F2(alias)3.028 E F0(,).27 E F2 -.1(ke) +3.028 G(ywor)-.2 E(d)-.37 E F0(,).77 E F2(function)3.028 E F0(,).24 E F2 -.2 +(bu)3.028 G(iltin).2 E F0 3.028(,o).24 G(r)512.284 148.8 Q F2(\214le)3.028 E F0 +(if)3.028 E F2(name)144 160.8 Q F0 .297(is an alias, shell reserv)2.798 F .297 +(ed w)-.15 F .297(ord, function, b)-.1 F .297(uiltin, or disk \214le, respecti) +-.2 F -.15(ve)-.25 G(ly).15 E 2.797(.I)-.65 G 2.797(ft)472.152 160.8 S .297 +(he name is not)481.059 160.8 R 1.097(found, then nothing is printed, and an e) +144 172.8 R 1.097(xit status of f)-.15 F 1.097(alse is returned.)-.1 F 1.097 +(If the)6.097 F F1(\255path)3.598 E F0 1.098(\215ag is used,)3.598 F F1(type) +144 184.8 Q F0 1.009(either returns the name of the disk \214le that w)3.509 F +1.008(ould be e)-.1 F -.15(xe)-.15 G 1.008(cuted if).15 F F2(name)3.508 E F0 +1.008(were speci\214ed as a)3.508 F .562(command name, or nothing if)144 196.8 +R F1(\255type)3.062 E F0 -.1(wo)3.062 G .562(uld not return).1 F F2(\214le) +3.063 E F0 5.563(.I).18 G 3.063(fac)389.542 196.8 S .563(ommand is hashed,) +407.878 196.8 R F1(\255path)3.063 E F0(prints)3.063 E .684(the hashed v)144 +208.8 R .684(alue, not necessarily the \214le that appears \214rst in)-.25 F/F3 +9/Times-Bold@0 SF -.666(PA)3.184 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .684 +(If the)5.184 F F1(\255all)3.184 E F0 .683(\215ag is used,)3.184 F F1(type) +3.183 E F0 1.135(prints all of the places that contain an e)144 220.8 R -.15 +(xe)-.15 G 1.135(cutable named).15 F F2(name)3.635 E F0 6.136(.T).18 G 1.136 +(his includes aliases and func-)418.256 220.8 R 1.011 +(tions, if and only if the)144 232.8 R F1(\255path)3.511 E F0 1.011 +(\215ag is not also used.)3.511 F 1.011 +(The table of hashed commands is not con-)6.011 F .786(sulted when using)144 +244.8 R F1(\255all)3.286 E F0(.)A F1(type)5.786 E F0(accepts)3.286 E F1 +3.286 E F0(,)A F13.286 E F0 3.286(,a)C(nd)335.698 244.8 Q F13.286 E +F0 .787(in place of)3.287 F F1(\255all)3.287 E F0(,)A F1(\255type)3.287 E F0 +3.287(,a)C(nd)466.906 244.8 Q F1(\255path)3.287 E F0 3.287(,r)C(espec-)514.46 +244.8 Q(ti)144 256.8 Q -.15(ve)-.25 G(ly).15 E 6.127(.A)-.65 G 3.627(na)181.577 +256.8 S -.18(rg)194.644 256.8 S 1.127(ument of).18 F F13.627 E F0 1.127 +(disables option checking for the rest of the ar)3.627 F(guments.)-.18 E F1 +(type)6.126 E F0(returns)3.626 E(true if an)144 268.8 Q 2.5(yo)-.15 G 2.5(ft) +192.45 268.8 S(he ar)201.06 268.8 Q(guments are found, f)-.18 E +(alse if none are found.)-.1 E F1(ulimit)108 285.6 Q F0([)2.5 E F1 +(\255SHacdfmstpnuv)A F0([)2.5 E F2(limit)A F0(]])A F1(Ulimit)144 297.6 Q F0 +(pro)3.056 E .556(vides control o)-.15 F -.15(ve)-.15 G 3.057(rt).15 G .557 +(he resources a)266.316 297.6 R -.25(va)-.2 G .557 +(ilable to the shell and to processes started by it, on).25 F .765 +(systems that allo)144 309.6 R 3.265(ws)-.25 G .765(uch control.)226.325 309.6 +R .765(The v)5.765 F .765(alue of)-.25 F F2(limit)3.265 E F0 .765 +(can be a number in the unit speci\214ed for the)3.265 F .301 +(resource, or the v)144 321.6 R(alue)-.25 E F1(unlimited)2.801 E F0 5.301(.T)C +(he)288.565 321.6 Q F1(H)2.801 E F0(and)2.801 E F1(S)2.801 E F0 .302 +(options specify that the hard or soft limit is set for)2.802 F .005(the gi)144 +333.6 R -.15(ve)-.25 G 2.505(nr).15 G 2.505(esource. A)186.38 333.6 R .004(har\ +d limit cannot be increased once it is set; a soft limit may be increased up) +2.505 F .008(to the v)144 345.6 R .008(alue of the hard limit.)-.25 F .008 +(If neither)5.008 F F1(H)2.508 E F0(nor)2.508 E F1(S)2.508 E F0 .008 +(is speci\214ed, the command applies to the soft limit.)2.508 F(If)144 357.6 Q +F2(limit)2.758 E F0 .258(is omitted, the current v)2.758 F .257 +(alue of the soft limit of the resource is printed, unless the)-.25 F F1(H) +2.757 E F0(option)2.757 E .575(is gi)144 369.6 R -.15(ve)-.25 G 3.075(n. When) +.15 F .576(more than one resource is speci\214ed, the limit name and unit is p\ +rinted before the)3.076 F -.25(va)144 381.6 S 2.5(lue. Other).25 F +(options are interpreted as follo)2.5 E(ws:)-.25 E F1144 393.6 Q F0 +(all current limits are reported)180 393.6 Q F1144 405.6 Q F0 +(the maximum size of core \214les created)180 405.6 Q F1144 417.6 Q F0 +(the maximum size of a process')180 417.6 Q 2.5(sd)-.55 G(ata se)317.76 417.6 Q +(gment)-.15 E F1144 429.6 Q F0 +(the maximum size of \214les created by the shell)180 429.6 Q F1144 441.6 +Q F0(the maximum resident set size)180 441.6 Q F1144 453.6 Q F0 +(the maximum stack size)180 453.6 Q F1144 465.6 Q F0 +(the maximum amount of cpu time in seconds)180 465.6 Q F1144 477.6 Q F0 +(the pipe size in 512-byte blocks \(this may not be set\))180 477.6 Q F1 +144 489.6 Q F0 .164 +(the maximum number of open \214le descriptors \(most systems do not allo)180 +489.6 R 2.664(wt)-.25 G .164(his v)481.708 489.6 R .164(alue to be)-.25 F +(set, only displayed\))180 501.6 Q F1144 513.6 Q F0 +(the maximum number of processes a)180 513.6 Q -.25(va)-.2 G +(ilable to a single user).25 E F1144 525.6 Q F0 +(The maximum amount of virtual memory a)180 525.6 Q -.25(va)-.2 G +(ilable to the shell).25 E .778(An ar)144 542.4 R .778(gument of)-.18 F F1 +3.278 E F0 .778(disables option checking for the rest of the ar)3.278 F +3.279(guments. If)-.18 F F2(limit)3.279 E F0 .779(is gi)3.279 F -.15(ve)-.25 G +.779(n, it is).15 F .394(the ne)144 554.4 R 2.894(wv)-.25 G .394 +(alue of the speci\214ed resource \(the)183.168 554.4 R F12.893 E F0 .393 +(option is display only\).)2.893 F .393(If no option is gi)5.393 F -.15(ve)-.25 +G .393(n, then).15 F F1144 566.4 Q F0 .43(is assumed.)2.93 F -1.11(Va) +5.43 G .43(lues are in 1024-byte increments, e)1.11 F .431(xcept for)-.15 F F1 +2.931 E F0 2.931(,w)C .431(hich is in seconds,)421.315 566.4 R F1 +2.931 E F0 2.931(,w)C(hich)522.78 566.4 Q .828 +(is in units of 512-byte blocks, and)144 578.4 R F13.327 E F0(and)3.327 E +F13.327 E F0 3.327(,w)C .827(hich are unscaled v)344.784 578.4 R 3.327 +(alues. The)-.25 F .827(return status is 0)3.327 F .621(unless an ille)144 +590.4 R -.05(ga)-.15 G 3.121(lo).05 G .621 +(ption is encountered, a non-numeric ar)217.603 590.4 R .622(gument other than) +-.18 F F1(unlimited)3.122 E F0 .622(is supplied)3.122 F(as)144 602.4 Q F2 +(limit)2.5 E F0 2.5(,o)C 2.5(ra)183.17 602.4 S 2.5(ne)193.44 602.4 S +(rror occurs while setting a ne)205.38 602.4 Q 2.5(wl)-.25 G(imit.)333.99 602.4 +Q F1(umask)108 619.2 Q F0([)2.5 E F1A F0 2.5(][)C F2(mode)162.59 619.2 Q +F0(])A .23(The user \214le-creation mask is set to)144 631.2 R F2(mode)2.73 E +F0 5.23(.I).18 G(f)323.21 631.2 Q F2(mode)2.73 E F0(be)2.729 E .229 +(gins with a digit, it is interpreted as an octal)-.15 F .066(number; otherwis\ +e it is interpreted as a symbolic mode mask similar to that accepted by)144 +643.2 R F2 -.15(ch)2.566 G(mod).15 E F0(\(1\).).77 E(If)144 655.2 Q F2(mode) +2.55 E F0 .05(is omitted, or if the)2.55 F F12.55 E F0 .049 +(option is supplied, the current v)2.55 F .049(alue of the mask is printed.) +-.25 F(The)5.049 E F12.549 E F0 .475 +(option causes the mask to be printed in symbolic form; the def)144 667.2 R +.475(ault output is an octal number)-.1 F 5.475(.A)-.55 G(n)535 667.2 Q(ar)144 +679.2 Q .125(gument of)-.18 F F12.625 E F0 .125 +(disables option checking for the rest of the ar)2.625 F 2.624(guments. The) +-.18 F .124(return status is 0 if the)2.624 F(mode w)144 691.2 Q +(as successfully changed or if no)-.1 E F2(mode)2.5 E F0(ar)2.5 E(gument w)-.18 +E(as supplied, and f)-.1 E(alse otherwise.)-.1 E 170.955(GNU 1993)72 768 R +(September 16)2.5 E(10)530 768 Q EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 +(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 +SF(unalias)108 84 Q F0<5bad>2.5 E F1(a)A F0 2.5(][)C/F2 10/Times-Italic@0 SF +(name)164.2 84 Q F0(...])2.5 E(Remo)144 96 Q -.15(ve)-.15 G F2(name)2.882 E F0 +2.732(sf)C .232(rom the list of de\214ned aliases.)211.374 96 R(If)5.232 E F1 +2.733 E F0 .233(is supplied, all alias de\214nitions are remo)2.733 F +-.15(ve)-.15 G(d.).15 E(The return v)144 108 Q(alue is true unless a supplied) +-.25 E F2(name)2.5 E F0(is not a de\214ned alias.)2.5 E F1(unset)108 124.8 Q F0 +<5bad>2.5 E F1(fv)A F0 2.5(][)C F2(name)159.74 124.8 Q F0(...])2.5 E -.15(Fo) +144 136.8 S 2.773(re).15 G(ach)164.953 136.8 Q F2(name)2.773 E F0 2.773(,r).18 +G(emo)212.049 136.8 Q .573 -.15(ve t)-.15 H .273(he corresponding v).15 F .273 +(ariable or)-.25 F 2.773(,g)-.4 G -2.15 -.25(iv e)369.094 136.8 T 2.773(nt).25 +G(he)391.467 136.8 Q F12.773 E F0 .273(option, function.)2.773 F .272 +(An ar)5.272 F(gument)-.18 E(of)144 148.8 Q F12.58 E F0 .08 +(disables option checking for the rest of the ar)2.58 F 2.58(guments. Note)-.18 +F(that)2.58 E/F3 9/Times-Bold@0 SF -.666(PA)2.58 G(TH)-.189 E/F4 9 +/Times-Roman@0 SF(,)A F3(IFS)2.33 E F4(,)A F3(PPID)2.33 E F4(,)A F3(PS1)2.331 E +F4(,)A F3(PS2)2.331 E F4(,)A F3(UID)144 160.8 Q F4(,)A F0(and)4.074 E F3(EUID) +4.324 E F0 1.824(cannot be unset.)4.074 F 1.824(If an)6.824 F 4.323(yo)-.15 G +(f)321.938 160.8 Q F3(RANDOM)4.323 E F4(,)A F3(SECONDS)4.073 E F4(,)A F3 +(LINENO)4.073 E F4(,)A F0(or)4.073 E F3(HISTCMD)4.323 E F0(are)4.073 E .328 +(unset, the)144 172.8 R 2.828(yl)-.15 G .328(ose their special properties, e) +193.116 172.8 R -.15(ve)-.25 G 2.828(ni).15 G 2.828(ft)330.436 172.8 S(he) +339.374 172.8 Q 2.828(ya)-.15 G .328(re subsequently reset.)360.932 172.8 R +.328(The e)5.328 F .329(xit status is true)-.15 F(unless a)144 184.8 Q F2(name) +2.5 E F0(does not e)2.5 E(xist or is non-unsettable.)-.15 E F1(wait)108 201.6 Q +F0([)2.5 E F2(n)A F0(])A -.8(Wa)144 213.6 S 1.061 +(it for the speci\214ed process and return its termination status.).8 F F2(n) +6.061 E F0 1.06(may be a process ID or a job)3.56 F .753 +(speci\214cation; if a job spec is gi)144 225.6 R -.15(ve)-.25 G .754 +(n, all processes in that job').15 F 3.254(sp)-.55 G .754(ipeline are w)404.012 +225.6 R .754(aited for)-.1 F 5.754(.I)-.55 G(f)502.458 225.6 Q F2(n)3.254 E F0 +.754(is not)3.254 F(gi)144 237.6 Q -.15(ve)-.25 G .027(n, all currently acti) +.15 F .327 -.15(ve c)-.25 H .027(hild processes are w).15 F .027(aited for)-.1 +F 2.526(,a)-.4 G .026(nd the return status is zero.)375.932 237.6 R(If)5.026 E +F2(n)2.526 E F0(speci\214es)2.526 E 2.595(an)144 249.6 S(on-e)156.035 249.6 Q +.095(xistant process or job, the return status is 127.)-.15 F .096 +(Otherwise, the return status is the e)5.095 F .096(xit status)-.15 F +(of the last process or job w)144 261.6 Q(aited for)-.1 E(.)-.55 E F3(SEE ALSO) +72 278.4 Q F0(bash\(1\), sh\(1\))108 290.4 Q 170.955(GNU 1993)72 768 R +(September 16)2.5 E(11)530 768 Q EP +%%Trailer +end +%%EOF diff --git a/documentation/builtins.txt b/documentation/builtins.txt 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 new file mode 100644 index 0000000000000000000000000000000000000000..21e532762fd6506b9ec4afbd7543f1175751cd39 GIT binary patch literal 191364 zcmdSCdz_qQefJ+SlOPCq0;FmcLNJN!E;(@)H6%e&2}zR$!H~l2?re6*?#wcW91v)2 ztx`3S;jZIId>U=hiWOUr73-nUdU#s2YOB@S85^q>ORIgf(#f zA6d!&yXcZt7pz?KTAnygkNvFw{gnS5IQ+c@3l6?z;cu+@y900e@v9zw?puy~%C2`G z`2IByed+4AEI9QeH!nDeWfqUmjO|;s`q67HFEysx$A9wouW0||lxxeSW~*Lq96bDl z1q*&_L6Kd*_~45VKk=S-9=Q9s^Zx#0-(UTb|8vv+1t)%g&4LqIW6}6bebvg|mOXEH z?^)&go=SP|p~BlIH`MOh+#hevl&eXz)U4F1-N{taR?(-`+S;(N7(o zUp2C7?NGuq$@kZM?Vq2&FI^rGo6S`#`(wPC^sa6H^z?GM-r%i7uZ$dgD@(oU6F*qj z+SO__+gj=3i`O1}%W)@6eDJ{cH`-}WnVcLr?Z(UNl~T2{Xmaw3LqB=@WbLlkJ-lxy zxuRPymy_+a$>tkg_we4NR4=#nM7P$ePS^ua;%e1E;NYbt3T;D7DK?|JI){K2n}A3S(a{{k7`zvQeXL-*v7+1S5o z)=VpkH%n7)mx($43rkCzuyaa_k@3 z2@U}FRB0Ae*{+wgi@o0EwN||f?x)Jr)5-ScT^wq1Cz-TC`{WL5iw5B;*Q$sU{IvhAO?9`bd6QhITu@q>ql{vk8}s-NRlSzC1g{zkJP+_TtyQ zW*s=GP1>phJB_s}(@lUGug%PqsuKWRFDIq$p7u{CHk2yUr7=)gslp#R*HF9os+)PL zQ@s9v3BG!3y4ZCCXpO?ogCyo32a4=i4g>LtzMw9hQ^@(LUB#a!q?<}w&l#fnT8lA#xf4xy2mmEmO z>Xq`z`;$hC6V)rX0%3CsKpM&3smeHDOeH!CrJ;}~8j#l*O8oc;1n|W_4M$gRsBwaNG8w3Zd-&qsP0ge<-KZtgl?Gc2 ziH*vxst#TSv}Q6UATGb(M96b1TC)2BIO_2MMZ#Jh&O%TJLdvrtfWIv)RX&}Q& z$xZ!Bd&|I+Z8uSFjMpo(hG7V)6e(s|BWdghL8W~|?ZQL9S!pISrS5(QKB<>yr%U7I z2~bz5PE@qQ3`E;3L$w@bZ>2ev)ZkeJ_Dl`JtCsgpSE}X4NC4BAi3c04+1YzG_iOcl zv&q`@bPcxJD*~IYb?u};6psl$&i?lwBE9;pYO^wpl)CtH-|vk&JpnGS0&rvqe<+W)BTw z48jt+>=&VH5TgHIAO^Y~#D(P02OC%T9Jr8~3L8km`|TxnXyBk~o2lM_FKk55((-uKiOJv1nN zir={7G2lM5=(+{HT6KDV0_LT7<|%s2O39?peP0gJCo);P_{iEVtXJP#X_SW!72f#) zsM*9)U)V`{QjsFHvJ1!w(?pnfLtUvro{;jEXiI$MK(;alKK7sDV-(USeo+vQ*C2AU zF+_j}(PN>sU0nV0UVgi%Xd`>`e`lx5+*OW2iZ^}j2EYaV5YVyEFQuMwP0BIt;_GjZ z>(9k!ien>nvxJ03!-_bvH$Giz;VYPkM}Sv{b=W*6hICKWh`8ifa7hC;dT{7zuXv@T z{y5&p&*D5iGst^~pCmex*w=5y9zn*n7Z3kPl4Hk_*%Fp19!-D8ZAtt`e<#v!g_L9v zXcCB*UaG$)R-BXdwE($otY*w8UAH)Acowl#T)PJjj{Vg(vlU40eHmZU%U9S z>v}V#=6F}uU%GW~q`m0f9~p%zZtCAA^QMu2Ov%GQKaKKisSXPX)ia=}g?-GuC*d4! zn*iLE*i42dy2;${;!f}u5DYfVpJq+{5{T@yE~#=2Ns zRY+VH!^#cW&H9OB0eB>#p9kdEHe(mgE-_l9u|fMr=#MGx4tDZ{{CJQcczBP6fAN0_{p}OEBkG zBw8{NV3Rm#OD?@stMD-Hh9JHz*&!yBZ@)4j#VfiZ8j1yhhr{ENAH@m@Tt3Vw#LYzCp`E9VH{}^|sC5PYL>W<47iSt*;D(vAAQCU_gM6PYL_h11Yx+BM!4d9cXX5sX z?55=_l9#86{~b3lR11D4J}`cHuuxH_NHq%Saq_7LNp!nxn> z-`*QJRQ$jRg2%kO0o8?vRW0w)?bXBK3ZMQrX`9sZ1=L{Lr(7FJYNRX32Q{4_2gygl zoqH;}H`66(Cn~WyB_US}@*A!B(g6)m4MX zi=d;{9~svjmFl|`8WcHkX>QM^w{Jq0Qxiqu(OHEX*bTtbq4J?R5pcFERQIzwKYj$*P|);$x2gRRWq9OGzNDX6p``%+P~D%=R|mt zKCFusg?1V=tukbT;I`RKDKb;j2URkWi8YRars57Tx!$qbJPqwwMUbQfSDK94C|ixF z6({@0%XQCrj!m}#f_J=4OU1AfoL!q_JO0)w-1T1;3^>Mx8hCoIG211abkvPWC`q?s zbf+FrZVTSrkEWYI`c)*HWfDZFW#BmliZ+P1to=9FC2OTiJQ&0EggD{l9#+fZEu#W_ zb}#LU0Nwj~Sf;dmlW7C9%f>W7}(hTagt4Q%Jl!X(3f21)s!vV+3b} zp*aD#5MtwCXMg7TG6*jT*5HPkh>kFUSyAR>?w2!YbTA7!$lfVcSv9a@7bX&wSV*sq zk|W}?3#?C6>K>rOg1YzAd-iD)B#zm6+b~5sh2Q+Y8Fl3jmSW(@Nz-Ks$98eak9%P^ zofDnpY!iLiL7gUZoxR4;VY|bA8$&?EmPVZdWp60)*aiQ=-N%>^VJ7s&Y*=G_A}oNk zgW-&G!DXgV6Pcd7bznbkt-fFJ=lFV!XjHWo4ef2lJ8==?nhMO~Ay7Blhy+f<{W2-% z3!|)_0OeK$Th#Nq^X!I(2=Td@>lD$LB}_-)GDuMzDvP)#owpC1`%fhMk6G)b5@`c}1Otx#0D4wiBCZ&mk_bI+Dx&Vlb?Ihmp zBE^N_fRb|maCIrw)`yB$za>(J)Pe-0Vu#a}@&q#FJDtr(7dKM^zcJbw{D`FV#8i+EQY68WJrxoH@MpJ~o~F{ALzTKJ2P__V zmdIy#XmhE)JCe*G`Wu5$Xx*i;D+;gS9!?@(2nQrH?vSg2d5#4e*H@cuBE*bIw}R1< z41CVbpAmzmb)DJV%Rx#L?~Z0*I3a%OR9IpgqDelLtH@5_JO8D#PPRx+%$Ax{Vr~ig zOsKgWm)t^(h2xsOhj@;A4smqe-;cuK0Yp@|Bs;aBY?MoN3y?{U0vU#Qqc!GXSwdcr z<({sYxyEwl*CQx)SEeJGZ!gQZlbxj~J?g~BI744J;q2Zh7v^$Y8eV%`xnNYEmxS6; zf$&WFJC-X|GP)*R6##&kfv4e?c(Uh^QZ~~q$6#LM@9B~UvCKq(SNkcVGl!%Gk{Cib z7YVW@>hyNrJS3evpZ}e@Ihu!S=NoF{0^C3ez^zxTBiw<7P-g@pWFhs@%!cJk-T&-SLoA;4AGyX&x$}=@%3Z7IKx7~Y zUm$%Jrs_y2m47**n+oLU!xC5bFxn=Xl zu*;~Y{9Fu6afq4f(CCyf9Jk5aXzMrpJU|+Hq@utbI>&&OMl-deE9s9zmhY zx+=d{yKvzxa}d%gTzJsJ;NS$V%B8Tirek83fCh?oWwLoOeu z;Y0s?y*P&qFZpJtD6_N3NOua$KNCgh-xH1{0fl*#_B+bQ}m8)nq$fzwbMuwP)zFPPZ#i&(`g$2Op-c z0Ga++k8jyJy6Nf-gKv=QE~nXL3%|I%loOM}BUIwPSU(tANiR5q0Tk9=x9!D)Ye$7+ zfn6OxzkbdjoU>Q(`i`+v7V}v&AC^?c~^dj?-{Mgrc|KzNMArrj22>Nj6B%1d8OBO(CHhuD{zs;Z zwJ&hMRIR%gS_XERKL6*Ocy=sc!dWPAOCZEkORV7>wHJNt7a(t*&{L*C^2H?GEOx0S zg_nGJk>i_9O{jDV4{Q`_^i&FebP6w}&f^0f%XNpIQXibS-C%p7j1rvobLTeaNNJVJ zI6(R|n9JMmXPb}YDYA^W0WjB+thwe6H8>g}? zPm5^*jV`%U_~#eKTacga2k)Pi^mcd4`%N$Ex~k<}0Bpz%v9|#xE+w-Svvg$fgPi+z zU28RK$R~&h=g9Rg0{g88NC`@BN*rPzdhFBOAGXHBCVm(*wWUNBYci?(h(UUX`R$Vx zq6#hYPLxXF_GdJoELY*r_He7KDa_h&xjnHla>dRelsp>Y!WDySzL)x*u;u{Gh=}^s zQT2u!R4<|>P>S509Q~PEs4|;Q`sbXJD2`54m9Q$(HdHI=O#UDi>oiUaQd)#!MSoCl z1&r;o>o)-&O1bj@BTjbzu1g%~%*K!Ag7a*r>(Bt^r?_ zG0qA0Qj{BcM2obu@EccnT3Hk*cF+YF7qe@nO4J*_b-=qf0a0o-Yh*{=W)KM|&Q}b$Zt0>S@y*$Wz!HgA1((GPmG~rqy@M(CT#Z!1N+Y291Z58N9V%ZPY z{nGO-Kct`@I4f~T6?K_pg_Lz9H|h{#WF@SI6>T6}#_RSrVYQ$5ufXCF@J2=TnSeA^ zdc%9q+LJ)zC;n?`P@{=Lv)F!;M(Ir}%8t6UUA$}+{&CWqs8N2bKuWalOlSe5r@cH9 zEH9>E;lc=%iIw7})1zmuNDZ8BX^%N; zkV%wUYc)w0yhqE!2ix1K6|JbAJ5Ozcd{|`h{4A*Fu8S7b1@jGy$m4YJ{liZ~Q#H=8 zx8cQ_fG>cR7mha|lJKL{D--%5*p=Y;q%&P)@iRYxjdAg}UNF}$Jh-gkQP{X(2?-=~ zRTL@;3SuVyob0KfZ{US~%x1Va4~|)C*CLMZ&B}IR;pI2?=RPBr3CC-M@(-?F@qjTC z_pn*qR{jvti?{->A;Wf)ix-1%kCNsdHWvCe5t!l3ta2h;aB7E7+KGQTzuj0rU}MK3j^4QLbNny@feRoDNrOM(JG8{Y02y; zBXBTTnFb{!<7ELH?=QbOaQ7`tmEkH!O#3}GTSMtkZQK=Kcmi39Q_-#&L3t0e0wa4H*%daQKnSom=!>QMKNK{tQJW%lqS4lPi+F;24a?!W6|ME*EM4Qcao2W^&E?c5&@*US6(aiBFe3z|&rQ=kIUg z3L42Ssxj)2#(rc6A*uczLj5(pb;^)7;T~Q~lL{I4;7@Wbal@W>CDh~z{t5iG1Po7}BAMEPn=GvHm)dTb* z3>{i@^7p7TA(Op7XLWRMBBIg6elOE3k<(FLGT8_fD04Nh>`pdibrCMBOU_CN2u!c{ zv7;h}1KFWFV8nP5H(8dKM|N4gLVweXuimn4DGIwLm8nca~dkLK%b#~mn)zAzr5UaffViYN>vdqmJqmg(pFmLG5 zx&OaaK}mZ6l3;oN4u~o<-#W$b{zDK5Lnu$IuKWL6b`hlF;bzPil<9Z>A?i&o)hLtD z)(;Lrv%rfQ>so_CQ#!?osxjrNP1v;%TdS&Q0@N3xsD|KOm1o4p`k1gmL))RNByOWh$6f0d)n#??7j0QYcWTBlmDu}^p??qQCZQdB z#v^xW=R`~3rBPGmq-)4!r{}?lYNQPq1F^03*#GUe`MHC;Z++>8u(|&{91aCwTdvxW z{c49!&7k6se%Vx+IZ*=$l4MY+dj1A-tdP{q*CxwOv7+T#0_JlUc2oZ{YkYxTN)1IW z@U+G9vNWUTok*N!Bxm*Q<}A-4xwImuXTNq9zV%BfnMo9th;@1hzFKL_Bobsn?w9Ig z6`Wic+~bonRru8?BuFp_2bOzv!JG=#>5{9{Dpp|>=(kfi@f}d9N^dQ}no&9asQi6# zxrrJoG7&G>M~N|=L|x#x71$3eJ_{e%!!g<${kkvQa@?17meiMgyXbdBp@|Flr_lWt7Pyu%Z zNHPdu_fFw&t}{3}E`Qd=@=v2QV!@_csBWjw!J&~Pr)A0_S~+t%f>HR|7u^xUi;{<` z-Gl%w%WYM4Xitu5ag)^KLPIZzyQ2~xzSodnxLJtGXUf1)v!^N$+^KZJEZ*8q2~(uT zNg}aPSZS1Y{L5~XXv;gib|@E395b9w?w@&)X7=J=e&hGU&OolcS=(}V@G0WKk;M(7 zdqvN^o*C4TU#O}cI+z8i=_a1f|JIH~yXB&JyI873ExmkVXnbhwcI5S0w>`^E5I>$J z-Ml^tO5n;;}ButPan|j zTTPWXI;Q5L9SBcwh4!8+mF(qCv3#TX-ZCcYmd5qAiS*V+4juoDPq`7K%Nm!Rs>BOi zKVps50|6bVjNb#K-sXqRGtMn~VUZUCTlGYsLQdnvolEAV@X4*x1D5G=e)RT6`>RvG zY8V6Ji4ni&0qflmn8S|0PT@Ttu_rT}B{N`B1=5kLC|n3y)rGw&Q{glgQ~6e)`u%qs zs%3K#UnD1rgjYjix`6qXMw9FOzOcvCO=5_PH##SZ3OyUSQ$8VqY=xQ5X_C{OMQ42) zK*2t(q{h+mKW9TA4t;60E*J`R9CCSVF+nd-uzZj!C#A_HXShtXat^m`;a8nSpb%h! z!nBw?MB(3vwuX?ydX-KKY<9`Pd!H@Tiw|aYqvlmSe_pFmKX1B*y>nipK7JmK#?*N) zuT4)3kyaeSM{W*{wRSbqa%^u`(F&BI?X?PjO8c9ME%Wl$_}FspDyxWX+@GJdcsFv&bzLXnP)c5YJMJ5;Mn<}sF1j##Ri zr>IyjK786s6>`d4Z(KNN_T?Wg?+b(#Dwwq^D+m`9Y$YLDr<;xYp&MbW)9i41x)12s zS&g@T3$p}W(daDv!4koGq)J(H4$S4WthmLCLP;|sM&7~hvok0?teAKr`$ZOFqqhQD z)CNrp8)|LAmVe2c)p1x5Agr!O&~${q-BL6-hv&js{QDL2htu`kz@~Xf1B3xyN1uW5 zb3m#~3mDz(-R>xiTc0gh-7cr#OqS+u9W`D{RIqcf<5=LTfBipG;y5xsaaVO)uQ7nt zNGZKuF0T(SxHZ)XbZC+w+tMy9i>&Cfa-|7ogwNJyMg5u9Jz+jNcfo?^e=BO;pCeju zF&pNy!q!(NNQ~_QuR#yuwWq!FHO_06(3x#?is#)aBxa|KI4u71=Y>Oft7l?TPpKk8 zSDZd=HM;G^`!`ro!T`f5(&cJa^hmWoVzXQ|HdJaVL4iQ*12JM6jS+?Dbs&$#APWaS)jvJIrTX5ms^ z-xVbP4`j+9r&?ejJ+B?f`?f{AbHqj-p2GJpm_I!KBiZq|5E;6~O-~lpqD;hcM-g?h zWBAB4EIvTq8!9B5%oOhwE1wkbu^cE073?$UFm2xEisPM2=C_Yu_M;6!=g2=g$#o50 z4=F}OwcL={_{i#=!rKU}i!l zPhCMT=Y)KwjI#4WJs-H_F>j0Vj(O{&Jne|CduCBt5N}UX+l`;6zY12BVY;K&SV4t+ zWT?j{umOH{fKPV74SN&v7sDl5 zNBMW!`?27E9pB%X*8my*iJ3l2K*!i%M#-wI$cM#Yj3+$*$5-)J^V3h-7bT-zH4P!p zOPHXcSg?m%%;lC~nNhZTqC!DB(Tz`kWgTs5KlpGijUZD4qp;V2xlG*{3|5mN$gEaN zzY8FMV2Le0Ql-yvdoyLS*`CZ3F4+%?>=fU4rrvdiH!Ct85X|S#OI(Ip%_rSvc^_Yk zCoEBvEr1ykU+4L-4H~jjJnetaxZ&cJ#nusuc;Fawa7t&~(DCcAUp;-oik!O7O@#xn zX&Roem(jOjqj=GUuk1DyB+DZ({?E|3B(+9x82?&(o2M9KqQQWS;?E;jkfRDsSD>N7 zM!eT4{P*U#y2=6Di~j!ZD|}>sgMy10x3snAAgT6o=EJ3b)#KuZ7VKaN^Am$bWYl41~444kSs@t*jyR-X@=jA$&x z7ZAmcXMCKFmz1j(9rq!1ykOpRF>W#(Lf@4SDQy+19~3apQ3C)_P}lmZCLm}c1F_^y z+efe1bk#=jk3>W;AX?=iOaUZESZJtg@e7T92%Fv1zvH|Sd6zea)Ag1~?uF+=?0CAi z3yuf@;*Ft+OTr84@S2zKV8|1C(dRlXMD!v*iK|aSaiH31)yP_^o$@2ZE)P9?vF2&b zikv~LnRWB{--a8aLA+|^-N(K9%m;J}a?BoQ*odVttgA5R{LZaHR~9`>v}6WqkCv!~ zkF?3q54Hmd@l@Yqx1Mq*_epHh@=c-)ztTBLLq#a85mqv=uUt;USuIOG8(S)r6>duSYNztG=eLw(~VCkZ*t=vdXB;lI$Ys% zUwfRxef16_^Cl~EuAE>tVQk!_Rp5$|_6h&_sZH>1*6`r83?4g$pWdmSvtt&|nsk}KSd)01(+G==n=jo8Wr4bx z3;=@CL(dScaN98_Z_J6mx&f z4tZGxCv*q0g~dT|of`+F{O(X-vKnzTZIx#>O)p7Hi}H7Hx_=Q%fpxTySw z5O~9sploVJSb4`YIhO>aOc{$;D{JGKK~V_aNEMM8qTbX8RUK=Q5Genw)v+kvGT~_+ zq$^|ZMEp2erM&5h>OKD}s9xQb#%4(w_`sTMOi<0M=4?Hl0{~A0S@@FjrQ&mbGc944 zlp{@)f(C_bx>SehZ{5Bo>4gplq(2K)5l!+ZyZecpz%=G($>KC*!H$u}JH=PN z*4hpMeBVm~;P#Rz5bMQ~ZaR%pq%E>y){kUPquC|2-mOh4DA09Cc!m0f ziSAxf0}~Ay9s;vdc+$tUVro3NSxx0(yYQ}0T5B#hW!5hyMM(H^i+}L;JbWCgOm|1u zia$_%!$-7c$oA^+0XM>54llq^(tJ*)d3^k>QaCSppVX2Ol#s+qJHMora@^?@k7G;o zy#_>e*C}8UlRMcl49Vl_Xl%qWAdh@lAzu@tqCa84>nxE*^u-#-jp z?c}9h(zlu}%eJTdx^87`Y;KVAcrVs&t^?2~G{p3wGpZy<3*(=*I=mrko%aH)P{1DR zaYZ??l~A`=GTD+=IUCt3GHm4jI0(y0Ps^kaO3!GC9SkxE8Q>wRW9lNa0AlS~ngk%p z%$2|bW}}<-L1r(#`qvchpB$Gr`XmV}!ZVZO=7s?XV$1Kr1*L$`CE*o8sLKJ~n z1Wz6}g5drqmy)`2Nn(ZcP?}*oYacz@Db}vj!qI;S&c{XX zy&P*CXTa8Z*L7CA=_g}=mJzadoD6nj6ChFQAXyImT0yV(IOHrG4Tqk`|9<(8qJ^`H ziG1@jlHD0s6XVmTBx@~45fL-!F@`7`iq(JuU8RyS*@bsKP^#(3;$Ndy;&c88jFq!;~0=kXRa5dc7Msk95T_mWoz z(5&)G2|LrAh|S?u7uer~3I2wJdf=ae-0crfC%uzPl%kq1X$*(F-1>A;U8LHu6*8z( zy!YK&g;OAJqQ;3sC)&q<`GcdpXa2bsRlO-*i-c!xy;Sd5JiI~2;JX#z3%f)h4;{ba zFpG7HH~+GQN3e-=1f%mVOmkiN&e!wN|5>9cW;{P4lLB=!n^E77YE3E z!GpjMTW6Rh5&}h#N$WB}X9X-M4=X(z& zS1lU;tj*LwR$95g21xTzcbwPiwC@M>uvDk;t$Qq*86Z4{$nEPb*;)CeSSQ7cbKSry z3dw{`wxhi;Lv-{tip{LkiOP)_jajv31=n)g_1mPsvARM~XjGuxUe{j+i@?Dc9ulr8 z)zxKcScDtbYFVd%Ng*3Dk>?xv2cNqjmL!FWIH>tIf3L2-uZR<~+5*tY+K~%K)&O(1 zU9@2${Hrerp{nNoS&DV?@E1>eQa}84;I?ADy-8ouHG0Q-!{BzR2059LkU5Z6lZ%sk z6=fKzu~ESTYHQ^K%usL|#{ujV|BqF4GS7~JFDja9V-1>((Brw@;3@ zfZlEEuHLX^a|{`Jja;YrySp@619ZUzsVgOpuq)O4b+z{$*=0u81T*Wcyg_v|Jd;+~ zV61)q$hwC0w#uyx2Tx_9#S&yn@KPoYA#tix1uzDk){a`=6qqm;HmEWA!qV~EH?H4u z^@i;!iDUdO{Q6%G;J|%W<9Mw+u%sSF)VRRHR7eBsUbr1f>5)llQi0gt{7yd;QG;%z z7C9wngvgr>n(+`A_=0x*G^!MV%McwN>kdM`WcV>B{QO}P2f&xQ*x@1be;{dE9Gp5i zgs|slB)W#dCNv|vXQ$~6JNk?~e9SZYdmKfe1$^Qer?~WO;_Mt(Ndwo#KcXF{U4zr8 z(1`vy*QZH$Sex#k;K4IK#WK0qGk@I$C(C*4FpAUYmaC@MRZ~_7)*s%N>t_oH;~Ipp zIm~%}vSSn|w<8S$f2Q(hC0uFLMTvC^t6?LTX*x#53TlPDEU;k+P&_qwTVX*j+a6pq z8kWIZ-z~)wKKfe9_Wv5-g3=oIFd~AiM2uk zlun8xC7#%sj_FdhN%ClkTW%4S0+~Yu`NB!4SxTDU^PWhKj7j{YW3-J;HS*?$f`~7S zg0ks~l}4i_glZ)yD>vE#ZvMnmJS1M$AU?XrQG#J4W2rf3-;|VO*;wcs8_PG!xA~Up zbsrIgSU>+sD_yKx!XoHs#W*#>jc}ob>x!>@hKm{|bC{#X{{f7&mVp7)rrX=aAHLbA zYUV24g=dKkn;w*DxxQOC-e=fiHWw=Ze0JXw@he>F2XSCsAsKw@og45v}2g+p=PEz%WlF2+ay9$rIK% z;_VVS+gac8ShJ`lTnQr^JVO!cjE87i36=zPhRj${EC`B*+6SQup#hu|jtLA3pL4OD z!Uq=8KYLef{~Q~_`}oL@qpkro73 z*sZ^0ng|-^@)b*Zd;;dRuY(m26?c9pn)LSR7ptT0297c3ty$l%@F#%^Yh@%oHW(<%nv~wsPwdZDVN>IVi2F zipYJ9fjO-f7X|&XYe}ee9qb!uS$()>fEU1oWRX8%$MJbj&Ts3St2@OfU!#Cy?9~%B z2d_V+w8+ho3){u#eNNA*#13rX`a;Z4z9xG5_2770(va{kC;6d##7&*fI;FvlpxozmX ztUI$LBA5|9ye#w#5UG_Yf&Z{rpy4@;3EfK32?_GPWT;5oPJ2Ma4L)0wq z8Y4{)!+MrUhAFMVh_JZJfheElcA0>Y(ZlXvIuKAJ0NF6IZfD{BOARsU$A{cvCnkSr zVgDyWp#AI-vFLoW;A=hwim>c4veXF~=rxC$IB5>S!G3Z&U-lPQ_O_C)hxu| z!9b%#_`p?Cw$Yynj$~61IgqT# z+U-R!DPFs|Tgt?1q+GU(?{x|<{c(ouaD1XUyWW*vnP7~M>r&$;L;hJCOPRo0=_3Qn zRhlF%G#$FsDO~ddk)z5B^pTr@MNs``C#{oQgvfpT=Q#C0g~=xxM&Jak2fASN+$NDL zj~W;eGb6I2*jAU;DL${ALYF%L3g+ft8CAVen&c@>QZ!S1$(u9o(#tm3Qvx%)S~6>b zrxB;|iHy9Hm-#B7j;ɽrFf&UoCPYs}}?W14HZ$o7+xGe!3;-Jh!Yt?ZO;oWv7DPw;)WZfGws5(mM?6~YmrZoFIyZRmzaX#6tgwuL2#R#I- z=uqL$P7C55J!JhCf3Z&9oAfksSSd24Gy}F2?0H-CdVR`s=Hr?8>L#EE%~fuQY0 z|9m;RN<)p)a}GR_EAui1CRryXkv<*ebPA2m&EggjJ$#zuI-1_rTn(zjzdeIiQi@FQ z+BdNDb(fv8#f9IjE?eP84wp=I{n6t3nVu3Q$HFh1Oaa4Wmuf?urJLf83z$wX0o-D1 zd2v2gK}MQ5B=h-S{mw|5IR|pBmE4$K+%5rQpDUd6dC6s0{`0Ey=Q@v%thFyms@6m0 zHnZ&ouemI~JopXCFD!{Z)8nK!O;pBmn^v{LH|FGr3NZO&tU(cqc!Y6!^whuZVHG)} z*o;+p2y~>*nWEVXM@kbuu{H*78azGCC!|Dfq5ClKdyuDm6ay1ER7wvH4O=^MtdN6q zq5^`Q;Xan2B5d>hxA!DjK&oAHUmzVatzGRDNVii)Neo8=w=Vf6t_B( zPS)fBvV;Of>-E5#_zdXbh66Tj7XGk78P*AXXPv_3|2KQkh5|wa&j--ps4TMZfekqM6(}`p;A|h!(){wV*|Zw zOIrYgRI5Z{{_jI-cxkED2#2iO-~&!wKTB88cO92ZrwxQ^O~R>Do6)N&OKfbXHe|?* zYV*P7+_vO_SnSW9rYPo+U=7L3+=dGue6B2Id2gbQ7hio%d*Pq{%Qm>s1TlTIHYURM z3mPlAFxj!*lgi0elGYnNgTIr>Lf`qR4^_F)S~Q_tuQ)QnHCGx5#bFukg`syi67j4G zGXv?dt9=h+^H&9+3D?Z4KvL)`#4|zO#xzb%W~B>686Zj6icgr& z=YOrUqaC%1L3i^s@i|o`9K}8)j*2xO$FA7C4#|VoQHqm*8pL_V>mM=1G{O?Z>KDFu zv5CV_m!c99FBgIpzWyzFz4`HGYIwnRB#;^6R<`4yI`T%GfC5v#7NB)i8Si8=@Adv5W&v#yJw>Tvm&R4 z4=)2pqTO}XLxmqbdSvdC#W#Jg=W-MSTNRt;XLJp6MDj%NY2?9}caBh3MN8GH%@pRu zm{F=>y3t);YA|Pwe_MzS`C*jl$>n~f!C;vE%UAU1wc{2Pbp=f}C@&-XVG2DQNnGv~ z$9LVh^=UiE6b{P_FGY`myhpB zTYcchbN(BGWa*porpz+<6gN_z-w{c9?+V&lvt`=ZD|dwcm|%oF)?4;?LO5fIRBRxV@Li(>oe^K;Xv=hQZT<{eXOZ*VMoTebG9G zKqLT;c^UO_b6$ge8>KCm0u(8DcHz2`*6gvttB+@p9pf?v!8;nTdG03qDOcmCfSL&{ zF7|zvWaHJ>D*C0fS1JCDqkBXb0h{qr-K?DTfIh7#tJ((R6ZZ3{AKz4Ai8!y(g_a|0&xd$AA@Mk{!wLWD;KFdih#*{z}pxF6HD> zji$=P@5_-UseiX3`Up-;p@elDs>=Ig0|Bh3%tyB^Sa8SgsNH^!D8by(h?2+3D}Ur; z;htQ8rwz&<`B-q|2wOfh%Kc!j;Ks-XVu%UVOc21)W|vL%On4=xYawa+`HTr4@v*m04o~7B(t8rYURo`Ok`(E?>)lt z7*t^G#eezTO~N+li6FF#&C5j^eev(WkXMhgdw+~cPP1^)gly|*nYdK=Abxl>N-St2 z3kR)v!S5`0rEG;=n^ZQi*=(EbW~^;e2r3Hjr2N8zk{>Dz2op;fPxquSY>aMDD%jLb z?iPd>F3J!~59$+QSKl8K@oyZD#}Cfo#OIEVKzA-_$y~L z_(;x?P~>6HAc*@*`DRFu`njnuaxWm%s}F!hvU!fhq*Yxp#W|b2a+G~4yqfm180P2{ z_DIWGq(ob?I#Qu`YqCV!FNqQ_e6pEm^ld+hZNqOMb|>nbE@C6CCp8}b^O&z4{R(n4 zUd|!=OiZWnJD19r=NnGYh>N7`F7>N%0(U0gMMn94j-}C{X&l9ZUkcykY&wO_tWF$M ze0Ayd7?j!fXu>Q+MG7x!=w7S>B4iAYUX`tFP@2=I_Oa(}vttFj+JycUX87$wZek8- z;)J61pLv`tTx2n+fkUOb4NoJ_82*LOV6BF1MG~BI4Ay{h-KjvJI>AaV2Kp;QfmPp0MnAsF{%>{iqz=FrF26aJ^v`?jS_}n;c`XOobDX-?VC;-{{Y z1;@XU{C)#u2*`8TKnRuGMJUqSm!zL5jn``rwzVWWx}w(D zTo=GeJWb&w9=^_rp^!`UrWGcah*r3coBB&`SU9M$#Dawg%9d3#LjxwHD^sNhLOU+%sekYtuI zu-oX7NJ@h_an~r-{Nf9a?2dHWF1-1|9$<^LM67U$a2Oa@g%C)cSb&gzqlXxBylG(m z*xBpG4U_DkS~D4Vox-XUGRA8cUUgzmr0?Y_eL^$i4Qj6nSN^*HH(!=SvJeC^j^ z3j9mizl1?8-<;;dAD!a48|WUt8w1+N^%Pz5$)bLv}R`cP{U=9^Okf=8p#HmpX5*PoxY2L0}<{qqdcrR_yaH}|M%XU+r>3Ag4VEcBc#ezm%-!>p~K z)T5S-kAd51K35TB1Z9dn%-St)G7294vpKp}&)T_TK;NG4=B9b6%?ryd{H~i}MMTTu z#`h7aIBl~r7#DU7bxUWr;d^B#a^IwEhp*9EoeAbNUw)*9QiUf--CZs6%3ey~`5nzA z6L>*+M}7#~@cAXQyXKj3M`8{<PS<}$cAS++<-mA6WP@%3xnreKO_ z2CURB1xc3AN(nLSkb!dQhp03a4ZHK3!DP{oa8QpLV{dkCgco?9Q7YTp8TqgVSCKm_ zhK`H&e(2@N6L2eP)fjV7F|D`Wt`sTfCG_D$o)ENok=yO!c-8a)D`2jndwh zm1ey0S3lFo)XGLti7r!q3G$O~AKO4O>PVPy(Xat~9!yb&DBg)4J|uquyZlc-FO93P zhrLLr+;glAqhbBg;obUfKUSAvIdacQ9_ouUb=Cjqd1Be=^Rdt`k3NyCG-wKf&9Nb9 zzVLJZOZI_0FiG$-jYy1Wd-^}*+S$snY{%1S14awoXvvQ4=8k6_Y03ot_l;(!tX>;4 zfpS6q+2@vrujk0ucJtZM9~@*LEj2<%4lNKi0f$rG_tk5}6iNSFbY4~{&>x2PTXl;5 zYfsEwXi6BJ;(}}A4Yn6OdcWc<9``}BWEFV`x6{86iI^+)mi{aoGN2jHR1Id^416~U2Ma_`rQdx<9Tr9 z?fSh?Kf8F(BQbs%2gSFGTfZ1|kxm-F&qFqfk;{`-6RJ;DxjxGLkVvbY!tkXTE3mCT1~bRsUm2wk&2*U0SjvEkwTNsG-_O@^}6r1QypdDof`> zfTVNV229cm1&NJtVDFzrrY$<|3))eoP15|4JuIg$QkNKstE)Bnx_4QOM9&99W{n(0~+9K%8+Z<1R+T%SI#vvXNNjmNu&) z6y>0~h!{{V&PT=fpC3nCBDX941;NI+56Z`-@H&XprgU4x?6y>iO2$=42be_iZJf zEIa~Cj$h7ag+4AJ%j9DqFmrk=Y3X)k;n~kON#UTy;T1t%UcA>DvDLKh>gy<*FO+Yf z4wb(~cHCgqvP8AV+m$V zEFmF4I_SlW#+98^_{M5ks8ED0Kjei@sa+HQ9hM%_bfw+0I%AEme=^k-k?J4nHZ4C) zxEj*6dr4~uoSTh9F?3)6ncGjdh6r2$ZZ4hi;b8i}KKVMNn3fh%W0)5^$CMa7F2R7IU_XNeqoS@1U^5MvfqT5iN5r_2y*}KK&TP zy|v|uX#kAWq^v9}0jXldse8pTPdW<@BY35r(&I8QYMYL5v-?r70w#&qPi7zZ^%u*V z@!w8z1Gv;_tocGnjYsK^ii2dZ=sS(d!Eq!-EQXsNso=kG${_H8u!I6#vLx;N{y6Jo zZ*YhFOG#o}2wIfuF}GW*W`O*=lRg_AAB7_VitviWGdbYwRzb!Z*I4 zA!I=0-zNu&cGG9 z1SL`po!k!6l}Cd_K;$TpsO(l7-p>HZ<+?9i3JZf&!IKLp*)m)n#u?}4y6n3@`FB+% z%~1#d*jZ*u`zkZ=7~|p^lvIle85T#cs7iA~pJ4v=7>mlk4n^f&=UYxGq43?~iBc0$ zUEXD_viX%}jsb|T#4UI*nD-bJ1y~~(QdIQ3?zLFKr_Rq3zGr*1gjdgh-fIYjkqSBr zN8yn6Rg3`By{F!)B4WQ2`13K|Da~N*5^NP}XIqTwMhq)VXT7fkQdBJP7GXeBwmfg= zNL1?!`_imy|ILLb-#`90Df!6Nc)Qo#jl|$jdRZT>h(3O*QR6qEGzct;5geo6dU@(W z`P`$7Su>|6U5xzoZ9xqlYdrxVgPQ9>XtDalnaEDn1$Y?BLDt;pc5%}}K&=u(9G+Cq z1DI|!TJamaocCH;7B(%nQ~2Z`N?<^ft5&XFJ8U0=Ve$-$l=4e8csDSRKKr2epj$YF zRdKE8PY=$p*3U?Kh+^*H**U)lG^;E9?P%i)3Y3$cziM^5-=b#>;^DPFIMYiY&R5gTsL8m^+mRxdyGw^0Nn38B!4OO}oq?|E z(BxcK6NDE@nkB;RL-oO0rVg!im25-Pv5i;L6D4X)pTGJ3WYZw$(I{LP)<#^<`;2gcA|P5Wyxj z82FqZ!XiR3a9eUT@3T>{dXfqu#!{$eFYYpUw^#DClThFCisf=mPDBp1p%;(v5w5RX z2<=QYw9yu#)aUUt?l@a0tG*re=X2 z$krSAjctA4h=diZ#1*~s0x{QFSie0#?L_eviEg=3D%gv427XTE-sH{s-GutTxTX;k zsxo)&d`D3uJdcU;nGA{58iliCW7g#FNF2DF^*niRZq;f{GVz#;R(aIKq^_}AlQ2K# zbCZM5NpK(YIsXzp7QC<5tW54d=5u3%>sb}!F&}K@ADo@q->~sIfiVV7y>;M8?*Vh< zWTkrx-}`Opaw7$$t~FZ%jc(O-C==AKevY1Q`bB0%oV^dstyEjq2N$n+NN?EJ-sn2R zWE?Dpg&x!khL5kuV)__cb=UV~a79uey;ZzvLoj9M-xa1jG8|(4U}l*>hjGbtugH1W z4tuC);H#hUkwGTa$j&^~&kGCW7rkOxqc0K5DV8%#A>x&DXoK|gFv(ltWglW_+W{rrW6V30D3T^IYnXH5vLlrQaDIh-!JgF$G8nZ&YU1fsyveup(qz!!YR9sWr^AZd zLph#S)IvD#C?uDQnE4ZiD323|ybZngQgY1j<=k2RIy1gwkSux<#iw7Y3zQBCtEHfu zBGrM-`K?)<71N<+L)C(fYr?&3FJ5`W)is*;e2_}xt>2mveanZ(H@}miZ$7oUQ+UPc zj=tb^n6Q*bCV&M%VgYndeQ7|I=VHlI#6dQq#aN;!oQM?7y<@U`4nF@f!yxUg4=B~S zL;r+U@X0G6*1O%MTUZo($EKEBs4;)lF>JaqP3E3;h$wNxii#0ovb_}9$%qXEbtQAm zMi=Xa84XddZ2G{*W$4g>WxiJ&QLKB6 zNCy&&I?J8oTS=MM%Uqa>O=&w+SoST(s;D#DysWf{Hyym`wJgQ=y>FCM_3TvQYM<;8 zE|pHp@IwY_@O_S0oRQYLkqtz2fnlLlZPMo^_=Wdl^xM1>x88=jw#3}4lRI4*4(qOM~zFd@=88l zBFe>h4M}+Xr2(}VnHQ^5GI{DLIt=CYG74PsYHDHgPB(L*M#xXC#JaZ#j3f~=1ixyZ zdba%(Bx6PRg&Bj<^TrkVn=d@pL7CxILEowFjZv_YAGyLeSDeaMvSRItBVD3(z{$KJ zUmG0jymM~Mnol45V*DJ$zciQyf-*5FH`eNXI>paDZ+q2FECb0%mp*5fY~SR?D&~p%aDXxUTB$81ceSiWsqiTl?+B z<(*p3NnRvrQGK4V9dhGEy(okm?=R)9!+T-Z^zu4|XaD5tcH!B7Kj#wf{x$oQ%41!V zMG-~P@q&?>mpqNVtQn5TEE&3`t02t&($zid+vTVuBOT;Uf9ch|kwoI+sGBlPMUYq# zSNTq%baalAWLK;;`Knyi;R~<*vPUQ{P=r!;II)M#bLMW}d)9N$@ZKy?CtrAOs82@` zd!c}IA#e-+F~PaU)Q|-{tU$xTAqC@2L6ojr?;Wmm&9$`#SOzaw?5dD z(!FJPyB@@@n-l4wOI(JzOm7Q>?UXq0e-`b9E)yBKQ52Pds!*`QUVYkjH<%s+qKVcl zb+kx^e|h96fD}w{aB|k_)8}Wce&83Qwfb{}W!B6M%RqaX=D7Db`BTi~;=;Q2O&N)9 zgvbQdOE#sk_Y_(#?_H1v!ZiggUcnfY&|9Vuo+``B6g{yD8Gjfyh)L{6v-~AND6*G6 zTtN|Sr*OjOf&ecG-$#E!3DZS7L?y0X<*gAO_O@R%H$)jTe>2u_6HlriVGwQ&Vv|U* zyTg+Ble-i^kKe6C!tw4d;lzZwNCHaS@O#wQa8Y=!GP z5^j@^Y!DC=m~mj4nnV8ST$#9s3V(ND#m6di%_0gbSq2H(w!!@;1@bg^%|`ik!_o}s zjmHXGP=?lgW0Yu}MQ1F#sehJ={Z3eOmH-Zeh4bi*SDZUWz<1m{xyex*&Xq?n^OQb& zuNi&N0+jo{ z@jrxCROfne0>KrOuJ+bReK4z%cd;l#(03L-veMP;zzM`f@oHHo#1CQRQ!Z^aaD?gK zwYVW6hTqwv6NGCqrqCX_!Nvi3ZfkT3pExHzn@6YE*PV*S?#e7SH30=wS#~0sX;xiS z#~BVn!=>G#OP;w&0sU_JfdT>(rklw ziCB|ms5oUNk=AeCkQYdwd_z2zOj>iq-+m1E+pT6Csp3uVCCaWQCdjR!B$AiJCK*R$*0TSZ6kC z40;gut#Pm01V5bJ4f{UgyD8a=WpAZfwCj%qIU_}$WTmP3r zZxqWVs|yICP(e!FCwfbq5{46KCv-1I=g$M9nC0t-qZ*MGw>*$to!U#yPz?a82?@B9~ z>JJ=G{ws$mz~R!u?p zR{*hf+m_8+M{iueW%Fjf*AgL-y6iCU54tgZ0VduwV~P`-&_>>ic~r3~#&tE8N+DNF zA?_4n(U6Bb2s1p*I&M336#`}i z_6C>^iKQ5x#|8QuA8(NmEX0b@8wwFV&PrmK(d)NHBf~#;?MU&O8Ei0bNuqaBdPCCM z2nuAy(Fv+15cl<2Y+h?+QF|8ms=LQt^omU{zIw~H6v9J==|3K?O{23LVYo4>X!?_} zsJqcRWgmot;PmuP2!fcf6Nl?Kkd}#oOoAlq^l`P!uGG)8dotZz#-i4=9D&phi-&Su zk+PV`rl~-+{Q#-AZ0;MMZmD-Zo#PcC35CvMs9=k%GLb zKT^Boj^46V%5S=Q>oud>6vBE8vvV6_$`nNmC$kOnvXK7-Gx!jPB8B329VAVtgwdR7 z4|6`{OGJD=|NHn~M&DxfyvH;5ZB)>;8@FxWwB_pTBBC{I+Tk(gT1HnL9#O0*ejZI! zs?nwUcjmu#9uyRsfy;ZUnq z2*(VAayo@S+M?7;7Lxs=EtIi9>_N(jtWmQYwAjv`{|e;xH@xSL+DC+zo^iiL#AO z7z!jU#Jxj1d^Kx&!eSF%`EE~0j`?;u$k|vub z4;6oJt*cMug+6ET^<53do;LiWBsD5+2$<7ALEPDFNyVMz-|ueVA|VzhYDkw@i6bw* z)a>RW$^k|MTa#BX_>>dTRJNIVjV@{cTp{0KR*SrWrIGJ zsu~Yy;u4o8n&gu#)u*@ajb9FqKkA&+@WppVMlMZe_nN87U-eK3O>w^>iFoNr&zae$ z2+ntR-^;d65AZVqIM3Uu9A5gR^Fh5;12TyehKRSu1IWd3v zRWbF7*VzB;DA#Q=1jVpdY#1%Lnt6yM11Q$knwB?~!yTij)A}MMlN?czmh~PEReaPoZdSW=ncJU2D*p8dWBV*v@bI!|{j8rV z%@X(2?(_Tt!0PkoL{<^ZHY5AoAeZ?>f{&@dkd;OiQvJJzI2bD~k{~}zBydM~K1fA@ zpa;in(2?~)`nRWRa;kXgd3xf!laIM3Fjw^!d-%pI`8T2w!>9Vj%*qUfDGzqfAgThg*jCRAtgi#(?no zmkGodT$VgPi7(53hoc&C?aMCH+GkxB);8j(ScOYGKi-S#Bv@aqk*xaM@N9+{E#ZD7 zKmSVhGdfBz*%v2d+czp0(cLZEe4X2}2aTQ^CT8NV&yCxJ>loPMw)k%DM_xSq)KlMl zpl^qM-et*omnG+1mYjQ8G7JKqe_8SZ5b@m0l3%$jx$Ux?wOm4=?5dKs1c)Znx}XRN z0F!N=)WPB$KV}#tMu^LyhU2Nl+%>1bOEIkX?Q`} zzKUsMekfn$TUS<)vC_nj7a1a6Bz%Nx{L=9zPJiwrj!3N&pZb<{ z?L}kf$Cvvn_0>*Bl&rjtd6Z?2VJ6KKMg~%gfWtJB?sv|}65j2?$=46K6pcd*|LJtT zGzH0`XH_OW)7^1Ift<7N+WDH^PEF4^`FiXl1~c2A+l5#DB4Ip=slyIkrYd0Ry+O5X z-La(HbgC(fuUAut9|tCGb(yO!mmFiKWGa0f<-862yRVQ@qaJSansP_>5?)WMv$xZb~mc1r77^ z+2R?^tz5c8)@^S0od*w_P0NoaZuC znF9^V3o}*3xtR5MV2b#wBsEM5oT#-lW%ibq7!>+kQBo~G!-H~vhu+jIXnbK+=^@#s zApE^Aiw4h%`-9SA(7S*kA3(!1z|O+{>a z5eiQP-$(bFzi{tovU5n+TMMq+kaq7G(G8FZRh*gv<)$pDTZwxF0x5xr63qO60>&#*1M^aFstXE1FCXMsH<8=e!($ zQHNCUR+lLMmS*t=TYLa8h=$?TWfy&^vI=aj^@(Px`i)& zc^cTbE0%l<_p^x>!K*)*{C{vZB7{w)2X6JEbDeiba+ z7);ro%HN#!yg@nn7&jAJ4kbG&)^0V()(j+X&3793p8ZA%%$Oc^--*eG#i`Teo^^`r zu4kwa8vWfL3}GkL5F|PD;I3vKjR$*IQV0W9vuO*f7;16w3szNPrlb@@I33#83Y@sd z3+*2HsimAaM*uMmLMJw(>o(*=8zmjf_wK*J#tE?UbA;8vs0zk_ho& z8y8Fm8eK@vB2avYrHd-fa0nk14oL*yB}c~Q5c^;37O@|G)I)}HfSpE}_RgCc_}(t| zUjn=yCyMy7)M_jy^}Stq*{4LN^x34Y&!fS=BFJfPvu}_KGE@~JjM|iseidJROJ?C0 zKmLB9Xuyy2c?ThTpk$w`ARq98sgq9{r*$+|w-rCV6~$PeNyfl3Fnb#95qRnb?!<@{ z2*ldTiji!rCRbj0$>z*3!>u3N)v~pE*Ar{`c>TI{fGGs4qO) zqrTzn3^Y+rAoe*ycz(bl3@Jm45Q>ug%Y`?bHMqhtbL(3As1*W*R3nW9V(=jlp;#p} z?WveIZQ2u+P_k&g0vb@JI1w2kwqLEr7NPzPO9NaLi|^^Bf!+b{7g)&`#>-qVE zm?O|<&5uC8u{RRv>YqI*IkjMaaej;c(;0E`9QB`XUz7}8rZQ;2%H79Z|M7*Z=gves z@W}c4h9r-2p_@^0?Vq+D(&HR+b>U(6B6K62!e{=~WwU}-nnc%X$i=ZQJl{+|EBLp5 zRx~NL?ce@YZirHy7I^(hI?4Vld&_)~?%sxfl8rmk9GV8!86h33;G+>T9nN|9g^RzW zXzcm^^+~|x(gbeM$jT2_#u1_SEm`o81FdI@pPR|Z0#kKT5zIgir7^9p=qQ$4d0HW2 z1rDjhZ`Nk@Q68^FsZLnd2@^8(F1RC@4ScYcNp^wlny8l+Cd%txx?FD1Oxa$gjU#)R z)C@5T^hP}~q3xO-4gUH+B0%xFXGu(&()ETPXnvMHh5b^Ja791~Kx@`qNxtozgp&eL zGV{HUH2sQc_vV`Z%9pIhz&DIfVg>_zW*OO$z)9T++RI4%+J~5QK~bxZqCgj&dzlB9 z2_acWxW>%LN)-KGrI!T1K9yV7 z_i#D<7&9C9S4l9{YgIEsyVRa&1-3$pAvks`kj!OUC=**p5=vj}^71#2IfR~;2JvAW zDr}ACh}h(*?pU=`!|+z0f5F-dqwk$L4ounnYs<>nB?65CS^7UQ2qQbFuBTQ72OBbx zbVg*^V3B0ghBlKrOUD;gutoz?W?AluOQS8cr%=!`TB~l?}x9yBZ3g0-XR~n2gGlJ)Kw ze5;<0y5R#h3eqYiKG`1x4u1U6K>N_0y;xBR1ffjHe2YQHQy2$%B+Xi>VQ-M>Xx`%yZEXLdEdg(QD8YF!p{ICP9X8c6?)T( z61*%x)2YQeHHI<`hp7)1iBcq(#9F6t%9lxOvMK_Z#OC%*FWz+ZsKy2U!F8jGGUyBe zKruW%Nuz|F09LUuL?^x_*)F`{@8*8C zG0LfBiaQ@FMW6>)*Q5^aszve&2nP<&#_9Px#pXu?0ua4detiqW5OasfU2r(F;$?^< zi-YqnYpcl5t9PK?y=o$j_Y?t@MFb`?+0t3G>hAzIkdD!Sf1%O8f~5DeRhP##UH!yG z{RS+@Ov4_xH9ETKYBuUE_kV1;rnkcEAG=c_{xKu_7_=Cc1EV1;)!Sh=rE8;=}d z&;VzR!C2wb+3m$A?idv`AjzPfC{N=RDrcF4zqs$~j{!dj-~`v(2~J(Y34(|mzJ5h} z;djSEW%9!BwzYT$rS=z#rXZ@kL0){Q3FUGFy?LoiT8S1ZMQWI1bqbHZIlC%bRVWXq z^)!s`4%_|yUya497U=_?D)O~jnQh79vBRU2`7cvA5C(#oyZ_O*NtXrW^v8CInq%Ox zc;YQU$@V$x>cm?(L=Zd!x*O4cc0)+$Pwq-fSOhTdccIZP-!so%&19CnrUx8$QiwM2h)FKvRAYz@;RiPcY)l{{Yma(Q(D7rKy`36`bA&mWT z^oPf5H37*Z;QBo6l^>T%AVtFkrDfy#GgrKqzo{lj|70aIzqMq^6mqyhGb;(_{rR^? zxw(Awhw_(mR1sr(8g>8EV0OcM{m)7wg{*tMrsX%Z~W{40ht>_}pmC+$=15SJK0=oAaH2q{CA*_%)p z!OCa67p>q_jUA;fa?DAwKZafU4S6%ODoDc^VQ`Ci(GUJ>?(k_rtj;qwbtk4%xOJUj zvLOK^exy;8lu?hPaIU|4?ls0yy!JxtSUXhsjnh1O7rwbhuhYa(*B7%pku2VySxOj0 zktH2=w&wc{z|bk4e;#*tG~A0{b5V%M8lF^qlASy)Xw@tSC)8K|`qq#}kE!Zuw7Z5|xXm^Ke5RHe+O?TXfMr zjBZB|KHaTZdAD9N;~JpYJ;QCM@F&N+u0Ve1qYR3Y9&P$8dgg<`i468ow_!7v^Du1d zQ$sYw$Lpbw6^?)AgPXvHaUuKKeb!}@8msmXavmV!Ee!>MZk4G82+edQ+>l z)+&@1XcLcQgo!6Js zwrUFzERsAg%!iiW2<}MKLy`(Ty@s6^ZSP-ya!3wIknDjZ#Uzw_jI-ST`O)Py%-Z`6gQcugm=v3SybW zuSCF%74E^?q@{s~9wmU! z-f8%Q!O=F{Zp2#$xOLsCQ})3yL!xK$3C3?WbfZi=AIjb7e<=LQz36h{u^-U%u%&1x zbbE{(U4r(EdWjtmK#N2-ToQ}|EP}#lHz27)569ab8CZl20LS@h<#Z=Zqj4U$&v3`8 ziT7lT3vhSNgL1V3_}d_v26opu{_a+gnIeVgfBd_fHsh(H-FaM3q$67Q(^wazaQ$vP zAS4q#pPBQc#(G*C;@MzJo<9AuiRsh7`>oZdC*sSl8`b^~02DFE==pV#?q1%l;@_D; z6q^>!W%5yUx^Qnv(rdT)O%ZbK!<~qVT&+|@e(+u?oB))2Bv(`oWvR*o%T?kB&21aP z(_n;9^iB69CMt+q2r8TSkD6C1=k4f_o+YG2pp2KZrzN-f(ETfXmuJ8M@}qwxX8G>T zGV74K1b*c+1mQdk-M`E@`LH!`cx%(E$HgEn^T|*|=7hi0h;`>fSHDXxc`-|e5rEd3 zARsuSWflSni-ksO?hrHb3udj6ALzJi6e@5G6zR#(&C-1wbfPCiD+EOJ;XSMh4TpBy zgaNRpa~?IFc0e(Z%uu1_;y-}M2Mg5dgIN-@u@Ec?VE=!wb1_;7RK_OLIvjzT_0r!5 zqfGXNDK)7?lpU-Ve81wizf+(y-OlY$?2@|^dSQ*x!XRPEgQ&$4U`6B=+WiLvjM;4# z8l;PNq0K9q!e_gH!1HVtD~|Pi#fPSG>QSM;;&X(XSUGWAD?V_4kufcB%}GUJEiZ(m z)CVK56H!AzZ~cNe-O0Vwi9r?vo}U1+ieNBe1jS_<;iTgN#v^E4)BMff!kQzUwo!kf z#r4nR!xy!22f8woWhNeJ6^4DnnpK-o_azFVp%>As#oisb-%31MuoM&D0d@lQaTS-I zf`OD?8HZH^LAV}TMS!ve$qr**RLKW3ro7F zNUP@&HiWxL6;+EOt&Gow|8;SZ;^M76qd_;{?x8rw>4-P!{QL$Y33@1YWA-i1a_FG{ z`)Uvq56VpDpCe!S8gva6mWCk!N}vr?A5-X#Kc!63prFo0QiUO&U>hhvik2XJo|^A! zW`OAwVcUaJaWfxrThwwIPUoMgF;8e1gt`>fnKl9vkR->P)-r<4`3loT!=m#L zufWr=;xaKrv2`3csTtQY&$Ov4aEiEUvFu&O>>hw*Yh9b@q+!5W zM_dO2r)zxp@Y99geU)2TZ+#6Qarb>|CLeAAz@kt669Mf_X?A4ti@F)u-ISnMwHJ=q zev(=-0KANWqoiOs8F<0@A`TfASr_HJA&Onx1KLalGYCO!CcD*rUX$Hkbju>Ng?6UZ zz8L3YfFjphj%r_{2EPTrIh34KYS@f2z{7ZEKt%Su++#32kNy(G^LQsDaO&u`Yj+FQ zX5<8ft~8Jpy}Tu!CDG=?^OwrtMW_atp~sQj_D5bT1~&duVj)B~v#yJVdZeu|2kCpM zmrDZ)VFRG_vEDIzlsCD(i}7ahNsMPX`gGWrPfUk>s=?~8b>sK>bREv944c4zIyf0idY&dY)+@ zA|v#D0Ak*Xcl*;pzH^^C4>TP_?mv|ny_Gh4Z!0PG%5|HZ(04vz2Va{&Vl#|R^(cta z%)ATZkono|5{QV2KvG{s5?5l2_nIziY?0UKl;4n2npqCz@ zd5Af3H*wqba)?R{x_}&}&&#rKk8{Sz6ZBo-p` z0#cVU#uQ_kBj^6%wL>7i-xV(!_x3@A7?|!J+kh|Z7`pv4WZUab1zNYA9je&3(Z9??;?C<+tejf`HGL7 zLvXo%Xn4Uf{LUA1czIEW1rEC*IlFTAura^6`j0~$WXU6dPc8qyhN#5xQ!2n_VVIq* zC@(u8C?S)`ZxXu^qslgF=O$BUsO%NjDq35tMK6V%59LdGoo-;_-B&$B~kkc2^#2{56P zPAe!xd-PL$hTBX^X`N9)L3Rs-?4lq$Ezxb-{?7bC=&BSY(UozrDp*S@9vCT^Ns5D4 z?&T!LAyt`{2cCgeg&N%_#uvpf>^V;uCIU7!VC%_gp5r9W_WDzdxr8WXucr;4o4NP-GuO&;?0PnGUzCzSY(XCz#W1=fkbu>)IDPyNniYNY zU_-`BKQc2?Ym-E0f{BU1_YYa5fgW^IQfEfSdYJRu7gz;Gj0M(dS_vJagrm_rM^DAK zsdB?^Fv_+&80=W2NrQ!nGJjBqz`FOHiNhJ0d4>7lx{)gi@F)Tu1a$s=6c0{{b_WM8 zN+uD<_lDNR+MME6>f?wXsJTmGGq<`ZQM%doppMR1n(T4pMqN~``MKyu&pTAO3cd4i z2)I1w-uW$Vvug0G-IW(C+^E+rgCB9x64)}c0lB_>o;oRfi>-CScf`#t@;c|D!h+!@ zhB|CHhE>Q6o{Y?#xjb`;S)cj2=n}xwbN$VlfL>EpR$kL)HJiE#H-$kV9LZV=;jVF> z`ttk0hMZEW_KNP2Um5&Yt9sWD^Nd7=^-7-9M-&`$K}114_&oHtUMT&#sG((<3=_YYdh4r}2&rB` z=6hei)E@|!C4;uHZlv+BF88V>uAqPtWX)CM?;~E}xZ7T3%~w#5twOZd%Zm^vB53ib zGT9hv_UH0yA(Rd5Isg0bAk8fVcsun&L*fRXM;4-L!d_P|oWd$w&;r1*5%adS;?gxy zxd?$|@n3`p*wPF3oz0mnS1{v)VQ_q)I)GppfUUkZkBA=N>l9532B^<2jWTww*1Ttv z;LUqN7v?>Tk3M-qv9{LTJY_+pwycpuS*+hIMuzJmC{Sn-vAv{rf zXrcQ82z12qO46iKxg4}XvpuyNYoUz`|Bw>BXlf{N9i0f7SLPBd&r-Uwg5RWimsU+}_2_R@R;$AW*<|)(KUA>1{fjYe; zAls{nq4@CzDoc?g%Yg`%7`qH0HlhL(dI8Kl!T|}^X_P6FntNl}F7bDO#zYxRnr3%7 zc=~a53LbI81x)ubM}R~qBfSqZt~5MzH-ZoddXE+6AQ|tpegGX~gN$T!!mZ5|ESbUM zV-F6uI}eL5xXb5w=B?~u-(t+-NP7kKyPK8K0UI-DuNicM36zUW!vc66qUB0sT(*T2 zE#(k5oA<9`J+FP)RpD@EmblTr68Te-|JT`<#wyb4mol~mJi)?o`isV^yy#6_Z_#+r zHdF=}u`zNpH2%ul{*J2z(}-;=R>(nFq8?`E=kXBqLjVKD0Yi<@2Tl1I{m^HEyN_fp zNp*Kzf=@3o55Rlhrng^Ucb|RiAihGJrjpfea!|r>C7V@E8AbMk7{v)+d?G<^Dyd@ST2VSa{nVT-ke8qoG!ysz>0o_KRSUBPLe6AIvy05~y z2&mYqVlfOfu)<}8u6m8Mu$QHWzIUGLHXu%54E)p*0?vRffJ=J{%lQ*iSf2L^tFRoK zD`xRvu`7m0!UT%>e;m0GjrVP_qnK4(KOLY=4eIDJ;U#bd**if_(0sfd*=+NFJZg99 zSk`iF9tq;u@-zX->OgbB0~X+dmFNsk?J_+ueVv-`t0oB|_nPeLS!*Jx9I{&rccDwV z5|Gi$S2&7m)4C`QgVB%z0^-7g8s+}R&~U_;rvkAg`ikllATw>CpvVRVJOR;UMSwuvrpAQM#dt+;7GLJ6V}jo|hMq?1>oF`klzx_U;oc;vuRIPEJUkn^DmLPit# zul$_HEUMIv-(@T2~Bu;V2c{I}othoVSep7t*SEoR!&37;bfEFaxUO|Fe`il}?cvQ?r8%vglH zA%oNp$XX4sqE$Nv=p|!6EqKY)H3oNArViPkQkQ|X0RxJcw|Ca}+wJm%6N`Ao3dLK+ z-Ue{h^>(4FmA6#E7w9`$J3@X#j}9mc!6r$sXYl}Z7CJhFL%VGsZg{!)zeXA(YovBt za`urvvboWX7Dm?0aY8qoMo)}yN>xJ`B{!9vbmVDXD})6DXrv2_qIGm!fRZMw@9ygC zkhO84*26P`1&F=_XDZx$*);AV-$oL0*ZR~}U2C*-t zGyB%JO7!E2l~_58R{{H~n?&_PmtyThk9bit92PBKt?=Fw&1t{ZNjdHtA8oFgM^ zh70I7BNxHQ%5&Qg=Qumntl>E{2$WWWW~|sSCqy6MxbYKXBmip|u3bQldHz^|UJ5E_ z23;up@h^Irh;HSFt%xxB_#;g%jk$xAWMBi~Ct3T(L%^8!fi>Wj)u%k(ggi;eZ9Or` z+yKP4CB+piyyGAj*f{`%7A+o6^UUOg07_kU(b4RFt38@gh$M&O!=`PT<2q4PqKnL1 z4gf<`6$?TV*bv=*>;{`A4(9jQb26R_PO#o4bYK%GUX(pjk7Rl7J@>T;A8${()3Si5Q^f3$3nzcx0t;x7Q#!PFzI4J)vy0$$IDW~n<|Dajb_BWlp3|}@TYrKFPF^A1oSGgWN{ke?8YvP4U!MVe{Qn6Wdy*e zCy~+2hi+svLiBz0hE}|0w*rBvu@|}I#gyLCSb?47yAnbGW9v46(U_6=9B!X4C<|UU zYAY}wd7Hzo8yIZYD1lf+;HhFH&ghrqLuiib;!5emICSjEkP_kj+!+qT8zA5u4DP_GB_?0gl)>l=zz~q zl{M~8ChRDnC6J6sCEG@%4sw2f|5c!AKJ>^-pd%s7K$QUQ8}z4_u>>w=Mc!*9n0NiT z6^P8M#evD%55ZK?WfK|XM5!lIcgekAsi%EI!J7{~c}Q|72B<8dL~8_ev}q%*?{O-B z+--70?QJ+V1HsjfbYaYZ@j;5aEglPz)bl^A(`&3Xp_e#Wgwi|~tP>S}r~#2uF*~3r z|3$@@2BuW4glaXS;a9IOoS<6cmDY@3Gr#lBzkJ~F2WZbPU9d>q{1)S>%dDW!tSJMr zK9oP0#oa(~_QNfRY*G6A(X=FV0nQ9zLqbPQWc=>QY3ks%iGUta=!%8rVElO61A4pX zXE<()niD?4#`OruI)dCLK9b>Wl{|$Mf$ir2|UgqDyGNk9S`S_IG=!?00BuU1?|UBbQ%TVFxY*Ma|SV#a=65gYclwc zb(7iHDf~ONLA@4SgvPcj&|Wrw-*5~mhai&@7?I}vYg77@B)P! z2J#I2BWvWtTs7`&#D@B`P^^1*=+A@9^1-e}7eOYFh^>xc$U5$^dsy0ANIziJ#z?FW zZ)(P*a7p3zFE*kJKksZA1#p6QPlp(WG+i-VK*oO$`cj*Yd3tWkL0+MaEi zu+9(vR2iw_ui|1pd|`($V6j2KctnRY{2lMC>QHONob#Cbu+qS6fzngaehwd>0soZ3 z4*PBEjwQF{!{=;M3S?VY;;C0^%a&-vrp1zFzFZ&l+hva-3USUlrk2`o)LLre#NhEX zJ;9mE#X0t?H71 zb(c?iW5dq_Bi~6M9`!D&-&g@ViJQ|N^c>jDBCp*Q0v+vBB@7-VvPE;qP8%aPnMH0& zc1SBjq4F3`lETgu_Zf;q0waV$pg4fFe99hR%ZwWz$k;lTPi5 z&fvwcAmDIsE(I->PZgO_rZu~8LFz?}ZHugA^qaR9sS&TTj5!9UzmMDVuoGbT(0gn! zNTCDS3LBRpf&^XUV0V$PX_!cOvUR>9kw~vw6SBr$!Nx#m)ck$f^5n+2;m|NZah~HN z8Xx4lVwK2AtcJu@#S2o&n?h7wO{c*TiZuXNL81fw02F}6D{YR&rLKk&N)fD5{wOhK zi|6_t8bcWhYdZXUC90aCjcDYEL>U`qSA6Tbj~<@tm4@BNJ%8t%i78|kuC-1qpTBcF zKhvmgLlje%VKl-quL%c07$7E0J+_W!SrkZ$d+HOEmNJpG2-2VX{2N7wTPLbO zzVg)DyQGtPj>0fku-Xzi7zJyQssYFOmUb=G8Uc*Qd|HD=PR;Xsn_=H*$~dJLqGDQ2 zEp_RjFVG=#sD$@1p5;1%qy>fbBEg-Cx1oH{e1I>~Rmo`VvSy4fgd@En>mie0dCkR^ zJ4p1(atEv+x&|Vgu=DuBzVmB7B5*orzH=(qoL&%d5`OI;-OCMqik(PPH>ga&BPaFk zFOd)p(w^)M(|8-UHU9#3<&e<)+CP$>w7n6O%K5nBSFT&5)WlN*yFC5~ zD7wE7GPD4o8Pd^s0}L!$*)2Bf9Zva=DQr|tldr)%WkcB%_6G|Ds?pgWw`o|aRw-I8iS>+dD9U338iIuf-i?ORm5D*`bu@L!X{6q^f=hI*O3h{pB;< zt*Wx8Gx2pS3)CRF$+knNRrotJA&#VH6e=V#vWG52rXHRwmD%vJRIES_K~CGhBWhP1 zlnaevk@V#WVi}=H=|J+uOkAhc&&*M&HpaE`eZtT%A0#TkwPslQ8ho!Tz#xuGKu~so zHE;uhHK@~pjKEw|ZPn3H?0?^j!QL=K)YXo3hM{lz2llxzd?VjkvV9|95rysKUd zq%(30yFDlv?Svk`5g9Kf9LVp409W|jPei>`Zfb5L#t7}WH&J{3P`!&t5*)j%F^7vd ztapkDCvf4y&k=zKcO(B2w7%BB(9U5|+e>&MdO=UpF^hSnU8xLdg|^lC_qd2{=h(x};$Bq528;elZTJdiI32BAedj1}zGscM59!zVkP~ zS6x$Pd--r*FU1wh_j1&Y%uQKdEg5-;9nfwU{*059kN#l0!ot0IKBzAQ=EhU5Yh1D)VS13`xq#vt>z43}j zRLles0VQOcXu|nW(@pNHq@}l58wHg}EL(%i_cixpF+v$u4*(j<#Z1IQ%aV-1fQmG1 zWPOh~<6N&5Q7n?v5R95=t#qc}@{|UpkWqwHiTZTQQ<(6`r|iLoqDoz3lDRIrV@G03 z0_Tb>K)?sgL;MB?{Sn6c@pg7Ec=Erwe97L}EHBKlI*}E-s_XW^)MFP2p7dPw{g?-p zdEEne7pfWe&(B980BhI?YGPBqvaZ&gG)@<+wdQZHSkIg&zo*B}NhQE&z_KWA&Z=P^ zehJWdxkF{X-PP9Y5SSMWgBJQS_W~NbKm`nx*tg9fUb&laVKeQ?s!{|X4>Q%svSF}{ zm2QI-Xb~m23pojB)FQ5=3*+r;ML1B)TJwcK1olbZvnGCz2D+v8(-JS3Y}5@{xfXpx zw_d4)D_-v==*X}n-IsiUK=}7Cb!U?4LGWc3zEWKoQC}* zK>wH?6&IqPh(7>(2Td8&hQ7dUN&icpkgBzwT5KXo{@FlW_de`r)a`wlEVA-$ks5WW zp^<}QnZS9tvdFhRb*aJ6CB~pRE6IofH$2GTpA)`rW?=>tLNEn_9Tx`Dytj9|4X~&P zZnvh>S^+j&`v-ST22*8*%*MxRHEwvu(O`zm` zk5To0V<#N_5YNoJun<#k9=Y|B1>z$~w|o6`)NA|3*Gj_{0!H{Bcup7LteWYlqZf+6 zWW7M{PyC285iWXtF;gvLX!B%H-o)!Mzr_T~bgITUHfy&a91^a((|TAi=+(k5fc*XR ztTjf`9u2^D;{;q8_G{;5B_f3sKY`0zPzg4#s@}ji+P%_oh9JXYOyU3rC*uUk7@vI) zx)IRJ#Du#&R|>fxzEd|kz5|TS=2`|Mx)bYnsRl<*{py~ZxkJ$oVn|Ba0ZW1DDKws# zFhMcsYwn20X?psJ%Ga0q`Q7Iu zsSD2&iPaQfyy2hUATN<&+q7*%#3M*%H4S9>5(t+b2Be>Q>jvl;_Rfdi@&S9n9l^6G zcU`0Jc>xYSFq^#rI@LQCOJ|(=I(EkS?i1^=TeXImAOqtFw=cf>je!n!WnQLjd$ilZ~GrV0Rp<;`xGrp%2T7^ zi)=7l)Eda0)Yi#k!N9=8Q2=E)>&W(m*1p()wwcayLUbTLz5bKZIEJgDd@=smNKXpA z|F$Ov_dSmfV2Oo|ATB5x+1;U6eGXOfysB^0^LX@e_{Ny6gXYk&VGxM1wDt6PT_>oe z3jwjD>5PY&V9>YSiB@@d8m9K9=Rs3I{uX+Nav#IAg5tvr`3VyfXQ?b!vV@BMo+agAiukKO? z!y>*lUu;W1uK7JtbUPsgt+_@cxJ9o$qeja1gvRy=vo2&o+>%N{f=A#r#cd=d&|@!% z(;u7I6zi$P!w6d6*-1%uPR7s>Reh{vgx?znp)zZN51Y@2Zv2@j#YO?_Chs#?jFSN# z^JG;6*F}N=WZ9^YLfVjed`MG}-Rk=_0OUydil;s;-W$vWZz15#TizI-rx8xr??`kY z4rC@bzGEl!@NwgoVl34zBnHTSmo$AML`_g>kWJ6f_ZAD&A9jZNNB!zyid zz;Uos#FlXJduCg1?>3UlUJLt60E?h7%O!8~SR3iMA?jAYd07?pE7y18O9b9nc$uNvRMkmJE?o7L}_2kQ6GWBukrU zDp>kr#0%D->{0xMJVtB}RtBV+*bCxTyeFp(f-pWn1T(Fdc!*lVc!4I__ucW5+Smo% zK}0xlICqrr=Wc^aWn@8*j^dHb10Ys#jLByfD9wD`# zy4g2)tgnNEn~PWsXMw2{KJR^YHan5Fd6ryG>}eDbP^)e?V6jWJg>0ma>Vbz>u&mB{ z3<6z561yQu9ug#o3k0i8_{dX_gHJ%LM9j!`Oe0b9kfPXgT-yg}2(uM$Smjkw8Lcn~ znUPuN&+-uhVi%Fl?wF-FxkLDjx7ssE0nMGzg1@maQPzN~YzVtJL=zDyf_pZx8wR%L zTJ8aTB*(4x%I5ea)JwB$Jf08bFLbqbf6y5soCToJPH`Baci~<-fBKT3Dq-PbV0(8g z(ZiR_*pPRG1{-S77D~g9A@#3^0|p4k0|w;NcBFo^Q_7Ws8n7Sca@y6)Weg^!4&=W4uUIOxU!j(U`^{uYrRHch+(MMisxRu zXkrTTii=(M;`nVuO#Yi_RG?&duV^epu&VSx1fK04bEAq?uXa~_>r1wVRB!A=Ph&3u zz#GCu)7-ua=JIwx2A(0*?XVy|BS+j}P7*v{;r62rAeeZzAhE&oe$)Zvu&pv|d_@|1 zWWb&6MK4ZeFE8}O5dI=pz70->J_~%-l|R09=0o3Y1hlt+;6c%NU-Sfg;$jwW7a#-9hu;0o5uGzv zkW6n;x>NyWUGg0-)88Tf!6^_*XKuHsr$UzAUj}^b*>02q=EE1SgskDWkT^Z5?GVAP z@WD9v3;&-FpYd<}UZohd&~rbJzx7%?f16z>CCWSTu$@OMTnadj_w3RI<-`AP0k44t zO(u*N$AsQ+ex}|L}7m<8vc+GjsXtCnz z-j`saduD8J=a%o2s;#DkA*oA?6kCJp4}7)4xL^4`>^MQE&)^;=(V@{d2b0sVmEs@h z@mnMl#FDUhB#1=T8%53`oCf~Q>X&9$B~ZhnMz5O*ZYDyN3Y4oI`Ox||Z~)H>>ZU=F zUt0HrXzAp2#!ZLKec=(FfLF4N5Ct1X%UWZqmtsG{Nx-PSVmpl*rXv$Vb^q1^&TiqO z*l+lgdMM$!hK*<&3%Tw7sH&NrU;x6{4s5!~SObNjg?#AkJ;qfn#W_NEW9%5xU~rpZ z)LLL#3L4>`u1Cf$0QTd%-_BLbz;+?o6!!O?M;V)eq3Zfu)l?m0cC~(KtKm2~k{O<7 zn-6{IyYNhdOqa}REjccu(b1J9mI6_jg#kcWjN^IXCApAk#9xn~_=-A;iUFu>8d0QfGeMIB0esF8f6B63FQVC12OC((|a1TKC3VoGCXXyF@)7(`y^!JyIG{PGKM@Xb^ zIUA7nB@in(z)5puOw|^#3D%9ayigl(F^=cRL2nGw z6INtQNWLR(oy{Y5znoK2S9IA#T9ir|v>2IX5Cbak(5rrqTTYK2G4QGr-uSJ8pf6lk zXFe+S+(8ncBF){uK~oHFT1t0>V!*D{{xvRZvP)2fWKY9g#CHw$S>-$*zIulcjzmlK zx>>kFV9UJebtcY)3LqGKy)OrMV)L;7TW-C(i9oA|(hem=bR zE;iK*uYJ9GDKk|a89R|tFt!`feJ4RWK@^c`E)X2usR%4&EJ0i+S z{F|6zdooy0HRBI>#agAp+BFVBRT-HkDTMuRVK@Z6lipycbJq1Bfm!2|CZFrazqCGU zf=kc~6WK^7(jzTl&bmH+U2W~HvzF7}J!_RM=Z2Kc)y^73KKL740u7xZ2_;1YiqBjE z4J~-vF%hWc0dwi(&WA2~J;4fhCt%|NSR(9ZD*7NAn>d$^qK&3y5}(HvuzfQNY?=-a z3Us3!{2Iu4cjyPd+)NXl2X!5;!l=#NT9`wVOlSqHMuKPJ8xpOIgpFG&EWpg@MmfQ~ z70|rrpWR9&_pEOh6;O}1boIve>a{FA=eUAQxv7U(Afz)&3t=f;Wz7cVitxgOXfP>p6ogjSQ z&obZ7azDF%j`@gLr6L5bVWCavHFMO&fU}nQftHCv3y05uq7Y}c<(nCN2@-{t*WqU- z)Or|GSBXwSH7CPTqW4_u1_8}b(4c03B4FP`EI#<=O-a-9LfAHR!dQkEkBXSl5fR-o zBx1%TQ^i@oZR-lXoKE(g57(nZ6q3NSO$0Q34b+-Sb;C1M%y23&lWRU9-3`TCG~$Xy zkyk%Gb7T&TrpnhnR3f$kh(})`h>p00sHKFMQ3KT{sCN}uO1Yk4P}t{iQ9*tYfMypX z*AwsYC63OBRLUmm1x1{v|N85dpUlE9tgA?9<}?DOOv8edx1m*x7cGgFg3r$+J7Jxm zHNW$r_r2AB`6L}f=59(l*i5fY04&p+K)I@w_rPvD5!A$c=2vU5NY!$TnT*uWEOaN7ax;}d^&I?eCSp;G)-(~nE<@d6kqlH; zn5MgdZD;X%B9megG6aH_aEM2T@mS-}A&kOreg6nQdZk_-Zw+>Zn;+CP^SC`(7uRY0 zR9;*Kxh%?I(Yd7ZoNueg!bS~Q)&Na_4RC8N19Qh{J@gX5HDt5`sslKv;;twJ;%0`F z&Cu!_;@w~0`IRwx=I^dN_vnPW`U)N z3yUSLh!O&e?8%9}Yr8iZ`@rti#C-i~+5CyAW!IkTx>+aQc2He4#7EzWR)#l@@FRPo z7R;h<+7ncU=|vqPMh`{BgY4XeozDPJ&jiA1FxLM5T9S=5KT90^fSKOoM@K(T&{7N> zhE@a!+W@7j_#!5T-gUF>Xy!8-P~jlff}xPjBd=6_g`@&xluLhrjGU#j4^o3N#UQa6 z+fJSjzy1<(Cq63fUPKHqkxP0e04M_hCxKB|IG)w~M7eIvsk&(yQP+%24oHWF7_aC$ zh7dKNqK)}Pio!3;t3mNOC+2UF_8xj0{pd=s+ebgHN9p4iRL+dd7TC*{>e3n8%BuVl|VutBq8 z^?Kj}t|99D!qQ~B%)fonYlZTW*IT4#kf#VT6}}BO z0-W_ngI3zRJOMW=H42hY+*1Nj+*`K^lFYz8&H5FY$q}rk2sD71C;EuOKt0_+O)LQ- zQi?^if`LqI1^ReV`r}a5D*zcpcK}37m(KxkKCOnU*s@K~Ovfx4(&q&bqvU3*LB!jx zhxO5U{VeK)GRthbR&crI3%6{As%rkSvQS+emSHm8+W4kW>a&Au7NW2_u~vztTbvr&%S+$n1DGYS46=M)iRUHOP>_O*HvPY6gIzvtq#l*3YC08|Jmy@`^NQkOu~_ z=M`67r}?S%Y{awzJVzr1cST(!wKGFYx>TMnl*UjEGPnx1d|8CB%4SJ_upC4W5U8bHx2eR?-BmJVd>+vZ zYQtFL;c+_}MZ63FG#9r}J8WIEtjlkAn;mVKdKFlKIlyn*NGlgIJRut<2;dzUykS_YN;@Ge^aH#+N@jSKSI-H}~73c9lh6+w>n)zxZS=kXlElMElvCog*^Aj)>uG9$~qtw=s@v zh)kDI6xOB>GXLTT$xsw{ngB@GBlyFz&!ISt4Oi-|AteloY{;W{Uk{;NE2dhV$S_Tb z41g=u-ZHX6E@tk!_zn`_d?X`#3c~t zn)WaEODGvjmsju;X+#m$*#qw+H5@XugRQXWywO+{0~yqcw$JlYs-Wm#r9e~)FUU;J zW9%!-H%3-Bx3uz}s*UT{7UwELE`IYs(K?Km$lkzW<{J$Wm^#xZ{a zIsuaD5GjK{4rGSALdo?kT}90E1}S@8F#1{P=DyxJ*a*7nGvyi^@+Qf^ZozQm93?|} zCt`;p2i%OJs~yQXplumVXxxluTHj-|B3|!bU^McIF&AjyENY-0pNdQSE))BGyxx9H zG>S$pKhlsscCWcc_FZ15ol7i;FOWX^iZn)Gi?~E+PCPs^FPIp3WjrE%p1Vo_m3HTE zVH;?K2D)~KU-2s8k18#MI|84EkuMAI4=WKO`JH{6vSv_BVr7f#Lm<>7As=L+(l-LU4-5caV6eS>|qQP;jRtj zEngQMX6)V2{5$eiNZWR&%#A(50YxJoQ5@F;B9W`Mj~rCrddYmflMy=wI<_YGxmP+_ zvktnrRB19PvS`OgILv6oqg`*u$MG%!mHtPr|Eccao{fed}rZK zS7hFaqptWM_C0^)#XCm^P%sopX1f@T7U)DHjgbKtQ=7%R4KK;#L>LiwzKU3@Zdlpw z+Rk%LXAMC!b19J&^BX6sS)_dr_hkK^n2Cy?%Ea5RVGbm?sedBeumJV*VKm+lZ#x%b zE?r>1AFndbj%Zh6CPG*lTGK5XjW5ZKGL}BBVGgJ+aQ0&nx@5Vc``h!;z513b-O^yY zI#7?U$s)hZgd_w1l@Q+geA2yiZjpF$9PD7t^AN2w8iBx%Ms6B)B>(tx>2&RflF>>^ zM`lzViYZ1lJ2I{`_c?{Vffd2enTt;V*A>udWU_bQ41h~?04NOSOs)utm@D|o_?xZv zEe&9b?Csrh6-o}qjb>A|4nviL&OM9hs9jznKAW_|-MDGtRq@C)ZpR-s1CNpZi2PVI zY^b$&bctGPKM@J7E|mP~D2naG;2c~%TG*k50)L4gE zp@te{Sz>A+(NtEfAwI}@lBVEnW8~)f*y?t7u?-!N2EVy}oOcr34 zuMonxbupf9Lo^EgD=Y84!!pD!gqg(JP=-Jsp;@MN(22SR1cmegiZ({BGA>r*$daWa zqsXk=@IEyEbr;?2ZV0zl#M+85PTod0;7_k8nO-bsVeRCz+gXcrUVk^WKSC6J1dP z`2PNt>_UapG_b=Y`S7-f^m{6LWSG*M3iUFY@mRIsN<&zB;B=R}`h$?4QO*|*dUU*(b7AW zoTF}~Z6zS4k4Qlr9R=dk_i%O_ZBTAkOhX7Zny7*b28anH13_)FcD8|=fvE^T{m4=f zcEzd$5{Y2FoekVU!3#ckc3IgwZi8xc$;8y7%qOjSbQJEQrKRp7w(tN7`g~}8es9qx zt(r>nA@qc)Af&J}_=ad3NV_R70n^-zhXeZDXH}Ma9W^|$3GBPJSsJ2vmn|4D8K_A1 zm+y)bZJ6eRDqTvaTmzwz+L0_>KAc^~rMi|KCZQsm#os7trW08Fzdv%s#dl*`S&NmT zN4tC33mxe_7D$;o5z29QL1uP`r(OvbM!SbsHlAX6YKvR^!d5ft*YgF~8q zfocre>Cg>N6%EbYK^a`x!jY!Z-5Zw+Xz8=@7Sk*kYvab?6(_vRe73)zuRoD2R6ww! zE7ctz!_~?)=0o4!ikM}IieofHT?81Mu<+fXpL__)5Mr6|G%?g)EPLqHtbENceYOa; z>hk)8@ZAz)5G0@r1YZ^iMkAiSr>i@`{lxrX2@T&u*VM*Y^tzEGD4 zzr-zBxipp(1mnK+)#@ff+7AMi8EN$m0K|-W!MAjA*5~(;Keu939yN1CJgiNingbzK z)3K3Fe1$p$Cz!1!C~OpAe_=UilnuD6H^u=*BQnd9=#s;1xL68OhwHI=3T2i6(}$`! zN%$(nUEyXZ%Ivhr46Hn}SUNZ03wvx{%tJdeNv54P3RNLd+G$LqD#`_PSsBfmquW!A zz}{4^p$Ko<UGm77-TQ>v!WUoS2^S`X5<6rT*wz=Hn7{roy%K;tD(@ zElBDn;2vFP%$SDa_GB{;egzr_QL(65%fNaMxdHQFUKztzkWmeBz)cFf&=od z6)%44I@X;XY=_CAYwudpklQ40K2qAZz!{OLV7A`*S?{I>Vyn5m9ql z;x8@609^*Vw_q#uz9BuBs~??mUySQW(!h&I(zxhz?0n{;u8o*uO>4eOGImFXI|T7D zxGIofg_UO$xbG5_NS|#d+7e-%TcwW4eZef*_FBt_A74oFU}`7miwzQBE?2I2FG|RC zR)9j+VRJKtHHyPX)+l+CnkaGDNkF{18ff-oktPjj%UgIrTA3kX1w{OQ^GBG`I!SelxIv8VIUXd(i=E&fj5Ls88l$ zNfpw-kEkw^%2;BO0k*NGR>NG1vv7tb2S-wG;ETL6o@D2Ld)0h+^BWT=54&u&FUCXr zn1GJ4fs*7Txv<2UZ+@c~(M+(x673V-QgN5YTRw?w5LHlgSkxVSSLB#GGM=aN7UR9? z*Z%R$=f17WBMEb#gMSd%MK*kx8R!A3%As}V!{K`XzAIO*uuaHxrFceJu1VDLR*V_W zZ93cxMH!`LQ%p+!#^;%9gOaBoZZa2|7>E>QpbGSSGcl-@12!{pxpKoVT98^w3gS>u zc<4DrtKb|<%gj_bX7Uy3cqfPh9SPPU{7I!f8GImfGu@EGvQKComcJAYv*m#)RkQ}` z6|Qhwi;+1QSL7BYBU#(`jx|9Q4~M->HI*?U%G6*VHIqAyad=c-85f1nTTt=f%o!9U zN5!+sIDiT+9MdvIpqs(&8&=w(k6+Rr<*47b`gmKP?w4VOlTo({4*wBKXOXm~%M+6x>M+z93 zx%7jzZA>lY(YV?&y-|Ymbe+f~0)N;lV@x~GowfyPL_YN9i=VMsMFG;r&9XpA&bOCk zOOn2DKAd)hUY9Wz=Vc~sj7N-o$%k)l=61zVqlt0Fo0TE}sp#2TP7wp%KNbij9Slts zr5ew8TziS$hyWA#&?rIsk`00EaHMsr`&M&Nq5cB6em$giVtUA1{>JJdN8v9S)hS+6 zOD+|~ge6aqGEo?Us1J-K<0&+kYczRpL^@RWA?-z)(ZOA4>V;giLrIZe6``;~693%> zI!JzoWs2l)X;bjNyTMX@<>Y2b*an`yKo z7%rer_ycU|&s>x}xj>5Q%`*AWt!p@~y1!i?JHQOIcAejnjt!VdFAr^n^uXU(BCeRIk3<0?G9LG`k_hp-w{`Lb-=x zB3cL{smRPBjf1&#jK_Aau$zItZWCRyHQV}7AR?vt;Dad5xBiM--SuvuHZMgiG9nB8 zp&Z*P{!)*MxR7Pgj=rAWh*g_a_ZTv`g+rB++6a zjBN5f@(AKFL{h3w`vSc9R!h@vD+~(l4)_1e=#)SSRO{LN4ya-u9soF@E@#mJiC+O9 z#T6vCu4MY)r$>?~tRJ8=v6{CfK=V>Rnt?aZj=%wisH!B5QZZh--3f2l%3i4o5@|Cw z5J6`X5WJtR6$`z{(n@&}EE2aj+|^0vI#~eX#JW2EZf{DljyKre+?y#3p=*y?p3JNB z>G}GRvN7Tb!X`QWe8nSwOY9Qh@)z4C*?cY|K@TTIn_gq!);tbKHF_WJ*d-`y>z?4F z=uXgw0%i%FNAeJr4qOx>;P3=}Gh~{4*uw~&Pva8q8&Wjo=0c3#){P#X72&Q~z!9+5 zC19gdiuzy>M`M7a;?@mZKl({X9p!*tv8ApK`?C7XQefv`9}z$z0-B7FV;a$ua@T8e zE<=kxL)fe0MLN;*Ag45DDaei>?Tly1clfYyU^%vQoHo2%xLBgV@oR&!blD0$<5de6 z8DD!tiqhIZ8fAMOW60Cac3ZE)w$xrU{%(?HLmpO1sb+XuGsM2Mm$3rW6c2&?&RZeM zu=Fv((dRNd5?Rfn2iL;gv!Hlw$vD=lMwfDXIT&upjY-GQh<&-xh5m%X_dq2^;VV+J z7EMge8mzKv*5adRK#!Z17c-%sN)XQg>x-h<4s!Ex#WG3?a4%w+);nIqD{1l-UmxU= z+Q)JFdV#2=JDLq$_C6Rq%xY864C}zaNs9pOvefxb#UEQhtGqr++K5o0K_d~A?~CNn zdl4ZR^9wT^~F{7!hq#z!FfK19@pw zzztXcZsX`j_wI$L3k6=nf{{K)J;vOu2Oq zHp^9l>ZXz3=8J1N1~sssbP8UYF`)STr<*q`gfH#ek!xLcCfhl#Lh?Yu2c5+uY{2;FGm}A zXZ+R9Q?V;;$18aq%R6)Ftvh$_nLqo3xXQg@aPJx5DNmgD(B5@rWi?nZ|5dj4WV6c- z#QL(SolcoE`|rxi+Uv_Ie(=RXC)D|KoGu);PT4Qc#FziR>4~bvPyW*^|GPbjW%n!} z%!kkIl?Rp&=7OI9)cA04s?Yw$6XmIo-FCkV&TxBAdfEQE+QEJ2JTV^!wgUKnU`0dA z>M;)H>ZXk?&Fj}WWy7}$z=K1W2+%EZI#pj=wtrFm;GWY!5C=R{+bMg;+5ntSn}(gL zd#m=NOZ;6xVm2;4&@MHLW1#VN^fYj}OMt^igTpQ^gOTj7T{yT`aJg~ihKAPFPDS-i z0UkeXJhmVn@269<{G9#ug6MF)#FM5^v{Qcf*Mn0S_Y|D!hu=zWK|bLIV*EXGow6r? zJO$zCR9~FiUr!?k`}W#YJLP}DWvb920(LkNcIebx@?tA%ng;h!!#!ZEJGqV_0Oy3% zQOn{iIDwQ+o0?Y+ZF*~fi{o-I3%qCgr&IN|hW(4`$RUhJQ@rv4N*@DCFA{BZmD<1u zRyAL_ZvDn4r@X&1!0$=JZ>M_S7l^;K16C7@=~Zq=(GYb02OkOm|BM0Nsh;s}0$ObV zX@L-386fvjv5BK)-WIum*1nz-L$CZ)fY-;2*G^R`yMK|W#DwXp=Cxqa^U?uCj~Swe z!)mAcx`!VFh+3nE)A4lQi;h;BJpF33ts@3b|uUGLdLY&fW8*x{yULVM)Ng#KNus*Wy zN@cRlV=oa>d4woEpJBtKe2gL zi&OT&AK+O4uj9XV(z;*{T6ADqyHwF0O5JHJ8L5Q$G`wIUJ@E4F#v zhE1&-8w0n&r0B4g;;h?XP}6dDmHqy`GY&PaQNN`8bwHcEJLO*)4)A%x_-x^Ov_GBd zKeaFlx9??l{0N<-r}f|s3%La zPifl4`x9AUqTelvs^!v8I?*UU-ckA~6Z)NU2RZcE#neotaH_xf8D=qBVUDs=)gS$n|bP#T((BzYzCYywL#?PxJuLUPSB0~*aKP=9MH*qKy^;p-WLZvXVN^n<57(L z-l_V*_xJk@whb-y!O5Hyq%-Pd;KT@M=H$?>lxAFi(?-7aB2akSALytCrXbr0gIy?Y;j0F88hh3eu%O|6RU2U?@+H?;;F=tRhA z1LkIml*{Nmw-XdmLBnW6bsE=7vI6wxbxAAnwL7y8|pvnB!;z9weNxb z^^1Wi2c+$MpwgcRl}7D#G+ecvZ9%f`&5i5`#4F*+Tqd>QXOr|PGR z_rvA^n!0c?w?Vq#F*mw8z5SmKyJ5`7T$Wi?ya;=`7h_31bc95 z&iRl1^-D*uS?@0eN=75RzZ5kHA3h0|J0231e(zL$sjGB*zMTcc#@^4k|161y?~znz z#B{>i)3 zKb`8?TlUv26fTQ9+Jc^E;FST|^BV7mWjGC8T3M$q}e=ZI=dDdmmA_8%$SN&ms{iWo!?XliO z7B=rK@rY09Yo9kXgZbf8wJ6q7qEmJG=|=bEO_o8=xJjie3-$4SO0|Nvyzg+z>od;* zL>vz!C)@W{*VN$uUZo;Z?ePsig)V>fieCi>H<&*4*Zs^@*xxD(B-W`V?>RL-Ij z`%-55@ES9%`Y=8J)S7K=STS#C_RQxnQcjeGI8~c|M&&@-gj+}^vx#IM`XmNjcP6o3 zRl4rfp~+PD7j3fIN`JCiN4&iow=@R4+p?h4!QL3@fWE)#&VZE+I@SHxsW)Hw zgaMVm({FFAT^aDR+fPbYh}mOeOClTbu67pp|HApXXry+2Zoz^D_$7k9=K4M`8BF~<r=Oi!#m6DhjEPjd(8ie2!% zN#r~eUGUR=&Z*u!=;v_pWUP&i>Vt+s$3d8D6)FAW2Hlb!k!@`q5nx?9CFyOAk^bB~ z2$+$+DS&I^;i^-8#zMbZiCT-%i4d318+z?8o&&(Jz;deI@m}@uc{qaX5MTNPc~M{{ zx>D9_h8f=;>kj1VNhnw2+uwQbvUoC=rIOeY&m^`aW7!mJ$nrh^@Ejs-OXB1G#O(;p z`|EsK3A+gg=Jtt9T(L(cAw>VlB(lNDoQxc&zc-f5BvQ$tmj#7tlW-?q)dm!p`RSlH zmCgpOUymy#IBdVm`;A3WJk+$xAJgfC#0c_GkAqETCBt|>B@eZhH}|Pt-x(wdtFLT4 zz#Xsey+mPiK&f=l-0`?FwDC?_x^Ma@D3#t3OLs)v5~apSCtN2%hLBWpxkxN9${?Al zy{o9kq%o42=TuaD{vX|-t@)Ws%Z zft%nYauZ0Z+kvilcW+R3bRv&M%Z?bdDgT?#2GB(&#=q^@k2||O z(vQUH8|?5RYSGAzFdH6z)w38{PW74pt5JQ+;37ujxBVPUdd{=Cm4MWg8%AQcXDkA{ zyD4ypiwF0-JW>a>u9@Y5>^&G1DxE}bJZp+bp^~tbL^2akXCtO61R;lvV&ikE(osr2 z4IreLwIq*u0aG}^U;US<@?IeD-M_u^B;vbH)h8;Hk0z3krP+8o)}FSE@ViSxiBcg>~4{#zw)DN_PlKMWu!>K&delb`Pb< z`^fgd{<86Y6G zN+fo|B56a}okDA$px^6>P=>YNt4RFr)E3;z93-Y4R|QxS(_Bupj+`h7MqiSBkPNg4 zx0_2cm5d~k=ylT*Pois9#3nk7k+u7$eY5GrQ+jsk z`1W`jMa*NKU2kx9C+y7ZS=zHRn$mjmrxZ%hW7&9wfg$9~M98mP=-b2^8m!3N1tFw-LdjW+z)f+{yHXgc^I5Zb`J#2KqnQ8 zO*2pr>K*CWj!1i7It|y8Kg9Rk&??h%ja=X$o>ZJGWf9^a_WHIQ!DA-E`Po&ZCcE)b zQdIPdpka^Oum_O=pMKins%V*bcc))FMc+qseQcPYLj%;Aru}2tS3YnOiA<;JPwhT^ z^FRji*5KCa6KSDZP9wKgFXF9Fs$67Hgw;Jp=6_=Z-L$4k?!Vn?qB9%#Nlqjdil4-j zZ<$nI8r`ZZs&6`pc$cM=sru6dpYbhE{|^M)GMPr+kxsxs64y%jTknO^i) z40`-es-i3Rg&_Ufui&)03QjiGX7n4AEXd14f`%1HrDVpGO0R4@6LeHNIU3_gMADOD z*+h3o+^A3ne{T)2mnl5VG&9(n=!s_n-RmUMy|QWa0YoGnQFL7NuBCa6k?eEo9zq{? zb)mr)Itq>Ga~T@FLCj=Q6{3k+7p1ahpf?^A5}sH#`nHDswLZy)6QO&nyuWe^T1yi} z)5(5L?;BiHWIt?j?T5bZL=XB62X{3b55my98jw9XIJoERva)yFhDKgXC)CWV;*!O- znO8$^?@)9Ec6XvbAG)h^#qwNZD%l?I&E}eu9r6BMm}k#glR5X&`NDd!|^UvOt=h2l|p7 z_Er?goYLMA%v|cnzdjhDkN)gAER>w;b8a`yfBKRM79XI3#5Uj%OZ_=z?MN>Y0HR-# z86q8tOgp;73LFGk%HPmAg^V&IiY$AkT^C9BwXy0A1-5e=BRi&cg0NI!_aUb- zh!Wx$_Lkv6qi~B0_fXR{gL}__ z`mGM#9kJko7m=3F{2d~P!`;JuZd^qBPV)|@3whiDqd5r}&7O1Yp&V+u){TY?#FE>L z5;6d$b7RjG(z_0arIY=+Q#~}7`kpQ7AdDln<(||uL?cJ&w)dVFOrbMys=oPc#*T|% zk<50{_z}E|Mj9gn&&m5EOMrqpUjq<;WA@A`gaeaBZ%);wpZVzQS~gh*srmXA4TT>G z;CRf%{7%)9J#1IxcduSLG56~0Dy(~T@se@xN>JbJU-93>1|N!>H&t1O|&3kK|GwK$tK;B<6p0Die zY+?Fot|dG4j&BTf$8)Qkr|#;E$FhCtc*d!?EWOhyuUquQn*V!n%lpbs>+CF>fwfL+ z@99a@E;_Vk`Cxw9Rj0@!qJ-hmXWvif)ZaY_s0{9V-WSStI10fo(^q~hgiE{5zi2(){$VFTwK44D2MM5%YN~GSyFIZlX@&Q z+aAKPpec}?NgdBbI1W!^mGjpZ#`}`e#yI1Y?K&+u5D{9Fc_2@h4xO48HWe1R2U^bq zHNpfZs={PNU!psUTJE7+0unp^oZqQ_YNWs#UnRN4W1Y~|q`X)WkasnOtW&)sw@CiR-?tN$ak{f)7 zCq_XdrC_o8=#;!<9?p9qfPxE+O6osQQ}r)Kqk7iz^92>%C;UIm*RK8;<=Kb`XU z?*cTKG&FE(esxiyw%)2+^%8)MWx7P&>K)3|#oH4z+KWT4<*)nrR8+Nq`A78HIH%UV z6sp)_tBM(nZBD-Po|)ToDNS+!;sSa@D;EYhJ83xkOtC1Z`m0+CI8W8$>W!y{$WP6h zop1VjbE}XniQ=UXvgc@^R!^>4eYk^lrY{&Q)UqC*_I&*U(c+pjJf>FMY;8glLWt(> z+3mUb6;Ao$HwB0Gj8UOe^Qli4YOPA__nh}$(k7Qp_QgZ=bx zUEqhk1WsGKm`v5#63^xg_?_}UEf1jnj6wZy?C5Aecc#Do=7MxpRQ4s|RZy zytyVgz?1F(?SVTr-)tx>vgT_2f~7?%Lk;OfwhLFXB-)*dP5XjlJZX;6nf{Z93yUPZ z0j4I7&6t|rd4Ud_wmX0ASQ+c?i!mk7skrXq-~>mVpfmlUwqi(1CZiAY2}v8KcFMjL zq|F`P=jqgJM7o;I03lk6URw-I*9}rp`St)IM3{cyg4`&pBKJ~qYJ^FK z?wOfQr{p4K>P}3k*?`QNUfgwh`HBF(6NYaoybt%cGyRJLJO`5uw3zOtSEt&X%1-7x zBd?#Q;gsD!=eg)m0?>}=aC*AmJ2P$_L;}__>#$m^au4t)?t9dbgD#qAhm+&_TLKbz z#!29Cq*400Q}ggW1ss;?n}pJvrzTi?bFVGzNhEfa-}cn)*0k{FYWfOt-ujIT#gDRB z9bRLggUOM0DxyCL5aPHYgfsoSXBO%fdUYa;RUsICKqWTgyYCB5Y0^*0nSS1r1@x%i zr)jNAD9JWuP=J+(EL)w(WK-z@v?qHfL>lhIMcoKokhqm8H23DIAljVM9{Ta2rnprz@jb)GOUROsKL$PJow_j+dok#QyEnqz)8tVDOp4=*3~F@Ne3VXcdbt zd0;E!nZ%Z445*tKdeMu6!#d`}a;kS&_u&i`^V$No+@A1{%3J6)!$Bz~*Dd=EDJgqMtj{?^w+Px(nqWODQK!REUyt zZ6X=ZHL>nBxy31;_4%nF908XJ*>TQ{2j@VDF7*jf7Z@Bni=HT_u+KTw-)J<41Z4$> zq{@mtCKAJnSQ?BYlZlIxnTU16U-9ko;H(Cn=`EKQ>ZI7gz)o}z3%lKbT{I;rO7R{l ze#35zzWhJfT575!wK&r|_ZGuJ)B+0!;?SCecz(Ssg|hGbatcAfQq$pnIyG0%ETDOe zngpaW$+xu-A~S4AZ|MV;&`l04s)a3IrwV=?4k}Ogb7%UG{;5#UI};gdFhLv(Q(|2+ z?oO99GNy52*BgXZk<<+#HxNOjA-b>d0CKgbrf;PI+J87$095aB80X zw_>=Kwz+Ys!B?QFw+r3-vamf=D1LU=b4R7MEPEu`8C`BC8*c z_v3Py#OF@nx+jX{NBf*p^VshTa!VwAz=Ve=d`1oCfi@&Na%j?shCAA%vHb17oq}*U zTDXn(yfgjOc?EQnwTg880!heiky~rp6P*JSL0|t7mJ)MF>V`Fv-f?zyqdZxa2YJT{kVo*!gS4*l#^5mnq(FE;8W65}`FXO3K zQQ=FL@<@f-6V!hYD2bz3VCfXv`7?z@$9o(U2P6xN7fP^% z_nx8RQtmyg?Cfk{?Br@Ty*2Id^!hWW;_4@-V%Wqv?X=jTrp34hd?vcxmcU|##*uut zz&REBaRWU9FH@{(m~&eDCjf>zlL+>wvWhP+FMso{FPwWB)4@WIR_v~Ou>1%2U0F7* z>=jRJ`r;4Q-C6d6&u+ENkK6id7d;V`PftDnM@65G*(mvmCVAG^K3PV1rF?qkm3J47 zuzcpM`S14k6wVCPE*!hl@DodV?_T)oqG!ADY~4e@dPTqg(`*)>E?V>3%>(YImF+!g ze0bhNd)Jkf)nL#3hYz#aWlvNse)6AY`9JJQEPJ9n^|9OTcRvi{^<__%Rs5>4;vxR` F{{gS%t#1GT literal 0 HcmV?d00001 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 D48 +D<12035AB4FC1207B3A2EA7FF80D187D9713>III<1318A21338137813F813B8EA01381202A212041208121812101220124012C0 +B5FCEA0038A6EA03FF10187F9713>I +II<1240EA7FFF13 +FEA2EA4004EA80081310A2EA00201340A21380120113005AA25A1206A2120EA512041019 +7E9813>I +II<39FFE1FFC039 +0E001C00AB380FFFFC380E001CAC39FFE1FFC01A1A7F991D>72 D<39FFE01FC0390E000F +00140C14085C5C5C495A0102C7FC5B130C131C132E1347EB8380EA0F03380E01C06D7EA2 +147080A280141E141F39FFE07FC01A1A7F991E>75 D82 D<39FF801FE0391E00070014066C13046C130CEB800800035BEA01C06D +5A00001360EB7040EB78801338011DC7FC131F130EAAEBFFC01B1A7F991D>89 +D97 D99 D<133F1307A9EA03E7EA0C17EA180F487E127012E0A6126012706C +5AEA1C373807C7E0131A7F9915>II103 D<12FC121CA9137CEA1D87381E0380A2121CAB38FF9FF014 +1A809915>I<1218123CA212181200A612FC121CAE12FF081A80990A>I<12FC121CA9EB1F +C0EB0F00130C5B13205B13E0121DEA1E70EA1C7813387F131E7F148038FF9FE0131A8099 +14>107 D<12FC121CB3A6EAFF80091A80990A>I110 DII114 DI<1208A41218A2 +1238EAFFC0EA3800A81320A41218EA1C40EA07800B177F960F>I<38FC1F80EA1C03AB13 +07120CEA0E0B3803F3F01410808F15>I<38FF0F80383C0700EA1C061304A26C5AA26C5A +A3EA03A0A2EA01C0A36C5A11107F8F14>I<39FE7F1F8039381C0700003C1306381C0C04 +130E380E16081317A238072310149013A33803C1A014E0380180C0A319107F8F1C>I<38 +FE3F80383C1E00EA1C086C5AEA0F306C5A6C5A12017F1203EA0270487E1208EA181CEA38 +1E38FC3FC012107F8F14>I<38FF0F80383C0700EA1C061304A26C5AA26C5AA3EA03A0A2 +EA01C0A36C5AA248C7FCA212E112E212E4127811177F8F14>I E +/Fd 1 59 df<126012F0A2126004047D830B>58 D E /Fe 68 127 +df<126012F0AD12601200A4126012F0A212600417789614>33 D<13801201A2EA07E0EA +1FF0EA39BCEA619CEAC18EA3EAE184EA7180127FEA1FE0EA0FF0EA01F8139C138EEA4186 +12E1A3EA718CEA39B8EA1FF0EA0FC0EA0180A212000F1D7E9914>36 +D40 D<128012C01260123012381218121C120EA31207A9120EA3121C121812 +381230126012C01280081D7C9914>I<127012F812FCA2127C120C1218123012E012C006 +0A798414>44 DI<127012F8A312700505798414>I48 D<1203A25A5A123F12F712471207AEEA7FF0A20C177C9614>III<137813F8EA01B8A2EA0338A21206120E120C121C12381230127012E0B51280A2 +38003800A548B4FCA211177F9614>I<127012F8A312701200A6127012F8A31270051079 +8F14>58 D<130E133E137C13F0EA03E0EA07C0EA1F00123E12F85A7E123E7EEA07C0EA03 +E0EA00F0137C133E130E0F137E9414>60 D<124012E012F8127C121EEA0F80EA07C0EA01 +F0EA00F8133E131E133E13F8EA01F0EA07C0EA0F80EA1E00127C5A12E012400F157E9514 +>62 DI65 DI< +3801F180EA07FFEA0E1FEA1C071238EA7003A348C7FCA738700380A338380700121CEA0E +0EEA07FCEA01F011177F9614>IIIII<38FE3F80A238380E00A8EA3FFEA2EA380EA938FE3F80A211177F9614>II75 +DI<38FC1F80A2007C1300EA7637A4EA7777 +A2EA7367A313E7EA71C7A2EA7007A638F80F80A211177F9614>I<38FE3F80A2383E0E00 +123BA4138E1239A213CEA31238A213EE136EA4133E12FEA211177F9614>III82 DI<387FFF80B5FCEA +E1C3A43801C000AFEA0FF8A211177F9614>I<38FE0FE0A238380380B0381C0700A2EA0E +0EEA07FCEA01F01317809614>I<38FC1F80A238380E00A3EA3C1EEA1C1CA46C5AA4EA06 +30EA0770A3EA0360A213E0A26C5A11177F9614>I<38FC1F80A238700700A7EA31C6EA33 +E6EA3BEE136EA5EA1B6CA2EA1A2CEA1E3CA311177F9614>I<38FC1F80A238380E00EA3C +1EEA1C1CEA1E3CEA0E38A26C5AA2EA036013E0A26C5AA8EA07F0A211177F9614>89 +DII<12 +04121FEA7FC0EAF1E012E00B057C9614>94 D97 +D<12FCA2121CA513F8EA1DFEEA1F07EA1E03001C1380EB01C0A6EB0380001E1300EA1F0E +EA1DFCEA0CF81217809614>II<137EA2130EA5EA07CEEA0FFEEA1C3EEA +301EEA700E12E0A61270EA301EEA383E381FEFC0EA07CF12177F9614>II<13FCEA01FEEA038EEA07041300A3EA7FFE12FFEA0700ACEAFFF8A20F17 +7F9614>II<12FCA2121CA51378EA1DFEEA1F86EA1E07121CAA38FF8FE0A21317809614>I<1206 +120FA21206C7FCA4B4FCA21207ACEAFFF8A20D187C9714>I<136013F0A213601300A4EA +1FF0A2EA0070B2EA40E0EAE0C0EA7F80EA3F000C207E9714>I<12FCA2121CA5EBFF80A2 +EB1C005B5B5BEA1DC0EA1FE0A2EA1E70EA1C38133C131C7F38FF1F80A21117809614>I< +EAFF80A21203B3EAFFFEA20F177E9614>III< +EA07C0EA1FF0EA3C78EA701CA2EAE00EA6EA701CEA783CEA3C78EA1FF0EA07C00F107E8F +14>IIIII< +1206120EA4EA7FFC12FFEA0E00A8130EA3131CEA07F8EA01F00F157F9414>II<38FE3F80A2383C1E00EA1C1CA36C5AA3 +EA0630EA0770A36C5AA311107F8F14>I<38FE3F80A238700700EA380EA3EA39CEA3EA1B +6C121AA3EA1E7CA2EA0E3811107F8F14>II<38FE3F80A2381C0E005BA2 +120E5BA212071330A2EA0370A25B1201A25BA3485A12730077C7FC127E123C11187F8F14 +>II126 +D E /Ff 51 122 df<903907FC0FE090393FFF3FF89039FC03FC783A03F007F0FC3807E0 +0F15E0D80FC0147802071300A7B71280A23A0FC007E000B3A239FFFC7FFFA226267FA524 +>11 DI<123C127E12FFA4127E123C08 +087C8711>46 D<131C133C13FC12FFA21200B3AA387FFFFCA216237CA21F>49 +D<48B4FC000713C0381E07F0383803F8386001FC387C00FE12FE14FF147FA2127C003813 +FFC7FC14FEA2EB01FC14F8EB03F0EB07E01480EB0F00131E5B1370EBE003EA01C0380380 +07380700061206380FFFFE5A5A4813FCB5FCA218237DA21F>I<48B4FC000713E0381E03 +F0383801F8003C13FC387E00FEA3123EEA1C01000013FCA2EB03F8EB07F0EB0FC03801FF +00A2380007E0EB01F014F8EB00FC14FE14FFA21210127C12FEA214FEA2387C01FC007013 +F8383E07F0380FFFC00001130018237DA21F>I<14381478A214F8130113031307130613 +0C131C13381330136013E0EA01C01380EA03005A120E5A12185A12705AB612C0A2390001 +F800A790387FFFC0A21A237EA21F>I<0018130C001F137CEBFFF814F014E014C01480EB +FC000018C7FCA513FF001B13E0381F03F0381C00F8000813FCC7127EA3147FA2127812FC +A3147E5A006013FC1270383801F8381E07E03807FFC03801FE0018237DA21F>II<1230123C003FB512C0A215804814005C5C3860 +0018A200E05B485B5CC6485AA249C7FC1306130EA25BA2133CA25BA213F8A41201A66C5A +13601A257DA41F>II<141CA2143EA3147FA24A7EA39038019FC0A29038031FE0140F01077FEB0607 +A2010C7F1403011C7FEB1801A2496C7EA2017FB5FCA29039E0007F8049133FA248488015 +1F00038190C7120FA2486E7ED8FFF090B51280A229257EA42E>65 +DI<9138FF8008010FEBF01890393FC03C +789039FE0006F8D801F81303484813014848130048481478121F48481438A2007F151890 +C8FCA2481500A97E16187F123FA26C6C1430120F6C6C14606C6C14C06C6CEB0180D800FE +EB070090383FC01E90380FFFF8010013C025257DA42C>IIII72 +DI75 DIII82 D<01FF1380000713E3380F80F7381E001F48130F481307140312F81401A2 +7E91C7FCB4FCEA7FE013FE383FFFE014F86C13FE00077F6C1480C67E010313C0EB003FEC +0FE01407A200C01303A315C07E6C13076C14806CEB0F0038FFC03E38E3FFF838803FE01B +257DA422>I<007FB612F8A2397E00FE010078EC00780070153800601518A200E0151C16 +0C5AA4C71400B3A390B512FEA226247EA32B>I87 D89 +D97 +DIII<137F3803FFC03807C1F0380F80F8EA1F0048137C127E147E +12FEA2B512FEA248C7FCA3127EA214067E6C130C380F80183807E0703803FFE038007F80 +17187E971C>II<3901FF07C00007EBDFE0380F83F1EA1F01393E00F800 +007E7FA6003E5B6C485A380F83E0EBFFC0001190C7FC0030C8FCA21238123C383FFFE06C +13FC806C7F481480383C003F48EB0FC000F81307A4007CEB0F806CEB1F00381F807E3807 +FFF8C613C01B247E971F>II<120FEA1F80EA3FC0A4EA1F80EA0F00 +C7FCA7EA7FC0A2120FB3A2EAFFF8A20D277EA611>I<131E133FEB7F80A4EB3F00131E90 +C7FCA73801FF80A2EA001FB3A8127800FC13005B133EEA787CEA3FF8EA0FE0113283A613 +>III<26FF80FE137F903A83FF81FFC03B0F8E0FC7 +07E0019813CC903A9007E803F001A013F0A201C013E0AF3BFFFC7FFE3FFFA230187E9733 +>I<38FF80FE903883FF80390F8E0FC0139890389007E013A0A213C0AF39FFFC7FFEA21F +187E9722>II<38FFC1FC +EBCFFF390FFC1FC09038F007E001C013F0140315F8140115FCA8EC03F8A215F0EBE00790 +38F00FE09038DC1F809038CFFF00EBC3F801C0C7FCA9EAFFFCA21E237F9722>I<38FF83 +E0EB8FF8380F8C7CEB90FC13B013A01478EBE0005BAEEAFFFEA216187F9719>114 +D<3807F8C0EA1FFFEA3C07EA7001EAF000A300FC1300B47EEA7FFC7F383FFF80000F13C0 +120338001FE01303EAC001A212E014C0EAF00338FC078038EFFF00EAC3FC13187E9718> +I<13C0A41201A312031207120F121FB512C0A2380FC000AC1460A63807E0C013E13801FF +8038007E0013237FA218>I<39FFC07FE0A2000F1307B0140FA200071317EBE0673903FF +C7FE38007F071F187E9722>I<39FFF80FF8A2390FC001C015803907E00300A26D5A0003 +1306EBF80E0001130C13FC00005B13FEEB7E30A26D5AA214E06D5AA26D5AA26DC7FCA21D +187F9720>I<39FFF83FF0A2390FC00F003807E00E6C6C5A6D5A6C6C5A00001360EB7EC0 +6D5AA2131F6D7E497E80EB33F81361EBE0FC3801C07E3803807F3907003F8048131F39FF +C07FF8A21D187F9720>120 D<39FFF80FF8A2390FC001C015803907E00300A26D5A0003 +1306EBF80E0001130C13FC00005B13FEEB7E30A26D5AA214E06D5AA26D5AA26DC7FCA213 +06A25B1230EA781CEAFC185B1370EA68E0EA7FC0001FC8FC1D237F9720>I +E /Fg 39 122 df12 +D<903803F03F90391E09E0809039380F80C09039701F01E0EBE03E021E13C02601C01CC7 +FCA548485A007FB612803903803803A43A0700700700A6000EEBE00EA64848485A001EEB +E01E3AFF8FF8FFC023207E9F26>14 D35 +D45 D<13181338EA01F8EA0E701200A513E0A6EA01C0A6EA0380 +A6EA07001380EAFFFC0E1E7B9D17>49 DI<120E121FA2121E120C1200 +AA1230127812F81278127008147C930D>58 D<001FB512FE4814FFC9FCA8B612FC6C14F8 +200C7D9023>61 D<3807FF803800F8001378A25BA6485AA6485AA6485AA648C7FC7FEAFF +F0111F7E9E10>73 D<3A07FF803FE03A00F8001F000178130C5D4913205D5D4AC7FC1402 +140848485A5C146014F013E1EBE4F83803C878EBD07CEBE03CEBC03E141E141F48487E81 +140781140381380F00016D487E39FFF00FFE231F7E9E23>75 D79 D<0007B5FC3900F803C090387800F015785B157C +A41578484813F815F0EC01E0EC03C0EC0F00EBFFFCD803C0C7FCA6485AA648C8FC7FEAFF +F81E1F7E9E1F>I83 +D<3A03FFC0FFC03A007F003E00013C1318013E1310011E5B011F5B6D5B0281C7FCEB0783 +14C2EB03C414E8EB01F0A2130080A2EB017CEB023CEB043EEB0C1EEB081F497E13200140 +7FEB8007000180EB0003000780391F8007F039FFC01FFE221F7F9E22>88 +D97 D<1207123F120F7EA2120EA65A137CEA1D +83381E0180001C13C0EB00E05A14F0A5387001E0A214C013031480EB0700EAE80EEACC38 +EA83E014207B9F19>I<13FEEA0383380E0780121C0038130090C7FC12785AA45AA37E5B +EA70026C5AEA1C18EA07E011147D9314>I<1438EB01F8EB00781438A21470A614E013FC +EA0382EA0601121CEA3C00383801C0127812F0A438E00380A412F0EA700738380F00381C +37803807C7E015207D9F19>I<13F8EA070EEA0E07121C383803801278127012F0A2B5FC +00F0C7FC5AA46C5AEA7002EA3004EA1C18EA07E011147D9314>II<140EEB3E11EBE1A33801C1C2380381E0EA07801301120FA3380703C01480EB87 +00EA04FC48C7FCA21218121CEA0FFF14C014E0381800F04813305A5AA3006013606C13C0 +381C0700EA07FC181F809417>I<13E0120712011200A2485AA6485AEB8F80EB90E013A0 +EBC0601380000713E01300A5380E01C0A6381C0380001E13C038FF8FF014207E9F19>I< +EA01C0EA03E0A213C0EA0180C7FCA6EA0380121F12071203A2EA0700A6120EA65A121EEA +FF800B1F7F9E0C>II<13E0120712011200A2485A +A6485AEB81FCEB80F014C0EB81801400EA07045B13181338137C131C120E7FA2130F7F14 +80EA1C03381E07C038FF8FF016207E9F18>I<13E0120712011200A2EA01C0A6EA0380A6 +EA0700A6120EA65A121EEAFF800B207F9F0C>I<390387C07C391F9861863907A0720739 +03C03403EB80380007EB7807EB0070A5000EEBE00EA64848485A001EEBE01E3AFFCFFCFF +C022147E9326>I<38038F80381F90E0EA07A03803C0601380000713E01300A5380E01C0 +A6381C0380001E13C038FF8FF014147E9319>I<13FCEA0387380E0180381C00C04813E0 +A24813F012F0A438E001E0A214C0130300F0138038700700EA380E6C5AEA07E014147D93 +17>IIIII<1380EA0100A35A5A5A121EEAFFF8EA0E00A45AA65A1310 +A41320A2EA1840EA0F800D1C7C9B12>I<381C0380EAFC1FEA3C07EA1C03A238380700A6 +EA700EA4131EA25BEA305E381F9F8011147B9319>I<38FF83F8381E00E0001C13C01480 +121E380E01005B13025B12075BA25BEA039013A013E05B5B120190C7FC15147C9318>I< +39FF9FE1FC393C078070391C030060148015401580EA0E0790380D81001309EB19C21311 +380F21C4EA0720EB40C814E8EB80F0A26C485A1460000213401E147C9321>I<381FF0FF +3803C0780001137014403800E0C0EBE180EB73001376133CA2131C132E134E1387EA0107 +380203801204380C01C0383C03E038FE07FC18147F9318>I<390FF83F803901E00E00EB +C00C140813E000005B143014205C13705CA20171C7FC1339133A133E133C133813181310 +A25BA25BEA70C0EAF08000F1C8FC12E61278191D809318>I E /Fh +44 122 df12 D45 D49 DII<157015F0140114031407 +140FA2141F143F147714F714E7EB01C7EB0387EB0707130F130E131C1338137013F013E0 +EA01C0EA0380EA07005A120E5A5A5A5AB712E0A3C7380FF000A9010FB512E0A3232E7EAD +28>I<000C1430390FC007F090B512E015C0158015005C14F85C1480000EC8FCA8EB1FF0 +EBFFFE390FE03F809038000FC0000EEB07E0000C14F0C713F8140315FCA215FEA2121812 +3E127F5AA215FCA25A0078EB07F815F06CEB0FE06CEB1FC0390FC07F806CB51200000113 +FC38003FE01F2E7CAD28>I<14FF010713E0011F7F90387F80F89038FE003CD801F8137C +484813FE00071301EA0FE0A2EA1FC0003F6D5A157892C7FC485AA338FF83FC90388FFF80 +90389C0FC09038B003F06E7E01E07F01C07F140081A2491480A4127FA4003F15007F121F +5D000F495AEA07E06C6C485A3901FC0FE06CB55A013F90C7FCEB0FFC212E7DAD28>I<12 +38123E003FB612C0A316804815005D5D5D0078C7123800705C5D00F0495A48495A4AC7FC +A2C7120E5C5C1478147014F0495AA213035C1307A2130FA2131F5CA2133FA4137FA86DC8 +FC131E22307CAF28>I<1578A215FCA34A7EA24A7EA24A7FA34A7FEC0E7F021E7FEC1C3F +A202387F151F02787FEC700FA202E07F1507010180ECC003A249486C7EA201078191C7FC +498191B6FCA24981011CC7123F013C810138141FA24981160F01F081491407A248488148 +6C1403B549B512FCA336317DB03D>65 DI<913A03FF800180023FEBF00349B5EAFC0701079038003F0FD91FF8EB07 +9FD93FC0EB01FFD9FF807F4848C8127F4848153F0007161F49150F485A001F1607A2485A +1703127FA24992C7FCA212FFA9127FA27FEF0380123FA26C7E1707000F17006C7E6D150E +0003161E6C6C151C6C6C6C1478D93FC05CD91FF8EB03E0D907FFEB3F800101D9FFFEC7FC +D9003F13F80203138031317CB03A>I69 DI72 DI<017FB512C0A39039001FF000B3AF121C123E127FEAFF80A25D14 +3FD87F005B007E5C003C49C7FC381F01FE3807FFF8C613C022317DB02A>III<90391FF8018090B51203000314C73907F007EF390F8000FF48C7 +127F003E141F150F5A150712FCA215037EA26C91C7FC13C0EA7FF0EBFF806C13F8ECFF80 +6C14F06C806C806C14FFC6FC013F1480010114C0D9001F13E01401EC003FED1FF0150F15 +07126000E01403A316E07EA26CEC07C07EB4EC0F8001C0EB1F00D8FBFC13FE00F1B512F8 +D8E03F5BD8C003138024317CB02D>83 D<007FB8FCA39039C00FF801D87E00EC003F007C +82007882A200708200F01780A3481603A5C792C7FCB3AA017FB6FCA331307DAF38>III97 DIIIII<90391FF007C09039FFFE3FE03A01F83F79F03907E00FC3000F14E19039C007E0 +E0001FECF000A2003F80A5001F5CA2000F5CEBE00F00075C2603F83FC7FC3806FFFE380E +1FF090C9FC121EA2121F7F90B57E6C14F015FC6C806C801680000F15C0003FC7127F007E +EC1FE0007C140F00FC1407A4007EEC0FC0003E1580003F141FD80FC0EB7E003907F803FC +0001B512F0D8001F90C7FC242F7E9F28>II< +EA03C0487E487E487EA46C5A6C5A6C5AC8FCA9EA01F8127FA31207B3A7B51280A311337D +B217>I108 +D<2703F007F8EB1FE000FFD93FFEEBFFF8913A783F01E0FC02C090388300FE280FF1801F +C6137F2607F30013CC01F602F8148001FC5CA3495CB3B500C3B5380FFFFCA33E207D9F43 +>I<3903F007F800FFEB3FFEEC783F02C013803A0FF1801FC03807F30001F614E013FCA3 +5BB3B500C3B5FCA328207D9F2D>II<3901F83FE000FFEBFFFC9038FBE07F9039FF003F80D807FEEB1FC049EB0FE04914 +F0ED07F8A216FC1503A216FEA816FC1507A216F8A2ED0FF06D14E06DEB1FC06DEB3F8090 +39FBC0FE009038F8FFF8EC3FC091C8FCABB512C0A3272E7E9F2D>I<3803F03F00FFEB7F +C09038F1C3E01487390FF30FF0EA07F6A29038FC07E0EC03C091C7FCA25BB2B512E0A31C +207E9F21>114 D<3801FF86000713FEEA1F00003C133E48131E140E12F8A36C90C7FCB4 +7E13FC387FFFC06C13F0806C7F00077F00017FEA003F01001380143F0060131F00E0130F +A27E15007E6C131E6C131C38FF807838F3FFF038C07F8019207D9F20>I<131CA5133CA3 +137CA213FC120112031207381FFFFEB5FCA2D803FCC7FCB0EC0380A71201EC0700EA00FE +EB7F0EEB3FFCEB07F0192E7FAD1F>II< +B5EB1FFCA3D80FF8EB03C0000715806D1307000315007F0001140E7F6C5CA2EC803C017F +1338ECC078013F1370ECE0F0011F5B14F1010F5B14F9903807FB80A214FF6D90C7FCA26D +5AA26D5AA21478A226207E9F2B>I<3A7FFF807FFCA33A03FC000F006C6C131E6C6C5BEC +803890387FC078013F5B90381FE1E090380FF3C0ECFF806D90C7FC6D5A13016D7E81815B +903803DFE09038078FF08190380F07FC90381E03FEEB3C01496C7E4914804848EB7FC000 +03EC3FE026FFFC01B5FCA328207F9F2B>120 DI +E /Fi 1 14 df<14FF010713E090381F00F80178131E01E01307D80180EB018048C812C0 +00061560481530A248151848150CA2481506A4481503A900601506A46C150CA26C15186C +1530A26C15606C15C06C6CEB0180D800E0EB07000178131E011F13F8903807FFE0010090 +C7FC282B7EA02D>13 D E /Fj 64 122 df<49B4FC011F13C090387F81E0EBFC013901F8 +07F01203EA07F0A4EC01C091C8FCA3EC3FF8B6FCA33807F003B3A33A7FFF3FFF80A3212A +7FA925>12 D<131CA3EB7F803803FFE0000F13F8381F9CFC383E1C1E003C7F007C7F0078 +EB0F8000F8131F143FA312FC00FEEB1F0000FF90C7FCEA7FDC13FCEBFFC06C7F6C7F6C13 +FC7E00017F6C6C7E131F131CEC3F800038131F127C00FE130FA312FC00F8140012705C00 +38131E003C5B381F9CF86CB45A00035BC690C7FC131CA319307CAC22>36 +D<123C127FEAFF80A213C0A3127F123E1200A2EA0180A3EA0300A21206120E5A5A12100A +157B8813>44 DI<121C127FA2EAFF80A3EA7F00A2121C09097B +8813>I<130E131E137EEA07FE12FFA212F81200B3ABB512FEA317277BA622>49 +DII<140FA25C5C5C5C5BA2EB03 +BFEB073F130E131C133C1338137013E0EA01C0EA038012071300120E5A5A5A12F0B612F8 +A3C7EA7F00A890381FFFF8A31D277EA622>I<00181303381F801FEBFFFE5C5C5C14C091 +C7FC001CC8FCA7EB7FC0381DFFF8381F80FC381E003F1208C7EA1F8015C0A215E0A21218 +127C12FEA315C05A0078EB3F80A26CEB7F00381F01FE6CB45A000313F0C613801B277DA6 +22>II<1238123E003FB512F0A34814E015C0158015003870000EA25C485B5C5CC6485AA249 +5A130791C7FC5B5B131E133EA2137E137CA213FCA41201A76C5A13701C297CA822>III<121C127FA2EAFF80A3EA7F00A2121CC7FCA9121C127FA2EA +FF80A3EA7F00A2121C091B7B9A13>I<48B4FC000F13E0381E03F0383801F8387800FC00 +FC13FE7EA3127C003813FCEA0001EB03F8EB07E0EB0FC01480EB1E00A25B1338A25BA790 +C7FCA5137013F8487E487EA36C5A6C5A1370172A7CA920>63 D65 DI<91387FE003903907FFFC07011FEBFF0F90397FF00F9F9039FF0001FFD801FC7F48 +48147F4848143F4848141F485A160F485A1607127FA290C9FC5AA97E7F1607123FA26C7E +160E6C7E6C6C141C6C6C143C6C6C14786CB4EB01F090397FF007C0011FB512800107EBFE +009038007FF028297CA831>IIII<91387FE003903907FFFC07011FEBFF0F +90397FF00F9F9039FF0001FFD801FC7F484880484880484880485A82485A82127FA290CA +FC5AA892B512F87E7F03001300123FA26C7EA26C7E6C7E6C7E6C7E6CB45B90387FF00701 +1FB5129F0107EBFE0F9039007FF0032D297CA835>III<90B512F8A301001300B3A91218127EB4FCA35C387E01FC007C5B +383E07F0380FFFE0000390C7FC1D297EA823>IIIIIIIII<9038FF80600003EBF0E0000F13 +F8381F80FD383F001F003E1307481303A200FC1301A214007EA26C140013C0EA7FFCEBFF +E06C13F86C13FE80000714806C14C0C6FC010F13E0EB007FEC1FF0140F140700E01303A4 +6C14E0A26C13076C14C0B4EB0F80EBE03F39E3FFFE0000E15B38C01FF01C297CA825>I< +007FB71280A39039807F807FD87C00140F00781507A20070150300F016C0A2481501A5C7 +91C7FCB3A490B612C0A32A287EA72F>IIII89 +D91 D<3803FF80000F13F0381F01FC38 +3F80FE147F801580EA1F00C7FCA4EB3FFF3801FC3FEA0FE0EA1F80EA3F00127E5AA4145F +007E13DF393F839FFC381FFE0F3803FC031E1B7E9A21>97 DIIIII<9038FF80F00003EBE3F8390FC1FE1C391F007C7C48137E +003EEB3E10007EEB3F00A6003E133E003F137E6C137C380FC1F8380BFFE00018138090C8 +FC1238A2123C383FFFF814FF6C14C06C14E06C14F0121F383C0007007CEB01F8481300A4 +007CEB01F0A2003FEB07E0390FC01F806CB5120038007FF01E287E9A22>II<1207EA0F80EA1FC0EA3FE0A3EA1FC0EA0F80EA0700C7FCA7EAFFE0A3 +120FB3A3EAFFFEA30F2B7EAA12>I107 DI<26 +FFC07FEB1FC0903AC1FFC07FF0903AC307E0C1F8D80FC49038F101FC9039C803F20001D8 +01FE7F01D05BA201E05BB03CFFFE3FFF8FFFE0A3331B7D9A38>I<38FFC07E9038C1FF80 +9038C30FC0D80FC413E0EBC80701D813F013D0A213E0B039FFFE3FFFA3201B7D9A25>I< +EB3FE03801FFFC3803F07E390FC01F80391F800FC0393F0007E0A2007EEB03F0A300FE14 +F8A8007E14F0A26CEB07E0A2391F800FC0390FC01F803907F07F003801FFFC38003FE01D +1B7E9A22>I<38FFE1FE9038EFFF809038FE0FE0390FF803F09038F001F801E013FC1400 +15FEA2157FA8157E15FEA215FC140101F013F89038F807F09038FC0FE09038EFFF809038 +E1FC0001E0C7FCA9EAFFFEA320277E9A25>I<38FFC1F0EBC7FCEBC63E380FCC7F13D813 +D0A2EBF03EEBE000B0B5FCA3181B7F9A1B>114 D<3803FE30380FFFF0EA3E03EA780012 +7000F01370A27E00FE1300EAFFE06CB4FC14C06C13E06C13F0000713F8C6FCEB07FC1300 +00E0137C143C7E14387E6C137038FF01E038E7FFC000C11300161B7E9A1B>I<13E0A412 +01A31203A21207120F381FFFE0B5FCA2380FE000AD1470A73807F0E0000313C03801FF80 +38007F0014267FA51A>I<39FFE07FF0A3000F1307B2140FA2000713173903F067FF3801 +FFC738007F87201B7D9A25>I<39FFFC03FFA3390FF000F0000714E07F0003EB01C0A2EB +FC0300011480EBFE070000140013FFEB7F0EA2149EEB3F9C14FC6D5AA26D5AA36D5AA26D +5AA2201B7F9A23>I<3BFFFC7FFC1FFCA33B0FE00FE001C02607F007EB0380A201F8EBF0 +0700031600EC0FF801FC5C0001150EEC1FFC2600FE1C5B15FE9039FF387E3C017F1438EC +787F6D486C5A16F0ECE01F011F5CA26D486C5AA2EC800701075CA22E1B7F9A31>I<39FF +FC1FFEA33907F003803803F8079038FC0F003801FE1E00005BEB7F3814F86D5A6D5A130F +806D7E130F497EEB3CFEEB38FFEB787F9038F03F803901E01FC0D803C013E0EB800F39FF +F03FFFA3201B7F9A23>I<39FFFC03FFA3390FF000F0000714E07F0003EB01C0A2EBFC03 +00011480EBFE070000140013FFEB7F0EA2149EEB3F9C14FC6D5AA26D5AA36D5AA26D5AA2 +5CA21307003890C7FCEA7C0FEAFE0E131E131C5BEA74F0EA3FE0EA0F8020277F9A23>I +E /Fk 91 127 df<127012F8B012701200A5127012F8A31270051C779B18>33 +DI +I<13C01201A3EA03F0EA0FFCEA3FFEEA7DCFEA71C738E1C38013C7A338F1C0001279123F +6C7EEA0FF8EA01FC13DE13CF13C73861C38012F1A212E1EBC7001271EA79DEEA3FFEEA1F +F8EA07E0EA01C0A3120011247D9F18>III<1238127CA2127E +123E120EA3121CA2123812F812F012C0070E789B18>I<137013F0EA01E0EA03C0EA0780 +EA0F00121E121C5AA25AA45AA81270A47EA27E121E7EEA0780EA03C0EA01F0120013700C +24799F18>I<126012F012787E7E7EEA07801203EA01C0A2EA00E0A41370A813E0A4EA01 +C0A2EA03801207EA0F00121E5A5A5A12600C247C9F18>II<136013F0A7387FFFC0B512E0A26C13C03800F000A7136013147E9718>I<121C +123E127E127F123F121F1207120E121E127C12F81260080C788518>I<387FFFC0B512E0 +A26C13C013047E8F18>I<1230127812FCA2127812300606778518>I<1303EB0780A2130F +14005B131EA2133E133C137C1378A213F85B12015B12035BA212075B120F90C7FCA25A12 +1E123E123CA2127C127812F85AA2126011247D9F18>IIIII<131F5B1377A213E7120113C7EA03 +8712071307120E121E123C1238127812F0B512F8A338000700A6EB7FF0A3151C7F9B18> +I<383FFF80A30038C7FCA8EA3BF8EA3FFE7F383C0780383003C0EA0001EB00E0A2126012 +F0A238E001C0EA7003387C0F80383FFF00EA1FFCEA03F0131C7E9B18>I<137E48B4FC00 +071380380F83C0EA1E03121C3838018090C7FC5AA2EAE1F8EAE7FEB5FC38FE078038F803 +C0EAF001EB00E05A7E1270A3383801C0EA3C03381E0780380FFF006C5AEA01F8131C7E9B +18>I<12E0B512E0A214C038E00380EB0700C65A131E131C5BA25B13F05BA2485AA3485A +A448C7FCA7131D7E9C18>I<1230127812FCA2127812301200A81230127812FCA2127812 +300614779318>58 D<1218123C127EA2123C12181200A81218123C127EA2123E121E120E +121C123C127812F01260071A789318>I<14C0EB03E01307EB1FC0EB3F80EBFE00485AEA +07F0485AEA3F8048C7FC12FCA2127F6C7EEA0FE06C7EEA01FC6C7EEB3F80EB1FC0EB07E0 +1303EB00C013187E9918>I<387FFFC0B512E0A3C8FCA4B512E0A36C13C0130C7E9318>I< +126012F87E127F6C7EEA0FE06C7EEA01FC6C7EEB3F80EB1FC0EB07E0A2EB1FC0EB3F80EB +FE00485AEA07F0485AEA3F8048C7FC12FC5A126013187E9918>II<137CEA01FEEA07FF380F8780381E03C0EA3C1DEA387F3870FFE0EA71 +E313C112E1EAE380A638E1C1C0127113E33870FF8038387F00EA3C1C381E00E0EA0F8338 +07FFC00001138038007E00131C7E9B18>I<137013F8A213D8A2EA01DCA3138CEA038EA4 +EA0707A5380FFF80A3EA0E03381C01C0A3387F07F000FF13F8007F13F0151C7F9B18>I< +EA7FFCB5FC6C1380381C03C01301EB00E0A4130114C01307381FFF80140014C0EA1C03EB +00E014F01470A414F014E01303387FFFC0B51280387FFE00141C7F9B18>IIIII<3801F1C0EA03FDEA0FFFEA1F0FEA1C03123813011270A290C7 +FC5AA5EB0FF0131F130F387001C0A213031238A2EA1C07EA1F0FEA0FFFEA03FDEA01F114 +1C7E9B18>I<387F07F038FF8FF8387F07F0381C01C0A9EA1FFFA3EA1C01AA387F07F038 +FF8FF8387F07F0151C7F9B18>II<387F07F038FF87F8387F07F0381C03C0EB07801400130E131E5B1338 +5B13F0121DA2EA1FB8A2131C121EEA1C0EA27FA2EB0380A2EB01C0387F03F038FF87F838 +7F03F0151C7F9B18>75 DI<38FC01 +F8EAFE03A2383B06E0A4138EA2EA398CA213DCA3EA38D8A213F81370A21300A638FE03F8 +A3151C7F9B18>I<387E07F038FF0FF8387F07F0381D81C0A313C1121CA213E1A3136113 +71A213311339A31319A2131D130DA3EA7F07EAFF87EA7F03151C7F9B18>IIIII<3803F1C0EA1FFF5AEA7C0FEA7003EAE001A390C7FC12701278123FEA1FF0 +EA07FEC67EEB0F80EB03C01301EB00E0A2126012E0130100F013C038F80780B5FCEBFE00 +EAE7F8131C7E9B18>I<387FFFF8B5FCA238E07038A400001300B2EA07FFA3151C7F9B18> +I<38FF83FEA3381C0070B36C13E0EA0F01380783C03803FF806C1300EA007C171C809B18 +>I<38FE03F8EAFF07EAFE03383C01E0001C13C0A3EA1E03000E1380A438070700A4EA03 +8EA4EA018C13DCA3EA00D813F8A21370151C7F9B18>I<38FE03F8A338700070A36C13E0 +A513F8EA39FC13DCA2001913C0A3138CA2EA1D8DA31305000D1380EA0F07A2EA0E03151C +7F9B18>I<387F0FE0139F130F380E0700120FEA070E138EEA039C13DCEA01F8A212005B +137013F07F487E13DCEA039E138EEA070F7F000E13801303001E13C0387F07F000FF13F8 +007F13F0151C7F9B18>I<38FE03F8EAFF07EAFE03381C01C0EA1E03000E1380EA0F0700 +071300A2EA038EA2EA01DCA3EA00F8A21370A9EA01FC487E6C5A151C7F9B18>I<383FFF +E05AA2387001C01303EB07801400C65A131E131C133C5B137013F0485A5B1203485A90C7 +FC5A001E13E0121C123C5A1270B5FCA3131C7E9B18>II<126012F0A27E1278127C123CA2123E121E121F7EA27F12077F1203A27F +12017F12007F1378A2137C133C133E131EA2131F7F14801307A2EB030011247D9F18>I< +EAFFF8A3EA0038B3ACEAFFF8A30D247F9F18>II<387FFFC0B512E0A26C13C013047E7F18>I<1206121E123E12381270 +A212E0A312F812FC127CA21238070E789E18>II<127E12FE127E120EA5133EEBFF80000F13C0EBC1E01380EB0070120E1438A600 +0F1370A2EB80E013C1EBFFC0000E138038063E00151C809B18>IIIII<3801E1F03807FFF85A381E +1E30381C0E00487EA5EA1C0EEA1E1EEA1FFC5BEA39E00038C7FC7EEA1FFEEBFFC04813E0 +387801F038700070481338A4007813F0EA7E03381FFFC06C13803801FC00151F7F9318> +I<127E12FE127E120EA5133EEBFF80000F13C013C1EB80E01300120EAB387FC7FC38FFE7 +FE387FC7FC171C809B18>II<1338137CA313381300A4EA0FFCA3EA001CB3A4EA6038EAF078EAFF +F0EA7FE0EA3F800E277E9C18>I<127E12FE127E120EA5EB3FF0A3EB0780EB0F00131E5B +5B5BEA0FF87F139C130EEA0E0F7FEB038014C0387FC7F812FF127F151C7F9B18>II<38F9C1C038FFF7F013FF383E3E38EA3C3CA2EA +3838AB38FE3E3EEB7E7EEB3E3E1714809318>IIII<3801F380EA07FBEA1FFFEA3E1FEA380FEA7007A2EAE003A6EA7007A2EA380FEA3C1F +EA1FFFEA0FFBEA03E3EA0003A7EB1FF0EB3FF8EB1FF0151E7E9318>I<38FF0FC0EB3FE0 +EB7FF0EA07F0EBE060EBC0005BA290C7FCA9EAFFFC7F5B14147E9318>II<487E1203A4387FFFC0B5FCA238038000A9144014 +E0A33801C1C013FF6C1380EB3E0013197F9818>I<387E07E0EAFE0FEA7E07EA0E00AC13 +01EA0F033807FFFC6C13FE3801FCFC1714809318>I<387F8FF000FF13F8007F13F0381C +01C0380E0380A338070700A3138FEA038EA3EA01DCA3EA00F8A2137015147F9318>I<38 +FF07F8138F1307383800E0A4381C01C0137113F9A213D9EA1DDD000D1380A3138DEA0F8F +A23807070015147F9318>I<387F8FF0139F138F380F0700EA078EEA039EEA01DC13F812 +00137013F07FEA01DCEA039E138EEA0707000E1380387F8FF000FF13F8007F13F015147F +9318>I<387F8FF000FF13F8007F13F0380E01C0EB0380A21207EB0700A2EA0387A2138E +EA01CEA213CC120013DC1378A31370A313F05B1279EA7BC0EA7F806CC7FC121E151E7F93 +18>I<383FFFF05AA2387001E0EB03C0EB078038000F00131E5B13F8485AEA03C0485A38 +0F0070121E5A5AB512F0A314147F9318>II<126012F0B3B0126004 +24769F18>I<127CB4FC13C01203C67EAB7FEB7FC0EB3FE0A2EB7FC0EBF0005BABEA03C0 +12FF90C7FC127C13247E9F18>II E /Fl 82 124 df<90381F83E09038F06E303901C07878380380F8903800F03048 +EB7000A7B612803907007000B2383FE3FF1D20809F1B>11 D<133FEBE0C0EA01C0380381 +E0EA0701A290C7FCA6B512E0EA0700B2383FC3FC1620809F19>II<90381F81F89038F04F043901C0 +7C06390380F80FEB00F05A0270C7FCA6B7FC3907007007B23A3FE3FE3FE02320809F26> +I<127012F8A71270AA1220A51200A5127012F8A3127005217CA00D>33 +DI<127012F812FCA212741204A31208A21210A212201240060E7C9F0D>39 +D<13401380EA01005A12061204120C5AA212381230A212701260A412E0AC1260A4127012 +30A212381218A27E120412067E7EEA008013400A2E7BA112>I<7E12407E12307E120812 +0C7EA212077EA213801201A413C0AC1380A412031300A25A1206A25A120812185A12205A +5A0A2E7EA112>I<127012F012F8A212781208A31210A31220A21240050E7C840D>44 +DI<127012F8A3127005057C840D>I<144014C0EB0180A3EB0300 +A31306A25BA35BA35BA25BA35BA3485AA348C7FCA21206A35AA35AA25AA35AA35AA2122D +7EA117>II<13801203120F12F31203B3A6EA +07C0EAFFFE0F1E7C9D17>III<1306A2130EA2131E132EA2134E138EA2EA +010E1202A212041208A212101220A2124012C0B512F038000E00A7EBFFE0141E7F9D17> +II<137CEA +0182EA0701380E0380EA0C0712183838030090C7FC12781270A2EAF1F0EAF21CEAF406EA +F807EB0380A200F013C0A51270A214801238EB07001218EA0C0E6C5AEA01F0121F7E9D17 +>I<1240387FFFE014C0A23840008038800100A21302485AA25B5BA25BA21360A213E05B +1201A41203A76C5A131F7E9D17>III<127012F8A312 +701200AA127012F8A3127005147C930D>I<127012F8A312701200AA127012F012F8A212 +781208A31210A31220A21240051D7C930D>I63 D<5B497EA3497EA3EB09E0A3EB10F0A3EB2078A3497EA2EBC03EEB801E +A248B5FCEB000FA20002EB0780A348EB03C0A2120C001E14E039FF801FFE1F207F9F22> +65 DI<90380FE010903838 +1C309038E002703803C00139078000F048C71270121E15305A1510127C127800F81400A9 +1278007C1410123CA26C1420A27E6C6C13406C6C13803900E00300EB380CEB0FF01C217E +9F21>IIII<90380FE0 +109038381C309038E002703803C00139078000F048C71270121E15305A1510127C127800 +F81400A7EC3FFEEC01F000781300127C123CA27EA27E6C7E3903C001703900E002309038 +380C1090380FF0001F217E9F24>I<39FFF07FF8390F000780AD90B5FCEB0007AF39FFF0 +7FF81D1F7E9E22>II<3807FFC038003E00131E +B3A3122012F8A3EAF01CEA403CEA6038EA1070EA0FC012207F9E17>I<39FFF007FC390F +0003E0EC0180150014025C5C5C5C5C5C49C7FC5B497E130FEB13C0EB21E01341EB80F0EB +0078A28080A280EC0780A2EC03C015E015F039FFF01FFE1F1F7E9E23>IIIIIIII<3803 +F040380C0CC0EA1803EA3001EA6000A212E01440A36C13007E127CEA7F80EA3FF86CB4FC +00071380C613C0EB1FE013031301EB00F014707EA46C136014E06C13C038F8018038C603 +00EA81FC14217E9F19>I<007FB512E038780F010060EB006000401420A200C014300080 +1410A400001400B3497E3803FFFC1C1F7E9E21>I<39FFF00FF8390F0003E0EC0080B3A4 +6CEB01001380120314026C6C5A6C6C5AEB3830EB0FC01D207E9E22>I<39FFF003FE391F +8000F86CC7126015206C6C1340A36C6C1380A2EBE00100011400A23800F002A213F8EB78 +04A26D5AA36D5AA2131F6D5AA2EB07C0A36D5AA36DC7FC1F207F9E22>I<3BFFF07FF81F +F03B1F000FC007C06C903907800180170015C001805C00071502EC09E013C000035DEC19 +F01410D801E05CA2EC2078D800F05CA2EC403C01785CA2EC801E017C1460013C14409038 +3D000F133F6D5CA2011E1307010E91C7FCA2010C7F010413022C207F9E2F>I<39FFF001 +FF391F800078000F146012076D1340000314807F3901F001001200EBF802EB7C06EB3C04 +EB3E08131EEB1F10EB0FB0EB07A014E06D5AACEB3FFC201F7F9E22>89 +D<387FFFFE387E003C127800701378006013F814F0384001E0130314C0EB07801200EB0F +00131EA25B137C13785B1201EBE002EA03C0A2EA0780000F13061300001E1304003E130C +123C48133C14FCB5FC171F7E9E1C>I<12FFA212C0B3B3A512FFA2082D7CA10D>II<12 +FFA21203B3B3A512FFA2082D80A10D>I<120812101220A21240A21280A312B812FCA212 +7C1238060E7D9F0D>96 DI<121C12FC121CAA13 +7CEA1D87381E0180EB00C0001C13E01470A21478A6147014F014E0001E13C0381A018038 +198700EA107C15207E9F19>IIII<137CEA01C6EA030F1207EA0E061300A7 +EAFFF0EA0E00B2EA7FE01020809F0E>I<14E03803E330EA0E3CEA1C1C38380E00EA780F +A5EA380E6C5AEA1E38EA33E00020C7FCA21230A2EA3FFE381FFF8014C0383001E0386000 +70481330A4006013606C13C0381C03803803FC00141F7F9417>I<121C12FC121CAA137C +1386EA1D03001E1380A2121CAE38FF8FF014207E9F19>I<1238127CA31238C7FCA6121C +12FC121CB1EAFF80091F7F9E0C>I<13E0EA01F0A3EA00E01300A61370EA07F012001370 +B3A31260EAF06013C0EA6180EA3F000C28829E0E>I<121C12FC121CAAEB1FE0EB0780EB +060013045B5B5B136013E0EA1DF0EA1E70EA1C38133C131C7F130F7F148014C038FF9FF0 +14207E9F18>I<121C12FC121CB3ABEAFF8009207F9F0C>I<391C3E03E039FCC30C30391D +039038391E01E01CA2001C13C0AE3AFF8FF8FF8021147E9326>III< +EA1C7CEAFD87381E018014C0381C00E014F014701478A6147014F014E0381E01C0EB0380 +381D8700EA1C7C90C7FCA8B47E151D7E9319>I<3801F04038070CC0EA0E02EA1C03EA38 +011278127012F0A6127012781238EA1C03EA0C05EA0709EA01F1EA0001A8EB0FF8151D7F +9318>III<1202A31206A2120EA2123EEAFFF8EA0E00AB1304A5EA07 +081203EA01F00E1C7F9B12>I<381C0380EAFC1FEA1C03AE1307120CEA061B3803E3F014 +147E9319>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382A2EA01C4 +A213E4EA00E8A21370A3132015147F9318>I<39FF9FE1FC393C078070391C030060EC80 +20000E1440A214C0D80704138014E0A239038861001471A23801D032143A143E3800E01C +A2EB6018EB40081E147F9321>I<38FF87F8381E03C0380E0180EB0300EA0702EA0384EA +01C813D8EA00F01370137813F8139CEA010E1202EA060738040380000C13C0003C13E038 +FE07FC16147F9318>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382 +A2EA01C4A213E4EA00E8A21370A31320A25BA3EAF080A200F1C7FC1262123C151D7F9318 +>III +E /Fm 9 118 df66 D70 D97 D<49B47E010F13F0017F13FC9038FF81FE +3A03FE007F80D807F8133F4848EB1FC0ED0FE0485A003F15F01507485A16F8A212FFA290 +B6FCA301C0C8FCA4127FA36C7E1678121F7F000F15F06C6C13016C6CEB03E06C6CEB0FC0 +3A00FFC07F8090393FFFFE00010F13F8010013C025267DA52C>101 +D<13FE12FFA412071203B0EDFF80020313F0020F7F91381E03FC91383801FE02607F4A7E +01FF15805C91C7FCA35BB3A4B5D8F83F13FEA42F3C7CBB36>104 +D<3901FC03F000FFEB0FFC4AB4FC91383C3F80EC707F00079038E0FFC000035BEBFD80A2 +01FFEB7F809138003F00151E92C7FC5BB3A3B512FCA422267DA528>114 +D<90383FF0383903FFFE7848EBFFF8381FC00F383F0003003E13005A157812FCA27E6C14 +0013C013FC387FFFF06C13FEECFF806C14C06C14E0000314F0C614F8011F13FCEB007FEC +07FE0070130100F01300157E7EA27E157C6C14FC6C14F890388001F09038F00FE000F9B5 +12C0D8F07F130038C01FF81F267DA526>I<130FA55BA45BA25BA25B5A5A5A001FEBFFF0 +B6FCA3000190C7FCB3153CA86C14781480017F13F090383FC1E090381FFFC06D13809038 +01FE001E377EB626>I<01FEEC3F8000FFEC3FFFA400071401000380B3A45DA25D120115 +066C6C4913C090267F807813FE6DB45A6D5B010313802F267CA536>I +E end +TeXDict begin + +1 0 bop 0 1176 a Fm(Bash)32 b(F)-8 b(eatures)p 0 1210 +1950 17 v 1261 1258 a Fl(Ov)o(erview)16 b(Do)q(cumen)o(tation)f(for)g +(Bash)1244 1312 y(Edition)h(1.14,)d(for)i Fk(bash)g Fl(V)l(ersion)h +(1.14.)1701 1366 y(August)f(1994)0 2467 y Fj(Brian)23 +b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 +b(oundation)0 2534 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 +b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2570 +1950 9 v eop +2 1 bop 0 2661 a Fl(Cop)o(yrigh)o(t)226 2660 y(c)214 +2661 y Fi(\015)15 b Fl(1991,)f(1993)g(F)l(ree)h(Soft)o(w)o(are)f(F)l +(oundation,)h(Inc.)p eop +1 2 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l +(eatures)1143 b(1)0 183 y Fh(1)41 b(Bourne)15 b(Shell)e(St)n(yle)h(F)-7 +b(eatures)62 369 y Fl(Bash)20 b(is)g(an)g(acron)o(ym)f(for)g(Bourne)i +(Again)f(SHell.)35 b(The)20 b(Bourne)h(shell)g(is)f(the)g(traditional)h +(Unix)f(shell)0 432 y(originally)f(written)f(b)o(y)f(Stephen)i(Bourne.) +27 b(All)19 b(of)e(the)h(Bourne)f(shell)j(builtin)f(commands)f(are)f(a) +o(v)m(ailable)i(in)0 494 y(Bash,)g(and)f(the)g(rules)h(for)e(ev)m +(aluation)j(and)e(quoting)g(are)g(tak)o(en)g(from)f(the)h(P)o(osix)g +(1003.2)f(sp)q(eci\014cation)j(for)0 556 y(the)15 b(`standard')f(Unix)i +(shell.)62 693 y(This)g(section)f(brie\015y)h(summarizes)f(things)g +(whic)o(h)h(Bash)f(inherits)h(from)e(the)g(Bourne)i(shell:)21 +b(shell)16 b(con)o(trol)0 755 y(structures,)i(builtins,)i(v)m +(ariables,)g(and)e(other)g(features.)27 b(It)18 b(also)g(lists)h(the)f +(signi\014can)o(t)h(di\013erences)g(b)q(et)o(w)o(een)0 +818 y(Bash)c(and)h(the)f(Bourne)h(Shell.)0 1041 y Fj(1.1)33 +b(Lo)r(oping)15 b(Constructs)62 1178 y Fl(Note)g(that)g(wherev)o(er)h +(y)o(ou)f(see)h(a)f(`)p Fk(;)p Fl(')g(in)h(the)g(description)h(of)e(a)g +(command's)g(syn)o(tax,)g(it)h(ma)o(y)e(b)q(e)j(replaced)0 +1240 y(indiscriminately)h(with)e(one)f(or)g(more)g(newlines.)62 +1377 y(Bash)h(supp)q(orts)f(the)g(follo)o(wing)h(lo)q(oping)g +(constructs.)0 1527 y Fk(until)120 b Fl(The)15 b(syn)o(tax)g(of)g(the)g +Fk(until)f Fl(command)h(is:)360 1589 y Fk(until)23 b +Fg(test-commands)r Fk(;)g(do)h Fg(consequen)o(t-commands)r +Fk(;)g(done)240 1663 y Fl(Execute)14 b Fg(consequen)o(t-commands)i +Fl(as)d(long)h(as)f(the)h(\014nal)h(command)e(in)i Fg(test-commands)g +Fl(has)e(an)240 1726 y(exit)j(status)e(whic)o(h)i(is)g(not)f(zero.)0 +1813 y Fk(while)120 b Fl(The)15 b(syn)o(tax)g(of)g(the)g +Fk(while)f Fl(command)h(is:)360 1875 y Fk(while)23 b +Fg(test-commands)r Fk(;)g(do)h Fg(consequen)o(t-commands)r +Fk(;)g(done)240 1949 y Fl(Execute)14 b Fg(consequen)o(t-commands)i +Fl(as)d(long)h(as)f(the)h(\014nal)h(command)e(in)i Fg(test-commands)g +Fl(has)e(an)240 2011 y(exit)j(status)e(of)h(zero.)0 2098 +y Fk(for)168 b Fl(The)15 b(syn)o(tax)g(of)g(the)g(for)g(command)g(is:) +360 2160 y Fk(for)23 b Fg(name)k Fk([in)c Fg(w)o(ords)i +Fk(...];)f(do)f Fg(commands)r Fk(;)h(done)240 2235 y +Fl(Execute)11 b Fg(commands)g Fl(for)f(eac)o(h)g(mem)o(b)q(er)h(in)g +Fg(w)o(ords)p Fl(,)f(with)g Fg(name)j Fl(b)q(ound)e(to)f(the)g(curren)o +(t)g(mem)o(b)q(er.)240 2297 y(If)15 b(\\)p Fk(in)g Fg(w)o(ords)r +Fl(")f(is)i(not)f(presen)o(t,)f(\\)p Fk(in)h("$@")p Fl(")f(is)i +(assumed.)0 2521 y Fj(1.2)33 b(Conditional)16 b(Constructs)0 +2670 y Fk(if)192 b Fl(The)15 b(syn)o(tax)g(of)g(the)g +Fk(if)g Fl(command)g(is:)p eop +2 3 bop 0 -58 a Fl(2)1646 b(Bash)15 b(F)l(eatures)360 +183 y Fk(if)24 b Fg(test-commands)r Fk(;)f(then)408 233 +y Fg(consequen)o(t-commands)r Fk(;)360 283 y([elif)g +Fg(more-test-commands)r Fk(;)g(then)408 333 y Fg(more-consequen)o(ts)r +Fk(;])360 382 y([else)g Fg(alternate-consequen)o(ts)r +Fk(;])360 432 y(fi)240 508 y Fl(Execute)e Fg(consequen)o(t-commands)h +Fl(only)f(if)g(the)g(\014nal)g(command)f(in)h Fg(test-commands)h +Fl(has)e(an)240 570 y(exit)c(status)e(of)h(zero.)20 b(Otherwise,)c(eac) +o(h)f Fk(elif)g Fl(list)h(is)f(executed)i(in)f(turn,)f(and)g(if)h(its)f +(exit)h(status)240 633 y(is)g(zero,)f(the)h(corresp)q(onding)h +Fg(more-consequen)o(ts)g Fl(is)f(executed)h(and)f(the)f(command)h +(completes.)240 695 y(If)i(\\)p Fk(else)d Fg(alternate-consequen)o(ts)r +Fl(")j(is)h(presen)o(t,)f(and)h(the)f(\014nal)h(command)f(in)h(the)g +(\014nal)g Fk(if)e Fl(or)240 757 y Fk(elif)e Fl(clause)h(has)f(a)g +(non-zero)g(exit)h(status,)e(then)h(execute)h Fg(alternate-consequen)o +(ts)p Fl(.)0 846 y Fk(case)144 b Fl(The)15 b(syn)o(tax)g(of)g(the)g +Fk(case)g Fl(command)g(is:)360 910 y Fk(case)23 b Fg(w)o(ord)i +Fk(in)f([)p Fg(pattern)f Fk([|)h Fg(pattern)p Fk(]...\))f +Fg(commands)i Fk(;;]...)e(esac)240 986 y Fl(Selectiv)o(ely)c(execute)e +Fg(commands)h Fl(based)e(up)q(on)h Fg(w)o(ord)h Fl(matc)o(hing)e +Fg(pattern)p Fl(.)23 b(The)16 b(`)p Fk(|)p Fl(')g(is)h(used)g(to)240 +1048 y(separate)e(m)o(ultiple)i(patterns.)240 1124 y(Here)d(is)h(an)f +(example)g(using)h Fk(case)e Fl(in)i(a)f(script)g(that)f(could)i(b)q(e) +g(used)f(to)g(describ)q(e)h(an)f(in)o(teresting)240 1186 +y(feature)h(of)g(an)g(animal:)360 1249 y Fk(echo)23 b(-n)h("Enter)f +(the)g(name)h(of)f(an)h(animal:)f(")360 1299 y(read)g(ANIMAL)360 +1349 y(echo)g(-n)h("The)f($ANIMAL)g(has)h(")360 1399 +y(case)f($ANIMAL)g(in)408 1448 y(horse)g(|)h(dog)f(|)h(cat\))f(echo)g +(-n)h("four";;)408 1498 y(man)f(|)h(kangaroo)f(\))g(echo)h(-n)f +("two";;)408 1548 y(*\))g(echo)h(-n)f("an)h(unknown)f(number)g(of";;) +360 1598 y(esac)360 1648 y(echo)g("legs.")0 1881 y Fj(1.3)33 +b(Shell)16 b(F)-6 b(unctions)62 2019 y Fl(Shell)20 b(functions)f(are)f +(a)g(w)o(a)o(y)g(to)f(group)h(commands)g(for)g(later)g(execution)h +(using)g(a)f(single)i(name)e(for)g(the)0 2082 y(group.)36 +b(They)21 b(are)f(executed)h(just)g(lik)o(e)g(a)g Fk(")p +Fl(regular)p Fk(")f Fl(command.)36 b(Shell)22 b(functions)g(are)e +(executed)h(in)h(the)0 2144 y(curren)o(t)15 b(shell)i(con)o(text;)d(no) +h(new)h(pro)q(cess)f(is)h(created)f(to)g(in)o(terpret)g(them.)62 +2282 y(F)l(unctions)h(are)f(declared)i(using)e(this)h(syn)o(tax:)120 +2407 y Fk([)24 b(function)e(])i Fg(name)j Fk(\(\))c({)h +Fg(command-list)q Fk(;)h(})62 2545 y Fl(This)16 b(de\014nes)h(a)e +(function)i(named)e Fg(name)p Fl(.)21 b(The)16 b Fg(b)q(o)q(dy)k +Fl(of)15 b(the)h(function)g(is)g(the)g Fg(command-list)h +Fl(b)q(et)o(w)o(een)f Fk({)0 2608 y Fl(and)d Fk(})p Fl(.)19 +b(This)14 b(list)g(is)g(executed)g(whenev)o(er)g Fg(name)i +Fl(is)d(sp)q(eci\014ed)j(as)c(the)i(name)f(of)g(a)g(command.)19 +b(The)13 b(exit)h(status)0 2670 y(of)h(a)g(function)h(is)f(the)h(exit)f +(status)g(of)f(the)i(last)f(command)g(executed)h(in)g(the)f(b)q(o)q(dy) +l(.)p eop +3 4 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l +(eatures)1143 b(3)62 183 y(When)17 b(a)e(function)i(is)g(executed,)g +(the)f(argumen)o(ts)f(to)g(the)i(function)f(b)q(ecome)h(the)f(p)q +(ositional)i(parameters)0 246 y(during)h(its)f(execution.)29 +b(The)18 b(sp)q(ecial)i(parameter)d Fk(#)h Fl(that)f(giv)o(es)h(the)g +(n)o(um)o(b)q(er)h(of)e(p)q(ositional)i(parameters)e(is)0 +308 y(up)q(dated)f(to)f(re\015ect)g(the)g(c)o(hange.)20 +b(P)o(ositional)c(parameter)e(0)h(is)h(unc)o(hanged.)62 +445 y(If)f(the)g(builtin)i(command)e Fk(return)f Fl(is)h(executed)h(in) +f(a)g(function,)g(the)g(function)g(completes)h(and)f(execution)0 +507 y(resumes)g(with)h(the)f(next)h(command)f(after)f(the)h(function)i +(call.)k(When)15 b(a)g(function)h(completes,)g(the)f(v)m(alues)h(of)0 +569 y(the)f(p)q(ositional)h(parameters)e(and)h(the)g(sp)q(ecial)i +(parameter)d Fk(#)h Fl(are)f(restored)g(to)h(the)g(v)m(alues)h(they)f +(had)g(prior)g(to)0 632 y(function)h(execution.)0 852 +y Fj(1.4)33 b(Bourne)15 b(Shell)i(Builtins)62 989 y Fl(The)d(follo)o +(wing)g(shell)h(builtin)g(commands)e(are)g(inherited)i(from)e(the)g +(Bourne)h(shell.)21 b(These)13 b(commands)g(are)0 1052 +y(implemen)o(ted)k(as)e(sp)q(eci\014ed)i(b)o(y)e(the)g(P)o(osix)h +(1003.2)d(standard.)0 1200 y Fk(:)216 b Fl(Do)15 b(nothing)g(b)q(ey)o +(ond)h(expanding)h(an)o(y)d(argumen)o(ts)h(and)g(p)q(erforming)h +(redirections.)0 1286 y Fk(.)216 b Fl(Read)15 b(and)g(execute)g +(commands)g(from)f(the)h Fg(\014lename)j Fl(argumen)o(t)c(in)h(the)g +(curren)o(t)g(shell)h(con)o(text.)0 1371 y Fk(break)120 +b Fl(Exit)15 b(from)g(a)g Fk(for)p Fl(,)f Fk(while)p +Fl(,)g(or)h Fk(until)f Fl(lo)q(op.)0 1457 y Fk(cd)192 +b Fl(Change)15 b(the)g(curren)o(t)h(w)o(orking)e(directory)l(.)0 +1542 y Fk(continue)48 b Fl(Resume)16 b(the)f(next)h(iteration)f(of)g +(an)g(enclosing)i Fk(for)p Fl(,)d Fk(while)p Fl(,)g(or)h +Fk(until)f Fl(lo)q(op.)0 1628 y Fk(echo)144 b Fl(Prin)o(t)15 +b(the)g(argumen)o(ts,)f(separated)h(b)o(y)g(spaces,)h(to)e(the)h +(standard)g(output.)0 1713 y Fk(eval)144 b Fl(The)17 +b(argumen)o(ts)g(are)f(concatenated)h(together)g(in)o(to)g(a)g(single)h +(command,)f(whic)o(h)h(is)g(then)f(read)240 1776 y(and)e(executed.)0 +1861 y Fk(exec)144 b Fl(If)16 b(a)g Fg(command)i Fl(argumen)o(t)d(is)i +(supplied,)h(it)f(replaces)g(the)f(shell.)24 b(If)17 +b(no)f Fg(command)i Fl(is)e(sp)q(eci\014ed,)240 1924 +y(redirections)g(ma)o(y)f(b)q(e)h(used)g(to)e(a\013ect)h(the)g(curren)o +(t)g(shell)i(en)o(vironmen)o(t.)0 2009 y Fk(exit)144 +b Fl(Exit)15 b(the)h(shell.)0 2095 y Fk(export)96 b Fl(Mark)14 +b(the)i(argumen)o(ts)e(as)h(v)m(ariables)h(to)f(b)q(e)h(passed)f(to)g +(c)o(hild)i(pro)q(cesses)e(in)h(the)f(en)o(vironmen)o(t.)0 +2180 y Fk(getopts)72 b Fl(P)o(arse)14 b(options)i(to)e(shell)j(scripts) +f(or)e(functions.)0 2266 y Fk(hash)144 b Fl(Remem)o(b)q(er)17 +b(the)g(full)g(pathnames)g(of)f(commands)g(sp)q(eci\014ed)i(as)e +(argumen)o(ts,)g(so)g(they)g(need)h(not)240 2328 y(b)q(e)f(searc)o(hed) +f(for)g(on)g(subsequen)o(t)h(in)o(v)o(o)q(cations.)0 +2413 y Fk(kill)144 b Fl(Send)16 b(a)f(signal)h(to)f(a)f(pro)q(cess.)0 +2499 y Fk(pwd)168 b Fl(Prin)o(t)15 b(the)g(curren)o(t)h(w)o(orking)e +(directory)l(.)0 2584 y Fk(read)144 b Fl(Read)16 b(a)f(line)i(from)d +(the)h(shell)i(input)f(and)g(use)f(it)h(to)e(set)h(the)g(v)m(alues)i +(of)e(sp)q(eci\014ed)i(v)m(ariables.)0 2670 y Fk(readonly)48 +b Fl(Mark)14 b(v)m(ariables)j(as)e(unc)o(hangable.)p +eop +4 5 bop 0 -58 a Fl(4)1646 b(Bash)15 b(F)l(eatures)0 183 +y Fk(return)96 b Fl(Cause)15 b(a)g(shell)i(function)f(to)e(exit)i(with) +g(a)e(sp)q(eci\014ed)k(v)m(alue.)0 283 y Fk(shift)120 +b Fl(Shift)16 b(p)q(ositional)g(parameters)f(to)f(the)i(left.)0 +383 y Fk(test)0 464 y([)216 b Fl(Ev)m(aluate)16 b(a)f(conditional)h +(expression.)0 564 y Fk(times)120 b Fl(Prin)o(t)15 b(out)g(the)g(user)h +(and)f(system)g(times)g(used)h(b)o(y)f(the)g(shell)i(and)f(its)f(c)o +(hildren.)0 664 y Fk(trap)144 b Fl(Sp)q(ecify)17 b(commands)e(to)f(b)q +(e)i(executed)g(when)g(the)f(shell)i(receiv)o(es)f(signals.)0 +764 y Fk(umask)120 b Fl(Set)15 b(the)h(shell)g(pro)q(cess's)f(\014le)i +(creation)e(mask.)0 863 y Fk(unset)120 b Fl(Cause)15 +b(shell)i(v)m(ariables)f(to)f(disapp)q(ear.)0 963 y Fk(wait)144 +b Fl(W)l(ait)15 b(un)o(til)h(c)o(hild)h(pro)q(cesses)f(exit)g(and)f +(rep)q(ort)g(their)g(exit)h(status.)0 1244 y Fj(1.5)33 +b(Bourne)15 b(Shell)i(V)-6 b(ariables)62 1388 y Fl(Bash)20 +b(uses)h(certain)f(shell)h(v)m(ariables)h(in)f(the)f(same)f(w)o(a)o(y)g +(as)h(the)g(Bourne)g(shell.)36 b(In)21 b(some)e(cases,)i(Bash)0 +1450 y(assigns)15 b(a)g(default)h(v)m(alue)g(to)f(the)g(v)m(ariable.)0 +1612 y Fk(IFS)168 b Fl(A)19 b(list)i(of)d(c)o(haracters)h(that)g +(separate)f(\014elds;)23 b(used)d(when)f(the)h(shell)h(splits)f(w)o +(ords)f(as)g(part)f(of)240 1674 y(expansion.)0 1774 y +Fk(PATH)144 b Fl(A)15 b(colon-separated)h(list)g(of)f(directories)h(in) +g(whic)o(h)g(the)f(shell)i(lo)q(oks)e(for)g(commands.)0 +1874 y Fk(HOME)144 b Fl(The)15 b(curren)o(t)h(user's)e(home)i +(directory)l(.)0 1974 y Fk(CDPATH)96 b Fl(A)15 b(colon-separated)h +(list)g(of)f(directories)h(used)g(as)e(a)h(searc)o(h)g(path)g(for)g +(the)g Fk(cd)g Fl(command.)0 2074 y Fk(MAILPATH)48 b +Fl(A)13 b(colon-separated)h(list)g(of)f(\014les)i(whic)o(h)f(the)g +(shell)h(p)q(erio)q(dically)h(c)o(hec)o(ks)e(for)e(new)i(mail.)20 +b(Y)l(ou)14 b(can)240 2136 y(also)f(sp)q(ecify)i(what)d(message)h(is)h +(prin)o(ted)f(b)o(y)h(separating)f(the)g(\014le)h(name)f(from)g(the)g +(message)g(with)240 2198 y(a)18 b(`)p Fk(?)p Fl('.)29 +b(When)19 b(used)g(in)g(the)g(text)f(of)g(the)h(message,)f +Fk($_)g Fl(stands)g(for)g(the)h(name)f(of)g(the)h(curren)o(t)240 +2261 y(mail\014le.)0 2360 y Fk(PS1)168 b Fl(The)15 b(primary)h(prompt)e +(string.)0 2460 y Fk(PS2)168 b Fl(The)15 b(secondary)h(prompt)e +(string.)0 2560 y Fk(OPTIND)96 b Fl(The)15 b(index)i(of)e(the)g(last)g +(option)g(pro)q(cessed)h(b)o(y)g(the)f Fk(getopts)f Fl(builtin.)0 +2660 y Fk(OPTARG)96 b Fl(The)15 b(v)m(alue)i(of)e(the)g(last)g(option)g +(argumen)o(t)g(pro)q(cessed)h(b)o(y)f(the)g Fk(getopts)f +Fl(builtin.)p eop +5 6 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l +(eatures)1143 b(5)0 183 y Fj(1.6)33 b(Other)15 b(Bourne)g(Shell)i(F)-6 +b(eatures)62 321 y Fl(Bash)15 b(implemen)o(ts)g(essen)o(tially)h(the)e +(same)g(grammar,)f(parameter)g(and)h(v)m(ariable)i(expansion,)f +(redirection,)0 384 y(and)h(quoting)g(as)f(the)h(Bourne)g(Shell.)23 +b(Bash)16 b(uses)g(the)g(P)o(osix)f(1003.2)f(standard)i(as)f(the)h(sp)q +(eci\014cation)h(of)e(ho)o(w)0 446 y(these)i(features)f(are)g(to)g(b)q +(e)h(implemen)o(ted.)25 b(There)17 b(are)f(some)g(di\013erences)h(b)q +(et)o(w)o(een)g(the)f(traditional)i(Bourne)0 508 y(shell)f(and)f(the)f +(P)o(osix)h(standard;)f(this)h(section)g(quic)o(kly)h(details)f(the)g +(di\013erences)g(of)f(signi\014cance.)23 b(A)16 b(n)o(um)o(b)q(er)0 +571 y(of)f(these)g(di\013erences)i(are)d(explained)k(in)e(greater)e +(depth)i(in)g(subsequen)o(t)g(sections.)0 789 y Ff(1.6.1)30 +b(Ma)s(jor)15 b(Di\013erences)h(from)e(the)h(Bourne)g(Shell)62 +928 y Fl(Bash)i(implemen)o(ts)g(the)g Fk(!)f Fl(k)o(eyw)o(ord)f(to)h +(negate)g(the)g(return)g(v)m(alue)i(of)e(a)g(pip)q(eline.)26 +b(V)l(ery)17 b(useful)g(when)g(an)0 990 y Fk(if)e Fl(statemen)o(t)f +(needs)i(to)f(act)f(only)i(if)g(a)f(test)f(fails.)62 +1128 y(Bash)i(includes)h(brace)e(expansion)h(\(see)g(Section)g(2.2)e +([Brace)h(Expansion],)g(page)g(7\).)62 1266 y(Bash)h(includes)h(the)f +(P)o(osix)f(and)h Fk(ksh)p Fl(-st)o(yle)f(pattern)g(remo)o(v)m(al)g +Fk(\045\045)h Fl(and)f Fk(##)g Fl(constructs)g(to)g(remo)o(v)o(e)g +(leading)0 1329 y(or)g(trailing)h(substrings)f(from)g(v)m(ariables.)62 +1467 y(The)j(P)o(osix)g(and)g Fk(ksh)p Fl(-st)o(yle)g +Fk($\(\))f Fl(form)g(of)h(command)f(substitution)i(is)f(implemen)o +(ted,)i(and)e(preferred)h(to)0 1529 y(the)c(Bourne)h(shell's)g +Fk(``)f Fl(\(whic)o(h)h(is)g(also)f(implemen)o(ted)i(for)d(bac)o(kw)o +(ards)h(compatibilit)o(y\).)62 1667 y(V)l(ariables)e(presen)o(t)g(in)f +(the)h(shell's)g(initial)h(en)o(vironmen)o(t)e(are)g(automatically)g +(exp)q(orted)h(to)e(c)o(hild)j(pro)q(cesses.)0 1730 y(The)19 +b(Bourne)g(shell)h(do)q(es)f(not)f(normally)h(do)g(this)g(unless)g(the) +g(v)m(ariables)h(are)e(explicitly)j(mark)o(ed)e(using)g(the)0 +1792 y Fk(export)14 b Fl(command.)62 1930 y(The)i(expansion)g +Fk(${#xx})p Fl(,)e(whic)o(h)i(returns)f(the)g(length)h(of)f +Fk($xx)p Fl(,)f(is)i(supp)q(orted.)62 2068 y(The)k Fk(IFS)g +Fl(v)m(ariable)h(is)f(used)g(to)f(split)i(only)f(the)g(results)g(of)g +(expansion,)h(not)e(all)i(w)o(ords.)33 b(This)20 b(closes)g(a)0 +2131 y(longstanding)c(shell)h(securit)o(y)e(hole.)62 +2269 y(It)i(is)g(p)q(ossible)i(to)d(ha)o(v)o(e)h(a)f(v)m(ariable)i(and) +f(a)g(function)h(with)f(the)g(same)f(name;)h Fk(sh)g +Fl(do)q(es)g(not)g(separate)f(the)0 2331 y(t)o(w)o(o)e(name)h(spaces.) +62 2469 y(Bash)j(functions)h(are)e(p)q(ermitted)i(to)e(ha)o(v)o(e)h(lo) +q(cal)g(v)m(ariables,)i(and)e(th)o(us)g(useful)h(recursiv)o(e)f +(functions)h(ma)o(y)0 2532 y(b)q(e)d(written.)62 2670 +y(The)g Fk(noclobber)e Fl(option)h(is)h(a)o(v)m(ailable)h(to)d(a)o(v)o +(oid)h(o)o(v)o(erwriting)g(existing)h(\014les)g(with)g(output)f +(redirection.)p eop +6 7 bop 0 -58 a Fl(6)1646 b(Bash)15 b(F)l(eatures)62 +183 y(Bash)i(allo)o(ws)g(y)o(ou)f(to)g(write)g(a)g(function)i(to)e(o)o +(v)o(erride)g(a)g(builtin,)j(and)e(pro)o(vides)g(access)f(to)g(that)g +(builtin's)0 246 y(functionalit)o(y)g(within)h(the)e(function)h(via)g +(the)f Fk(builtin)f Fl(and)h Fk(command)g Fl(builtins.)62 +382 y(The)f Fk(command)e Fl(builtin)j(allo)o(ws)f(selectiv)o(e)g +(disabling)h(of)e(functions)h(when)f(command)g(lo)q(okup)h(is)g(p)q +(erformed.)62 519 y(Individual)k(builtins)g(ma)o(y)c(b)q(e)i(enabled)h +(or)e(disabled)i(using)e(the)h Fk(enable)e Fl(builtin.)62 +656 y(F)l(unctions)i(ma)o(y)f(b)q(e)h(exp)q(orted)f(to)g(c)o(hildren)i +(via)e(the)h(en)o(vironmen)o(t.)62 793 y(The)g(Bash)f +Fk(read)g Fl(builtin)i(will)g(read)f(a)f(line)h(ending)h(in)f +Fk(\\)f Fl(with)h(the)f Fk(-r)g Fl(option,)g(and)h(will)h(use)e(the)h +Fk($REPLY)0 856 y Fl(v)m(ariable)h(as)d(a)h(default)h(if)g(no)f +(argumen)o(ts)f(are)h(supplied.)62 993 y(The)j Fk(return)f +Fl(builtin)j(ma)o(y)d(b)q(e)h(used)h(to)e(ab)q(ort)g(execution)h(of)g +(scripts)g(executed)g(with)g(the)g Fk(.)g Fl(or)f Fk(source)0 +1055 y Fl(builtins.)62 1192 y(The)f Fk(umask)e Fl(builtin)k(allo)o(ws)d +(sym)o(b)q(olic)h(mo)q(de)g(argumen)o(ts)e(similar)j(to)d(those)h +(accepted)h(b)o(y)f Fk(chmod)p Fl(.)62 1329 y(The)d Fk(test)e +Fl(builtin)k(is)d(sligh)o(tly)i(di\013eren)o(t,)e(as)g(it)h(implemen)o +(ts)g(the)f(P)o(osix)g(1003.2)f(algorithm,)h(whic)o(h)h(sp)q(eci\014es) +0 1391 y(the)j(b)q(eha)o(vior)h(based)g(on)f(the)g(n)o(um)o(b)q(er)g +(of)g(argumen)o(ts.)p eop +7 8 bop 0 -58 a Fl(Chapter)15 b(2:)k(C-Shell)f(St)o(yle)d(F)l(eatures) +1254 b(7)0 183 y Fh(2)41 b(C-Shell)13 b(St)n(yle)h(F)-7 +b(eatures)62 355 y Fl(The)18 b(C-Shell)h(\()p Fk(csh)p +Fl(\))e(w)o(as)f(created)i(b)o(y)f(Bill)j(Jo)o(y)d(at)g(UC)g(Berk)o +(eley)l(.)28 b(It)18 b(is)g(generally)h(considered)f(to)f(ha)o(v)o(e)0 +417 y(b)q(etter)e(features)f(for)g(in)o(teractiv)o(e)h(use)g(than)f +(the)h(original)h(Bourne)f(shell.)21 b(Some)15 b(of)f(the)h +Fk(csh)f Fl(features)g(presen)o(t)0 480 y(in)21 b(Bash)f(include)i(job) +e(con)o(trol,)g(history)g(expansion,)h(`protected')e(redirection,)j +(and)e(sev)o(eral)g(v)m(ariables)i(for)0 542 y(con)o(trolling)16 +b(the)f(in)o(teractiv)o(e)h(b)q(eha)o(viour)g(of)f(the)g(shell)i +(\(e.g.)i Fk(IGNOREEOF)p Fl(\).)62 679 y(See)d(Chapter)f(6)g([Using)g +(History)g(In)o(teractiv)o(ely],)h(page)f(33)f(for)h(details)h(on)f +(history)g(expansion.)0 888 y Fj(2.1)33 b(Tilde)16 b(Expansion)62 +1025 y Fl(Bash)k(has)f(tilde)i(\()p Fk(~)p Fl(\))e(expansion,)i +(similar,)g(but)f(not)f(iden)o(tical,)j(to)d(that)f(of)h +Fk(csh)p Fl(.)33 b(The)19 b(follo)o(wing)i(table)0 1087 +y(sho)o(ws)15 b(what)f(unquoted)i(w)o(ords)e(b)q(eginning)k(with)d(a)g +(tilde)i(expand)e(to.)0 1233 y Fk(~)216 b Fl(The)15 b(curren)o(t)h(v)m +(alue)g(of)f Fk($HOME)p Fl(.)0 1313 y Fk(~/foo)120 b +Fl(`)p Fk($HOME/foo)p Fl(')0 1384 y Fk(~fred/foo)240 +1446 y Fl(The)15 b(sub)q(directory)i Fk(foo)d Fl(of)h(the)g(home)h +(directory)f(of)g(the)g(user)g Fk(fred)p Fl(.)0 1526 +y Fk(~+/foo)96 b Fl(`)p Fk($PWD/foo)p Fl(')0 1605 y Fk(~-)192 +b Fl(`)p Fk($OLDPWD/foo)p Fl(')62 1751 y(Bash)21 b(will)h(also)f(tilde) +h(expand)g(w)o(ords)e(follo)o(wing)h(redirection)h(op)q(erators)e(and)h +(w)o(ords)f(follo)o(wing)h(`)p Fk(=)p Fl(')f(in)0 1813 +y(assignmen)o(t)15 b(statemen)o(ts.)0 2022 y Fj(2.2)33 +b(Brace)14 b(Expansion)62 2159 y Fl(Brace)d(expansion)h(is)g(a)e(mec)o +(hanism)i(b)o(y)f(whic)o(h)h(arbitrary)e(strings)h(ma)o(y)f(b)q(e)i +(generated.)18 b(This)12 b(mec)o(hanism)f(is)0 2222 y(similar)j(to)e +Fg(pathname)g(expansion)i Fl(\(see)f(the)f(Bash)h(man)o(ual)g(page)g +(for)f(details\),)h(but)g(the)g(\014le)g(names)g(generated)0 +2284 y(need)j(not)f(exist.)21 b(P)o(atterns)14 b(to)h(b)q(e)h(brace)g +(expanded)g(tak)o(e)f(the)h(form)e(of)h(an)h(optional)g +Fg(pream)o(ble)p Fl(,)f(follo)o(w)o(ed)h(b)o(y)0 2346 +y(a)h(series)g(of)g(comma-separated)f(strings)h(b)q(et)o(w)o(een)g(a)g +(pair)h(of)e(braces,)h(follo)o(w)o(ed)h(b)o(y)f(an)g(optional)g +Fg(p)q(ostam)o(ble)p Fl(.)0 2408 y(The)f(pream)o(ble)h(is)f(prep)q +(ended)i(to)d(eac)o(h)h(string)g(con)o(tained)h(within)g(the)f(braces,) +g(and)g(the)g(p)q(ostam)o(ble)g(is)h(then)0 2471 y(app)q(ended)g(to)d +(eac)o(h)i(resulting)g(string,)f(expanding)h(left)g(to)e(righ)o(t.)62 +2608 y(Brace)19 b(expansions)g(ma)o(y)f(b)q(e)i(nested.)30 +b(The)19 b(results)g(of)f(eac)o(h)h(expanded)h(string)f(are)f(not)g +(sorted;)i(left)f(to)0 2670 y(righ)o(t)c(order)g(is)h(preserv)o(ed.)k +(F)l(or)14 b(example,)p eop +8 9 bop 0 -58 a Fl(8)1646 b(Bash)15 b(F)l(eatures)120 +183 y Fk(a{d,c,b}e)62 322 y Fl(expands)h(in)o(to)f Fg(ade)h(ace)f(ab)q +(e)p Fl(.)62 461 y(Brace)h(expansion)g(is)g(p)q(erformed)g(b)q(efore)g +(an)o(y)f(other)g(expansions,)h(and)g(an)o(y)f(c)o(haracters)g(sp)q +(ecial)i(to)e(other)0 524 y(expansions)k(are)f(preserv)o(ed)h(in)g(the) +f(result.)30 b(It)18 b(is)h(strictly)g(textual.)29 b(Bash)18 +b(do)q(es)h(not)f(apply)h(an)o(y)f(syn)o(tactic)0 586 +y(in)o(terpretation)d(to)g(the)g(con)o(text)g(of)g(the)g(expansion)h +(or)f(the)g(text)g(b)q(et)o(w)o(een)g(the)g(braces.)62 +725 y(A)h(correctly-formed)f(brace)h(expansion)g(m)o(ust)f(con)o(tain)g +(unquoted)h(op)q(ening)h(and)e(closing)i(braces,)e(and)h(at)0 +787 y(least)f(one)h(unquoted)f(comma.)20 b(An)o(y)15 +b(incorrectly)h(formed)f(brace)g(expansion)h(is)g(left)g(unc)o(hanged.) +62 926 y(This)22 b(construct)f(is)h(t)o(ypically)h(used)f(as)f +(shorthand)g(when)h(the)f(common)g(pre\014x)h(of)f(the)g(strings)h(to)e +(b)q(e)0 988 y(generated)15 b(is)h(longer)f(than)g(in)h(the)g(ab)q(o)o +(v)o(e)f(example:)120 1115 y Fk(mkdir)23 b(/usr/local/src/bash/{old,ne) +o(w,dist,b)o(ugs})62 1254 y Fl(or)120 1380 y Fk(chown)g(root)g +(/usr/{ucb/{ex,edit},lib/{ex?.?)o(*,how_e)o(x}})0 1623 +y Fj(2.3)33 b(C)14 b(Shell)j(Builtins)62 1762 y Fl(Bash)f(has)f(sev)o +(eral)g(builtin)i(commands)e(whose)h(de\014nition)h(is)e(v)o(ery)g +(similar)h(to)f Fk(csh)p Fl(.)0 1915 y Fk(pushd)360 1979 +y(pushd)23 b([)p Fg(dir)28 b Fk(|)c(+)p Fg(n)g Fk(|)f +Fg(-n)p Fk(])240 2056 y Fl(Sa)o(v)o(e)14 b(the)g(curren)o(t)h +(directory)f(on)g(a)g(list)i(and)e(then)h Fk(cd)f Fl(to)f +Fg(dir)p Fl(.)21 b(With)14 b(no)h(argumen)o(ts,)e(exc)o(hanges)240 +2118 y(the)i(top)g(t)o(w)o(o)f(directories.)240 2210 +y Fk(+)p Fg(n)191 b Fl(Brings)13 b(the)f Fg(n)p Fl(th)h(directory)f +(\(coun)o(ting)h(from)e(the)i(left)f(of)g(the)g(list)i(prin)o(ted)f(b)o +(y)f Fk(dirs)p Fl(\))480 2272 y(to)j(the)g(top)g(of)f(the)i(list)g(b)o +(y)f(rotating)f(the)h(stac)o(k.)240 2363 y Fk(-)p Fg(n)191 +b Fl(Brings)21 b(the)f Fg(n)p Fl(th)g(directory)h(\(coun)o(ting)f(from) +g(the)g(righ)o(t)g(of)g(the)g(list)h(prin)o(ted)g(b)o(y)480 +2425 y Fk(dirs)p Fl(\))14 b(to)h(the)g(top)g(of)g(the)g(list)h(b)o(y)f +(rotating)f(the)i(stac)o(k.)240 2517 y Fg(dir)185 b Fl(Mak)o(es)14 +b(the)g(curren)o(t)h(w)o(orking)f(directory)g(b)q(e)i(the)e(top)g(of)g +(the)h(stac)o(k,)e(and)i(then)g Fg(cd)r Fl(s)480 2579 +y(to)g Fg(dir)p Fl(.)20 b(Y)l(ou)c(can)f(see)g(the)h(sa)o(v)o(ed)e +(directory)i(list)g(with)f(the)h Fk(dirs)e Fl(command.)0 +2670 y Fk(popd)p eop +9 10 bop 0 -58 a Fl(Chapter)15 b(2:)k(C-Shell)f(St)o(yle)d(F)l(eatures) +1254 b(9)360 183 y Fk(popd)23 b([+)p Fg(n)h Fk(|)g(-)p +Fg(n)p Fk(])240 265 y Fl(P)o(ops)17 b(the)g(directory)h(stac)o(k,)f +(and)h Fk(cd)p Fl(s)f(to)f(the)i(new)g(top)f(directory)l(.)27 +b(When)17 b(no)h(argumen)o(ts)e(are)240 327 y(giv)o(en,)f(remo)o(v)o +(es)e(the)i(top)e(directory)i(from)f(the)g(stac)o(k)g(and)g +Fk(cd)p Fl(s)g(to)g(the)g(new)h(top)f(directory)l(.)20 +b(The)240 389 y(elemen)o(ts)14 b(are)g(n)o(um)o(b)q(ered)g(from)f(0)g +(starting)g(at)g(the)h(\014rst)f(directory)h(listed)h(with)f +Fk(dirs)p Fl(;)f(i.e.)20 b Fk(popd)240 452 y Fl(is)c(equiv)m(alen)o(t)h +(to)d Fk(popd)h(+0)p Fl(.)240 553 y Fk(+)p Fg(n)191 b +Fl(Remo)o(v)o(es)19 b(the)g Fg(n)p Fl(th)g(directory)g(\(coun)o(ting)g +(from)f(the)i(left)f(of)f(the)h(list)h(prin)o(ted)g(b)o(y)480 +615 y Fk(dirs)p Fl(\),)14 b(starting)g(with)i(zero.)240 +716 y Fk(-)p Fg(n)191 b Fl(Remo)o(v)o(es)16 b(the)h Fg(n)p +Fl(th)f(directory)h(\(coun)o(ting)g(from)e(the)i(righ)o(t)f(of)g(the)h +(list)g(prin)o(ted)g(b)o(y)480 778 y Fk(dirs)p Fl(\),)d(starting)g +(with)i(zero.)0 879 y Fk(dirs)360 948 y(dirs)23 b([+)p +Fg(n)h Fk(|)g(-)p Fg(n)p Fk(])g([-)p Fg(l)r Fk(])240 +1030 y Fl(Displa)o(y)19 b(the)f(list)i(of)d(curren)o(tly)i(remem)o(b)q +(ered)g(directories.)31 b(Directories)19 b(\014nd)g(their)g(w)o(a)o(y)e +(on)o(to)240 1092 y(the)e(list)h(with)g(the)f Fk(pushd)f +Fl(command;)h(y)o(ou)g(can)g(get)g(bac)o(k)g(up)h(through)f(the)g(list) +h(with)f(the)h Fk(popd)240 1155 y Fl(command.)240 1256 +y Fk(+)p Fg(n)191 b Fl(Displa)o(ys)20 b(the)g Fg(n)p +Fl(th)f(directory)h(\(coun)o(ting)g(from)f(the)h(left)f(of)h(the)f +(list)i(prin)o(ted)f(b)o(y)480 1318 y Fk(dirs)15 b Fl(when)g(in)o(v)o +(ok)o(ed)h(without)f(options\),)g(starting)f(with)i(zero.)240 +1419 y Fk(-)p Fg(n)191 b Fl(Displa)o(ys)18 b(the)f Fg(n)p +Fl(th)g(directory)g(\(coun)o(ting)g(from)g(the)g(righ)o(t)g(of)f(the)h +(list)h(prin)o(ted)g(b)o(y)480 1481 y Fk(dirs)d Fl(when)g(in)o(v)o(ok)o +(ed)h(without)f(options\),)g(starting)f(with)i(zero.)240 +1582 y Fk(-)p Fg(l)204 b Fl(Pro)q(duces)16 b(a)g(longer)g(listing;)i +(the)e(default)g(listing)i(format)c(uses)i(a)g(tilde)h(to)f(denote)480 +1644 y(the)f(home)g(directory)l(.)0 1745 y Fk(history)360 +1815 y(history)23 b([)p Fg(n)p Fk(])h([)f([-w)h(-r)g(-a)f(-n])h([)p +Fg(\014lename)s Fk(]])240 1896 y Fl(Displa)o(y)c(the)g(history)g(list)h +(with)f(line)i(n)o(um)o(b)q(ers.)34 b(Lines)21 b(pre\014xed)g(with)f +(with)g(a)g Fk(*)f Fl(ha)o(v)o(e)h(b)q(een)240 1958 y(mo)q(di\014ed.)25 +b(An)17 b(argumen)o(t)f(of)g Fg(n)g Fl(sa)o(ys)g(to)g(list)h(only)g +(the)g(last)f Fg(n)h Fl(lines.)25 b(Option)17 b Fk(-w)f +Fl(means)h(write)240 2021 y(out)i(the)g(curren)o(t)g(history)g(to)f +(the)i(history)f(\014le;)i Fk(-r)e Fl(means)g(to)g(read)g(the)g(curren) +o(t)g(history)g(\014le)240 2083 y(and)e(mak)o(e)g(its)g(con)o(ten)o(ts) +f(the)h(history)g(list.)26 b(An)18 b(argumen)o(t)e(of)g +Fk(-a)h Fl(means)g(to)f(app)q(end)j(the)e(new)240 2145 +y(history)f(lines)i(\(history)d(lines)j(en)o(tered)e(since)h(the)f(b)q +(eginning)j(of)c(the)h(curren)o(t)g(Bash)g(session\))h(to)240 +2208 y(the)g(history)f(\014le.)25 b(Finally)l(,)18 b(the)f +Fk(-n)f Fl(argumen)o(t)g(means)h(to)f(read)g(the)h(history)f(lines)i +(not)f(already)240 2270 y(read)i(from)g(the)g(history)g(\014le)h(in)o +(to)f(the)h(curren)o(t)f(history)g(list.)33 b(These)19 +b(are)g(lines)i(app)q(ended)g(to)240 2332 y(the)d(history)h(\014le)g +(since)g(the)g(b)q(eginning)h(of)e(the)g(curren)o(t)h(Bash)f(session.) +30 b(If)18 b Fg(\014lename)k Fl(is)d(giv)o(en,)240 2394 +y(then)c(it)f(is)h(used)g(as)e(the)i(history)f(\014le,)h(else)g(if)g +Fk($HISTFILE)e Fl(has)h(a)g(v)m(alue,)h(that)e(is)i(used,)g(otherwise) +240 2457 y(`)p Fk(~/.bash_history)p Fl(')d(is)k(used.)0 +2558 y Fk(logout)96 b Fl(Exit)15 b(a)g(login)h(shell.)0 +2659 y Fk(source)96 b Fl(A)15 b(synon)o(ym)g(for)g Fk(.)g +Fl(\(see)g(Section)h(1.4)e([Bourne)h(Shell)j(Builtins],)e(page)f(3\))p +eop +10 11 bop 0 -58 a Fl(10)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fj(2.4)33 b(C)14 b(Shell)j(V)-6 b(ariables)0 320 +y Fk(IGNOREEOF)240 382 y Fl(If)12 b(this)h(v)m(ariable)g(is)g(set,)f +(it)h(represen)o(ts)f(the)g(n)o(um)o(b)q(er)g(of)g(consecutiv)o(e)h +Fk(EOF)p Fl(s)f(Bash)g(will)i(read)e(b)q(efore)240 445 +y(exiting.)21 b(By)15 b(default,)h(Bash)f(will)i(exit)e(up)q(on)h +(reading)g(a)f(single)h Fk(EOF)p Fl(.)0 519 y Fk(cdable_vars)240 +582 y Fl(If)g(this)g(v)m(ariable)i(is)e(set,)g(Bash)g(treats)e(argumen) +o(ts)h(to)h(the)g Fk(cd)f Fl(command)h(whic)o(h)h(are)e(not)h(direc-) +240 644 y(tories)f(as)g(names)g(of)g(v)m(ariables)h(whose)f(v)m(alues)i +(are)e(the)g(directories)h(to)f(c)o(hange)g(to.)p eop +11 12 bop 0 -58 a Fl(Chapter)15 b(3:)k(Korn)d(Shell)h(St)o(yle)e(F)l +(eatures)1164 b(11)0 183 y Fh(3)41 b(Korn)15 b(Shell)f(St)n(yle)g(F)-7 +b(eatures)62 373 y Fl(This)23 b(section)g(describ)q(es)h(features)e +(primarily)h(inspired)h(b)o(y)f(the)f(Korn)g(Shell)j(\()p +Fk(ksh)p Fl(\).)40 b(In)22 b(some)g(cases,)0 435 y(the)17 +b(P)o(osix)f(1003.2)f(standard)h(has)h(adopted)g(these)f(commands)h +(and)g(v)m(ariables)h(from)e(the)g(Korn)h(Shell;)i(Bash)0 +498 y(implemen)o(ts)d(those)f(features)g(using)h(the)f(P)o(osix)h +(standard)e(as)h(a)g(guide.)0 728 y Fj(3.1)33 b(Korn)15 +b(Shell)i(Constructs)62 865 y Fl(Bash)h(includes)j(the)d(Korn)g(Shell)i +Fk(select)d Fl(construct.)28 b(This)18 b(construct)g(allo)o(ws)g(the)g +(easy)g(generation)g(of)0 928 y(men)o(us.)i(It)15 b(has)g(almost)g(the) +g(same)g(syn)o(tax)g(as)g(the)g Fk(for)g Fl(command.)62 +1065 y(The)h(syn)o(tax)e(of)h(the)g Fk(select)g Fl(command)g(is:)120 +1190 y Fk(select)23 b Fg(name)k Fk([in)c Fg(w)o(ords)i +Fk(...];)e(do)h Fg(commands)r Fk(;)f(done)62 1328 y Fl(The)13 +b(list)g(of)g(w)o(ords)e(follo)o(wing)j Fk(in)e Fl(is)h(expanded,)h +(generating)f(a)f(list)h(of)f(items.)20 b(The)13 b(set)f(of)g(expanded) +i(w)o(ords)0 1390 y(is)19 b(prin)o(ted)g(on)g(the)f(standard)g(error,)g +(eac)o(h)h(preceded)h(b)o(y)e(a)g(n)o(um)o(b)q(er.)30 +b(If)19 b(the)f(\\)p Fk(in)d Fg(w)o(ords)r Fl(")i(is)i(omitted,)g(the)0 +1452 y(p)q(ositional)g(parameters)d(are)h(prin)o(ted.)26 +b(The)18 b Fk(PS3)e Fl(prompt)h(is)h(then)f(displa)o(y)o(ed)i(and)e(a)g +(line)i(is)e(read)g(from)g(the)0 1515 y(standard)h(input.)32 +b(If)19 b(the)g(line)h(consists)f(of)g(the)g(n)o(um)o(b)q(er)g(corresp) +q(onding)h(to)e(one)h(of)f(the)h(displa)o(y)o(ed)h(w)o(ords,)0 +1577 y(then)13 b(the)g(v)m(alue)h(of)e Fg(name)k Fl(is)d(set)f(to)g +(that)g(w)o(ord.)19 b(If)13 b(the)g(line)h(is)f(empt)o(y)l(,)g(the)g(w) +o(ords)f(and)h(prompt)f(are)h(displa)o(y)o(ed)0 1639 +y(again.)19 b(If)14 b Fk(EOF)g Fl(is)g(read,)f(the)h +Fk(select)f Fl(command)h(completes.)20 b(An)o(y)14 b(other)f(v)m(alue)i +(read)e(causes)h Fg(name)j Fl(to)c(b)q(e)h(set)0 1702 +y(to)h(n)o(ull.)21 b(The)15 b(line)i(read)e(is)h(sa)o(v)o(ed)f(in)h +(the)f(v)m(ariable)i Fk(REPLY)p Fl(.)62 1839 y(The)d +Fg(commands)h Fl(are)f(executed)g(after)f(eac)o(h)g(selection)i(un)o +(til)g(a)e Fk(break)g Fl(or)g Fk(return)g Fl(command)g(is)h(executed,)0 +1901 y(at)h(whic)o(h)h(p)q(oin)o(t)f(the)h Fk(select)e +Fl(command)h(completes.)0 2131 y Fj(3.2)33 b(Korn)15 +b(Shell)i(Builtins)62 2269 y Fl(This)f(section)g(describ)q(es)h(Bash)e +(builtin)i(commands)e(tak)o(en)g(from)g Fk(ksh)p Fl(.)0 +2420 y Fk(fc)360 2483 y(fc)24 b([-e)f Fg(ename)s Fk(])h([-nlr])f([)p +Fg(\014rst)q Fk(])g([)p Fg(last)q Fk(])360 2532 y(fc)h(-s)f([)p +Fg(pat=rep)q Fk(])h([)p Fg(command)r Fk(])240 2608 y +Fl(Fix)19 b(Command.)29 b(In)20 b(the)e(\014rst)h(form,)f(a)g(range)g +(of)h(commands)f(from)g Fg(\014rst)h Fl(to)f Fg(last)i +Fl(is)f(selected)240 2670 y(from)f(the)g(history)h(list.)30 +b(Both)18 b Fg(\014rst)h Fl(and)g Fg(last)g Fl(ma)o(y)f(b)q(e)h(sp)q +(eci\014ed)i(as)d(a)g(string)h(\(to)e(lo)q(cate)i(the)p +eop +12 13 bop 0 -58 a Fl(12)1623 b(Bash)15 b(F)l(eatures)240 +183 y(most)h(recen)o(t)h(command)g(b)q(eginning)i(with)f(that)e +(string\))h(or)f(as)h(a)g(n)o(um)o(b)q(er)g(\(an)g(index)h(in)o(to)f +(the)240 246 y(history)g(list,)h(where)g(a)f(negativ)o(e)g(n)o(um)o(b)q +(er)h(is)g(used)g(as)f(an)g(o\013set)f(from)h(the)g(curren)o(t)g +(command)240 308 y(n)o(um)o(b)q(er\).)k(If)15 b Fg(last)i +Fl(is)f(not)f(sp)q(eci\014ed)i(it)f(is)g(set)f(to)g Fg(\014rst)p +Fl(.)21 b(If)15 b Fg(\014rst)h Fl(is)g(not)f(sp)q(eci\014ed)j(it)e(is)g +(set)f(to)g(the)240 370 y(previous)f(command)g(for)e(editing)j(and)f +(-16)f(for)g(listing.)20 b(If)14 b(the)g Fk(-l)f Fl(\015ag)g(is)h(giv)o +(en,)g(the)f(commands)240 432 y(are)19 b(listed)i(on)e(standard)g +(output.)32 b(The)19 b Fk(-n)g Fl(\015ag)g(suppresses)h(the)g(command)f +(n)o(um)o(b)q(ers)g(when)240 495 y(listing.)31 b(The)18 +b Fk(-r)g Fl(\015ag)h(rev)o(erses)f(the)g(order)g(of)g(the)h(listing.) +30 b(Otherwise,)20 b(the)f(editor)f(giv)o(en)h(b)o(y)240 +557 y Fg(ename)d Fl(is)d(in)o(v)o(ok)o(ed)h(on)f(a)g(\014le)h(con)o +(taining)g(those)e(commands.)19 b(If)14 b Fg(ename)i +Fl(is)d(not)g(giv)o(en,)h(the)f(v)m(alue)240 619 y(of)h(the)g(follo)o +(wing)i(v)m(ariable)f(expansion)h(is)f(used:)20 b Fk +(${FCEDIT:-${EDITOR:-vi}})o Fl(.)d(This)e(sa)o(ys)f(to)240 +681 y(use)g(the)g(v)m(alue)g(of)f(the)h Fk(FCEDIT)f Fl(v)m(ariable)i +(if)f(set,)f(or)g(the)h(v)m(alue)g(of)f(the)h Fk(EDITOR)f +Fl(v)m(ariable)i(if)f(that)e(is)240 744 y(set,)i(or)g +Fk(vi)h Fl(if)g(neither)h(is)f(set.)20 b(When)15 b(editing)h(is)f +(complete,)g(the)g(edited)h(commands)f(are)f(ec)o(ho)q(ed)240 +806 y(and)h(executed.)240 881 y(In)h(the)g(second)g(form,)f +Fg(command)i Fl(is)f(re-executed)h(after)e(eac)o(h)h(instance)g(of)f +Fg(pat)i Fl(in)f(the)g(selected)240 944 y(command)f(is)h(replaced)g(b)o +(y)f Fg(rep)p Fl(.)240 1019 y(A)20 b(useful)i(alias)f(to)e(use)i(with)f +(the)h Fk(fc)f Fl(command)g(is)h Fk(r='fc)14 b(-s')p +Fl(,)21 b(so)f(that)f(t)o(yping)i Fk(r)15 b(cc)20 b Fl(runs)240 +1081 y(the)c(last)g(command)h(b)q(eginning)h(with)f Fk(cc)e +Fl(and)i(t)o(yping)f Fk(r)g Fl(re-executes)h(the)g(last)f(command)g +(\(see)240 1144 y(Section)g(3.4)e([Aliases],)h(page)h(13\).)0 +1232 y Fk(let)168 b Fl(The)15 b Fk(let)f Fl(builtin)j(allo)o(ws)d +(arithmetic)h(to)f(b)q(e)i(p)q(erformed)e(on)h(shell)h(v)m(ariables.)21 +b(F)l(or)14 b(details,)h(refer)240 1294 y(to)g(Section)h(4.7.3)d +([Arithmetic)j(Builtins],)h(page)e(26.)0 1383 y Fk(typeset)72 +b Fl(The)17 b Fk(typeset)f Fl(command)h(is)h(supplied)h(for)d +(compatibilit)o(y)j(with)e(the)g(Korn)g(shell;)i(ho)o(w)o(ev)o(er,)e +(it)240 1445 y(has)j(b)q(een)i(made)f(obsolete)g(b)o(y)f(the)h +Fk(declare)e Fl(command)i(\(see)f(Section)i(4.4)d([Bash)i(Builtins],) +240 1508 y(page)15 b(17\).)0 1738 y Fj(3.3)33 b(Korn)15 +b(Shell)i(V)-6 b(ariables)0 1889 y Fk(REPLY)120 b Fl(The)15 +b(default)h(v)m(ariable)h(for)d(the)i Fk(read)e Fl(builtin.)0 +1978 y Fk(RANDOM)96 b Fl(Eac)o(h)19 b(time)h(this)f(parameter)g(is)h +(referenced,)h(a)e(random)f(in)o(teger)i(is)g(generated.)32 +b(Assigning)20 b(a)240 2040 y(v)m(alue)c(to)f(this)h(v)m(ariable)g +(seeds)g(the)f(random)g(n)o(um)o(b)q(er)g(generator.)0 +2129 y Fk(SECONDS)72 b Fl(This)13 b(v)m(ariable)g(expands)g(to)e(the)h +(n)o(um)o(b)q(er)g(of)g(seconds)h(since)g(the)f(shell)h(w)o(as)f +(started.)18 b(Assignmen)o(t)240 2191 y(to)12 b(this)i(v)m(ariable)g +(resets)e(the)h(coun)o(t)g(to)f(the)h(v)m(alue)i(assigned,)e(and)g(the) +g(expanded)h(v)m(alue)g(b)q(ecomes)240 2253 y(the)h(v)m(alue)i +(assigned)f(plus)g(the)f(n)o(um)o(b)q(er)h(of)e(seconds)i(since)g(the)g +(assignmen)o(t.)0 2342 y Fk(PS3)168 b Fl(The)15 b(v)m(alue)i(of)e(this) +g(v)m(ariable)i(is)f(used)f(as)g(the)g(prompt)g(for)g(the)g +Fk(select)f Fl(command.)0 2430 y Fk(PS4)168 b Fl(This)18 +b(is)f(the)g(prompt)g(prin)o(ted)h(b)q(efore)f(the)g(command)g(line)i +(is)f(ec)o(ho)q(ed)g(when)f(the)g Fk(-x)g Fl(option)g(is)240 +2493 y(set)e(\(see)g(Section)h(4.5)e([The)i(Set)f(Builtin],)h(page)g +(20\).)0 2581 y Fk(PWD)168 b Fl(The)15 b(curren)o(t)h(w)o(orking)e +(directory)i(as)f(set)g(b)o(y)g(the)g Fk(cd)g Fl(builtin.)0 +2670 y Fk(OLDPWD)96 b Fl(The)15 b(previous)h(w)o(orking)f(directory)h +(as)e(set)h(b)o(y)h(the)f Fk(cd)g Fl(builtin.)p eop +13 14 bop 0 -58 a Fl(Chapter)15 b(3:)k(Korn)d(Shell)h(St)o(yle)e(F)l +(eatures)1164 b(13)0 183 y Fk(TMOUT)120 b Fl(If)14 b(set)g(to)g(a)g(v)m +(alue)h(greater)e(than)h(zero,)g(the)g(v)m(alue)i(is)e(in)o(terpreted)h +(as)f(the)g(n)o(um)o(b)q(er)g(of)g(seconds)h(to)240 246 +y(w)o(ait)f(for)f(input)i(after)e(issuing)i(the)g(primary)f(prompt.)19 +b(Bash)14 b(terminates)g(after)f(that)g(n)o(um)o(b)q(er)h(of)240 +308 y(seconds)i(if)f(input)i(do)q(es)e(not)g(arriv)o(e.)0 +528 y Fj(3.4)33 b(Aliases)62 665 y Fl(The)19 b(shell)i(main)o(tains)e +(a)f(list)i(of)e Fg(aliases)k Fl(that)c(ma)o(y)g(b)q(e)h(set)g(and)g +(unset)g(with)g(the)g Fk(alias)f Fl(and)h Fk(unalias)0 +727 y Fl(builtin)e(commands.)62 864 y(The)i(\014rst)f(w)o(ord)f(of)h +(eac)o(h)h(command,)f(if)h(unquoted,)g(is)g(c)o(hec)o(k)o(ed)g(to)f +(see)g(if)h(it)g(has)f(an)g(alias.)30 b(If)18 b(so,)h(that)0 +927 y(w)o(ord)12 b(is)i(replaced)g(b)o(y)f(the)g(text)f(of)h(the)g +(alias.)20 b(The)13 b(alias)h(name)f(and)g(the)g(replacemen)o(t)g(text) +g(ma)o(y)f(con)o(tain)h(an)o(y)0 989 y(v)m(alid)18 b(shell)h(input,)f +(including)h(shell)g(metac)o(haracters,)c(with)i(the)g(exception)h +(that)e(the)h(alias)g(name)g(ma)o(y)f(not)0 1051 y(con)o(tain)g +Fk(=)p Fl(.)k(The)c(\014rst)f(w)o(ord)f(of)h(the)h(replacemen)o(t)g +(text)f(is)h(tested)f(for)g(aliases,)h(but)g(a)f(w)o(ord)f(that)h(is)h +(iden)o(tical)0 1113 y(to)g(an)h(alias)h(b)q(eing)g(expanded)g(is)g +(not)e(expanded)i(a)f(second)h(time.)25 b(This)18 b(means)f(that)f(one) +h(ma)o(y)f(alias)i Fk(ls)f Fl(to)0 1176 y Fk("ls)e(-F")p +Fl(,)j(for)f(instance,)j(and)e(Bash)g(do)q(es)h(not)f(try)f(to)h +(recursiv)o(ely)h(expand)g(the)f(replacemen)o(t)h(text.)28 +b(If)19 b(the)0 1238 y(last)14 b(c)o(haracter)f(of)h(the)g(alias)h(v)m +(alue)g(is)g(a)e(space)i(or)e(tab)h(c)o(haracter,)f(then)i(the)f(next)g +(command)g(w)o(ord)f(follo)o(wing)0 1300 y(the)i(alias)h(is)g(also)f(c) +o(hec)o(k)o(ed)h(for)e(alias)i(expansion.)62 1437 y(Aliases)i(are)f +(created)g(and)g(listed)h(with)f(the)g Fk(alias)g Fl(command,)f(and)h +(remo)o(v)o(ed)g(with)g(the)g Fk(unalias)f Fl(com-)0 +1499 y(mand.)62 1636 y(There)i(is)h(no)f(mec)o(hanism)g(for)f(using)i +(argumen)o(ts)e(in)i(the)f(replacemen)o(t)g(text,)g(as)f(in)i +Fk(csh)p Fl(.)28 b(If)18 b(argumen)o(ts)0 1699 y(are)d(needed,)h(a)f +(shell)i(function)f(should)g(b)q(e)g(used.)62 1836 y(Aliases)h(are)d +(not)h(expanded)i(when)e(the)g(shell)i(is)f(not)f(in)o(teractiv)o(e.)62 +1973 y(The)d(rules)g(concerning)g(the)g(de\014nition)h(and)e(use)h(of)f +(aliases)h(are)e(somewhat)h(confusing.)19 b(Bash)12 b(alw)o(a)o(ys)e +(reads)0 2035 y(at)k(least)h(one)g(complete)h(line)g(of)f(input)g(b)q +(efore)h(executing)g(an)o(y)e(of)g(the)h(commands)g(on)g(that)f(line.) +21 b(Aliases)16 b(are)0 2097 y(expanded)c(when)g(a)f(command)g(is)g +(read,)h(not)f(when)g(it)h(is)f(executed.)20 b(Therefore,)11 +b(an)g(alias)h(de\014nition)h(app)q(earing)0 2159 y(on)h(the)g(same)g +(line)h(as)f(another)f(command)h(do)q(es)h(not)e(tak)o(e)g(e\013ect)h +(un)o(til)h(the)f(next)g(line)i(of)d(input)i(is)g(read.)k(This)0 +2222 y(means)f(that)f(the)h(commands)f(follo)o(wing)i(the)f(alias)g +(de\014nition)i(on)d(that)g(line)j(are)d(not)h(a\013ected)f(b)o(y)h +(the)g(new)0 2284 y(alias.)24 b(This)16 b(b)q(eha)o(vior)h(is)g(also)f +(an)g(issue)h(when)g(functions)g(are)f(executed.)24 b(Aliases)17 +b(are)f(expanded)h(when)g(the)0 2346 y(function)e(de\014nition)h(is)e +(read,)g(not)f(when)i(the)f(function)g(is)h(executed,)g(b)q(ecause)f(a) +g(function)h(de\014nition)h(is)e(itself)0 2408 y(a)g(comp)q(ound)g +(command.)20 b(As)13 b(a)h(consequence,)h(aliases)g(de\014ned)g(in)g(a) +e(function)i(are)f(not)f(a)o(v)m(ailable)j(un)o(til)f(after)0 +2471 y(that)i(function)h(is)g(executed.)27 b(T)l(o)17 +b(b)q(e)h(safe,)f(alw)o(a)o(ys)g(put)g(alias)h(de\014nitions)h(on)f(a)f +(separate)f(line,)k(and)d(do)g(not)0 2533 y(use)f Fk(alias)e +Fl(in)i(comp)q(ound)g(commands.)62 2670 y(Note)f(that)g(for)f(almost)h +(ev)o(ery)g(purp)q(ose,)g(aliases)h(are)f(sup)q(erseded)i(b)o(y)e +(shell)i(functions.)p eop +14 15 bop 0 -58 a Fl(14)1623 b(Bash)15 b(F)l(eatures)0 +183 y Ff(3.4.1)30 b(Alias)15 b(Builtins)0 333 y Fk(alias)360 +395 y(alias)23 b([)p Fg(name)s Fk([=)p Fg(v)m(alue)s +Fk(])h(...])240 470 y Fl(Without)16 b(argumen)o(ts,)e(prin)o(t)i(the)g +(list)g(of)g(aliases)g(on)f(the)h(standard)f(output.)22 +b(If)15 b(argumen)o(ts)g(are)240 532 y(supplied,)k(an)e(alias)g(is)g +(de\014ned)h(for)e(eac)o(h)h Fg(name)i Fl(whose)d Fg(v)m(alue)21 +b Fl(is)c(giv)o(en.)25 b(If)17 b(no)f Fg(v)m(alue)21 +b Fl(is)c(giv)o(en,)240 594 y(the)e(name)g(and)h(v)m(alue)g(of)f(the)g +(alias)h(is)g(prin)o(ted.)0 681 y Fk(unalias)360 744 +y(unalias)23 b([-a])g([)p Fg(name)k Fk(...)c(])240 818 +y Fl(Remo)o(v)o(e)15 b(eac)o(h)g Fg(name)j Fl(from)d(the)g(list)h(of)f +(aliases.)20 b(If)c Fk(-a)f Fl(is)g(supplied,)i(all)g(aliases)e(are)g +(remo)o(v)o(ed.)p eop +15 16 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(15)0 183 y Fh(4)41 b(Bash)15 b(Sp)r(eci\014c)f(F)-7 +b(eatures)62 369 y Fl(This)16 b(section)g(describ)q(es)h(the)e +(features)g(unique)h(to)f(Bash.)0 593 y Fj(4.1)33 b(In)n(v)n(oking)17 +b(Bash)62 730 y Fl(In)c(addition)h(to)e(the)h(single-c)o(haracter)g +(shell)h(command-line)g(options)f(\(see)f(Section)i(4.5)d([The)i(Set)f +(Builtin],)0 792 y(page)17 b(20\),)f(there)h(are)g(sev)o(eral)h(m)o +(ulti-c)o(haracter)f(options)g(that)g(y)o(ou)f(can)i(use.)26 +b(These)17 b(options)g(m)o(ust)g(app)q(ear)0 854 y(on)e(the)g(command)g +(line)i(b)q(efore)f(the)f(single-c)o(haracter)h(options)f(to)g(b)q(e)h +(recognized.)0 1003 y Fk(-norc)120 b Fl(Don't)20 b(read)h(the)g(`)p +Fk(~/.bashrc)p Fl(')e(initialization)24 b(\014le)e(in)g(an)f(in)o +(teractiv)o(e)g(shell.)39 b(This)22 b(is)f(on)g(b)o(y)240 +1066 y(default)16 b(if)f(the)h(shell)h(is)e(in)o(v)o(ok)o(ed)h(as)e +Fk(sh)p Fl(.)0 1140 y Fk(-rcfile)g Fg(\014lename)240 +1203 y Fl(Execute)i(commands)f(from)f Fg(\014lename)19 +b Fl(\(instead)c(of)g(`)p Fk(~/.bashrc)p Fl('\))e(in)j(an)f(in)o +(teractiv)o(e)h(shell.)0 1277 y Fk(-noprofile)240 1339 +y Fl(Don't)k(load)h(the)h(system-wide)f(startup)g(\014le)h(`)p +Fk(/etc/profile)p Fl(')c(or)j(an)o(y)g(of)f(the)i(p)q(ersonal)f(ini-) +240 1402 y(tialization)g(\014les)g(`)p Fk(~/.bash_profile)p +Fl(',)d(`)p Fk(~/.bash_login)p Fl(',)g(or)h(`)p Fk(~/.profile)p +Fl(')f(when)i(bash)g(is)240 1464 y(in)o(v)o(ok)o(ed)15 +b(as)g(a)g(login)h(shell.)0 1551 y Fk(-version)48 b Fl(Displa)o(y)16 +b(the)f(v)o(ersion)g(n)o(um)o(b)q(er)h(of)f(this)g(shell.)0 +1637 y Fk(-login)96 b Fl(Mak)o(e)13 b(this)h(shell)h(act)e(as)g(if)h +(it)g(w)o(ere)g(directly)h(in)o(v)o(ok)o(ed)e(from)g(login.)20 +b(This)15 b(is)f(equiv)m(alen)o(t)h(to)e(`)p Fk(exec)240 +1700 y(-)i(bash)p Fl(')i(but)h(can)g(b)q(e)h(issued)g(from)f(another)f +(shell,)j(suc)o(h)f(as)e Fk(csh)p Fl(.)28 b(If)18 b(y)o(ou)g(w)o(an)o +(ted)g(to)f(replace)240 1762 y(y)o(our)e(curren)o(t)g(login)h(shell)h +(with)e(a)g(Bash)g(login)h(shell,)h(y)o(ou)e(w)o(ould)g(sa)o(y)g(`)p +Fk(exec)f(bash)h(-login)p Fl('.)0 1837 y Fk(-nobraceexpansion)240 +1899 y Fl(Do)g(not)f(p)q(erform)h(curly)h(brace)g(expansion)g(\(see)f +(Section)h(2.2)e([Brace)h(Expansion],)g(page)g(7\).)0 +1973 y Fk(-nolineediting)240 2036 y Fl(Do)c(not)g(use)h(the)f(GNU)h +(Readline)h(library)g(\(see)e(Chapter)g(7)g([Command)g(Line)i +(Editing],)g(page)e(37\))240 2098 y(to)k(read)g(in)o(teractiv)o(e)g +(command)g(lines.)0 2185 y Fk(-posix)96 b Fl(Change)14 +b(the)g(b)q(eha)o(vior)g(of)f(Bash)h(where)g(the)g(default)g(op)q +(eration)g(di\013ers)g(from)f(the)h(P)o(osix)g(1003.2)240 +2247 y(standard)19 b(to)g(matc)o(h)g(the)h(standard.)32 +b(This)20 b(is)g(in)o(tended)h(to)e(mak)o(e)g(Bash)h(b)q(eha)o(v)o(e)g +(as)f(a)g(strict)240 2309 y(sup)q(erset)d(of)e(that)h(standard.)62 +2458 y(There)20 b(are)f(sev)o(eral)g(single-c)o(haracter)h(options)g(y) +o(ou)f(can)g(giv)o(e)h(whic)o(h)g(are)f(not)f(a)o(v)m(ailable)j(with)f +(the)f Fk(set)0 2521 y Fl(builtin.)0 2670 y Fk(-c)c Fg(string)63 +b Fl(Read)16 b(and)f(execute)h(commands)f(from)g Fg(string)k +Fl(after)14 b(pro)q(cessing)i(the)f(options,)g(then)h(exit.)p +eop +16 17 bop 0 -58 a Fl(16)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fk(-i)192 b Fl(F)l(orce)15 b(the)g(shell)i(to)e(run)g(in)o +(teractiv)o(ely)l(.)0 285 y Fk(-s)192 b Fl(If)11 b(this)h(\015ag)f(is)h +(presen)o(t,)f(or)g(if)h(no)f(argumen)o(ts)f(remain)i(after)f(option)g +(pro)q(cessing,)i(then)e(commands)240 347 y(are)16 b(read)g(from)f(the) +h(standard)g(input.)24 b(This)16 b(option)h(allo)o(ws)f(the)g(p)q +(ositional)i(parameters)d(to)g(b)q(e)240 410 y(set)g(when)h(in)o(v)o +(oking)f(an)h(in)o(teractiv)o(e)f(shell.)62 574 y(An)i +Fg(in)o(teractiv)o(e)j Fl(shell)e(is)f(one)g(whose)f(input)i(and)f +(output)f(are)g(b)q(oth)h(connected)h(to)e(terminals)h(\(as)f(deter-)0 +636 y(mined)g(b)o(y)f Fk(isatty\(\))p Fl(\),)f(or)h(one)g(started)f +(with)i(the)f Fk(-i)g Fl(option.)0 927 y Fj(4.2)33 b(Bash)14 +b(Startup)j(Files)62 1071 y Fl(When)f(and)f(ho)o(w)g(Bash)g(executes)h +(startup)e(\014les.)120 1203 y Fk(For)23 b(Login)h(shells)f(\(subject)f +(to)i(the)f(-noprofile)g(option\):)215 1303 y(On)h(logging)f(in:)287 +1353 y(If)h(`/etc/profile')e(exists,)g(then)i(source)f(it.)287 +1452 y(If)h(`~/.bash_profile')d(exists,)i(then)g(source)g(it,)359 +1502 y(else)g(if)h(`~/.bash_login')d(exists,)i(then)h(source)f(it,)430 +1552 y(else)h(if)f(`~/.profile')f(exists,)h(then)h(source)f(it.)215 +1652 y(On)h(logging)f(out:)287 1701 y(If)h(`~/.bash_logout')d(exists,)i +(source)g(it.)120 1801 y(For)g(non-login)g(interactive)f(shells)h +(\(subject)g(to)h(the)f(-norc)g(and)h(-rcfile)f(options\):)215 +1851 y(On)h(starting)f(up:)287 1901 y(If)h(`~/.bashrc')e(exists,)h +(then)g(source)g(it.)120 2000 y(For)g(non-interactive)f(shells:)215 +2050 y(On)i(starting)f(up:)287 2100 y(If)h(the)f(environment)f +(variable)h(ENV)h(is)f(non-null,)g(expand)g(the)287 2150 +y(variable)g(and)g(source)g(the)h(file)f(named)g(by)h(the)f(value.)47 +b(If)24 b(Bash)f(is)287 2199 y(not)g(started)g(in)h(Posix)f(mode,)g(it) +h(looks)f(for)h(BASH_ENV)e(before)287 2249 y(ENV.)62 +2394 y Fl(So,)15 b(t)o(ypically)l(,)h(y)o(our)f Fk(~/.bash_profile)e +Fl(con)o(tains)j(the)f(line)120 2526 y Fk(if)24 b([)f(-f)h(~/.bashrc)f +(];)g(then)g(source)g(~/.bashrc;)g(fi)0 2670 y Fl(after)14 +b(\(or)h(b)q(efore\))g(an)o(y)g(login)h(sp)q(eci\014c)h +(initializations.)p eop +17 18 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(17)62 183 y(If)16 b(Bash)g(is)g(in)o(v)o(ok)o(ed)g(as)f +Fk(sh)p Fl(,)g(it)g(tries)h(to)f(mimic)i(the)f(b)q(eha)o(vior)g(of)f +Fk(sh)g Fl(as)g(closely)i(as)e(p)q(ossible.)23 b(F)l(or)15 +b(a)g(login)0 246 y(shell,)g(it)e(attempts)f(to)g(source)i(only)f(`)p +Fk(/etc/profile)p Fl(')e(and)i(`)p Fk(~/.profile)p Fl(',)e(in)j(that)e +(order.)19 b(The)13 b Fk(-noprofile)0 308 y Fl(option)h(ma)o(y)g(still) +h(b)q(e)g(used)g(to)f(disable)h(this)g(b)q(eha)o(vior.)20 +b(A)14 b(shell)i(in)o(v)o(ok)o(ed)e(as)g Fk(sh)g Fl(do)q(es)g(not)g +(attempt)f(to)h(source)0 370 y(an)o(y)h(other)g(startup)f(\014les.)62 +507 y(When)h(Bash)g(is)g(started)f(in)h Fg(POSIX)21 b +Fl(mo)q(de,)14 b(as)g(with)h(the)g Fk(-posix)f Fl(command)g(line)j +(option,)d(it)h(follo)o(ws)g(the)0 570 y(P)o(osix)j(1003.2)e(standard)h +(for)h(startup)f(\014les.)29 b(In)18 b(this)g(mo)q(de,)h(the)f +Fk(ENV)f Fl(v)m(ariable)i(is)g(expanded)g(and)f(that)f(\014le)0 +632 y(sourced;)e(no)g(other)g(startup)g(\014les)h(are)f(read.)0 +859 y Fj(4.3)33 b(Is)14 b(This)i(Shell)h(In)n(teractiv)n(e?)62 +996 y Fl(Y)l(ou)c(ma)o(y)f(wish)h(to)f(determine)i(within)g(a)e +(startup)g(script)h(whether)g(Bash)g(is)g(running)h(in)o(teractiv)o +(ely)g(or)e(not.)0 1058 y(T)l(o)17 b(do)g(this,)h(examine)g(the)g(v)m +(ariable)g Fk($PS1)p Fl(;)g(it)f(is)h(unset)g(in)g(non-in)o(teractiv)o +(e)g(shells,)h(and)e(set)g(in)i(in)o(teractiv)o(e)0 1120 +y(shells.)i(Th)o(us:)120 1245 y Fk(if)j([)f(-z)h("$PS1")f(];)h(then)120 +1295 y(echo)f(This)h(shell)f(is)g(not)h(interactive)120 +1345 y(else)120 1395 y(echo)f(This)h(shell)f(is)g(interactive)120 +1444 y(fi)62 1582 y Fl(Y)l(ou)16 b(can)f(ask)f(an)h(in)o(teractiv)o(e)h +(Bash)f(to)f(not)h(run)g(y)o(our)g(`)p Fk(~/.bashrc)p +Fl(')e(\014le)j(with)g(the)f Fk(-norc)f Fl(\015ag.)20 +b(Y)l(ou)15 b(can)0 1644 y(c)o(hange)j(the)f(name)h(of)f(the)h(`)p +Fk(~/.bashrc)p Fl(')d(\014le)k(to)e(an)o(y)g(other)g(\014le)i(name)e +(with)h Fk(-rcfile)c Fg(\014lename)s Fl(.)28 b(Y)l(ou)18 +b(can)0 1706 y(ask)d(Bash)g(to)g(not)f(run)i(y)o(our)f(`)p +Fk(~/.bash_profile)p Fl(')d(\014le)k(with)g(the)f Fk(-noprofile)f +Fl(\015ag.)0 1933 y Fj(4.4)33 b(Bash)14 b(Builtin)k(Commands)62 +2070 y Fl(This)e(section)g(describ)q(es)h(builtin)g(commands)e(whic)o +(h)h(are)f(unique)i(to)d(or)h(ha)o(v)o(e)g(b)q(een)h(extended)g(in)g +(Bash.)0 2220 y Fk(builtin)360 2283 y(builtin)23 b([)p +Fg(shell-builti)q(n)k Fk([)p Fg(args)r Fk(]])240 2358 +y Fl(Run)20 b(a)f(shell)h(builtin.)34 b(This)20 b(is)g(useful)g(when)f +(y)o(ou)g(wish)h(to)e(rename)h(a)g(shell)i(builtin)g(to)e(b)q(e)g(a)240 +2420 y(function,)d(but)f(need)h(the)f(functionalit)o(y)i(of)e(the)g +(builtin)i(within)g(the)e(function)h(itself.)0 2508 y +Fk(bind)360 2570 y(bind)23 b([-m)h Fg(k)o(eymap)q Fk(])g([-lvd])f([-q)g +Fg(name)s Fk(])360 2620 y(bind)g([-m)h Fg(k)o(eymap)q +Fk(])g(-f)f Fg(\014lename)360 2670 y Fk(bind)g([-m)h +Fg(k)o(eymap)q Fk(])g Fg(k)o(eyseq:function-name)p eop +18 19 bop 0 -58 a Fl(18)1623 b(Bash)15 b(F)l(eatures)240 +183 y(Displa)o(y)k(curren)o(t)e(Readline)k(\(see)c(Chapter)h(7)g +([Command)f(Line)i(Editing],)g(page)f(37\))f(k)o(ey)h(and)240 +246 y(function)24 b(bindings,)j(or)c(bind)h(a)f(k)o(ey)g(sequence)i(to) +d(a)h(Readline)j(function)e(or)e(macro.)44 b(The)240 +308 y(binding)25 b(syn)o(tax)d(accepted)i(is)g(iden)o(tical)h(to)d +(that)h(of)f(`)p Fk(.inputrc)p Fl(')f(\(see)i(Section)h(7.3)f([Read-) +240 370 y(line)f(Init)g(File],)h(page)d(40\),)h(but)g(eac)o(h)g +(binding)i(m)o(ust)d(b)q(e)i(passed)f(as)f(a)h(separate)f(argumen)o(t:) +240 432 y(`)p Fk("\\C-x\\C-r":re-read-init)o(-file)p +Fl(')o(.)d(Options,)e(if)f(supplied,)i(ha)o(v)o(e)e(the)g(follo)o(wing) +h(meanings:)240 518 y Fk(-m)g(keymap)33 b Fl(Use)14 b +Fg(k)o(eymap)h Fl(as)e(the)h(k)o(eymap)f(to)g(b)q(e)h(a\013ected)g(b)o +(y)f(the)h(subsequen)o(t)g(bindings.)22 b(Ac-)480 580 +y(ceptable)14 b Fg(k)o(eymap)h Fl(names)e(are)g Fk(emacs)p +Fl(,)g Fk(emacs-standard)p Fl(,)e Fk(emacs-meta)p Fl(,)h +Fk(emacs-)480 643 y(ctlx)p Fl(,)k Fk(vi)p Fl(,)h Fk(vi-move)p +Fl(,)f Fk(vi-command)p Fl(,)g(and)h Fk(vi-insert)p Fl(.)23 +b Fk(vi)17 b Fl(is)g(equiv)m(alen)o(t)i(to)d Fk(vi-)480 +705 y(command)p Fl(;)e Fk(emacs)g Fl(is)i(equiv)m(alen)o(t)h(to)d +Fk(emacs-standard)p Fl(.)240 791 y Fk(-l)192 b Fl(List)16 +b(the)f(names)g(of)g(all)h(readline)h(functions)240 877 +y Fk(-v)192 b Fl(List)16 b(curren)o(t)f(function)h(names)f(and)g +(bindings)240 962 y Fk(-d)192 b Fl(Dump)13 b(function)h(names)f(and)h +(bindings)h(in)f(suc)o(h)f(a)g(w)o(a)o(y)f(that)h(they)g(can)g(b)q(e)h +(re-read)240 1036 y Fk(-f)h(filename)480 1099 y Fl(Read)h(k)o(ey)f +(bindings)i(from)d Fg(\014lename)240 1184 y Fk(-q)192 +b Fl(Query)16 b(ab)q(out)f(whic)o(h)h(k)o(eys)f(in)o(v)o(ok)o(e)g(the)g +(named)h Fg(function)0 1270 y Fk(command)360 1332 y(command)23 +b([-pVv])g Fg(command)j Fk([)p Fg(args)e Fk(...])240 +1406 y Fl(Runs)18 b Fg(command)i Fl(with)d Fg(arg)k Fl(ignoring)d +(shell)h(functions.)28 b(If)18 b(y)o(ou)f(ha)o(v)o(e)g(a)g(shell)i +(function)f(called)240 1468 y Fk(ls)p Fl(,)f(and)h(y)o(ou)f(wish)h(to)f +(call)h(the)g(command)f Fk(ls)p Fl(,)g(y)o(ou)g(can)h(sa)o(y)e(`)p +Fk(command)e(ls)p Fl('.)26 b(The)18 b Fk(-p)f Fl(option)240 +1530 y(means)g(to)g(use)g(a)g(default)h(v)m(alue)g(for)f +Fk($PATH)g Fl(that)f(is)i(guaran)o(teed)f(to)f(\014nd)i(all)g(of)f(the) +g(standard)240 1593 y(utilities.)240 1667 y(If)i(either)h(the)f +Fk(-V)g Fl(or)f Fk(-v)h Fl(option)g(is)h(supplied,)i(a)c(description)j +(of)d Fg(command)j Fl(is)f(prin)o(ted.)32 b(The)240 1729 +y Fk(-v)19 b Fl(option)h(causes)f(a)g(single)i(w)o(ord)d(indicating)j +(the)f(command)f(or)g(\014le)h(name)f(used)h(to)f(in)o(v)o(ok)o(e)240 +1791 y Fg(command)e Fl(to)d(b)q(e)i(prin)o(ted;)g(the)f +Fk(-V)g Fl(option)g(pro)q(duces)h(a)f(more)g(v)o(erb)q(ose)g +(description.)0 1877 y Fk(declare)360 1939 y(declare)23 +b([-frxi])g([)p Fg(name)s Fk([=)p Fg(v)m(alue)s Fk(]])240 +2013 y Fl(Declare)15 b(v)m(ariables)h(and/or)d(giv)o(e)i(them)f +(attributes.)20 b(If)15 b(no)f Fg(name)s Fl(s)g(are)g(giv)o(en,)h(then) +f(displa)o(y)i(the)240 2075 y(v)m(alues)k(of)f(v)m(ariables)i(instead.) +33 b Fk(-f)19 b Fl(means)g(to)g(use)h(function)g(names)f(only)l(.)33 +b Fk(-r)19 b Fl(sa)o(ys)g(to)f(mak)o(e)240 2137 y Fg(name)s +Fl(s)d(readonly)l(.)22 b Fk(-x)15 b Fl(sa)o(ys)g(to)g(mark)g +Fg(name)s Fl(s)g(for)g(exp)q(ort.)21 b Fk(-i)16 b Fl(sa)o(ys)f(that)f +(the)i(v)m(ariable)h(is)f(to)f(b)q(e)240 2199 y(treated)c(as)h(an)f(in) +o(teger;)i(arithmetic)f(ev)m(aluation)h(\(see)f(Section)h(4.7)d([Shell) +k(Arithmetic],)e(page)g(24\))240 2262 y(is)17 b(p)q(erformed)f(when)h +(the)g(v)m(ariable)g(is)g(assigned)g(a)f(v)m(alue.)24 +b(Using)17 b Fk(+)f Fl(instead)h(of)f Fk(-)g Fl(turns)g(o\013)g(the)240 +2324 y(attribute)h(instead.)24 b(When)17 b(used)h(in)f(a)f(function,)i +Fk(declare)e Fl(mak)o(es)g Fg(name)s Fl(s)g(lo)q(cal,)i(as)e(with)h +(the)240 2386 y Fk(local)d Fl(command.)0 2472 y Fk(enable)360 +2534 y(enable)23 b([-n])g([-a])h([)p Fg(name)i Fk(...])240 +2608 y Fl(Enable)19 b(and)f(disable)h(builtin)i(shell)e(commands.)28 +b(This)19 b(allo)o(ws)f(y)o(ou)f(to)h(use)g(a)f(disk)i(command)240 +2670 y(whic)o(h)d(has)f(the)g(same)f(name)h(as)g(a)f(shell)j(builtin.) +22 b(If)15 b Fk(-n)g Fl(is)g(used,)g(the)g Fg(name)s +Fl(s)g(b)q(ecome)h(disabled.)p eop +19 20 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(19)240 183 y(Otherwise)18 b Fg(name)s +Fl(s)f(are)g(enabled.)28 b(F)l(or)17 b(example,)h(to)f(use)h(the)f +Fk(test)g Fl(binary)h(found)g(via)g Fk($PATH)240 246 +y Fl(instead)c(of)f(the)g(shell)i(builtin)g(v)o(ersion,)e(t)o(yp)q(e)h +(`)p Fk(enable)g(-n)h(test)p Fl('.)j(The)13 b Fk(-a)g +Fl(option)g(means)h(to)e(list)240 308 y(eac)o(h)j(builtin)j(with)d(an)g +(indication)j(of)c(whether)i(or)e(not)h(it)h(is)f(enabled.)0 +396 y Fk(help)360 459 y(help)23 b([)p Fg(pattern)p Fk(])240 +535 y Fl(Displa)o(y)13 b(helpful)i(information)e(ab)q(out)f(builtin)j +(commands.)k(If)13 b Fg(pattern)f Fl(is)i(sp)q(eci\014ed,)h +Fk(help)d Fl(giv)o(es)240 597 y(detailed)22 b(help)g(on)f(all)h +(commands)f(matc)o(hing)f Fg(pattern)p Fl(,)i(otherwise)f(a)f(list)i +(of)f(the)f(builtins)j(is)240 659 y(prin)o(ted.)0 748 +y Fk(local)360 811 y(local)g Fg(name)s Fk([=)p Fg(v)m(alue)s +Fk(])240 886 y Fl(F)l(or)10 b(eac)o(h)g(argumen)o(t,)g(create)h(a)f(lo) +q(cal)h(v)m(ariable)h(called)g Fg(name)p Fl(,)f(and)f(giv)o(e)h(it)g +Fg(v)m(alue)p Fl(.)19 b Fk(local)10 b Fl(can)g(only)240 +948 y(b)q(e)18 b(used)f(within)i(a)d(function;)j(it)e(mak)o(es)f(the)i +(v)m(ariable)g Fg(name)i Fl(ha)o(v)o(e)c(a)h(visible)i(scop)q(e)f +(restricted)240 1010 y(to)d(that)f(function)i(and)f(its)h(c)o(hildren.) +0 1099 y Fk(type)360 1162 y(type)23 b([-all])g([-type)g(|)h(-path])f([) +p Fg(name)k Fk(...])240 1237 y Fl(F)l(or)15 b(eac)o(h)g +Fg(name)p Fl(,)g(indicate)h(ho)o(w)f(it)h(w)o(ould)f(b)q(e)h(in)o +(terpreted)g(if)f(used)h(as)f(a)g(command)g(name.)240 +1313 y(If)e(the)g Fk(-type)g Fl(\015ag)f(is)i(used,)f +Fk(type)g Fl(returns)g(a)f(single)j(w)o(ord)d(whic)o(h)i(is)f(one)g(of) +g(\\alias",)g(\\function",)240 1375 y(\\builtin",)i(\\\014le")f(or)g +(\\k)o(eyw)o(ord",)e(if)i Fg(name)i Fl(is)e(an)g(alias,)g(shell)h +(function,)g(shell)g(builtin,)h(disk)e(\014le,)240 1437 +y(or)h(shell)h(reserv)o(ed)g(w)o(ord,)e(resp)q(ectiv)o(ely)l(.)240 +1512 y(If)j(the)g Fk(-path)g Fl(\015ag)f(is)i(used,)g +Fk(type)e Fl(either)i(returns)f(the)g(name)g(of)g(the)g(disk)g(\014le)i +(that)d(w)o(ould)h(b)q(e)240 1575 y(executed,)f(or)e(nothing)i(if)g +Fk(-type)e Fl(w)o(ould)i(not)f(return)g(\\\014le".)240 +1650 y(If)f(the)g Fk(-all)g Fl(\015ag)f(is)i(used,)f(returns)g(all)h +(of)f(the)g(places)g(that)g(con)o(tain)g(an)g(executable)h(named)f +Fg(\014le)p Fl(.)240 1712 y(This)i(includes)h(aliases)f(and)g +(functions,)f(if)h(and)f(only)h(if)g(the)f Fk(-path)f +Fl(\015ag)h(is)h(not)f(also)g(used.)240 1788 y Fk(Type)g +Fl(accepts)g Fk(-a)p Fl(,)f Fk(-t)p Fl(,)h(and)g Fk(-p)g +Fl(as)g(equiv)m(alen)o(t)i(to)d Fk(-all)p Fl(,)h Fk(-type)p +Fl(,)f(and)h Fk(-path)p Fl(,)f(resp)q(ectiv)o(ely)l(.)0 +1876 y Fk(ulimit)360 1939 y(ulimit)23 b([-acdmstfpnuvSH])f([)p +Fg(limit)q Fk(])240 2015 y(Ulimit)15 b Fl(pro)o(vides)i(con)o(trol)f(o) +o(v)o(er)f(the)i(resources)f(a)o(v)m(ailable)i(to)d(pro)q(cesses)i +(started)e(b)o(y)h(the)h(shell,)240 2077 y(on)e(systems)g(that)f(allo)o +(w)i(suc)o(h)f(con)o(trol.)20 b(If)15 b(an)g(option)h(is)g(giv)o(en,)f +(it)g(is)h(in)o(terpreted)g(as)f(follo)o(ws:)240 2165 +y Fk(-S)192 b Fl(c)o(hange)16 b(and)g(rep)q(ort)g(the)g(soft)f(limit)i +(asso)q(ciated)f(with)h(a)e(resource)h(\(the)g(default)g(if)480 +2228 y(the)f Fk(-H)g Fl(option)h(is)f(not)g(giv)o(en\).)240 +2316 y Fk(-H)192 b Fl(c)o(hange)15 b(and)h(rep)q(ort)f(the)g(hard)g +(limit)i(asso)q(ciated)e(with)h(a)e(resource.)240 2405 +y Fk(-a)192 b Fl(all)16 b(curren)o(t)f(limits)i(are)e(rep)q(orted.)240 +2493 y Fk(-c)192 b Fl(the)15 b(maxim)o(um)g(size)i(of)d(core)h(\014les) +i(created.)240 2582 y Fk(-d)192 b Fl(the)15 b(maxim)o(um)g(size)i(of)d +(a)h(pro)q(cess's)g(data)g(segmen)o(t.)240 2670 y Fk(-m)192 +b Fl(the)15 b(maxim)o(um)g(residen)o(t)h(set)f(size.)p +eop +20 21 bop 0 -58 a Fl(20)1623 b(Bash)15 b(F)l(eatures)240 +183 y Fk(-s)192 b Fl(the)15 b(maxim)o(um)g(stac)o(k)g(size.)240 +268 y Fk(-t)192 b Fl(the)15 b(maxim)o(um)g(amoun)o(t)g(of)g(cpu)g(time) +h(in)g(seconds.)240 353 y Fk(-f)192 b Fl(the)15 b(maxim)o(um)g(size)i +(of)d(\014les)i(created)g(b)o(y)f(the)g(shell.)240 438 +y Fk(-p)192 b Fl(the)15 b(pip)q(e)i(bu\013er)e(size.)240 +523 y Fk(-n)192 b Fl(the)15 b(maxim)o(um)g(n)o(um)o(b)q(er)h(of)f(op)q +(en)h(\014le)g(descriptors.)240 608 y Fk(-u)192 b Fl(the)15 +b(maxim)o(um)g(n)o(um)o(b)q(er)h(of)f(pro)q(cesses)g(a)o(v)m(ailable)i +(to)e(a)g(single)h(user.)240 693 y Fk(-v)192 b Fl(the)15 +b(maxim)o(um)g(amoun)o(t)g(of)g(virtual)g(memory)g(a)o(v)m(ailable)i +(to)d(the)i(pro)q(cess.)240 778 y(If)i Fg(limit)i Fl(is)e(giv)o(en,)g +(it)g(is)g(the)f(new)h(v)m(alue)h(of)e(the)g(sp)q(eci\014ed)j +(resource.)27 b(Otherwise,)18 b(the)g(curren)o(t)240 +841 y(v)m(alue)h(of)d(the)i(sp)q(eci\014ed)h(resource)f(is)f(prin)o +(ted.)27 b(If)18 b(no)f(option)h(is)g(giv)o(en,)f(then)h(`)p +Fk(-f)p Fl(')e(is)i(assumed.)240 903 y(V)l(alues)f(are)e(in)i(1024-b)o +(yte)d(incremen)o(ts,)i(except)h(for)e(`)p Fk(-t)p Fl(',)f(whic)o(h)j +(is)f(in)h(seconds,)e(`)p Fk(-p)p Fl(',)g(whic)o(h)h(is)240 +965 y(in)g(units)g(of)f(512-b)o(yte)f(blo)q(c)o(ks,)i(and)f(`)p +Fk(-n)p Fl(')f(and)h(`)p Fk(-u)p Fl(',)f(whic)o(h)i(are)f(unscaled)i(v) +m(alues.)0 1185 y Fj(4.5)33 b(The)15 b(Set)g(Builtin)62 +1322 y Fl(This)h(builtin)i(is)d(so)g(o)o(v)o(erloaded)g(that)g(it)g +(deserv)o(es)h(its)f(o)o(wn)g(section.)0 1470 y Fk(set)360 +1531 y(set)23 b([-abefhkmnptuvxldCHP])e([-o)j Fg(option)p +Fk(])g([)p Fg(argumen)o(t)g Fk(...])240 1616 y(-a)192 +b Fl(Mark)14 b(v)m(ariables)j(whic)o(h)f(are)f(mo)q(di\014ed)h(or)f +(created)g(for)g(exp)q(ort.)240 1701 y Fk(-b)192 b Fl(Cause)19 +b(the)g(status)f(of)g(terminated)h(bac)o(kground)g(jobs)g(to)f(b)q(e)h +(rep)q(orted)g(immedi-)480 1764 y(ately)l(,)c(rather)g(than)g(b)q +(efore)g(prin)o(ting)h(the)g(next)f(primary)g(prompt.)240 +1849 y Fk(-e)192 b Fl(Exit)15 b(immediately)i(if)f(a)f(command)g(exits) +g(with)h(a)f(non-zero)g(status.)240 1934 y Fk(-f)192 +b Fl(Disable)16 b(\014le)g(name)g(generation)f(\(globbing\).)240 +2019 y Fk(-h)192 b Fl(Lo)q(cate)19 b(and)h(remem)o(b)q(er)f(\(hash\))f +(commands)h(as)g(functions)h(are)e(de\014ned,)k(rather)480 +2081 y(than)15 b(when)h(the)f(function)h(is)g(executed.)240 +2166 y Fk(-k)192 b Fl(All)16 b(k)o(eyw)o(ord)d(argumen)o(ts)h(are)g +(placed)i(in)f(the)g(en)o(vironmen)o(t)f(for)g(a)g(command,)g(not)480 +2228 y(just)h(those)g(that)f(precede)j(the)e(command)g(name.)240 +2313 y Fk(-m)192 b Fl(Job)15 b(con)o(trol)g(is)h(enabled)h(\(see)e +(Chapter)g(5)g([Job)g(Con)o(trol],)f(page)h(29\).)240 +2398 y Fk(-n)192 b Fl(Read)16 b(commands)f(but)g(do)g(not)g(execute)h +(them.)240 2472 y Fk(-o)f Fg(option-name)480 2534 y Fl(Set)g(the)h +(\015ag)e(corresp)q(onding)j(to)d Fg(option-name)s Fl(:)480 +2608 y Fk(allexport)720 2670 y Fl(same)h(as)g Fk(-a)p +Fl(.)p eop +21 22 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(21)480 183 y Fk(braceexpand)720 246 y +Fl(the)16 b(shell)i(will)g(p)q(erform)e(brace)g(expansion)h(\(see)f +(Section)h(2.2)e([Brace)720 308 y(Expansion],)g(page)g(7\).)480 +396 y Fk(emacs)120 b Fl(use)15 b(an)g(emacs-st)o(yle)h(line)g(editing)h +(in)o(terface)e(\(see)g(Chapter)g(7)g([Com-)720 458 y(mand)g(Line)i +(Editing],)e(page)g(37\).)480 547 y Fk(errexit)72 b Fl(same)15 +b(as)g Fk(-e)p Fl(.)480 622 y Fk(histexpand)720 685 y +Fl(same)g(as)g Fk(-H)p Fl(.)480 760 y Fk(ignoreeof)720 +822 y Fl(the)g(shell)i(will)g(not)e(exit)g(up)q(on)h(reading)g(EOF.)480 +898 y Fk(interactive-comments)720 960 y Fl(allo)o(w)h(a)g(w)o(ord)g(b)q +(eginning)i(with)f(a)e(`)p Fk(#)p Fl(')h(to)f(cause)i(that)e(w)o(ord)h +(and)g(all)720 1022 y(remaining)11 b(c)o(haracters)f(on)g(that)f(line)j +(to)e(b)q(e)h(ignored)f(in)h(an)g(in)o(teractiv)o(e)720 +1084 y(shell.)480 1173 y Fk(monitor)72 b Fl(same)15 b(as)g +Fk(-m)p Fl(.)480 1248 y Fk(noclobber)720 1310 y Fl(same)g(as)g +Fk(-C)p Fl(.)480 1399 y Fk(noexec)96 b Fl(same)15 b(as)g +Fk(-n)p Fl(.)480 1487 y Fk(noglob)96 b Fl(same)15 b(as)g +Fk(-f)p Fl(.)480 1576 y Fk(nohash)96 b Fl(same)15 b(as)g +Fk(-d)p Fl(.)480 1664 y Fk(notify)96 b Fl(same)15 b(as)g +Fk(-b)p Fl(.)480 1753 y Fk(nounset)72 b Fl(same)15 b(as)g +Fk(-u)p Fl(.)480 1841 y Fk(physical)48 b Fl(same)15 b(as)g +Fk(-P)p Fl(.)480 1930 y Fk(posix)120 b Fl(c)o(hange)11 +b(the)h(b)q(eha)o(vior)f(of)g(Bash)h(where)f(the)g(default)h(op)q +(eration)g(di\013ers)720 1992 y(from)17 b(the)g(P)o(osix)g(1003.2)f +(standard)h(to)f(matc)o(h)h(the)h(standard.)25 b(This)720 +2054 y(is)19 b(in)o(tended)g(to)f(mak)o(e)g(Bash)g(b)q(eha)o(v)o(e)g +(as)g(a)g(strict)g(sup)q(erset)h(of)f(that)720 2116 y(standard.)480 +2192 y Fk(privileged)720 2254 y Fl(same)d(as)g Fk(-p)p +Fl(.)480 2342 y Fk(verbose)72 b Fl(same)15 b(as)g Fk(-v)p +Fl(.)480 2431 y Fk(vi)192 b Fl(use)16 b(a)e Fk(vi)p Fl(-st)o(yle)i +(line)g(editing)h(in)o(terface.)480 2519 y Fk(xtrace)96 +b Fl(same)15 b(as)g Fk(-x)p Fl(.)240 2608 y Fk(-p)192 +b Fl(T)l(urn)14 b(on)g(privileged)j(mo)q(de.)j(In)14 +b(this)h(mo)q(de,)f(the)g Fk($ENV)g Fl(\014le)h(is)f(not)g(pro)q +(cessed,)h(and)480 2670 y(shell)21 b(functions)g(are)f(not)f(inherited) +j(from)d(the)h(en)o(vironmen)o(t.)34 b(This)20 b(is)g(enabled)p +eop +22 23 bop 0 -58 a Fl(22)1623 b(Bash)15 b(F)l(eatures)480 +183 y(automatically)g(on)f(startup)f(if)i(the)f(e\013ectiv)o(e)g(user)h +(\(group\))e(id)i(is)g(not)e(equal)i(to)f(the)480 246 +y(real)j(user)g(\(group\))e(id.)25 b(T)l(urning)18 b(this)f(option)g +(o\013)f(causes)g(the)h(e\013ectiv)o(e)g(user)g(and)480 +308 y(group)e(ids)h(to)e(b)q(e)i(set)f(to)g(the)g(real)h(user)f(and)g +(group)g(ids.)240 396 y Fk(-t)192 b Fl(Exit)15 b(after)g(reading)h(and) +f(executing)h(one)g(command.)240 485 y Fk(-u)192 b Fl(T)l(reat)15 +b(unset)g(v)m(ariables)i(as)d(an)i(error)e(when)i(substituting.)240 +573 y Fk(-v)192 b Fl(Prin)o(t)15 b(shell)i(input)f(lines)h(as)e(they)g +(are)g(read.)240 661 y Fk(-x)192 b Fl(Prin)o(t)15 b(commands)g(and)h +(their)f(argumen)o(ts)g(as)f(they)i(are)f(executed.)240 +750 y Fk(-l)192 b Fl(Sa)o(v)o(e)15 b(and)g(restore)g(the)g(binding)i +(of)e(the)g Fg(name)j Fl(in)e(a)f Fk(for)g Fl(command.)240 +838 y Fk(-d)192 b Fl(Disable)18 b(the)f(hashing)h(of)f(commands)f(that) +h(are)f(lo)q(ok)o(ed)i(up)f(for)g(execution.)26 b(Nor-)480 +900 y(mally)l(,)15 b(commands)g(are)f(remem)o(b)q(ered)h(in)h(a)e(hash) +h(table,)f(and)h(once)g(found,)g(do)f(not)480 963 y(ha)o(v)o(e)h(to)f +(b)q(e)i(lo)q(ok)o(ed)g(up)g(again.)240 1051 y Fk(-C)192 +b Fl(Disallo)o(w)16 b(output)f(redirection)h(to)f(existing)h(\014les.) +240 1140 y Fk(-H)192 b Fl(Enable)16 b(!)k(st)o(yle)15 +b(history)g(substitution.)21 b(This)16 b(\015ag)f(is)h(on)f(b)o(y)g +(default.)240 1228 y Fk(-P)192 b Fl(If)14 b(set,)g(do)g(not)g(follo)o +(w)g(sym)o(b)q(olic)h(links)h(when)f(p)q(erforming)f(commands)g(suc)o +(h)h(as)e Fk(cd)480 1290 y Fl(whic)o(h)h(c)o(hange)f(the)g(curren)o(t)g +(directory)l(.)20 b(The)13 b(ph)o(ysical)i(directory)e(is)h(used)g +(instead.)240 1379 y Fk(--)192 b Fl(If)16 b(no)f(argumen)o(ts)f(follo)o +(w)i(this)f(\015ag,)g(then)h(the)f(p)q(ositional)i(parameters)d(are)h +(unset.)480 1441 y(Otherwise,)e(the)e(p)q(ositional)i(parameters)e(are) +g(set)h(to)f(the)g Fg(argumen)o(ts)p Fl(,)g(ev)o(en)h(if)g(some)480 +1503 y(of)j(them)g(b)q(egin)h(with)g(a)f Fk(-)p Fl(.)240 +1592 y Fk(-)216 b Fl(Signal)15 b(the)g(end)f(of)g(options,)g(cause)h +(all)g(remaining)g Fg(argumen)o(ts)g Fl(to)f(b)q(e)h(assigned)g(to)480 +1654 y(the)h(p)q(ositional)h(parameters.)22 b(The)16 +b Fk(-x)f Fl(and)i Fk(-v)e Fl(options)h(are)g(turned)g(o\013.)22 +b(If)16 b(there)480 1716 y(are)f(no)g(argumen)o(ts,)f(the)h(p)q +(ositional)i(parameters)d(remain)i(unc)o(hanged.)240 +1805 y(Using)21 b(`)p Fk(+)p Fl(')e(rather)g(than)h(`)p +Fk(-)p Fl(')f(causes)h(these)h(\015ags)e(to)h(b)q(e)g(turned)h(o\013.) +33 b(The)21 b(\015ags)e(can)h(also)g(b)q(e)240 1867 y(used)e(up)q(on)g +(in)o(v)o(o)q(cation)g(of)f(the)g(shell.)28 b(The)17 +b(curren)o(t)h(set)f(of)g(\015ags)f(ma)o(y)h(b)q(e)h(found)g(in)g +Fk($-)p Fl(.)26 b(The)240 1929 y(remaining)14 b(N)f Fg(argumen)o(ts)h +Fl(are)f(p)q(ositional)h(parameters)e(and)i(are)e(assigned,)i(in)g +(order,)f(to)f Fk($1)p Fl(,)h Fk($2)p Fl(,)240 1991 y(..)19 +b Fk($N)p Fl(.)h(If)15 b(no)h(argumen)o(ts)e(are)h(giv)o(en,)g(all)h +(shell)h(v)m(ariables)g(are)d(prin)o(ted.)0 2221 y Fj(4.6)33 +b(Bash)14 b(V)-6 b(ariables)62 2359 y Fl(These)16 b(v)m(ariables)g(are) +f(set)g(or)g(used)h(b)o(y)f(bash,)g(but)g(other)g(shells)i(do)e(not)g +(normally)g(treat)g(them)g(sp)q(ecially)l(.)0 2496 y +Fk(HISTCONTROL)0 2545 y(history_control)240 2608 y Fl(Set)i(to)g(a)g(v) +m(alue)h(of)f(`)p Fk(ignorespace)p Fl(',)e(it)j(means)f(don't)g(en)o +(ter)g(lines)i(whic)o(h)f(b)q(egin)g(with)g(a)f(space)240 +2670 y(or)f(tab)f(in)o(to)h(the)h(history)f(list.)23 +b(Set)16 b(to)g(a)g(v)m(alue)h(of)f(`)p Fk(ignoredups)p +Fl(',)d(it)k(means)f(don't)f(en)o(ter)h(lines)p eop +23 24 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(23)240 183 y(whic)o(h)16 b(matc)o(h)f(the)g(last)g(en)o +(tered)g(line.)22 b(A)15 b(v)m(alue)h(of)f(`)p Fk(ignoreboth)p +Fl(')e(com)o(bines)j(the)f(t)o(w)o(o)f(options.)240 246 +y(Unset,)f(or)f(set)g(to)g(an)o(y)h(other)f(v)m(alue)i(than)e(those)h +(ab)q(o)o(v)o(e,)f(means)h(to)f(sa)o(v)o(e)g(all)h(lines)i(on)d(the)h +(history)240 308 y(list.)0 398 y Fk(HISTFILE)48 b Fl(The)15 +b(name)h(of)e(the)i(\014le)g(to)e(whic)o(h)j(the)e(command)g(history)g +(is)h(sa)o(v)o(ed.)0 488 y Fk(HISTSIZE)48 b Fl(If)15 +b(set,)g(this)h(is)f(the)h(maxim)o(um)f(n)o(um)o(b)q(er)g(of)g +(commands)g(to)g(remem)o(b)q(er)g(in)h(the)f(history)l(.)0 +564 y Fk(histchars)240 627 y Fl(Up)j(to)g(three)g(c)o(haracters)g(whic) +o(h)h(con)o(trol)e(history)h(expansion,)i(quic)o(k)f(substitution,)g +(and)f(tok-)240 689 y(enization)j(\(see)e(Section)i(6.1)e([History)g +(In)o(teraction],)h(page)f(33\).)33 b(The)20 b(\014rst)f(c)o(haracter)g +(is)h(the)240 751 y Fg(history-expansion-c)o(har)p Fl(,)d(that)e(is,)i +(the)f(c)o(haracter)f(whic)o(h)i(signi\014es)g(the)g(start)d(of)i(a)g +(history)g(ex-)240 814 y(pansion,)23 b(normally)f(`)p +Fk(!)p Fl('.)37 b(The)21 b(second)h(c)o(haracter)e(is)i(the)f(c)o +(haracter)g(whic)o(h)h(signi\014es)h(`quic)o(k)240 876 +y(substitution')d(when)h(seen)f(as)g(the)g(\014rst)g(c)o(haracter)f(on) +h(a)g(line,)i(normally)f(`)p Fk(^)p Fl('.)33 b(The)20 +b(optional)240 938 y(third)15 b(c)o(haracter)f(is)h(the)f(c)o(haracter) +g(whic)o(h)h(signi\014es)h(the)f(remainder)g(of)f(the)h(line)h(is)f(a)f +(commen)o(t,)240 1000 y(when)f(found)f(as)g(the)g(\014rst)g(c)o +(haracter)f(of)h(a)g(w)o(ord,)f(usually)j(`)p Fk(#)p +Fl('.)k(The)12 b(history)g(commen)o(t)g(c)o(haracter)240 +1063 y(causes)k(history)g(substitution)g(to)f(b)q(e)h(skipp)q(ed)i(for) +d(the)h(remaining)h(w)o(ords)d(on)i(the)g(line.)23 b(It)16 +b(do)q(es)240 1125 y(not)f(necessarily)h(cause)g(the)f(shell)i(parser)e +(to)f(treat)h(the)g(rest)g(of)f(the)i(line)h(as)d(a)h(commen)o(t.)0 +1215 y Fk(HISTCMD)72 b Fl(The)16 b(history)g(n)o(um)o(b)q(er,)f(or)h +(index)h(in)f(the)g(history)g(list,)g(of)f(the)h(curren)o(t)g(command.) +21 b(If)16 b Fk(HISTCMD)240 1277 y Fl(is)g(unset,)f(it)g(loses)h(its)f +(sp)q(ecial)i(prop)q(erties,)f(ev)o(en)f(if)h(it)f(is)h(subsequen)o +(tly)h(reset.)0 1354 y Fk(hostname_completion_file)0 +1416 y(HOSTFILE)48 b Fl(Con)o(tains)17 b(the)h(name)g(of)f(a)h(\014le)h +(in)f(the)g(same)f(format)g(as)g(`)p Fk(/etc/hosts)p +Fl(')f(that)h(should)i(b)q(e)f(read)240 1478 y(when)g(the)g(shell)i +(needs)f(to)e(complete)i(a)e(hostname.)28 b(Y)l(ou)18 +b(can)g(c)o(hange)g(the)g(\014le)h(in)o(teractiv)o(ely;)240 +1540 y(the)c(next)h(time)g(y)o(ou)f(attempt)f(to)h(complete)h(a)f +(hostname,)g(Bash)g(will)i(add)f(the)f(con)o(ten)o(ts)g(of)g(the)240 +1603 y(new)g(\014le)i(to)d(the)i(already)f(existing)h(database.)0 +1679 y Fk(MAILCHECK)240 1741 y Fl(Ho)o(w)k(often)g(\(in)h(seconds\))f +(that)g(the)g(shell)i(should)f(c)o(hec)o(k)g(for)f(mail)h(in)g(the)f +(\014les)i(sp)q(eci\014ed)g(in)240 1803 y Fk(MAILPATH)p +Fl(.)0 1880 y Fk(PROMPT_COMMAND)240 1942 y Fl(If)15 b(presen)o(t,)g +(this)g(con)o(tains)g(a)g(string)g(whic)o(h)h(is)f(a)g(command)f(to)h +(execute)g(b)q(efore)h(the)f(prin)o(ting)g(of)240 2004 +y(eac)o(h)g(primary)h(prompt)e(\()p Fk($PS1)p Fl(\).)0 +2094 y Fk(UID)168 b Fl(The)15 b(n)o(umeric)i(real)e(user)g(id)h(of)f +(the)g(curren)o(t)h(user.)0 2185 y Fk(EUID)144 b Fl(The)15 +b(n)o(umeric)i(e\013ectiv)o(e)e(user)g(id)h(of)f(the)g(curren)o(t)h +(user.)0 2275 y Fk(HOSTTYPE)48 b Fl(A)15 b(string)g(describing)i(the)f +(mac)o(hine)g(Bash)f(is)h(running)g(on.)0 2365 y Fk(OSTYPE)96 +b Fl(A)15 b(string)g(describing)i(the)f(op)q(erating)f(system)g(Bash)g +(is)h(running)g(on.)0 2455 y Fk(FIGNORE)72 b Fl(A)14 +b(colon-separated)h(list)g(of)f(su\016xes)g(to)g(ignore)g(when)h(p)q +(erforming)g(\014lename)g(completion)h(A)e(\014le)240 +2518 y(name)j(whose)h(su\016x)f(matc)o(hes)g(one)g(of)g(the)h(en)o +(tries)f(in)i Fk(FIGNORE)d Fl(is)i(excluded)h(from)e(the)g(list)h(of) +240 2580 y(matc)o(hed)d(\014le)h(names.)k(A)15 b(sample)h(v)m(alue)h +(is)e(`)p Fk(.o:~)p Fl(')0 2670 y Fk(INPUTRC)72 b Fl(The)15 +b(name)h(of)e(the)i(Readline)h(startup)e(\014le,)h(o)o(v)o(erriding)f +(the)g(default)h(of)f(`)p Fk(~/.inputrc)p Fl('.)p eop +24 25 bop 0 -58 a Fl(24)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fk(BASH_VERSION)240 246 y Fl(The)g(v)o(ersion)h(n)o(um)o(b)q(er)f +(of)g(the)g(curren)o(t)h(instance)g(of)e(Bash.)0 318 +y Fk(IGNOREEOF)240 380 y Fl(Con)o(trols)g(the)h(action)f(of)g(the)h +(shell)h(on)f(receipt)g(of)g(an)f Fk(EOF)g Fl(c)o(haracter)g(as)g(the)h +(sole)g(input.)21 b(If)15 b(set,)240 443 y(then)j(the)g(v)m(alue)h(of)f +(it)g(is)g(the)g(n)o(um)o(b)q(er)h(of)e(consecutiv)o(e)i +Fk(EOF)f Fl(c)o(haracters)f(that)g(can)h(b)q(e)g(read)g(as)240 +505 y(the)d(\014rst)f(c)o(haracters)f(on)i(an)f(input)h(line)i(b)q +(efore)d(the)h(shell)h(will)g(exit.)k(If)15 b(the)f(v)m(ariable)i +(exists)f(but)240 567 y(do)q(es)h(not)f(ha)o(v)o(e)g(a)g(n)o(umeric)h +(v)m(alue)h(\(or)d(has)h(no)h(v)m(alue\))g(then)f(the)h(default)g(is)g +(10.)k(If)15 b(the)h(v)m(ariable)240 629 y(do)q(es)e(not)g(exist,)g +(then)g Fk(EOF)f Fl(signi\014es)j(the)e(end)g(of)g(input)h(to)e(the)h +(shell.)21 b(This)14 b(is)h(only)f(in)h(e\013ect)f(for)240 +692 y(in)o(teractiv)o(e)i(shells.)0 764 y Fk(no_exit_on_failed_exec)240 +826 y Fl(If)e(this)h(v)m(ariable)g(exists,)g(the)f(shell)h(will)h(not)e +(exit)g(in)h(the)g(case)f(that)f(it)h(couldn't)h(execute)g(the)f +(\014le)240 889 y(sp)q(eci\014ed)j(in)f(the)g Fk(exec)e +Fl(command.)0 972 y Fk(nolinks)72 b Fl(If)20 b(presen)o(t,)g(sa)o(ys)e +(not)h(to)g(follo)o(w)g(sym)o(b)q(olic)i(links)f(when)g(doing)g +(commands)f(that)g(c)o(hange)g(the)240 1034 y(curren)o(t)i(w)o(orking)h +(directory)l(.)39 b(By)22 b(default,)h(bash)f(follo)o(ws)f(the)h +(logical)h(c)o(hain)f(of)f(directories)240 1096 y(when)16 +b(p)q(erforming)f(commands)g(suc)o(h)h(as)f Fk(cd)f Fl(whic)o(h)j(c)o +(hange)e(the)g(curren)o(t)g(directory)l(.)240 1169 y(F)l(or)g(example,) +g(if)h(`)p Fk(/usr/sys)p Fl(')d(is)j(a)f(link)h(to)f(`)p +Fk(/usr/local/sys)p Fl(')d(then:)360 1229 y Fk($)24 b(cd)f(/usr/sys;)g +(echo)g($PWD)360 1278 y(/usr/sys)360 1328 y($)h(cd)f(..;)h(pwd)360 +1378 y(/usr)240 1451 y Fl(If)15 b Fk(nolinks)g Fl(exists,)g(then:)360 +1511 y Fk($)24 b(cd)f(/usr/sys;)g(echo)g($PWD)360 1561 +y(/usr/local/sys)360 1610 y($)h(cd)f(..;)h(pwd)360 1660 +y(/usr/local)240 1733 y Fl(See)12 b(also)e(the)i(description)g(of)e +(the)i Fk(-P)e Fl(option)h(to)g(the)g Fk(set)f Fl(builtin,)k(Section)e +(4.5)e([The)g(Set)h(Builtin],)240 1795 y(page)k(20.)0 +2010 y Fj(4.7)33 b(Shell)16 b(Arithmetic)0 2209 y Ff(4.7.1)30 +b(Arithmetic)16 b(Ev)m(aluation)62 2346 y Fl(The)f(shell)g(allo)o(ws)f +(arithmetic)h(expressions)g(to)e(b)q(e)i(ev)m(aluated,)g(as)e(one)h(of) +g(the)g(shell)i(expansions)e(or)g(b)o(y)g(the)0 2408 +y Fk(let)h Fl(builtin.)62 2545 y(Ev)m(aluation)i(is)g(done)f(in)h(long) +f(in)o(tegers)g(with)g(no)g(c)o(hec)o(k)g(for)g(o)o(v)o(er\015o)o(w,)e +(though)i(division)i(b)o(y)e(0)f(is)i(trapp)q(ed)0 2608 +y(and)g(\015agged)f(as)g(an)h(error.)23 b(The)17 b(follo)o(wing)g(list) +h(of)e(op)q(erators)g(is)h(group)q(ed)g(in)o(to)f(lev)o(els)i(of)e +(equal-precedence)0 2670 y(op)q(erators.)j(The)c(lev)o(els)i(are)e +(listed)h(in)g(order)f(of)g(decreasing)h(precedence.)p +eop +25 26 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(25)0 183 y Fk(-)15 b(+)177 b Fl(unary)15 +b(min)o(us)h(and)f(plus)0 271 y Fk(!)g(~)177 b Fl(logical)16 +b(and)g(bit)o(wise)g(negation)0 359 y Fk(*)f(/)g(\045)138 +b Fl(m)o(ultiplication,)17 b(division,)g(remainder)0 +447 y Fk(+)e(-)177 b Fl(addition,)16 b(subtraction)0 +535 y Fk(<<)f(>>)129 b Fl(left)16 b(and)f(righ)o(t)g(bit)o(wise)h +(shifts)0 622 y Fk(<=)f(>=)g(<)g(>)51 b Fl(comparison)0 +710 y Fk(==)15 b(!=)129 b Fl(equalit)o(y)16 b(and)f(inequalit)o(y)0 +798 y Fk(&)216 b Fl(bit)o(wise)16 b(AND)0 886 y Fk(^)216 +b Fl(bit)o(wise)16 b(exclusiv)o(e)h(OR)0 974 y Fk(|)216 +b Fl(bit)o(wise)16 b(OR)0 1062 y Fk(&&)192 b Fl(logical)16 +b(AND)0 1149 y Fk(||)192 b Fl(logical)16 b(OR)0 1225 +y Fk(=)f(*=)g(/=)g(\045=)g(+=)g(-=)f(<<=)h(>>=)g(&=)g(^=)g(|=)240 +1287 y Fl(assignmen)o(t)62 1437 y(Shell)h(v)m(ariables)e(are)f(allo)o +(w)o(ed)h(as)f(op)q(erands;)h(parameter)e(expansion)j(is)e(p)q +(erformed)h(b)q(efore)g(the)f(expression)0 1499 y(is)k(ev)m(aluated.)26 +b(The)17 b(v)m(alue)i(of)d(a)h(parameter)f(is)h(co)q(erced)h(to)e(a)h +(long)g(in)o(teger)g(within)h(an)f(expression.)25 b(A)17 +b(shell)0 1561 y(v)m(ariable)g(need)f(not)e(ha)o(v)o(e)h(its)h(in)o +(teger)f(attribute)g(turned)h(on)f(to)f(b)q(e)i(used)g(in)g(an)f +(expression.)62 1699 y(Constan)o(ts)21 b(with)i(a)f(leading)i(0)e(are)g +(in)o(terpreted)h(as)f(o)q(ctal)h(n)o(um)o(b)q(ers.)41 +b(A)23 b(leading)h Fk(0x)e Fl(or)g Fk(0X)g Fl(denotes)0 +1761 y(hexadecimal.)e(Otherwise,)14 b(n)o(um)o(b)q(ers)e(tak)o(e)f(the) +i(form)e([)p Fg(base#)r Fl(]n,)g(where)i Fg(base)h Fl(is)f(a)f(decimal) +h(n)o(um)o(b)q(er)g(b)q(et)o(w)o(een)0 1823 y(2)h(and)g(36)g(represen)o +(ting)g(the)h(arithmetic)f(base,)g(and)h Fg(n)f Fl(is)h(a)e(n)o(um)o(b) +q(er)i(in)g(that)e(base.)20 b(If)14 b Fg(base)j Fl(is)e(omitted,)f +(then)0 1886 y(base)h(10)g(is)h(used.)62 2023 y(Op)q(erators)i(are)f +(ev)m(aluated)i(in)g(order)e(of)h(precedence.)29 b(Sub-expressions)20 +b(in)e(paren)o(theses)g(are)g(ev)m(aluated)0 2085 y(\014rst)d(and)g(ma) +o(y)g(o)o(v)o(erride)g(the)g(precedence)i(rules)f(ab)q(o)o(v)o(e.)0 +2296 y Ff(4.7.2)30 b(Arithmetic)16 b(Expansion)62 2433 +y Fl(Arithmetic)h(expansion)f(allo)o(ws)g(the)f(ev)m(aluation)i(of)e +(an)g(arithmetic)i(expression)f(and)g(the)f(substitution)h(of)0 +2495 y(the)f(result.)21 b(There)15 b(are)g(t)o(w)o(o)f(formats)g(for)g +(arithmetic)i(expansion:)120 2620 y Fk($[)24 b(expression)e(])120 +2670 y($\(\()h(expression)g(\)\))p eop +26 27 bop 0 -58 a Fl(26)1623 b(Bash)15 b(F)l(eatures)62 +183 y(The)e(expression)h(is)f(treated)f(as)g(if)h(it)g(w)o(ere)g +(within)h(double)g(quotes,)e(but)h(a)f(double)i(quote)f(inside)h(the)f +(braces)0 246 y(or)i(paren)o(theses)g(is)h(not)f(treated)g(sp)q +(ecially)l(.)22 b(All)17 b(tok)o(ens)e(in)h(the)f(expression)h(undergo) +g(parameter)e(expansion,)0 308 y(command)h(substitution,)h(and)f(quote) +g(remo)o(v)m(al.)20 b(Arithmetic)c(substitutions)g(ma)o(y)f(b)q(e)h +(nested.)62 446 y(The)k(ev)m(aluation)g(is)g(p)q(erformed)f(according)h +(to)f(the)g(rules)h(listed)h(ab)q(o)o(v)o(e.)31 b(If)20 +b(the)f(expression)h(is)g(in)o(v)m(alid,)0 508 y(Bash)15 +b(prin)o(ts)h(a)f(message)f(indicating)j(failure)g(and)e(no)g +(substitution)h(o)q(ccurs.)0 724 y Ff(4.7.3)30 b(Arithmetic)16 +b(Builtins)0 875 y Fk(let)360 938 y(let)23 b Fg(expression)i +Fk([)p Fg(expression)p Fk(])240 1014 y Fl(The)16 b Fk(let)f +Fl(builtin)i(allo)o(ws)f(arithmetic)g(to)f(b)q(e)h(p)q(erformed)g(on)f +(shell)i(v)m(ariables.)22 b(Eac)o(h)15 b Fg(expression)240 +1076 y Fl(is)e(ev)m(aluated)h(according)g(to)e(the)h(rules)g(giv)o(en)h +(previously)g(\(see)f(Section)g(4.7.1)f([Arithmetic)h(Ev)m(al-)240 +1138 y(uation],)18 b(page)f(24\).)27 b(If)18 b(the)g(last)f +Fg(expression)i Fl(ev)m(aluates)f(to)f(0,)h Fk(let)f +Fl(returns)h(1;)g(otherwise)g(0)f(is)240 1201 y(returned.)0 +1433 y Fj(4.8)33 b(Con)n(trolling)17 b(the)e(Prompt)62 +1571 y Fl(The)j(v)m(alue)g(of)e(the)h(v)m(ariable)i Fk($PROMPT_COMMAND) +c Fl(is)i(examined)h(just)f(b)q(efore)g(Bash)h(prin)o(ts)f(eac)o(h)g +(primary)0 1633 y(prompt.)32 b(If)19 b(it)h(is)f(set)g(and)h(non-n)o +(ull,)h(then)f(the)f(v)m(alue)i(is)f(executed)g(just)f(as)g(if)g(y)o +(ou)g(had)h(t)o(yp)q(ed)f(it)h(on)f(the)0 1696 y(command)c(line.)62 +1833 y(In)20 b(addition,)g(the)f(follo)o(wing)h(table)f(describ)q(es)h +(the)f(sp)q(ecial)i(c)o(haracters)d(whic)o(h)i(can)f(app)q(ear)g(in)g +(the)g Fk(PS1)0 1896 y Fl(v)m(ariable:)0 2047 y Fk(\\t)192 +b Fl(the)15 b(time,)g(in)h(HH:MM:SS)f(format.)0 2136 +y Fk(\\d)192 b Fl(the)15 b(date,)g(in)h Fk(")p Fl(W)l(eekda)o(y)f(Mon)o +(th)f(Date)p Fk(")h Fl(format)f(\(e.g.)19 b Fk(")p Fl(T)l(ue)c(Ma)o(y)g +(26)p Fk(")p Fl(\).)0 2225 y Fk(\\n)192 b Fl(newline.)0 +2314 y Fk(\\s)g Fl(the)15 b(name)g(of)g(the)h(shell,)g(the)f(basename)h +(of)e Fk($0)h Fl(\(the)g(p)q(ortion)h(follo)o(wing)g(the)f(\014nal)h +(slash\).)0 2403 y Fk(\\w)192 b Fl(the)15 b(curren)o(t)g(w)o(orking)g +(directory)l(.)0 2492 y Fk(\\W)192 b Fl(the)15 b(basename)h(of)e +Fk($PWD)p Fl(.)0 2581 y Fk(\\u)192 b Fl(y)o(our)15 b(username.)0 +2670 y Fk(\\h)192 b Fl(the)15 b(hostname.)p eop +27 28 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l +(eatures)1226 b(27)0 183 y Fk(\\#)192 b Fl(the)15 b(command)g(n)o(um)o +(b)q(er)h(of)f(this)g(command.)0 270 y Fk(\\!)192 b Fl(the)15 +b(history)g(n)o(um)o(b)q(er)h(of)f(this)g(command.)0 +358 y Fk(\\nnn)144 b Fl(the)15 b(c)o(haracter)g(corresp)q(onding)h(to)e +(the)i(o)q(ctal)f(n)o(um)o(b)q(er)h Fk(nnn)p Fl(.)0 445 +y Fk(\\$)192 b Fl(if)16 b(the)f(e\013ectiv)o(e)g(uid)i(is)e(0,)g +Fk(#)p Fl(,)g(otherwise)g Fk($)p Fl(.)0 532 y Fk(\\\\)192 +b Fl(a)15 b(bac)o(kslash.)0 619 y Fk(\\[)192 b Fl(b)q(egin)18 +b(a)e(sequence)i(of)e(non-prin)o(ting)h(c)o(haracters.)23 +b(This)17 b(could)h(b)q(e)f(used)g(to)f(em)o(b)q(ed)h(a)f(terminal)240 +681 y(con)o(trol)f(sequence)h(in)o(to)f(the)h(prompt.)0 +769 y Fk(\\])192 b Fl(end)16 b(a)f(sequence)h(of)f(non-prin)o(ting)h(c) +o(haracters.)p eop +28 29 bop 0 -58 a Fl(28)1623 b(Bash)15 b(F)l(eatures)p +eop +29 30 bop 0 -58 a Fl(Chapter)15 b(5:)k(Job)d(Con)o(trol)1435 +b(29)0 183 y Fh(5)41 b(Job)15 b(Con)n(trol)62 391 y Fl(This)i(c)o +(hapter)e(disusses)i(what)e(job)h(con)o(trol)g(is,)g(ho)o(w)f(it)h(w)o +(orks,)f(and)h(ho)o(w)f(Bash)h(allo)o(ws)g(y)o(ou)g(to)f(access)h(its)0 +453 y(facilities.)0 715 y Fj(5.1)33 b(Job)14 b(Con)n(trol)i(Basics)62 +856 y Fl(Job)21 b(con)o(trol)e(refers)h(to)g(the)g(abilit)o(y)h(to)e +(selectiv)o(ely)j(stop)e(\(susp)q(end\))h(the)f(execution)h(of)e(pro)q +(cesses)i(and)0 918 y(con)o(tin)o(ue)f(\(resume\))e(their)h(execution)i +(at)d(a)g(later)h(p)q(oin)o(t.)32 b(A)19 b(user)g(t)o(ypically)h(emplo) +o(ys)f(this)h(facilit)o(y)g(via)f(an)0 980 y(in)o(teractiv)o(e)d(in)o +(terface)f(supplied)j(join)o(tly)d(b)o(y)g(the)h(system's)e(terminal)i +(driv)o(er)g(and)f(Bash.)62 1122 y(The)22 b(shell)h(asso)q(ciates)e(a)h +Fg(job)g Fl(with)g(eac)o(h)f(pip)q(elin)q(e.)41 b(It)22 +b(k)o(eeps)g(a)f(table)h(of)f(curren)o(tly)h(executing)h(jobs,)0 +1184 y(whic)o(h)e(ma)o(y)e(b)q(e)i(listed)g(with)g(the)f +Fk(jobs)f Fl(command.)34 b(When)21 b(Bash)f(starts)e(a)i(job)g(async)o +(hronously)g(\(in)h(the)0 1246 y(bac)o(kground\),)14 +b(it)i(prin)o(ts)f(a)g(line)i(that)d(lo)q(oks)i(lik)o(e:)120 +1375 y Fk([1])23 b(25647)62 1516 y Fl(indicating)14 b(that)d(this)h +(job)g(is)g(job)f(n)o(um)o(b)q(er)i(1)e(and)h(that)f(the)h(pro)q(cess)g +(ID)g(of)f(the)h(last)f(pro)q(cess)h(in)h(the)f(pip)q(eline)0 +1578 y(asso)q(ciated)j(with)f(this)h(job)f(is)h(25647.)k(All)c(of)f +(the)h(pro)q(cesses)g(in)g(a)f(single)i(pip)q(eline)h(are)d(mem)o(b)q +(ers)h(of)f(the)g(same)0 1641 y(job.)20 b(Bash)15 b(uses)g(the)h +Fg(job)g Fl(abstraction)e(as)h(the)h(basis)f(for)g(job)g(con)o(trol.)62 +1782 y(T)l(o)i(facilitate)g(the)g(implemen)o(tation)h(of)e(the)h(user)f +(in)o(terface)h(to)f(job)h(con)o(trol,)f(the)h(system)f(main)o(tains)h +(the)0 1844 y(notion)i(of)g(a)g(curren)o(t)g(terminal)h(pro)q(cess)f +(group)g(ID.)g(Mem)o(b)q(ers)g(of)g(this)h(pro)q(cess)f(group)g(\(pro)q +(cesses)g(whose)0 1906 y(pro)q(cess)g(group)g(ID)g(is)g(equal)g(to)g +(the)g(curren)o(t)f(terminal)i(pro)q(cess)f(group)g(ID\))f(receiv)o(e)i +(k)o(eyb)q(oard-generated)0 1968 y(signals)14 b(suc)o(h)f(as)f +Fk(SIGINT)p Fl(.)18 b(These)13 b(pro)q(cesses)g(are)g(said)g(to)f(b)q +(e)i(in)f(the)g(foreground.)19 b(Bac)o(kground)12 b(pro)q(cesses)h(are) +0 2031 y(those)i(whose)f(pro)q(cess)i(group)e(ID)h(di\013ers)h(from)e +(the)h(terminal's;)g(suc)o(h)g(pro)q(cesses)g(are)g(imm)o(une)h(to)e(k) +o(eyb)q(oard-)0 2093 y(generated)19 b(signals.)30 b(Only)20 +b(foreground)e(pro)q(cesses)h(are)f(allo)o(w)o(ed)h(to)f(read)h(from)e +(or)h(write)h(to)f(the)h(terminal.)0 2155 y(Bac)o(kground)i(pro)q +(cesses)h(whic)o(h)h(attempt)e(to)g(read)g(from)g(\(write)g(to\))g(the) +h(terminal)g(are)f(sen)o(t)h(a)f Fk(SIGTTIN)0 2218 y +Fl(\()p Fk(SIGTTOU)p Fl(\))14 b(signal)i(b)o(y)f(the)g(terminal)h(driv) +o(er,)f(whic)o(h,)h(unless)g(caugh)o(t,)f(susp)q(ends)h(the)f(pro)q +(cess.)62 2359 y(If)h(the)g(op)q(erating)g(system)f(on)g(whic)o(h)i +(Bash)e(is)h(running)h(supp)q(orts)f(job)f(con)o(trol,)g(Bash)h(allo)o +(ws)f(y)o(ou)h(to)f(use)0 2421 y(it.)20 b(T)o(yping)15 +b(the)g Fg(susp)q(end)j Fl(c)o(haracter)c(\(t)o(ypically)i(`)p +Fk(^Z)p Fl(',)e(Con)o(trol-Z\))f(while)k(a)d(pro)q(cess)h(is)h(running) +g(causes)f(that)0 2483 y(pro)q(cess)i(to)f(b)q(e)i(stopp)q(ed)f(and)g +(returns)g(y)o(ou)f(to)g(Bash.)25 b(T)o(yping)17 b(the)g +Fg(dela)o(y)o(ed)h(susp)q(end)i Fl(c)o(haracter)c(\(t)o(ypically)0 +2545 y(`)p Fk(^Y)p Fl(',)11 b(Con)o(trol-Y\))h(causes)g(the)h(pro)q +(cess)f(to)g(b)q(e)h(stopp)q(ed)f(when)h(it)g(attempts)e(to)g(read)i +(input)g(from)e(the)i(terminal,)0 2608 y(and)k(con)o(trol)f(to)f(b)q(e) +i(returned)g(to)f(Bash.)23 b(Y)l(ou)16 b(ma)o(y)g(then)h(manipulate)g +(the)g(state)e(of)h(this)h(job,)f(using)h(the)f Fk(bg)0 +2670 y Fl(command)h(to)f(con)o(tin)o(ue)h(it)g(in)h(the)f(bac)o +(kground,)g(the)g Fk(fg)f Fl(command)h(to)f(con)o(tin)o(ue)h(it)g(in)h +(the)f(foreground,)f(or)p eop +30 31 bop 0 -58 a Fl(30)1623 b(Bash)15 b(F)l(eatures)0 +183 y(the)h Fk(kill)f Fl(command)g(to)g(kill)i(it.)k(A)16 +b(`)p Fk(^Z)p Fl(')f(tak)o(es)f(e\013ect)i(immediately)l(,)h(and)f(has) +f(the)h(additional)h(side)f(e\013ect)f(of)0 246 y(causing)h(p)q(ending) +h(output)e(and)g(t)o(yp)q(eahead)h(to)e(b)q(e)i(discarded.)62 +382 y(There)i(are)g(a)f(n)o(um)o(b)q(er)i(of)e(w)o(a)o(ys)g(to)g(refer) +h(to)f(a)g(job)h(in)h(the)e(shell.)30 b(The)18 b(c)o(haracter)f(`)p +Fk(\045)p Fl(')g(in)o(tro)q(duces)i(a)e(job)0 445 y(name.)i(Job)c(n)o +(um)o(b)q(er)f Fk(n)f Fl(ma)o(y)h(b)q(e)g(referred)g(to)f(as)h(`)p +Fk(\045n)p Fl('.)k(A)c(job)g(ma)o(y)f(also)g(b)q(e)i(referred)f(to)f +(using)i(a)e(pre\014x)h(of)g(the)0 507 y(name)j(used)g(to)f(start)g +(it,)h(or)f(using)h(a)g(substring)g(that)f(app)q(ears)g(in)i(its)f +(command)f(line.)27 b(F)l(or)16 b(example,)h(`)p Fk(\045ce)p +Fl(')0 569 y(refers)d(to)g(a)g(stopp)q(ed)h Fk(ce)f Fl(job.)20 +b(Using)15 b(`)p Fk(\045?ce)p Fl(',)e(on)h(the)h(other)f(hand,)h +(refers)f(to)g(an)o(y)g(job)g(con)o(taining)h(the)g(string)0 +632 y(`)p Fk(ce)p Fl(')h(in)j(its)e(command)h(line.)28 +b(If)18 b(the)g(pre\014x)g(or)f(substring)h(matc)o(hes)f(more)g(than)g +(one)h(job,)f(Bash)h(rep)q(orts)f(an)0 694 y(error.)i(The)c(sym)o(b)q +(ols)g(`)p Fk(\045\045)p Fl(')f(and)h(`)p Fk(\045+)p +Fl(')f(refer)h(to)f(the)h(shell's)h(notion)f(of)g(the)g(curren)o(t)g +(job,)f(whic)o(h)i(is)f(the)g(last)g(job)0 756 y(stopp)q(ed)h(while)h +(it)f(w)o(as)f(in)h(the)g(foreground.)k(The)c(previous)g(job)f(ma)o(y)g +(b)q(e)h(referenced)h(using)f(`)p Fk(\045-)p Fl('.)k(In)c(output)0 +818 y(p)q(ertaining)h(to)f(jobs)g(\(e.g.,)f(the)h(output)g(of)f(the)i +Fk(jobs)e Fl(command\),)h(the)g(curren)o(t)g(job)g(is)g(alw)o(a)o(ys)g +(\015agged)g(with)0 881 y(a)f(`)p Fk(+)p Fl(',)f(and)h(the)g(previous)h +(job)f(with)h(a)f(`)p Fk(-)p Fl('.)62 1018 y(Simply)21 +b(naming)f(a)f(job)g(can)h(b)q(e)g(used)g(to)f(bring)h(it)g(in)o(to)f +(the)g(foreground:)28 b(`)p Fk(\0451)p Fl(')19 b(is)h(a)f(synon)o(ym)g +(for)g(`)p Fk(fg)0 1080 y(\0451)p Fl(')14 b(bringing)j(job)e(1)g(from)f +(the)h(bac)o(kground)h(in)o(to)f(the)g(foreground.)k(Similarly)l(,)f(`) +p Fk(\0451)c(&)p Fl(')h(resumes)g(job)g(1)g(in)h(the)0 +1142 y(bac)o(kground,)f(equiv)m(alen)o(t)i(to)d(`)p Fk(bg)h(\0451)p +Fl(')62 1279 y(The)20 b(shell)h(learns)e(immediately)i(whenev)o(er)f(a) +f(job)g(c)o(hanges)g(state.)31 b(Normally)l(,)21 b(Bash)e(w)o(aits)g +(un)o(til)h(it)f(is)0 1341 y(ab)q(out)14 b(to)g(prin)o(t)h(a)f(prompt)g +(b)q(efore)g(rep)q(orting)h(c)o(hanges)f(in)i(a)e(job's)f(status)h(so)g +(as)g(to)g(not)g(in)o(terrupt)g(an)o(y)g(other)0 1404 +y(output.)21 b(If)15 b(the)h(the)g Fk(-b)f Fl(option)g(to)g(the)h +Fk(set)f Fl(builtin)j(is)e(set,)f(Bash)g(rep)q(orts)g(suc)o(h)h(c)o +(hanges)g(immediately)h(\(see)0 1466 y(Section)f(4.5)e([The)h(Set)h +(Builtin],)g(page)f(20\).)k(This)d(feature)f(is)h(also)f(con)o(trolled) +h(b)o(y)f(the)g(v)m(ariable)i Fk(notify)p Fl(.)62 1603 +y(If)j(y)o(ou)g(attempt)f(to)g(exit)h(bash)g(while)i(jobs)e(are)f +(stopp)q(ed,)i(the)f(shell)i(prin)o(ts)e(a)f(message)h(w)o(arning)g(y)o +(ou.)0 1665 y(Y)l(ou)d(ma)o(y)f(then)h(use)g(the)g Fk(jobs)f +Fl(command)g(to)g(insp)q(ect)i(their)f(status.)24 b(If)17 +b(y)o(ou)f(do)h(this,)g(or)f(try)g(to)g(exit)h(again)0 +1727 y(immediately)l(,)g(y)o(ou)e(are)f(not)h(w)o(arned)g(again,)g(and) +g(the)h(stopp)q(ed)f(jobs)g(are)g(terminated.)0 1950 +y Fj(5.2)33 b(Job)14 b(Con)n(trol)i(Builtins)0 2100 y +Fk(bg)360 2162 y(bg)24 b([)p Fg(jobsp)q(ec)s Fk(])240 +2236 y Fl(Place)16 b Fg(jobsp)q(ec)i Fl(in)o(to)d(the)g(bac)o(kground,) +f(as)h(if)g(it)g(had)g(b)q(een)h(started)e(with)i(`)p +Fk(&)p Fl('.)i(If)e Fg(jobsp)q(ec)i Fl(is)d(not)240 2298 +y(supplied,)i(the)e(curren)o(t)h(job)f(is)g(used.)0 2385 +y Fk(fg)360 2447 y(fg)24 b([)p Fg(jobsp)q(ec)s Fk(])240 +2521 y Fl(Bring)f Fg(jobsp)q(ec)j Fl(in)o(to)c(the)h(foreground)f(and)g +(mak)o(e)g(it)h(the)f(curren)o(t)h(job.)41 b(If)23 b +Fg(jobsp)q(ec)i Fl(is)e(not)240 2583 y(supplied,)17 b(the)e(curren)o(t) +h(job)f(is)g(used.)0 2670 y Fk(jobs)p eop +31 32 bop 0 -58 a Fl(Chapter)15 b(5:)k(Job)d(Con)o(trol)1435 +b(31)360 183 y Fk(jobs)23 b([-lpn])g([)p Fg(jobsp)q(ec)s +Fk(])360 233 y(jobs)g(-x)h Fg(command)h Fk([)p Fg(jobsp)q(ec)s +Fk(])240 308 y Fl(The)16 b(\014rst)g(form)f(lists)i(the)f(activ)o(e)g +(jobs.)22 b(The)16 b Fk(-l)g Fl(option)g(lists)g(pro)q(cess)h(IDs)f(in) +g(addition)i(to)d(the)240 370 y(normal)h(information;)f(the)h +Fk(-p)g Fl(option)g(lists)g(only)g(the)g(pro)q(cess)g(ID)g(of)f(the)h +(job's)f(pro)q(cess)h(group)240 432 y(leader.)k(The)14 +b Fk(-n)g Fl(option)g(displa)o(ys)h(only)f(jobs)g(that)f(ha)o(v)o(e)h +(c)o(hanged)g(status)f(since)i(last)f(not\014ed.)20 b(If)240 +495 y Fg(jobsp)q(ec)g Fl(is)d(giv)o(en,)h(output)e(is)h(restricted)g +(to)f(information)h(ab)q(out)g(that)f(job.)24 b(If)17 +b Fg(jobsp)q(ec)j Fl(is)d(not)240 557 y(supplied,)g(the)e(status)g(of)g +(all)h(jobs)f(is)g(listed.)240 632 y(If)e(the)f Fk(-x)g +Fl(option)g(is)h(supplied,)i Fk(jobs)d Fl(replaces)h(an)o(y)f +Fg(jobsp)q(ec)j Fl(found)e(in)g Fg(command)h Fl(or)e +Fg(argumen)o(ts)240 694 y Fl(with)f(the)h(corresp)q(onding)g(pro)q +(cess)f(group)g(ID,)g(and)g(executes)h Fg(command)p Fl(,)f(passing)h +(it)f Fg(argumen)o(t)q Fl(s,)240 756 y(returning)16 b(its)f(exit)h +(status.)0 843 y Fk(suspend)360 906 y(suspend)23 b([-f])240 +980 y Fl(Susp)q(end)c(the)e(execution)i(of)e(this)g(shell)i(un)o(til)g +(it)e(receiv)o(es)i(a)e Fk(SIGCONT)f Fl(signal.)27 b(The)18 +b Fk(-f)f Fl(option)240 1043 y(means)e(to)g(susp)q(end)h(ev)o(en)g(if)f +(the)h(shell)g(is)g(a)f(login)h(shell.)62 1192 y(When)g(job)f(con)o +(trol)g(is)g(activ)o(e,)g(the)h Fk(kill)e Fl(and)i Fk(wait)e +Fl(builtins)k(also)d(accept)g Fg(jobsp)q(ec)k Fl(argumen)o(ts.)0 +1416 y Fj(5.3)33 b(Job)14 b(Con)n(trol)i(V)-6 b(ariables)0 +1553 y Fk(auto_resume)240 1615 y Fl(This)20 b(v)m(ariable)h(con)o +(trols)e(ho)o(w)g(the)h(shell)h(in)o(teracts)e(with)h(the)g(user)f(and) +h(job)f(con)o(trol.)33 b(If)20 b(this)240 1678 y(v)m(ariable)k(exists)e +(then)h(single)g(w)o(ord)f(simple)i(commands)e(without)g(redirects)h +(are)f(treated)f(as)240 1740 y(candidates)f(for)e(resumption)i(of)e(an) +h(existing)h(job.)32 b(There)19 b(is)h(no)f(am)o(biguit)o(y)g(allo)o(w) +o(ed;)i(if)e(y)o(ou)240 1802 y(ha)o(v)o(e)c(more)f(than)h(one)h(job)e +(b)q(eginning)k(with)d(the)g(string)g(that)g(y)o(ou)f(ha)o(v)o(e)h(t)o +(yp)q(ed,)g(then)h(the)f(most)240 1864 y(recen)o(tly)j(accessed)g(job)f +(will)i(b)q(e)e(selected.)28 b(The)17 b(name)g(of)g(a)g(stopp)q(ed)h +(job,)f(in)h(this)g(con)o(text,)e(is)240 1927 y(the)f(command)g(line)h +(used)g(to)e(start)g(it.)20 b(If)15 b(this)g(v)m(ariable)i(is)e(set)g +(to)f(the)h(v)m(alue)h Fk(exact)p Fl(,)e(the)h(string)240 +1989 y(supplied)h(m)o(ust)c(matc)o(h)h(the)g(name)g(of)g(a)g(stopp)q +(ed)h(job)f(exactly;)h(if)f(set)g(to)g Fk(substring)p +Fl(,)f(the)h(string)240 2051 y(supplied)22 b(needs)d(to)g(matc)o(h)g(a) +f(substring)i(of)f(the)g(name)g(of)g(a)g(stopp)q(ed)g(job.)32 +b(The)19 b Fk(substring)240 2114 y Fl(v)m(alue)g(pro)o(vides)g +(functionalit)o(y)g(analogous)f(to)f(the)h Fk(\045?)g +Fl(job)g(id)h(\(see)f(Section)h(5.1)e([Job)h(Con)o(trol)240 +2176 y(Basics],)f(page)g(29\).)25 b(If)17 b(set)g(to)f(an)o(y)h(other)f +(v)m(alue,)j(the)e(supplied)i(string)e(m)o(ust)g(b)q(e)g(a)g(pre\014x)h +(of)e(a)240 2238 y(stopp)q(ed)g(job's)e(name;)h(this)h(pro)o(vides)f +(functionalit)o(y)i(analogous)e(to)f(the)i Fk(\045)f +Fl(job)g(id.)0 2325 y Fk(notify)96 b Fl(Setting)18 b(this)g(v)m +(ariable)g(to)f(a)g(v)m(alue)i(is)f(equiv)m(alen)o(t)h(to)d(`)p +Fk(set)f(-b)p Fl(';)i(unsetting)h(it)g(is)g(equiv)m(alen)o(t)h(to)240 +2387 y(`)p Fk(set)14 b(+b)p Fl(')h(\(see)g(Section)h(4.5)e([The)h(Set)h +(Builtin],)g(page)f(20\).)p eop +32 33 bop 0 -58 a Fl(32)1623 b(Bash)15 b(F)l(eatures)p +eop +33 34 bop 0 -58 a Fl(Chapter)15 b(6:)k(Using)d(History)f(In)o(teractiv) +o(ely)1135 b(33)0 183 y Fh(6)41 b(Using)14 b(History)h(In)n(teractiv)n +(ely)62 355 y Fl(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g +(the)g(GNU)g(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g +(user's)h(stand-)0 417 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f +(considered)i(a)d(user's)h(guide.)23 b(F)l(or)15 b(information)h(on)g +(using)h(the)f(GNU)g(History)f(Library)0 479 y(in)h(y)o(our)f(o)o(wn)f +(programs,)g(see)i(the)f(GNU)g(Readline)i(Library)f(Man)o(ual.)0 +688 y Fj(6.1)33 b(History)15 b(In)n(teraction)62 825 +y Fl(The)j(History)g(library)g(pro)o(vides)h(a)e(history)h(expansion)h +(feature)e(that)g(is)i(similar)g(to)e(the)h(history)f(expan-)0 +887 y(sion)k(pro)o(vided)h(b)o(y)f Fk(csh)p Fl(.)36 b(The)22 +b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o(tax)f(used)i(to)e +(manipulate)i(the)f(history)0 949 y(information.)62 1086 +y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.) +18 b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e +(the)g(previous)0 1148 y(history)h(should)h(b)q(e)f(used)h(during)f +(substitution.)20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g +(of)g(that)f(line)i(for)f(inclusion)0 1211 y(in)o(to)f(the)h(curren)o +(t)f(one.)18 b(The)12 b(line)h(selected)f(from)f(the)g(previous)h +(history)g(is)f(called)i(the)e Fg(ev)o(en)o(t)p Fl(,)h(and)f(the)h(p)q +(ortions)0 1273 y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h +(are)g(called)h Fg(w)o(ords)p Fl(.)j(The)c(line)h(is)f(brok)o(en)f(in)o +(to)h(w)o(ords)f(in)h(the)f(same)h(fashion)0 1335 y(that)j(Bash)h(do)q +(es,)h(so)e(that)g(sev)o(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f +(surrounded)i(b)o(y)f(quotes)f(are)h(considered)h(as)0 +1398 y(one)c(w)o(ord.)0 1590 y Ff(6.1.1)30 b(Ev)n(en)n(t)16 +b(Designators)62 1727 y Fl(An)g(ev)o(en)o(t)f(designator)g(is)g(a)g +(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g(history)f +(list.)0 1872 y Fk(!)216 b Fl(Start)14 b(a)g(history)h(substitution,)g +(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f(the)h +(end)g(of)g(the)g(line,)240 1934 y Fk(=)g Fl(or)g Fk(\()p +Fl(.)0 2014 y Fk(!!)192 b Fl(Refer)16 b(to)e(the)i(previous)f(command.) +20 b(This)c(is)g(a)f(synon)o(ym)g(for)f Fk(!-1)p Fl(.)0 +2093 y Fk(!n)192 b Fl(Refer)16 b(to)e(command)h(line)i +Fg(n)p Fl(.)0 2173 y Fk(!-n)168 b Fl(Refer)16 b(to)e(the)i(command)f +Fg(n)g Fl(lines)i(bac)o(k.)0 2252 y Fk(!string)72 b Fl(Refer)16 +b(to)e(the)i(most)e(recen)o(t)h(command)g(starting)g(with)g +Fg(string)p Fl(.)0 2323 y Fk(!?string)p Fl([)p Fk(?)p +Fl(])240 2385 y(Refer)h(to)e(the)i(most)e(recen)o(t)h(command)g(con)o +(taining)h Fg(string)p Fl(.)0 2465 y Fk(!#)192 b Fl(The)15 +b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e(far.)0 +2535 y Fk(^string1^string2^)240 2598 y Fl(Quic)o(k)j(Substitution.)22 +b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h +Fg(string1)h Fl(with)e Fg(string2)p Fl(.)21 b(Equiv-)240 +2660 y(alen)o(t)15 b(to)g Fk(!!:s/string1/string2/)p +Fl(.)p eop +34 35 bop 0 -58 a Fl(34)1623 b(Bash)15 b(F)l(eatures)0 +183 y Ff(6.1.2)30 b(W)-5 b(ord)15 b(Designators)62 320 +y Fl(A)i Fk(:)g Fl(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j +(from)d(the)g(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted) +g(if)g(the)g(w)o(ord)0 382 y(designator)d(b)q(egins)h(with)f(a)f +Fk(^)p Fl(,)h Fk($)p Fl(,)f Fk(*)h Fl(or)f Fk(\045)p +Fl(.)20 b(W)l(ords)13 b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q +(eginning)i(of)d(the)h(line,)i(with)e(the)0 445 y(\014rst)h(w)o(ord)f +(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f(\(zero\).)0 593 +y Fk(0)h(\(zero\))57 b Fl(The)15 b Fk(0)p Fl(th)g(w)o(ord.)20 +b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f(command)g(w)o +(ord.)0 679 y Fk(n)216 b Fl(The)15 b Fg(n)p Fl(th)h(w)o(ord.)0 +765 y Fk(^)216 b Fl(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o +(ord)g(1.)0 851 y Fk($)216 b Fl(The)15 b(last)h(argumen)o(t.)0 +937 y Fk(\045)216 b Fl(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g +(most)g(recen)o(t)g Fk(?string?)f Fl(searc)o(h.)0 1022 +y Fk(x-y)168 b Fl(A)15 b(range)g(of)g(w)o(ords;)f Fk(-)p +Fg(y)19 b Fl(abbreviates)c Fk(0-)p Fg(y)t Fl(.)0 1108 +y Fk(*)216 b Fl(All)17 b(of)f(the)g(w)o(ords,)f(except)i(the)f +Fk(0)p Fl(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f +Fk(1-$)p Fl(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 +1170 y Fk(*)f Fl(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g +(ev)o(en)o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e +(case.)0 1256 y Fk(x*)192 b Fl(Abbreviates)16 b Fk(x-$)0 +1342 y(x-)192 b Fl(Abbreviates)16 b Fk(x-$)f Fl(lik)o(e)h +Fk(x*)p Fl(,)e(but)i(omits)f(the)g(last)g(w)o(ord.)0 +1547 y Ff(6.1.3)30 b(Mo)r(di\014ers)62 1684 y Fl(After)20 +b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h(add)g(a)g +(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 +1746 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g +Fk(:)p Fl(.)0 1895 y Fk(h)216 b Fl(Remo)o(v)o(e)15 b(a)g(trailing)h +(pathname)f(comp)q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 +1980 y Fk(r)216 b Fl(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g +(the)g(form)g(`)p Fk(.)p Fl(')p Fg(su\016x)p Fl(,)f(lea)o(ving)i(the)f +(basename.)0 2066 y Fk(e)216 b Fl(Remo)o(v)o(e)15 b(all)h(but)g(the)f +(trailing)h(su\016x.)0 2152 y Fk(t)216 b Fl(Remo)o(v)o(e)15 +b(all)h(leading)h(pathname)e(comp)q(onen)o(ts,)g(lea)o(ving)h(the)f +(tail.)0 2238 y Fk(p)216 b Fl(Prin)o(t)15 b(the)g(new)h(command)f(but)g +(do)g(not)g(execute)h(it.)0 2323 y Fk(q)216 b Fl(Quote)15 +b(the)h(substituted)g(w)o(ords,)e(escaping)i(further)f(substitutions.)0 +2409 y Fk(x)216 b Fl(Quote)22 b(the)f(substituted)h(w)o(ords)f(as)g +(with)h Fk(q)p Fl(,)h(but)e(break)h(in)o(to)f(w)o(ords)g(at)g(spaces,)i +(tabs,)f(and)240 2471 y(newlines.)0 2545 y Fk(s/old/new/)240 +2608 y Fl(Substitute)16 b Fg(new)k Fl(for)15 b(the)h(\014rst)f(o)q +(ccurrence)h(of)g Fg(old)h Fl(in)g(the)e(ev)o(en)o(t)h(line.)22 +b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2670 y(used)e(in)f(place)h +(of)f Fk(/)p Fl(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q(e)i(quoted)f +(in)h Fg(old)h Fl(and)e Fg(new)17 b Fl(with)12 b(a)g(single)h(bac)o +(kslash.)p eop +35 36 bop 0 -58 a Fl(Chapter)15 b(6:)k(Using)d(History)f(In)o(teractiv) +o(ely)1135 b(35)240 183 y(If)13 b Fk(&)h Fl(app)q(ears)f(in)h +Fg(new)p Fl(,)f(it)h(is)g(replaced)g(b)o(y)f Fg(old)p +Fl(.)20 b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h +Fk(&)p Fl(.)19 b(The)13 b(\014nal)240 246 y(delimiter)k(is)f(optional)g +(if)f(it)h(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 +333 y Fk(&)216 b Fl(Rep)q(eat)16 b(the)f(previous)h(substitution.)0 +420 y Fk(g)216 b Fl(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o +(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 +b(in)g(conjunction)g(with)f Fk(s)p Fl(,)f(as)240 482 +y(in)i Fk(gs/old/new/)p Fl(,)d(or)i(with)h Fk(&)p Fl(.)p +eop +36 37 bop 0 -58 a Fl(36)1623 b(Bash)15 b(F)l(eatures)p +eop +37 38 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(37)0 183 y Fh(7)41 b(Command)16 b(Line)f(Editing)62 +408 y Fl(This)h(c)o(hapter)f(describ)q(es)i(the)e(basic)h(features)f +(of)g(the)g(GNU)g(command)g(line)i(editing)f(in)o(terface.)0 +701 y Fj(7.1)33 b(In)n(tro)r(duction)17 b(to)e(Line)h(Editing)62 +845 y Fl(The)g(follo)o(wing)g(paragraphs)e(describ)q(e)j(the)e +(notation)g(used)h(to)e(represen)o(t)i(k)o(eystrok)o(es.)62 +990 y(The)f(text)e Fk(C-K)h Fl(is)g(read)g(as)g(`Con)o(trol-K')f(and)h +(describ)q(es)i(the)e(c)o(haracter)f(pro)q(duced)i(when)g(the)f(Con)o +(trol)f(k)o(ey)0 1052 y(is)j(depressed)g(and)f(the)h +Fk(K)f Fl(k)o(ey)g(is)g(struc)o(k.)62 1197 y(The)i(text)f +Fk(M-K)g Fl(is)i(read)e(as)g(`Meta-K')g(and)h(describ)q(es)h(the)f(c)o +(haracter)f(pro)q(duced)h(when)h(the)e(meta)g(k)o(ey)h(\(if)0 +1259 y(y)o(ou)g(ha)o(v)o(e)f(one\))h(is)g(depressed,)h(and)f(the)g +Fk(K)g Fl(k)o(ey)g(is)g(struc)o(k.)25 b(If)17 b(y)o(ou)f(do)h(not)g(ha) +o(v)o(e)f(a)h(meta)f(k)o(ey)l(,)h(the)g(iden)o(tical)0 +1321 y(k)o(eystrok)o(e)i(can)g(b)q(e)i(generated)e(b)o(y)h(t)o(yping)f +Fk(ESC)h Fg(\014rst)p Fl(,)g(and)f(then)h(t)o(yping)g +Fk(K)p Fl(.)33 b(Either)20 b(pro)q(cess)g(is)g(kno)o(wn)f(as)0 +1383 y Fg(metafying)g Fl(the)c Fk(K)g Fl(k)o(ey)l(.)62 +1528 y(The)h(text)e Fk(M-C-K)g Fl(is)i(read)f(as)f(`Meta-Con)o(trol-k') +g(and)h(describ)q(es)h(the)g(c)o(haracter)e(pro)q(duced)i(b)o(y)f +Fg(metafying)0 1590 y Fk(C-K)p Fl(.)62 1735 y(In)i(addition,)h(sev)o +(eral)e(k)o(eys)g(ha)o(v)o(e)g(their)h(o)o(wn)f(names.)23 +b(Sp)q(eci\014cally)m(,)c Fk(DEL)p Fl(,)d Fk(ESC)p Fl(,)f +Fk(LFD)p Fl(,)h Fk(SPC)p Fl(,)g Fk(RET)p Fl(,)g(and)g +Fk(TAB)0 1797 y Fl(all)e(stand)f(for)f(themselv)o(es)i(when)f(seen)h +(in)g(this)f(text,)g(or)g(in)g(an)g(init)i(\014le)f(\(see)f(Section)h +(7.3)e([Readline)j(Init)f(File],)0 1859 y(page)h(40,)f(for)h(more)g +(info\).)0 2152 y Fj(7.2)33 b(Readline)16 b(In)n(teraction)62 +2296 y Fl(Often)g(during)h(an)f(in)o(teractiv)o(e)g(session)h(y)o(ou)e +(t)o(yp)q(e)h(in)h(a)f(long)g(line)h(of)f(text,)f(only)h(to)g(notice)g +(that)f(the)h(\014rst)0 2359 y(w)o(ord)d(on)i(the)f(line)i(is)e(missp)q +(elled.)23 b(The)14 b(Readline)i(library)f(giv)o(es)g(y)o(ou)e(a)h(set) +g(of)g(commands)g(for)f(manipulating)0 2421 y(the)18 +b(text)g(as)g(y)o(ou)g(t)o(yp)q(e)g(it)h(in,)g(allo)o(wing)g(y)o(ou)f +(to)g(just)g(\014x)g(y)o(our)g(t)o(yp)q(o,)g(and)h(not)f(forcing)g(y)o +(ou)g(to)g(ret)o(yp)q(e)g(the)0 2483 y(ma)s(jorit)o(y)d(of)h(the)g +(line.)25 b(Using)17 b(these)g(editing)h(commands,)e(y)o(ou)g(mo)o(v)o +(e)f(the)i(cursor)f(to)g(the)g(place)h(that)f(needs)0 +2545 y(correction,)g(and)h(delete)g(or)f(insert)g(the)h(text)e(of)h +(the)g(corrections.)23 b(Then,)17 b(when)g(y)o(ou)f(are)g(satis\014ed)g +(with)h(the)0 2608 y(line,)h(y)o(ou)e(simply)i(press)f +Fk(RETURN)p Fl(.)23 b(Y)l(ou)17 b(do)f(not)g(ha)o(v)o(e)g(to)g(b)q(e)i +(at)e(the)g(end)h(of)f(the)h(line)h(to)e(press)h Fk(RETURN)p +Fl(;)f(the)0 2670 y(en)o(tire)g(line)h(is)e(accepted)h(regardless)f(of) +g(the)g(lo)q(cation)h(of)f(the)h(cursor)e(within)j(the)e(line.)p +eop +38 39 bop 0 -58 a Fl(38)1623 b(Bash)15 b(F)l(eatures)0 +183 y Ff(7.2.1)30 b(Readline)15 b(Bare)g(Essen)n(tials)62 +320 y Fl(In)f(order)f(to)f(en)o(ter)h(c)o(haracters)g(in)o(to)g(the)g +(line,)i(simply)f(t)o(yp)q(e)f(them.)19 b(The)14 b(t)o(yp)q(ed)f(c)o +(haracter)f(app)q(ears)i(where)0 383 y(the)h(cursor)h(w)o(as,)e(and)h +(then)h(the)g(cursor)f(mo)o(v)o(es)f(one)i(space)g(to)e(the)i(righ)o +(t.)k(If)c(y)o(ou)f(mist)o(yp)q(e)h(a)f(c)o(haracter,)f(y)o(ou)0 +445 y(can)h(use)h(y)o(our)f(erase)g(c)o(haracter)f(to)h(bac)o(k)g(up)g +(and)h(delete)g(the)f(mist)o(yp)q(ed)h(c)o(haracter.)62 +582 y(Sometimes)f(y)o(ou)e(ma)o(y)h(miss)g(t)o(yping)g(a)g(c)o +(haracter)g(that)f(y)o(ou)h(w)o(an)o(ted)f(to)g(t)o(yp)q(e,)h(and)h +(not)e(notice)i(y)o(our)f(error)0 644 y(un)o(til)k(y)o(ou)e(ha)o(v)o(e) +g(t)o(yp)q(ed)h(sev)o(eral)g(other)f(c)o(haracters.)23 +b(In)18 b(that)d(case,)i(y)o(ou)f(can)h(t)o(yp)q(e)g +Fk(C-B)f Fl(to)g(mo)o(v)o(e)g(the)g(cursor)0 706 y(to)f(the)h(left,)g +(and)g(then)g(correct)f(y)o(our)h(mistak)o(e.)21 b(Afterw)o(ards,)14 +b(y)o(ou)i(can)g(mo)o(v)o(e)f(the)h(cursor)f(to)g(the)h(righ)o(t)g +(with)0 769 y Fk(C-F)p Fl(.)62 906 y(When)i(y)o(ou)f(add)g(text)g(in)h +(the)f(middle)i(of)e(a)g(line,)i(y)o(ou)e(will)i(notice)e(that)g(c)o +(haracters)f(to)h(the)g(righ)o(t)g(of)g(the)0 968 y(cursor)h(are)h +(`pushed)g(o)o(v)o(er')e(to)h(mak)o(e)g(ro)q(om)g(for)g(the)h(text)f +(that)g(y)o(ou)g(ha)o(v)o(e)h(inserted.)31 b(Lik)o(ewise,)20 +b(when)f(y)o(ou)0 1030 y(delete)f(text)f(b)q(ehind)i(the)f(cursor,)f(c) +o(haracters)f(to)h(the)g(righ)o(t)g(of)g(the)h(cursor)f(are)g(`pulled)i +(bac)o(k')d(to)h(\014ll)i(in)f(the)0 1092 y(blank)g(space)f(created)g +(b)o(y)g(the)h(remo)o(v)m(al)f(of)f(the)i(text.)25 b(A)17 +b(list)h(of)e(the)h(basic)h(bare)f(essen)o(tials)h(for)e(editing)j(the) +0 1155 y(text)c(of)f(an)i(input)g(line)h(follo)o(ws.)0 +1304 y Fk(C-B)168 b Fl(Mo)o(v)o(e)14 b(bac)o(k)h(one)h(c)o(haracter.)0 +1391 y Fk(C-F)168 b Fl(Mo)o(v)o(e)14 b(forw)o(ard)g(one)h(c)o +(haracter.)0 1478 y Fk(DEL)168 b Fl(Delete)16 b(the)f(c)o(haracter)g +(to)f(the)h(left)h(of)f(the)g(cursor.)0 1566 y Fk(C-D)168 +b Fl(Delete)16 b(the)f(c)o(haracter)g(underneath)h(the)f(cursor.)0 +1640 y(Prin)o(ting)h(c)o(haracters)240 1703 y(Insert)f(the)h(c)o +(haracter)e(in)o(to)h(the)h(line)h(at)d(the)h(cursor.)0 +1790 y Fk(C-_)168 b Fl(Undo)15 b(the)h(last)f(thing)h(that)e(y)o(ou)h +(did.)21 b(Y)l(ou)15 b(can)h(undo)f(all)h(the)g(w)o(a)o(y)e(bac)o(k)h +(to)f(an)i(empt)o(y)e(line.)0 1997 y Ff(7.2.2)30 b(Readline)15 +b(Mo)n(v)n(emen)n(t)h(Commands)62 2134 y Fl(The)c(ab)q(o)o(v)o(e)g +(table)g(describ)q(es)i(the)e(most)f(basic)h(p)q(ossible)i(k)o(eystrok) +o(es)d(that)g(y)o(ou)g(need)i(in)g(order)f(to)f(do)h(editing)0 +2197 y(of)g(the)h(input)h(line.)21 b(F)l(or)12 b(y)o(our)g(con)o(v)o +(enience,)i(man)o(y)f(other)f(commands)h(ha)o(v)o(e)f(b)q(een)i(added)f +(in)h(addition)g(to)e Fk(C-B)p Fl(,)0 2259 y Fk(C-F)p +Fl(,)i Fk(C-D)p Fl(,)h(and)g Fk(DEL)p Fl(.)20 b(Here)15 +b(are)g(some)g(commands)g(for)f(mo)o(ving)h(more)g(rapidly)i(ab)q(out)e +(the)g(line.)0 2408 y Fk(C-A)168 b Fl(Mo)o(v)o(e)14 b(to)h(the)g(start) +f(of)h(the)g(line.)0 2496 y Fk(C-E)168 b Fl(Mo)o(v)o(e)14 +b(to)h(the)g(end)h(of)f(the)g(line.)0 2583 y Fk(M-F)168 +b Fl(Mo)o(v)o(e)14 b(forw)o(ard)g(a)h(w)o(ord.)0 2670 +y Fk(M-B)168 b Fl(Mo)o(v)o(e)14 b(bac)o(kw)o(ard)h(a)g(w)o(ord.)p +eop +39 40 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(39)0 183 y Fk(C-L)168 b Fl(Clear)15 b(the)h(screen,)f(reprin)o(ting)h +(the)f(curren)o(t)g(line)i(at)e(the)g(top.)62 350 y(Notice)22 +b(ho)o(w)e Fk(C-F)h Fl(mo)o(v)o(es)f(forw)o(ard)g(a)g(c)o(haracter,)i +(while)g Fk(M-F)f Fl(mo)o(v)o(es)f(forw)o(ard)g(a)h(w)o(ord.)36 +b(It)21 b(is)h(a)f(lo)q(ose)0 412 y(con)o(v)o(en)o(tion)15 +b(that)g(con)o(trol)g(k)o(eystrok)o(es)f(op)q(erate)h(on)g(c)o +(haracters)f(while)j(meta)e(k)o(eystrok)o(es)f(op)q(erate)h(on)g(w)o +(ords.)0 696 y Ff(7.2.3)30 b(Readline)15 b(Killing)g(Commands)62 +841 y Fg(Killing)25 b Fl(text)18 b(means)g(to)f(delete)i(the)g(text)e +(from)h(the)g(line,)i(but)e(to)g(sa)o(v)o(e)f(it)i(a)o(w)o(a)o(y)d(for) +i(later)g(use,)h(usually)0 903 y(b)o(y)c Fg(y)o(anking)k +Fl(\(re-inserting\))c(it)g(bac)o(k)g(in)o(to)g(the)g(line.)21 +b(If)16 b(the)f(description)h(for)e(a)h(command)f(sa)o(ys)h(that)f(it)h +(`kills')0 966 y(text,)f(then)i(y)o(ou)f(can)g(b)q(e)h(sure)f(that)g(y) +o(ou)g(can)g(get)g(the)g(text)g(bac)o(k)g(in)h(a)f(di\013eren)o(t)g +(\(or)f(the)i(same\))e(place)i(later.)62 1111 y(When)g(y)o(ou)f(use)g +(a)g(kill)i(command,)e(the)h(text)e(is)i(sa)o(v)o(ed)f(in)h(a)f +Fg(kill-ring)p Fl(.)22 b(An)o(y)16 b(n)o(um)o(b)q(er)f(of)g(consecutiv) +o(e)h(kills)0 1173 y(sa)o(v)o(e)g(all)i(of)e(the)h(killed)i(text)d +(together,)g(so)g(that)g(when)h(y)o(ou)f(y)o(ank)h(it)g(bac)o(k,)f(y)o +(ou)h(get)f(it)h(all.)25 b(The)17 b(kill)h(ring)f(is)0 +1236 y(not)e(line)i(sp)q(eci\014c;)g(the)f(text)f(that)g(y)o(ou)g +(killed)j(on)d(a)h(previously)g(t)o(yp)q(ed)g(line)h(is)f(a)o(v)m +(ailable)i(to)d(b)q(e)h(y)o(ank)o(ed)f(bac)o(k)0 1298 +y(later,)g(when)h(y)o(ou)e(are)h(t)o(yping)h(another)e(line.)62 +1443 y(Here)i(is)f(the)h(list)g(of)e(commands)h(for)g(killing)j(text.)0 +1610 y Fk(C-K)168 b Fl(Kill)17 b(the)f(text)e(from)h(the)g(curren)o(t)g +(cursor)g(p)q(osition)h(to)f(the)g(end)h(of)f(the)g(line.)0 +1714 y Fk(M-D)168 b Fl(Kill)17 b(from)d(the)h(cursor)g(to)f(the)h(end)g +(of)g(the)g(curren)o(t)f(w)o(ord,)g(or)g(if)i(b)q(et)o(w)o(een)f(w)o +(ords,)f(to)g(the)h(end)g(of)240 1776 y(the)g(next)h(w)o(ord.)0 +1880 y Fk(M-DEL)120 b Fl(Kill)16 b(from)d(the)i(cursor)e(the)h(start)f +(of)h(the)g(previous)h(w)o(ord,)e(or)g(if)i(b)q(et)o(w)o(een)f(w)o +(ords,)f(to)h(the)g(start)e(of)240 1942 y(the)j(previous)h(w)o(ord.)0 +2046 y Fk(C-W)168 b Fl(Kill)18 b(from)e(the)g(cursor)g(to)f(the)h +(previous)h(whitespace.)24 b(This)17 b(is)f(di\013eren)o(t)h(than)f +Fk(M-DEL)f Fl(b)q(ecause)240 2109 y(the)g(w)o(ord)g(b)q(oundaries)h +(di\013er.)62 2275 y(And,)e(here)g(is)h(ho)o(w)e(to)g +Fg(y)o(ank)j Fl(the)e(text)f(bac)o(k)g(in)o(to)h(the)f(line.)22 +b(Y)l(anking)14 b(means)g(to)f(cop)o(y)g(the)h(most-recen)o(tly-)0 +2337 y(killed)j(text)e(from)g(the)g(kill)i(bu\013er.)0 +2504 y Fk(C-Y)168 b Fl(Y)l(ank)15 b(the)h(most)e(recen)o(tly)i(killed)h +(text)e(bac)o(k)g(in)o(to)g(the)h(bu\013er)f(at)f(the)i(cursor.)0 +2608 y Fk(M-Y)168 b Fl(Rotate)13 b(the)h(kill-ring,)i(and)e(y)o(ank)g +(the)g(new)g(top.)19 b(Y)l(ou)14 b(can)g(only)g(do)g(this)g(if)g(the)g +(prior)g(command)240 2670 y(is)i Fk(C-Y)e Fl(or)h Fk(M-Y)p +Fl(.)p eop +40 41 bop 0 -58 a Fl(40)1623 b(Bash)15 b(F)l(eatures)0 +183 y Ff(7.2.4)30 b(Readline)15 b(Argumen)n(ts)62 330 +y Fl(Y)l(ou)k(can)g(pass)f(n)o(umeric)i(argumen)o(ts)d(to)h(Readline)j +(commands.)30 b(Sometimes)19 b(the)f(argumen)o(t)g(acts)g(as)g(a)0 +392 y(rep)q(eat)f(coun)o(t,)f(other)g(times)g(it)h(is)g(the)g +Fg(sign)f Fl(of)g(the)h(argumen)o(t)f(that)f(is)i(signi\014can)o(t.)25 +b(If)16 b(y)o(ou)h(pass)f(a)g(negativ)o(e)0 455 y(argumen)o(t)g(to)g(a) +h(command)g(whic)o(h)h(normally)f(acts)g(in)h(a)e(forw)o(ard)g +(direction,)i(that)f(command)f(will)j(act)d(in)i(a)0 +517 y(bac)o(kw)o(ard)13 b(direction.)21 b(F)l(or)13 b(example,)h(to)f +(kill)i(text)e(bac)o(k)h(to)f(the)h(start)e(of)h(the)h(line,)h(y)o(ou)e +(migh)o(t)h(t)o(yp)q(e)g Fk(M--)f(C-K)p Fl(.)62 664 y(The)19 +b(general)g(w)o(a)o(y)f(to)g(pass)g(n)o(umeric)i(argumen)o(ts)e(to)g(a) +g(command)h(is)g(to)f(t)o(yp)q(e)g(meta)g(digits)i(b)q(efore)f(the)0 +726 y(command.)36 b(If)21 b(the)g(\014rst)f(`digit')h(y)o(ou)g(t)o(yp)q +(e)f(is)i(a)e(min)o(us)h(sign)g(\()p Fk(-)p Fl(\),)g(then)g(the)g(sign) +g(of)g(the)f(argumen)o(t)g(will)0 788 y(b)q(e)i(negativ)o(e.)40 +b(Once)22 b(y)o(ou)f(ha)o(v)o(e)h(t)o(yp)q(ed)g(one)f(meta)g(digit)i +(to)e(get)g(the)h(argumen)o(t)f(started,)h(y)o(ou)f(can)h(t)o(yp)q(e)0 +851 y(the)c(remainder)h(of)f(the)g(digits,)h(and)f(then)h(the)f +(command.)29 b(F)l(or)17 b(example,)i(to)f(giv)o(e)g(the)g +Fk(C-D)g Fl(command)g(an)0 913 y(argumen)o(t)c(of)h(10,)f(y)o(ou)h +(could)h(t)o(yp)q(e)g Fk(M-1)23 b(0)h(C-D)p Fl(.)0 1226 +y Fj(7.3)33 b(Readline)16 b(Init)g(File)62 1373 y Fl(Although)g(the)g +(Readline)h(library)g(comes)e(with)h(a)f(set)g(of)g(Emacs-lik)o(e)h(k)o +(eybindings)h(installed)g(b)o(y)f(default,)0 1435 y(it)e(is)g(p)q +(ossible)i(that)d(y)o(ou)g(w)o(ould)h(lik)o(e)h(to)e(use)h(a)f +(di\013eren)o(t)h(set)g(of)f(k)o(eybindings.)21 b(Y)l(ou)14 +b(can)g(customize)g(programs)0 1497 y(that)i(use)i(Readline)h(b)o(y)e +(putting)h(commands)f(in)h(an)f Fg(init)i Fl(\014le)f(in)g(y)o(our)f +(home)g(directory)l(.)26 b(The)18 b(name)f(of)g(this)0 +1559 y(\014le)h(is)g(tak)o(en)f(from)g(the)g(v)m(alue)i(of)e(the)g +(shell)i(v)m(ariable)g Fk(INPUTRC)p Fl(.)25 b(If)18 b(that)f(v)m +(ariable)h(is)g(unset,)g(the)f(default)h(is)0 1622 y(`)p +Fk(~/.inputrc)p Fl('.)62 1769 y(When)h(a)g(program)e(whic)o(h)j(uses)f +(the)g(Readline)i(library)e(starts)f(up,)h(the)g(init)h(\014le)g(is)f +(read,)g(and)g(the)g(k)o(ey)0 1831 y(bindings)e(are)e(set.)62 +1978 y(In)j(addition,)h(the)f Fk(C-x)c(C-r)k Fl(command)f(re-reads)g +(this)h(init)h(\014le,)g(th)o(us)e(incorp)q(orating)h(an)o(y)f(c)o +(hanges)h(that)0 2040 y(y)o(ou)d(migh)o(t)g(ha)o(v)o(e)g(made)g(to)f +(it.)0 2336 y Ff(7.3.1)30 b(Readline)15 b(Init)g(Syn)n(tax)62 +2483 y Fl(There)h(are)f(only)h(a)f(few)g(basic)h(constructs)f(allo)o(w) +o(ed)h(in)g(the)g(Readline)i(init)e(\014le.)22 b(Blank)16 +b(lines)h(are)e(ignored.)0 2545 y(Lines)j(b)q(eginning)g(with)f(a)f +Fk(#)g Fl(are)g(commen)o(ts.)22 b(Lines)c(b)q(eginning)g(with)f(a)f +Fk($)g Fl(indicate)h(conditional)h(constructs)0 2608 +y(\(see)d(Section)g(7.3.2)e([Conditional)j(Init)f(Constructs],)f(page)g +(43\).)19 b(Other)c(lines)h(denote)f(v)m(ariable)h(settings)f(and)0 +2670 y(k)o(ey)g(bindings.)p eop +41 42 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(41)0 183 y(V)l(ariable)16 b(Settings)240 246 y(Y)l(ou)j(can)g(c)o +(hange)g(the)g(state)f(of)g(a)g(few)h(v)m(ariables)h(in)g(Readline)h(b) +o(y)d(using)i(the)f Fk(set)f Fl(command)240 308 y(within)e(the)f(init)h +(\014le.)k(Here)15 b(is)g(ho)o(w)g(y)o(ou)f(w)o(ould)h(sp)q(ecify)h +(that)e(y)o(ou)g(wish)i(to)e(use)h Fk(vi)f Fl(line)j(editing)240 +370 y(commands:)360 433 y Fk(set)23 b(editing-mode)g(vi)240 +509 y Fl(Righ)o(t)14 b(no)o(w,)f(there)h(are)f(only)h(a)f(few)h(v)m +(ariables)g(whic)o(h)h(can)f(b)q(e)g(set;)f(so)g(few,)h(in)g(fact,)f +(that)g(w)o(e)g(just)240 571 y(list)j(them)f(here:)240 +647 y Fk(editing-mode)480 709 y Fl(The)e Fk(editing-mode)e +Fl(v)m(ariable)j(con)o(trols)e(whic)o(h)h(editing)h(mo)q(de)f(y)o(ou)f +(are)g(using.)20 b(By)480 771 y(default,)f(Readline)h(starts)c(up)i(in) +h(Emacs)e(editing)i(mo)q(de,)f(where)g(the)g(k)o(eystrok)o(es)480 +833 y(are)c(most)g(similar)h(to)f(Emacs.)19 b(This)c(v)m(ariable)h(can) +f(b)q(e)g(set)f(to)g(either)h Fk(emacs)f Fl(or)g Fk(vi)p +Fl(.)240 909 y Fk(horizontal-scroll-mode)480 971 y Fl(This)k(v)m +(ariable)g(can)f(b)q(e)g(set)g(to)f(either)i Fk(On)f +Fl(or)f Fk(Off)p Fl(.)25 b(Setting)17 b(it)g(to)f Fk(On)h +Fl(means)g(that)480 1033 y(the)d(text)g(of)f(the)h(lines)i(that)d(y)o +(ou)h(edit)h(will)g(scroll)g(horizon)o(tally)g(on)f(a)g(single)h +(screen)480 1096 y(line)f(when)f(they)g(are)f(longer)h(than)f(the)h +(width)g(of)f(the)g(screen,)h(instead)g(of)g(wrapping)480 +1158 y(on)o(to)h(a)h(new)h(screen)f(line.)22 b(By)15 +b(default,)h(this)f(v)m(ariable)i(is)f(set)e(to)h Fk(Off)p +Fl(.)240 1234 y Fk(mark-modified-lines)480 1296 y Fl(This)h(v)m +(ariable,)g(when)g(set)f(to)f Fk(On)p Fl(,)h(sa)o(ys)f(to)g(displa)o(y) +j(an)e(asterisk)g(\(`)p Fk(*)p Fl('\))e(at)i(the)g(start)480 +1358 y(of)f(history)h(lines)i(whic)o(h)e(ha)o(v)o(e)g(b)q(een)h(mo)q +(di\014ed.)21 b(This)15 b(v)m(ariable)h(is)g Fk(off)e +Fl(b)o(y)h(default.)240 1434 y Fk(bell-style)480 1496 +y Fl(Con)o(trols)h(what)f(happ)q(ens)j(when)f(Readline)h(w)o(an)o(ts)e +(to)f(ring)i(the)f(terminal)h(b)q(ell.)26 b(If)480 1558 +y(set)13 b(to)g Fk(none)p Fl(,)g(Readline)j(nev)o(er)e(rings)g(the)g(b) +q(ell.)21 b(If)14 b(set)f(to)g Fk(visible)p Fl(,)g(Readline)j(uses)480 +1621 y(a)g(visible)j(b)q(ell)g(if)e(one)g(is)g(a)o(v)m(ailable.)27 +b(If)17 b(set)f(to)g Fk(audible)g Fl(\(the)h(default\),)g(Readline)480 +1683 y(attempts)d(to)h(ring)g(the)h(terminal's)f(b)q(ell.)240 +1758 y Fk(comment-begin)480 1821 y Fl(The)21 b(string)h(to)e(insert)i +(at)e(the)h(b)q(eginning)j(of)c(the)i(line)g(when)g(the)f +Fk(vi-comment)480 1883 y Fl(command)15 b(is)h(executed.)21 +b(The)15 b(default)h(v)m(alue)g(is)g Fk("#")p Fl(.)240 +1958 y Fk(meta-flag)480 2021 y Fl(If)d(set)g(to)f Fk(on)p +Fl(,)g(Readline)j(will)g(enable)f(eigh)o(t-bit)f(input)h(\(it)f(will)h +(not)f(strip)g(the)g(eigh)o(th)480 2083 y(bit)i(from)g(the)g(c)o +(haracters)f(it)h(reads\),)f(regardless)h(of)g(what)f(the)h(terminal)h +(claims)g(it)480 2145 y(can)f(supp)q(ort.)20 b(The)c(default)g(v)m +(alue)g(is)g Fk(off)p Fl(.)240 2221 y Fk(convert-meta)480 +2283 y Fl(If)23 b(set)f(to)f Fk(on)p Fl(,)j(Readline)h(will)f(con)o(v)o +(ert)d(c)o(haracters)h(with)g(the)h(eigth)g(bit)f(set)h(to)480 +2345 y(an)17 b(ASCI)q(I)g(k)o(ey)g(sequence)h(b)o(y)e(stripping)i(the)f +(eigth)g(bit)g(and)g(prep)q(ending)i(an)d Fk(ESC)480 +2408 y Fl(c)o(haracter,)h(con)o(v)o(erting)g(them)g(to)f(a)h +(meta-pre\014xed)h(k)o(ey)f(sequence.)27 b(The)17 b(default)480 +2470 y(v)m(alue)f(is)g Fk(on)p Fl(.)240 2545 y Fk(output-meta)480 +2608 y Fl(If)d(set)f(to)g Fk(on)p Fl(,)h(Readline)i(will)f(displa)o(y)g +(c)o(haracters)d(with)i(the)g(eigh)o(th)g(bit)g(set)g(directly)480 +2670 y(rather)i(than)g(as)f(a)h(meta-pre\014xed)h(escap)q(e)g +(sequence.)21 b(The)16 b(default)f(is)h Fk(off)p Fl(.)p +eop +42 43 bop 0 -58 a Fl(42)1623 b(Bash)15 b(F)l(eatures)240 +183 y Fk(completion-query-items)480 246 y Fl(The)d(n)o(um)o(b)q(er)g +(of)f(p)q(ossible)j(completions)e(that)f(determines)i(when)f(the)g +(user)g(is)g(ask)o(ed)480 308 y(whether)k(he)h(w)o(an)o(ts)d(to)i(see)g +(the)g(list)h(of)e(p)q(ossibiliti)q(es.)25 b(If)16 b(the)g(n)o(um)o(b)q +(er)h(of)e(p)q(ossible)480 370 y(completions)i(is)f(greater)f(than)h +(this)h(v)m(alue,)f(Readline)j(will)e(ask)f(the)g(user)g(whether)480 +432 y(or)k(not)h(he)h(wishes)f(to)g(view)g(them;)j(otherwise,)e(they)f +(are)g(simply)h(listed.)39 b(The)480 495 y(default)16 +b(limit)g(is)g Fk(100)p Fl(.)240 588 y Fk(keymap)96 b +Fl(Sets)13 b(Readline's)i(idea)e(of)g(the)g(curren)o(t)f(k)o(eymap)h +(for)f(k)o(ey)h(binding)i(commands.)k(Ac-)480 651 y(ceptable)d +Fk(keymap)e Fl(names)h(are)g Fk(emacs)p Fl(,)f Fk(emacs-standard)p +Fl(,)f Fk(emacs-meta)p Fl(,)g Fk(emacs-)480 713 y(ctlx)p +Fl(,)j Fk(vi)p Fl(,)h Fk(vi-move)p Fl(,)f Fk(vi-command)p +Fl(,)g(and)h Fk(vi-insert)p Fl(.)23 b Fk(vi)17 b Fl(is)g(equiv)m(alen)o +(t)i(to)d Fk(vi-)480 775 y(command)p Fl(;)22 b Fk(emacs)e +Fl(is)h(equiv)m(alen)o(t)h(to)e Fk(emacs-standard)p Fl(.)35 +b(The)20 b(default)i(v)m(alue)f(is)480 838 y Fk(emacs)p +Fl(.)33 b(The)21 b(v)m(alue)g(of)e(the)i Fk(editing-mode)d +Fl(v)m(ariable)j(also)f(a\013ects)f(the)h(default)480 +900 y(k)o(eymap.)240 978 y Fk(show-all-if-ambiguous)480 +1040 y Fl(This)d(alters)f(the)h(default)g(b)q(eha)o(vior)g(of)f(the)g +(completion)i(functions.)24 b(If)17 b(set)f(to)g Fk(on)p +Fl(,)480 1102 y(w)o(ords)d(whic)o(h)h(ha)o(v)o(e)f(more)h(than)f(one)h +(p)q(ossible)h(completion)g(cause)f(the)f(matc)o(hes)h(to)480 +1165 y(b)q(e)h(listed)g(immediately)h(instead)f(of)f(ringing)h(the)f(b) +q(ell.)22 b(The)14 b(default)h(v)m(alue)g(is)g Fk(off)p +Fl(.)240 1243 y Fk(expand-tilde)480 1305 y Fl(If)20 b(set)f(to)g +Fk(on)p Fl(,)h(tilde)h(expansion)f(is)g(p)q(erformed)g(when)g(Readline) +i(attempts)d(w)o(ord)480 1367 y(completion.)i(The)15 +b(default)h(is)g Fk(off)p Fl(.)0 1445 y(Key)g(Bindings)240 +1508 y(The)k(syn)o(tax)f(for)g(con)o(trolling)i(k)o(ey)e(bindings)j(in) +e(the)g(init)h(\014le)g(is)f(simple.)35 b(First)19 b(y)o(ou)g(ha)o(v)o +(e)h(to)240 1570 y(kno)o(w)13 b(the)h(name)g(of)f(the)h(command)g(that) +f(y)o(ou)g(w)o(an)o(t)g(to)g(c)o(hange.)20 b(The)14 b(follo)o(wing)g +(pages)g(con)o(tain)240 1632 y(tables)i(of)f(the)h(command)g(name,)f +(the)h(default)g(k)o(eybinding,)i(and)e(a)f(short)g(description)i(of)f +(what)240 1694 y(the)f(command)g(do)q(es.)240 1772 y(Once)h(y)o(ou)e +(kno)o(w)g(the)h(name)g(of)f(the)h(command,)f(simply)i(place)g(the)f +(name)f(of)h(the)f(k)o(ey)h(y)o(ou)f(wish)240 1835 y(to)g(bind)j(the)e +(command)g(to,)f(a)g(colon,)i(and)f(then)g(the)g(name)g(of)g(the)g +(command)g(on)g(a)f(line)j(in)f(the)240 1897 y(init)h(\014le.)22 +b(The)16 b(name)g(of)f(the)h(k)o(ey)f(can)h(b)q(e)g(expressed)h(in)f +(di\013eren)o(t)g(w)o(a)o(ys,)f(dep)q(ending)i(on)f(whic)o(h)240 +1959 y(is)g(most)e(comfortable)h(for)g(y)o(ou.)240 2037 +y Fg(k)o(eyname)s Fl(:)k Fg(function-name)g Fl(or)c Fg(macro)480 +2100 y(k)o(eyname)j Fl(is)d(the)h(name)f(of)g(a)g(k)o(ey)g(sp)q(elled)i +(out)e(in)h(English.)21 b(F)l(or)15 b(example:)600 2165 +y Fk(Control-u:)22 b(universal-argument)600 2215 y(Meta-Rubout:)g +(backward-kill-word)600 2265 y(Control-o:)g(">&output")480 +2343 y Fl(In)12 b(the)g(ab)q(o)o(v)o(e)f(example,)h(`)p +Fk(C-u)p Fl(')f(is)h(b)q(ound)g(to)f(the)h(function)g +Fk(universal-argument)p Fl(,)480 2405 y(and)h(`)p Fk(C-o)p +Fl(')f(is)h(b)q(ound)h(to)f(run)g(the)g(macro)f(expressed)i(on)f(the)g +(righ)o(t)g(hand)g(side)h(\(that)480 2467 y(is,)h(to)g(insert)h(the)f +(text)g(`)p Fk(>&output)p Fl(')e(in)o(to)i(the)g(line\).)240 +2545 y Fk(")p Fg(k)o(eyseq)q Fk(")p Fl(:)20 b Fg(function-name)e +Fl(or)d Fg(macro)480 2608 y(k)o(eyseq)j Fl(di\013ers)f(from)f +Fg(k)o(eyname)k Fl(ab)q(o)o(v)o(e)c(in)i(that)e(strings)h(denoting)h +(an)f(en)o(tire)g(k)o(ey)480 2670 y(sequence)i(can)f(b)q(e)h(sp)q +(eci\014ed,)i(b)o(y)d(placing)h(the)f(k)o(ey)g(sequence)h(in)g(double)h +(quotes.)p eop +43 44 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(43)480 183 y(Some)18 b(GNU)g(Emacs)f(st)o(yle)h(k)o(ey)g(escap)q(es)g +(can)g(b)q(e)h(used,)g(as)e(in)i(the)f(follo)o(wing)h(ex-)480 +246 y(ample,)c(but)h(the)f(sp)q(ecial)i(c)o(haracter)e(names)g(are)g +(not)f(recognized.)600 308 y Fk("\\C-u":)23 b(universal-argument)600 +358 y("\\C-x\\C-r":)f(re-read-init-file)600 407 y("\\e[11~":)h +("Function)f(Key)i(1")480 482 y Fl(In)13 b(the)g(ab)q(o)o(v)o(e)g +(example,)g(`)p Fk(C-u)p Fl(')f(is)h(b)q(ound)h(to)e(the)h(function)g +Fk(universal-argument)480 544 y Fl(\(just)g(as)f(it)i(w)o(as)e(in)i +(the)f(\014rst)g(example\),)h(`)p Fk(C-x)g(C-r)p Fl(')f(is)g(b)q(ound)i +(to)d(the)h(function)h Fk(re-)480 607 y(read-init-file)p +Fl(,)g(and)i(`)p Fk(ESC)e([)h(1)g(1)g(~)p Fl(')h(is)g(b)q(ound)h(to)f +(insert)g(the)g(text)f(`)p Fk(Function)480 669 y(Key)g(1)p +Fl('.)24 b(The)18 b(follo)o(wing)f(escap)q(e)h(sequences)g(are)f(a)o(v) +m(ailable)i(when)e(sp)q(ecifying)i(k)o(ey)480 731 y(sequences:)480 +818 y Fk(\\C-)168 b Fl(con)o(trol)15 b(pre\014x)480 906 +y Fk(\\M-)168 b Fl(meta)15 b(pre\014x)480 993 y Fk(\\e)192 +b Fl(an)15 b(escap)q(e)h(c)o(haracter)480 1080 y Fk(\\\\)192 +b Fl(bac)o(kslash)480 1167 y Fk(\\")g(")480 1254 y(\\')g(')480 +1342 y Fl(When)14 b(en)o(tering)h(the)f(text)f(of)h(a)f(macro,)g +(single)j(or)d(double)i(quotes)f(should)h(b)q(e)f(used)480 +1404 y(to)g(indicate)j(a)e(macro)f(de\014nition.)22 b(Unquoted)15 +b(text)g(is)g(assumed)g(to)g(b)q(e)g(a)g(function)480 +1466 y(name.)27 b(Bac)o(kslash)18 b(will)h(quote)e(an)o(y)g(c)o +(haracter)g(in)h(the)g(macro)f(text,)g(including)j Fk(")480 +1528 y Fl(and)c Fk(')p Fl(.)22 b(F)l(or)16 b(example,)h(the)f(follo)o +(wing)h(binding)h(will)f(mak)o(e)f Fk(C-x)f(\\)g Fl(insert)i(a)f +(single)480 1591 y Fk(\\)f Fl(in)o(to)g(the)g(line:)600 +1653 y Fk("\\C-x\\\\":)23 b("\\\\")0 1860 y Ff(7.3.2)30 +b(Conditional)15 b(Init)g(Constructs)62 1997 y Fl(Readline)j(implemen)o +(ts)e(a)f(facilit)o(y)h(similar)g(in)g(spirit)g(to)f(the)g(conditional) +i(compilation)f(features)f(of)g(the)g(C)0 2060 y(prepro)q(cessor)f +(whic)o(h)h(allo)o(ws)f(k)o(ey)g(bindings)h(and)f(v)m(ariable)i +(settings)e(to)f(b)q(e)h(p)q(erformed)h(as)e(the)h(result)g(of)g +(tests.)0 2122 y(There)h(are)g(three)h(parser)e(directiv)o(es)j(used.)0 +2271 y Fk($if)168 b Fl(The)14 b Fk($if)e Fl(construct)h(allo)o(ws)h +(bindings)h(to)e(b)q(e)h(made)f(based)h(on)f(the)h(editing)g(mo)q(de,)g +(the)f(terminal)240 2334 y(b)q(eing)k(used,)e(or)g(the)g(application)i +(using)f(Readline.)22 b(The)16 b(text)f(of)g(the)g(test)g(extends)g(to) +g(the)g(end)240 2396 y(of)g(the)g(line;)i(no)e(c)o(haracters)f(are)h +(required)h(to)f(isolate)g(it.)240 2483 y Fk(mode)144 +b Fl(The)19 b Fk(mode=)f Fl(form)g(of)h(the)g Fk($if)f +Fl(directiv)o(e)i(is)f(used)h(to)e(test)g(whether)h(Readline)i(is)480 +2545 y(in)h Fk(emacs)f Fl(or)f Fk(vi)h Fl(mo)q(de.)38 +b(This)22 b(ma)o(y)f(b)q(e)h(used)g(in)g(conjunction)g(with)f(the)h(`)p +Fk(set)480 2608 y(keymap)p Fl(')d(command,)i(for)e(instance,)j(to)d +(set)h(bindings)i(in)f(the)f Fk(emacs-standard)480 2670 +y Fl(and)15 b Fk(emacs-ctlx)f Fl(k)o(eymaps)h(only)h(if)f(Readline)j +(is)e(starting)e(out)h(in)h Fk(emacs)f Fl(mo)q(de.)p +eop +44 45 bop 0 -58 a Fl(44)1623 b(Bash)15 b(F)l(eatures)240 +183 y Fk(term)144 b Fl(The)21 b Fk(term=)f Fl(form)g(ma)o(y)h(b)q(e)g +(used)h(to)e(include)j(terminal-sp)q(eci\014c)h(k)o(ey)c(bindings,)480 +246 y(p)q(erhaps)15 b(to)f(bind)j(the)d(k)o(ey)h(sequences)h(output)e +(b)o(y)h(the)g(terminal's)g(function)h(k)o(eys.)480 308 +y(The)f(w)o(ord)g(on)f(the)i(righ)o(t)e(side)i(of)f(the)g(`)p +Fk(=)p Fl(')f(is)h(tested)g(against)g(the)g(full)h(name)f(of)g(the)480 +370 y(terminal)k(and)g(the)g(p)q(ortion)g(of)f(the)h(terminal)g(name)g +(b)q(efore)g(the)g(\014rst)f(`)p Fk(-)p Fl('.)29 b(This)480 +432 y(allo)o(ws)15 b Fg(sun)h Fl(to)e(matc)o(h)h(b)q(oth)g +Fg(sun)h Fl(and)f Fg(sun-cmd)p Fl(,)h(for)f(instance.)240 +510 y Fk(application)480 572 y Fl(The)j Fg(application)i +Fl(construct)e(is)g(used)h(to)e(include)k(application-sp)q(eci\014c)g +(settings.)480 634 y(Eac)o(h)d(program)g(using)h(the)f(Readline)j +(library)e(sets)f(the)h Fg(application)h(name)p Fl(,)f(and)480 +697 y(y)o(ou)c(can)h(test)f(for)g(it.)21 b(This)16 b(could)g(b)q(e)h +(used)f(to)e(bind)j(k)o(ey)f(sequences)g(to)f(functions)480 +759 y(useful)h(for)e(a)h(sp)q(eci\014c)i(program.)h(F)l(or)d(instance,) +g(the)g(follo)o(wing)h(command)e(adds)h(a)480 821 y(k)o(ey)g(sequence)h +(that)f(quotes)g(the)g(curren)o(t)g(or)g(previous)h(w)o(ord)e(in)i +(Bash:)600 886 y Fk($if)23 b(bash)600 936 y(#)h(Quote)f(the)g(current)g +(or)h(previous)f(word)600 986 y("\\C-xq":)g("\\eb\\"\\ef\\"")600 +1036 y($endif)0 1129 y($endif)96 b Fl(This)16 b(command,)e(as)h(y)o(ou) +g(sa)o(w)g(in)h(the)f(previous)h(example,)f(terminates)h(an)f +Fk($if)f Fl(command.)0 1222 y Fk($else)120 b Fl(Commands)15 +b(in)h(this)f(branc)o(h)h(of)e(the)i Fk($if)e Fl(directiv)o(e)j(are)e +(executed)h(if)g(the)f(test)g(fails.)0 1472 y Fj(7.4)33 +b(Bindable)16 b(Readline)h(Commands)0 1706 y Ff(7.4.1)30 +b(Commands)15 b(F)-5 b(or)15 b(Mo)n(ving)0 1846 y Fk(beginning-of-line) +e(\(C-a\))240 1908 y Fl(Mo)o(v)o(e)h(to)h(the)g(start)f(of)h(the)g +(curren)o(t)g(line.)0 1986 y Fk(end-of-line)f(\(C-e\))240 +2048 y Fl(Mo)o(v)o(e)g(to)h(the)g(end)h(of)f(the)g(line.)0 +2126 y Fk(forward-char)f(\(C-f\))240 2188 y Fl(Mo)o(v)o(e)g(forw)o(ard) +g(a)h(c)o(haracter.)0 2266 y Fk(backward-char)e(\(C-b\))240 +2328 y Fl(Mo)o(v)o(e)h(bac)o(k)h(a)g(c)o(haracter.)0 +2406 y Fk(forward-word)f(\(M-f\))240 2468 y Fl(Mo)o(v)o(e)g(forw)o(ard) +g(to)h(the)g(end)h(of)f(the)g(next)g(w)o(ord.)k(W)l(ords)c(are)g(comp)q +(osed)h(of)e(letters)i(and)f(digits.)0 2545 y Fk(backward-word)e +(\(M-b\))240 2608 y Fl(Mo)o(v)o(e)j(bac)o(k)g(to)g(the)h(start)f(of)g +(this,)h(or)g(the)f(previous,)i(w)o(ord.)24 b(W)l(ords)16 +b(are)g(comp)q(osed)i(of)e(letters)240 2670 y(and)f(digits.)p +eop +45 46 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(45)0 183 y Fk(clear-screen)14 b(\(C-l\))240 246 y Fl(Clear)h(the)g +(screen)g(and)g(redra)o(w)f(the)h(curren)o(t)g(line,)h(lea)o(ving)g +(the)f(curren)o(t)f(line)j(at)d(the)h(top)f(of)h(the)240 +308 y(screen.)0 386 y Fk(redraw-current-line)e(\(\))240 +448 y Fl(Refresh)j(the)f(curren)o(t)g(line.)22 b(By)15 +b(default,)h(this)f(is)h(un)o(b)q(ound.)0 688 y Ff(7.4.2)30 +b(Commands)15 b(F)-5 b(or)15 b(Manipulating)g(The)g(History)0 +829 y Fk(accept-line)f(\(Newline,)g(Return\))240 891 +y Fl(Accept)k(the)g(line)h(regardless)f(of)f(where)h(the)g(cursor)f +(is.)28 b(If)18 b(this)g(line)h(is)g(non-empt)o(y)l(,)f(add)g(it)g(to) +240 953 y(the)d(history)f(list)h(according)g(to)f(the)g(setting)h(of)f +(the)g Fk(HISTCONTROL)f Fl(v)m(ariable.)21 b(If)15 b(this)g(line)h(w)o +(as)d(a)240 1015 y(history)i(line,)i(then)e(restore)g(the)g(history)g +(line)i(to)e(its)g(original)h(state.)0 1094 y Fk(previous-history)d +(\(C-p\))240 1156 y Fl(Mo)o(v)o(e)h(`up')h(through)g(the)g(history)g +(list.)0 1234 y Fk(next-history)f(\(C-n\))240 1296 y +Fl(Mo)o(v)o(e)g(`do)o(wn')g(through)h(the)h(history)f(list.)0 +1375 y Fk(beginning-of-history)d(\(M-<\))240 1437 y Fl(Mo)o(v)o(e)i(to) +h(the)g(\014rst)g(line)i(in)f(the)f(history)l(.)0 1515 +y Fk(end-of-history)e(\(M->\))240 1578 y Fl(Mo)o(v)o(e)h(to)h(the)g +(end)h(of)f(the)g(input)h(history)l(,)f(i.e.,)g(the)g(line)i(y)o(ou)e +(are)g(en)o(tering.)0 1656 y Fk(reverse-search-history)d(\(C-r\))240 +1718 y Fl(Searc)o(h)18 b(bac)o(kw)o(ard)f(starting)g(at)g(the)g(curren) +o(t)h(line)h(and)f(mo)o(ving)f(`up')h(through)f(the)h(history)f(as)240 +1780 y(necessary)l(.)j(This)c(is)g(an)f(incremen)o(tal)h(searc)o(h.)0 +1859 y Fk(forward-search-history)c(\(C-s\))240 1921 y +Fl(Searc)o(h)j(forw)o(ard)e(starting)h(at)g(the)g(curren)o(t)h(line)h +(and)f(mo)o(ving)f(`do)o(wn')g(through)g(the)g(the)h(history)240 +1983 y(as)g(necessary)l(.)20 b(This)c(is)g(an)f(incremen)o(tal)h(searc) +o(h.)0 2062 y Fk(non-incremental-reverse-se)o(arch-hi)o(story)c +(\(M-p\))240 2124 y Fl(Searc)o(h)18 b(bac)o(kw)o(ard)f(starting)g(at)g +(the)g(curren)o(t)h(line)h(and)f(mo)o(ving)f(`up')h(through)f(the)h +(history)f(as)240 2186 y(necessary)e(using)h(a)f(non-incremen)o(tal)i +(searc)o(h)e(for)g(a)f(string)i(supplied)h(b)o(y)e(the)h(user.)0 +2264 y Fk(non-incremental-forward-se)o(arch-hi)o(story)c(\(M-n\))240 +2327 y Fl(Searc)o(h)j(forw)o(ard)e(starting)h(at)g(the)g(curren)o(t)h +(line)h(and)f(mo)o(ving)f(`do)o(wn')g(through)g(the)g(the)h(history)240 +2389 y(as)g(necessary)g(using)h(a)f(non-incremen)o(tal)i(searc)o(h)e +(for)f(a)h(string)g(supplied)j(b)o(y)d(the)g(user.)0 +2467 y Fk(history-search-forward)d(\(\))240 2529 y Fl(Searc)o(h)h(forw) +o(ard)f(through)h(the)g(history)g(for)g(the)g(string)g(of)g(c)o +(haracters)f(b)q(et)o(w)o(een)i(the)f(start)f(of)h(the)240 +2592 y(curren)o(t)j(line)i(and)e(the)h(curren)o(t)f(p)q(oin)o(t.)23 +b(This)17 b(is)f(a)g(non-incremen)o(tal)i(searc)o(h.)23 +b(By)16 b(default,)h(this)240 2654 y(command)e(is)h(un)o(b)q(ound.)p +eop +46 47 bop 0 -58 a Fl(46)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fk(history-search-backward)d(\(\))240 246 y Fl(Searc)o(h)k(bac)o +(kw)o(ard)g(through)g(the)g(history)g(for)g(the)g(string)g(of)g(c)o +(haracters)g(b)q(et)o(w)o(een)g(the)g(start)f(of)240 +308 y(the)i(curren)o(t)g(line)h(and)f(the)g(curren)o(t)g(p)q(oin)o(t.) +25 b(This)17 b(is)g(a)g(non-incremen)o(tal)h(searc)o(h.)25 +b(By)17 b(default,)240 370 y(this)f(command)f(is)g(un)o(b)q(ound.)0 +450 y Fk(yank-nth-arg)f(\(M-C-y\))240 512 y Fl(Insert)19 +b(the)g(\014rst)f(argumen)o(t)g(to)g(the)h(previous)g(command)g +(\(usually)g(the)g(second)g(w)o(ord)f(on)h(the)240 575 +y(previous)e(line\).)23 b(With)16 b(an)g(argumen)o(t)f +Fg(n)p Fl(,)h(insert)h(the)f Fg(n)p Fl(th)g(w)o(ord)f(from)g(the)h +(previous)h(command)240 637 y(\(the)d(w)o(ords)g(in)h(the)g(previous)g +(command)f(b)q(egin)i(with)f(w)o(ord)f(0\).)19 b(A)14 +b(negativ)o(e)h(argumen)o(t)f(inserts)240 699 y(the)h +Fg(n)p Fl(th)h(w)o(ord)e(from)h(the)g(end)h(of)e(the)i(previous)g +(command.)0 779 y Fk(yank-last-arg)d(\(M-.,)i(M-_\))240 +841 y Fl(Insert)k(last)g(argumen)o(t)g(to)f(the)h(previous)h(command)f +(\(the)g(last)g(w)o(ord)f(on)h(the)g(previous)h(line\).)240 +904 y(With)15 b(an)h(argumen)o(t,)e(b)q(eha)o(v)o(e)h(exactly)h(lik)o +(e)g Fk(yank-nth-arg)p Fl(.)0 1158 y Ff(7.4.3)30 b(Commands)15 +b(F)-5 b(or)15 b(Changing)g(T)-5 b(ext)0 1301 y Fk(delete-char)14 +b(\(C-d\))240 1363 y Fl(Delete)f(the)f(c)o(haracter)f(under)i(the)f +(cursor.)19 b(If)12 b(the)g(cursor)g(is)g(at)g(the)g(b)q(eginning)i(of) +e(the)g(line,)i(there)240 1425 y(are)k(no)g(c)o(haracters)g(in)h(the)g +(line,)h(and)f(the)f(last)g(c)o(haracter)g(t)o(yp)q(ed)h(w)o(as)e(not)h +(C-d,)h(then)g(return)240 1487 y(EOF.)0 1567 y Fk(backward-delete-char) +12 b(\(Rubout\))240 1630 y Fl(Delete)g(the)f(c)o(haracter)f(b)q(ehind)j +(the)e(cursor.)18 b(A)11 b(n)o(umeric)h(arg)e(sa)o(ys)g(to)g(kill)j +(the)e(c)o(haracters)f(instead)240 1692 y(of)15 b(deleting)h(them.)0 +1772 y Fk(quoted-insert)d(\(C-q,)i(C-v\))240 1834 y Fl(Add)i(the)f +(next)h(c)o(haracter)f(that)f(y)o(ou)h(t)o(yp)q(e)h(to)f(the)g(line)i +(v)o(erbatim.)24 b(This)17 b(is)g(ho)o(w)e(to)h(insert)h(k)o(ey)240 +1897 y(sequences)f(lik)o(e)h Fk(C-Q)p Fl(,)d(for)h(example.)0 +1976 y Fk(tab-insert)f(\(M-TAB\))240 2039 y Fl(Insert)h(a)g(tab)g(c)o +(haracter.)0 2119 y Fk(self-insert)f(\(a,)g(b,)h(A,)g(1,)g(!,)g(...\)) +240 2181 y Fl(Insert)g(y)o(ourself.)0 2261 y Fk(transpose-chars)e +(\(C-t\))240 2323 y Fl(Drag)h(the)h(c)o(haracter)g(b)q(efore)g(the)h +(cursor)f(forw)o(ard)f(o)o(v)o(er)g(the)h(c)o(haracter)g(at)f(the)i +(cursor,)e(mo)o(ving)240 2386 y(the)k(cursor)h(forw)o(ard)e(as)h(w)o +(ell.)30 b(If)19 b(the)f(insertion)i(p)q(oin)o(t)f(is)g(at)e(the)i(end) +g(of)f(the)g(line,)j(then)e(this)240 2448 y(transp)q(oses)c(the)g(last) +g(t)o(w)o(o)f(c)o(haracters)h(of)f(the)i(line.)21 b(Negativ)o(e)15 +b(argumen)o(tss)f(don't)h(w)o(ork.)0 2528 y Fk(transpose-words)e +(\(M-t\))240 2590 y Fl(Drag)f(the)h(w)o(ord)f(b)q(ehind)i(the)f(cursor) +g(past)f(the)h(w)o(ord)f(in)h(fron)o(t)f(of)h(the)f(cursor)h(mo)o(ving) +f(the)h(cursor)240 2652 y(o)o(v)o(er)h(that)h(w)o(ord)f(as)h(w)o(ell.)p +eop +47 48 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(47)0 183 y Fk(upcase-word)14 b(\(M-u\))240 246 y Fl(Upp)q(ercase)h +(the)e(curren)o(t)h(\(or)f(follo)o(wing\))h(w)o(ord.)k(With)c(a)f +(negativ)o(e)h(argumen)o(t,)f(do)g(the)h(previous)240 +308 y(w)o(ord,)g(but)h(do)h(not)e(mo)o(v)o(e)h(the)g(cursor.)0 +383 y Fk(downcase-word)e(\(M-l\))240 445 y Fl(Lo)o(w)o(ercase)g(the)i +(curren)o(t)f(\(or)f(follo)o(wing\))h(w)o(ord.)19 b(With)14 +b(a)g(negativ)o(e)g(argumen)o(t,)f(do)h(the)g(previous)240 +507 y(w)o(ord,)g(but)h(do)h(not)e(mo)o(v)o(e)h(the)g(cursor.)0 +582 y Fk(capitalize-word)e(\(M-c\))240 644 y Fl(Capitalize)j(the)e +(curren)o(t)g(\(or)f(follo)o(wing\))i(w)o(ord.)j(With)d(a)f(negativ)o +(e)g(argumen)o(t,)f(do)h(the)g(previous)240 707 y(w)o(ord,)g(but)h(do)h +(not)e(mo)o(v)o(e)h(the)g(cursor.)0 916 y Ff(7.4.4)30 +b(Killing)15 b(And)h(Y)-5 b(anking)0 1053 y Fk(kill-line)14 +b(\(C-k\))240 1115 y Fl(Kill)j(the)f(text)e(from)h(the)g(curren)o(t)g +(cursor)g(p)q(osition)h(to)f(the)g(end)h(of)f(the)g(line.)0 +1190 y Fk(backward-kill-line)e(\(C-x)h(Rubout\))240 1252 +y Fl(Kill)j(bac)o(kw)o(ard)e(to)f(the)i(b)q(eginning)h(of)e(the)g +(line.)0 1327 y Fk(unix-line-discard)e(\(C-u\))240 1390 +y Fl(Kill)j(bac)o(kw)o(ard)d(from)f(the)i(cursor)f(to)g(the)h(b)q +(eginning)i(of)d(the)g(curren)o(t)h(line.)21 b(Sa)o(v)o(e)13 +b(the)h(killed)h(text)240 1452 y(on)g(the)g(kill-ring.)0 +1527 y Fk(kill-whole-line)e(\(\))240 1589 y Fl(Kill)18 +b(all)f(c)o(haracters)e(on)h(the)g(curren)o(t)f(line,)j(no)e(matter)e +(where)i(the)g(cursor)g(is.)22 b(By)16 b(default,)h(this)240 +1651 y(is)f(un)o(b)q(ound.)0 1726 y Fk(kill-word)e(\(M-d\))240 +1789 y Fl(Kill)j(from)d(the)h(cursor)g(to)f(the)h(end)g(of)g(the)g +(curren)o(t)f(w)o(ord,)g(or)g(if)i(b)q(et)o(w)o(een)f(w)o(ords,)f(to)g +(the)h(end)g(of)240 1851 y(the)g(next)h(w)o(ord.)j(W)l(ord)c(b)q +(oundaries)h(are)f(the)g(same)g(as)g Fk(forward-word)p +Fl(.)0 1926 y Fk(backward-kill-word)e(\(M-DEL\))240 1988 +y Fl(Kill)k(the)f(w)o(ord)e(b)q(ehind)j(the)f(cursor.)j(W)l(ord)c(b)q +(oundaries)i(are)d(the)i(same)f(as)f Fk(backward-word)p +Fl(.)0 2063 y Fk(unix-word-rubout)f(\(C-w\))240 2125 +y Fl(Kill)i(the)e(w)o(ord)f(b)q(ehind)j(the)f(cursor,)e(using)i(white)f +(space)h(as)e(a)h(w)o(ord)f(b)q(oundary)l(.)20 b(The)13 +b(killed)i(text)240 2187 y(is)h(sa)o(v)o(ed)e(on)i(the)f(kill-ring.)0 +2262 y Fk(delete-horizontal-space)d(\(\))240 2325 y Fl(Delete)k(all)g +(spaces)f(and)h(tabs)e(around)i(p)q(oin)o(t.)k(By)15 +b(default,)h(this)f(is)h(un)o(b)q(ound.)0 2399 y Fk(yank)f(\(C-y\))240 +2462 y Fl(Y)l(ank)g(the)h(top)f(of)f(the)i(kill)h(ring)e(in)o(to)g(the) +h(bu\013er)f(at)f(the)i(curren)o(t)f(cursor)g(p)q(osition.)0 +2537 y Fk(yank-pop)f(\(M-y\))240 2599 y Fl(Rotate)f(the)h(kill-ring,)i +(and)e(y)o(ank)g(the)g(new)g(top.)19 b(Y)l(ou)14 b(can)g(only)g(do)g +(this)g(if)g(the)g(prior)g(command)240 2661 y(is)i(y)o(ank)f(or)f(y)o +(ank-p)q(op.)p eop +48 49 bop 0 -58 a Fl(48)1623 b(Bash)15 b(F)l(eatures)0 +183 y Ff(7.4.5)30 b(Sp)r(ecifying)15 b(Numeric)h(Argumen)n(ts)0 +324 y Fk(digit-argument)d(\(M-0,)i(M-1,)f(...)h(M--\))240 +386 y Fl(Add)k(this)f(digit)h(to)f(the)g(argumen)o(t)f(already)i(accum) +o(ulating,)g(or)f(start)f(a)g(new)i(argumen)o(t.)28 b(M{)240 +448 y(starts)14 b(a)h(negativ)o(e)g(argumen)o(t.)0 527 +y Fk(universal-argument)e(\(\))240 589 y Fl(Eac)o(h)k(time)h(this)g(is) +f(executed,)i(the)e(argumen)o(t)g(coun)o(t)g(is)h(m)o(ultiplied)i(b)o +(y)d(four.)26 b(The)18 b(argumen)o(t)240 651 y(coun)o(t)i(is)h +(initially)j(one,)d(so)f(executing)i(this)f(function)g(the)g(\014rst)f +(time)h(mak)o(es)f(the)h(argumen)o(t)240 714 y(coun)o(t)15 +b(four.)20 b(By)15 b(default,)g(this)h(is)g(not)e(b)q(ound)j(to)d(a)h +(k)o(ey)l(.)0 954 y Ff(7.4.6)30 b(Letting)14 b(Readline)h(T)n(yp)r(e)h +(F)-5 b(or)14 b(Y)-5 b(ou)0 1095 y Fk(complete)14 b(\(TAB\))240 +1157 y Fl(A)o(ttempt)i(to)h(do)g(completion)i(on)e(the)g(text)g(b)q +(efore)h(the)f(cursor.)26 b(This)18 b(is)g(application-sp)q(eci\014c.) +240 1219 y(Generally)l(,)h(if)f(y)o(ou)f(are)h(t)o(yping)g(a)f +(\014lename)i(argumen)o(t,)e(y)o(ou)g(can)h(do)f(\014lename)i +(completion;)g(if)240 1282 y(y)o(ou)f(are)f(t)o(yping)i(a)e(command,)i +(y)o(ou)e(can)i(do)f(command)g(completion,)h(if)g(y)o(ou)e(are)h(t)o +(yping)g(in)h(a)240 1344 y(sym)o(b)q(ol)e(to)f(GDB,)g(y)o(ou)g(can)h +(do)g(sym)o(b)q(ol)g(name)g(completion,)h(if)f(y)o(ou)f(are)h(t)o +(yping)g(in)g(a)g(v)m(ariable)240 1406 y(to)e(Bash,)h(y)o(ou)f(can)h +(do)g(v)m(ariable)h(name)f(completion,)h(and)f(so)f(on.)22 +b(See)16 b(the)g(Bash)g(man)o(ual)g(page)240 1468 y(for)f(a)f(complete) +i(list)g(of)f(a)o(v)m(ailable)i(completion)f(functions.)0 +1547 y Fk(possible-completions)c(\(M-?\))240 1609 y Fl(List)k(the)f(p)q +(ossible)i(completions)f(of)f(the)g(text)g(b)q(efore)h(the)f(cursor.)0 +1687 y Fk(insert-completions)e(\(\))240 1750 y Fl(Insert)22 +b(all)h(completions)g(of)f(the)g(text)f(b)q(efore)h(p)q(oin)o(t)h(that) +e(w)o(ould)h(ha)o(v)o(e)g(b)q(een)h(generated)f(b)o(y)240 +1812 y Fk(possible-completions)p Fl(.)17 b(By)e(default,)h(this)f(is)h +(not)f(b)q(ound)h(to)f(a)g(k)o(ey)l(.)0 2052 y Ff(7.4.7)30 +b(Keyb)r(oard)15 b(Macros)0 2193 y Fk(start-kbd-macro)e(\(C-x)i(\(\)) +240 2255 y Fl(Begin)h(sa)o(ving)f(the)h(c)o(haracters)e(t)o(yp)q(ed)i +(in)o(to)f(the)g(curren)o(t)g(k)o(eyb)q(oard)g(macro.)0 +2334 y Fk(end-kbd-macro)e(\(C-x)i(\)\))240 2396 y Fl(Stop)f(sa)o(ving)h +(the)g(c)o(haracters)f(t)o(yp)q(ed)h(in)o(to)f(the)h(curren)o(t)f(k)o +(eyb)q(oard)h(macro)f(and)h(sa)o(v)o(e)f(the)g(de\014ni-)240 +2458 y(tion.)0 2537 y Fk(call-last-kbd-macro)f(\(C-x)h(e\))240 +2599 y Fl(Re-execute)20 b(the)f(last)f(k)o(eyb)q(oard)g(macro)g +(de\014ned,)i(b)o(y)f(making)f(the)h(c)o(haracters)f(in)h(the)g(macro) +240 2661 y(app)q(ear)c(as)g(if)h(t)o(yp)q(ed)f(at)g(the)g(k)o(eyb)q +(oard.)p eop +49 50 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 +b(49)0 183 y Ff(7.4.8)30 b(Some)15 b(Miscellaneous)h(Commands)0 +320 y Fk(re-read-init-file)d(\(C-x)h(C-r\))240 382 y +Fl(Read)i(in)g(the)f(con)o(ten)o(ts)f(of)h(y)o(our)g(init)h(\014le,)g +(and)f(incorp)q(orate)h(an)o(y)e(bindings)j(or)e(v)m(ariable)i(assign-) +240 445 y(men)o(ts)e(found)g(there.)0 515 y Fk(abort)f(\(C-g\))240 +578 y Fl(Ab)q(ort)f(the)h(curren)o(t)f(editing)i(command)e(and)h(ring)g +(the)f(terminal's)h(b)q(ell)h(\(sub)s(ject)f(to)e(the)i(setting)240 +640 y(of)h Fk(bell-style)p Fl(\).)0 710 y Fk(do-uppercase-version)d +(\(M-a,)j(M-b,)f(...\))240 773 y Fl(Run)i(the)f(command)g(that)g(is)h +(b)q(ound)g(to)e(the)i(corresop)q(onding)g(upp)q(ercase)g(c)o +(haracter.)0 843 y Fk(prefix-meta)e(\(ESC\))240 906 y +Fl(Mak)o(e)g(the)g(next)h(c)o(haracter)f(that)g(y)o(ou)g(t)o(yp)q(e)h +(b)q(e)g(meta\014ed.)20 b(This)15 b(is)g(for)f(p)q(eople)i(without)e(a) +h(meta)240 968 y(k)o(ey)l(.)20 b(T)o(yping)c(`)p Fk(ESC)e(f)p +Fl(')h(is)g(equiv)m(alen)o(t)i(to)e(t)o(yping)g(`)p Fk(M-f)p +Fl('.)0 1038 y Fk(undo)g(\(C-_,)f(C-x)h(C-u\))240 1101 +y Fl(Incremen)o(tal)h(undo,)f(separately)h(remem)o(b)q(ered)g(for)e +(eac)o(h)h(line.)0 1171 y Fk(revert-line)f(\(M-r\))240 +1234 y Fl(Undo)20 b(all)h(c)o(hanges)f(made)g(to)f(this)i(line.)35 +b(This)21 b(is)f(lik)o(e)h(t)o(yping)f(the)g Fk(undo)g +Fl(command)g(enough)240 1296 y(times)15 b(to)g(get)g(bac)o(k)g(to)f +(the)i(b)q(eginning.)0 1366 y Fk(tilde-expand)e(\(M-~\))240 +1429 y Fl(P)o(erform)g(tilde)j(expansion)f(on)f(the)g(curren)o(t)g(w)o +(ord.)0 1499 y Fk(dump-functions)e(\(\))240 1562 y Fl(Prin)o(t)18 +b(all)h(of)f(the)g(functions)h(and)g(their)g(k)o(ey)f(bindings)i(to)d +(the)i(readline)h(output)e(stream.)28 b(If)18 b(a)240 +1624 y(n)o(umeric)i(argumen)o(t)d(is)i(supplied,)j(the)d(output)f(is)h +(formatted)f(in)h(suc)o(h)g(a)f(w)o(a)o(y)g(that)g(it)h(can)f(b)q(e)240 +1686 y(made)d(part)g(of)g(an)g Fg(inputrc)k Fl(\014le.)0 +1757 y Fk(display-shell-version)12 b(\(C-x)j(C-v\))240 +1819 y Fl(Displa)o(y)h(v)o(ersion)f(information)h(ab)q(out)f(the)g +(curren)o(t)g(instance)h(of)f(Bash.)0 1890 y Fk(shell-expand-line)e +(\(M-C-e\))240 1952 y Fl(Expand)f(the)h(line)g(the)f(w)o(a)o(y)g(the)g +(shell)h(do)q(es)g(when)f(it)h(reads)f(it.)19 b(This)12 +b(p)q(erforms)g(alias)h(and)f(history)240 2014 y(expansion)k(as)f(w)o +(ell)h(as)f(all)h(of)f(the)g(shell)i(w)o(ord)d(expansions.)0 +2085 y Fk(history-expand-line)f(\(M-^\))240 2147 y Fl(P)o(erform)h +(history)h(expansion)h(on)g(the)f(curren)o(t)g(line.)0 +2217 y Fk(insert-last-argument)d(\(M-.,)j(M-_\))240 2280 +y Fl(A)g(synon)o(ym)g(for)g Fk(yank-last-arg)p Fl(.)0 +2350 y Fk(operate-and-get-next)d(\(C-o\))240 2413 y Fl(Accept)i(the)f +(curren)o(t)h(line)g(for)f(execution)i(and)e(fetc)o(h)g(the)h(next)f +(line)i(relativ)o(e)f(to)f(the)g(curren)o(t)g(line)240 +2475 y(from)h(the)i(history)f(for)f(editing.)22 b(An)o(y)15 +b(argumen)o(t)f(is)i(ignored.)0 2545 y Fk(emacs-editing-mode)d(\(C-e\)) +240 2608 y Fl(When)k(in)h Fk(vi)e Fl(editing)i(mo)q(de,)f(this)g +(causes)g(a)g(switc)o(h)g(bac)o(k)f(to)h(emacs)f(editing)i(mo)q(de,)f +(as)g(if)g(the)240 2670 y(command)e Fk(set)g(-o)g(emacs)f +Fl(had)i(b)q(een)g(executed.)p eop +50 51 bop 0 -58 a Fl(50)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fj(7.5)33 b(Readline)16 b(vi)g(Mo)r(de)62 320 y +Fl(While)d(the)f(Readline)i(library)e(do)q(es)g(not)g(ha)o(v)o(e)f(a)g +(full)i(set)f(of)f Fk(vi)g Fl(editing)i(functions,)g(it)f(do)q(es)g +(con)o(tain)g(enough)0 382 y(to)i(allo)o(w)h(simple)i(editing)f(of)f +(the)g(line.)21 b(The)15 b(Readline)i Fk(vi)e Fl(mo)q(de)g(b)q(eha)o(v) +o(es)h(as)e(sp)q(eci\014ed)j(in)f(the)f(P)o(osix)g(1003.2)0 +445 y(standard.)62 582 y(In)f(order)g(to)e(switc)o(h)i(in)o(teractiv)o +(ely)g(b)q(et)o(w)o(een)g Fk(Emacs)f Fl(and)h Fk(Vi)f +Fl(editing)h(mo)q(des,)g(use)g(the)f Fk(set)i(-o)g(emacs)e +Fl(and)0 644 y Fk(set)i(-o)g(vi)h Fl(commands)h(\(see)f(Section)i(4.5)e +([The)g(Set)h(Builtin],)i(page)d(20\).)24 b(The)17 b(Readline)i +(default)e(is)h Fk(emacs)0 706 y Fl(mo)q(de.)62 843 y(When)h(y)o(ou)f +(en)o(ter)g(a)g(line)i(in)g Fk(vi)e Fl(mo)q(de,)h(y)o(ou)f(are)g +(already)g(placed)i(in)f(`insertion')g(mo)q(de,)g(as)f(if)h(y)o(ou)f +(had)0 906 y(t)o(yp)q(ed)e(an)f(`)p Fk(i)p Fl('.)20 b(Pressing)c +Fk(ESC)f Fl(switc)o(hes)h(y)o(ou)f(in)o(to)h(`command')f(mo)q(de,)g +(where)h(y)o(ou)f(can)h(edit)g(the)g(text)f(of)g(the)0 +968 y(line)20 b(with)e(the)g(standard)g Fk(vi)f Fl(mo)o(v)o(emen)o(t)g +(k)o(eys,)h(mo)o(v)o(e)g(to)f(previous)i(history)f(lines)h(with)g(`)p +Fk(k)p Fl(',)e(and)h(follo)o(wing)0 1030 y(lines)f(with)e(`)p +Fk(j)p Fl(',)f(and)i(so)e(forth.)p eop +51 52 bop 0 -58 a Fl(App)q(endix)17 b(A:)e(V)l(ariable)i(Index)1345 +b(51)0 183 y Fh(App)r(endix)13 b(A)41 b(V)-7 b(ariable)14 +b(Index)0 438 y Fj(A)0 504 y Fe(auto)p 82 504 12 2 v +13 w(resume)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(31)0 616 y Fj(B)0 +683 y Fe(BASH)p 82 683 V 13 w(VERSION)5 b Fd(:)s(:)h(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)18 +b Fc(24)0 741 y Fe(bell-style)t Fd(:)s(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 +b Fc(41)0 853 y Fj(C)0 919 y Fe(cdable)p 122 919 V 12 +w(vars)7 b Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(10)0 977 y Fe(CDPATH)9 +b Fd(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(4)0 +1035 y Fe(comment-be)o(gi)o(n)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(41)0 1093 +y Fe(completion)o(-q)o(uer)o(y-)o(ite)o(ms)7 b Fd(:)s(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)20 b Fc(42)0 1152 y Fe(convert-me)o(ta)8 +b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)24 b Fc(41)0 1263 y Fj(E)0 1330 y Fe(editing-mo)o(de)8 +b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)24 b Fc(41)0 1388 y Fe(EUID)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)17 b Fc(23)0 1446 y Fe(expand-til)o(de)8 +b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)24 b Fc(42)0 1558 y Fj(F)0 1624 y Fe(FIGNORE)9 +b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(23)0 1736 +y Fj(H)0 1803 y Fe(histchars)6 b Fd(:)s(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)19 +b Fc(23)0 1861 y Fe(HISTCMD)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(23)0 1919 y Fe(HISTCONTRO)o(L)t Fd(:)s(:)6 b(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fc(22)0 1977 y Fe(HISTFILE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 +b Fc(23)0 2035 y Fe(history)p 142 2035 V 11 w(control)8 +b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 +b Fc(22)0 2093 y Fe(HISTSIZE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 +b Fc(23)0 2151 y Fe(HOME)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)18 b Fc(4)0 2209 y Fe(horizontal)o(-s)o(cro)o(ll)o(-mo)o(de) +7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(41)0 2268 +y Fe(HOSTFILE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(23)0 +2326 y Fe(hostname)p 162 2326 V 11 w(completion)p 372 +2326 V 10 w(file)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(23)0 +2384 y Fe(HOSTTYPE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 +b Fc(23)0 2496 y Fj(I)0 2562 y Fe(IFS)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fc(4)0 2620 y Fe(IGNOREEOF)6 +b Fd(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)22 b Fc(10,)13 b(24)0 2678 y Fe(INPUTRC)c +Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(23)1015 438 y +Fj(K)1015 504 y Fe(keymap)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 +b Fc(42)1015 636 y Fj(M)1015 702 y Fe(MAILCHECK)7 b Fd(:)s(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)20 b Fc(23)1015 760 y Fe(MAILPATH)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)22 b Fc(4)1015 818 y Fe(mark-modifi)o(ed)o(-li)o(nes)7 +b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)24 b +Fc(41)1015 876 y Fe(meta-flag)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 +b Fc(41)1015 1008 y Fj(N)1015 1074 y Fe(no)p 1057 1074 +V 14 w(exit)p 1151 1074 V 12 w(on)p 1203 1074 V 14 w(failed)p +1337 1074 V 12 w(exec)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 +b Fc(24)1015 1132 y Fe(nolinks)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 +b Fc(24)1015 1190 y Fe(notify)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +24 b Fc(31)1015 1322 y Fj(O)1015 1388 y Fe(OLDPWD)9 b +Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(12)1015 1446 +y Fe(OPTARG)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 +b Fc(4)1015 1504 y Fe(OPTIND)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)25 b Fc(4)1015 1562 y Fe(OSTYPE)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)24 b Fc(23)1015 1620 y Fe(output-meta)s Fd(:)s(:)6 +b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)17 b Fc(41)1015 1752 y Fj(P)1015 1818 y Fe(PATH)5 +b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(4)1015 1876 y Fe(PROMPT)p 1137 1876 V 12 w(COMMAND)9 +b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)25 b Fc(23)1015 1934 y Fe(PS1)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(4)1015 1992 y Fe(PS2)7 +b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 +b Fc(4)1015 2051 y Fe(PS3)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)19 b Fc(12)1015 2109 y Fe(PS4)6 b Fd(:)f(:)h(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(12)1015 2167 y Fe(PWD)6 +b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(12)1015 2298 y Fj(R)1015 2364 y Fe(RANDOM)9 b Fd(:)d(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)24 b Fc(12)1015 2423 y Fe(REPLY)s +Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)16 b Fc(12)1015 +2554 y Fj(S)1015 2620 y Fe(SECONDS)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)22 b Fc(12)1015 2678 y Fe(show-all-if)o(-a)o(mbi)o(guo)o(us)7 +b Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(42)p +eop +52 53 bop 0 -58 a Fl(52)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fj(T)0 250 y Fe(TMOUT)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)16 b Fc(13)1015 183 y Fj(U)1015 250 y Fe(UID)6 +b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(23)p eop +53 54 bop 0 -58 a Fl(App)q(endix)17 b(B:)e(Concept)h(Index)1347 +b(53)0 183 y Fh(App)r(endix)13 b(B)41 b(Concept)16 b(Index)0 +438 y Fj($)0 504 y Fe($else)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)16 b Fc(44)0 562 y Fe($endif)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)23 b Fc(44)0 621 y Fe($if)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)18 b Fc(43)0 732 y Fj(.)0 799 y Fe(.)9 +b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(3)0 911 y Fj(:)0 977 y Fe(:)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(3)0 1089 y Fj([)0 +1155 y Fe([)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)22 b Fc(4)0 1267 y Fj(A)0 1334 y Fe(abort)11 +b(\(C-g\))c Fd(:)t(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)g(:)20 b Fc(49)0 1392 y Fe(accept-lin)o(e)10 +b(\(Newline)o(,)g(Return\))5 b Fd(:)s(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 1450 +y Fe(alias)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 +b Fc(14)0 1562 y Fj(B)0 1628 y Fe(backward-c)o(ha)o(r)10 +b(\(C-b\))c Fd(:)t(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(44)0 1686 y Fe(backward-d)o(el)o(ete)o(-c)o(har)9 +b(\(Rubout\))e Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)23 b Fc(46)0 1745 y Fe(backward-k)o(il)o(l-l)o(in)o +(e)10 b(\(C-x)h(Rubout\))d Fd(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 1803 y Fe(backward-k)o(il)o(l-w)o +(or)o(d)10 b(\(M-DEL\))5 b Fd(:)t(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(47)0 +1861 y Fe(backward-w)o(or)o(d)10 b(\(M-b\))c Fd(:)t(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(44)0 1919 y Fe(beginning-)o(of)o(-hi)o +(st)o(ory)9 b(\(M-<\))c Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 +1977 y Fe(beginning-)o(of)o(-li)o(ne)9 b(\(C-a\))g Fd(:)c(:)h(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)22 b Fc(44)0 2035 y Fe(bg)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(30)0 2093 y Fe(bind)t +Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)17 +b Fc(17)0 2151 y Fe(break)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)17 b Fc(3)0 2209 y Fe(builtin)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)22 b Fc(17)0 2321 y Fj(C)0 2388 y Fe(call-last-)o(kb)o(d-m)o(ac)o +(ro)9 b(\(C-x)j(e\))7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 b Fc(48)0 2446 +y Fe(capitalize)o(-w)o(ord)9 b(\(M-c\))s Fd(:)t(:)d(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)16 b Fc(47)0 2504 y Fe(case)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(2)0 2562 y Fe(cd)8 +b Fd(:)d(:)h(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 +b Fc(3)0 2620 y Fe(clear-scre)o(en)9 b(\(C-l\))e Fd(:)t(:)f(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(45)0 2678 y Fe(command)9 +b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(18)1015 438 +y Fe(complete)10 b(\(TAB\))t Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(48)1015 496 y +Fe(continue)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b +Fc(3)1015 627 y Fj(D)1015 693 y Fe(declare)9 b Fd(:)t(:)d(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)22 b Fc(18)1015 751 y Fe(delete-char)9 b(\(C-d\))f +Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(46)1015 809 y Fe(delete-hori)o(zo)o(nta)o(l-s)o(pa)o(ce)9 +b(\(\))c Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(47)1015 867 y Fe(digit-argum)o(en)o +(t)10 b(\(M-0,)h(M-1,)g(...)h(M--\))5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)1015 925 y Fe(dirs)5 +b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(9)1015 984 y Fe(display-she)o(ll)o(-ve)o(rsi)o(on)9 +b(\(C-x)i(C-v\))f Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)24 b Fc(49)1015 1042 y Fe(do-uppercas)o(e-)o(ver)o(sio)o(n) +10 b(\(M-a,)g(M-b,)i(...\))c Fd(:)t(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)21 b Fc(49)1015 1100 y Fe(downcase-wo)o(rd)9 b(\(M-l\))d +Fd(:)t(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(47)1015 1158 y Fe(dump-functi)o(on)o(s)10 b(\(\))e +Fd(:)d(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(49)1015 1288 y Fj(E)1015 1355 y Fe(echo)5 b Fd(:)g(:)i(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1413 y +Fe(emacs-editi)o(ng)o(-mo)o(de)9 b(\(C-e\))f Fd(:)t(:)e(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +21 b Fc(49)1015 1471 y Fe(enable)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)24 b Fc(18)1015 1529 y Fe(end-kbd-mac)o(ro)9 b(\(C-x)j(\)\))7 +b Fd(:)t(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(48)1015 +1587 y Fe(end-of-hist)o(or)o(y)10 b(\(M->\))t Fd(:)t(:)d(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)1015 1645 y Fe(end-of-line)9 +b(\(C-e\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +22 b Fc(44)1015 1703 y Fe(eval)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1762 y(ev)o(en)o(t)14 +b(designators)e Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)23 b Fc(33)1015 1820 y Fe(exec)5 b Fd(:)g(:)i(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1878 y +Fe(exit)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(3)1015 1936 y(expansion)t Fd(:)9 b(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fc(33)1015 1994 y Fe(export)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)25 b Fc(3)1015 2124 y Fj(F)1015 2191 y Fe(fc)7 +b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 +b Fc(11)1015 2249 y Fe(fg)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)20 b Fc(30)1015 2307 y Fe(for)7 b Fd(:)e(:)h(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(1)1015 2365 +y Fe(forward-cha)o(r)10 b(\(C-f\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)20 b Fc(44)1015 2423 y Fe(forward-sea)o(rc)o(h-h)o +(ist)o(or)o(y)10 b(\(C-s\))f Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 b Fc(45)1015 2481 +y Fe(forward-wor)o(d)10 b(\(M-f\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)20 b Fc(44)1015 2612 y Fj(G)1015 +2678 y Fe(getopts)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 +b Fc(3)p eop +54 55 bop 0 -58 a Fl(54)1623 b(Bash)15 b(F)l(eatures)0 +183 y Fj(H)0 250 y Fe(hash)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)18 b Fc(3)0 308 y Fe(help)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)17 b Fc(19)0 366 y Fe(history)7 +b Fd(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(9)0 424 +y(history)14 b(ev)o(en)o(ts)t Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(33)0 +482 y(History)m(,)c(ho)o(w)g(to)g(use)c Fd(:)e(:)f(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(31)0 540 y Fe(history-ex)o(pa)o +(nd-)o(li)o(ne)9 b(\(M-^\))e Fd(:)t(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 +b Fc(49)0 598 y Fe(history-se)o(ar)o(ch-)o(ba)o(ckw)o(ard)9 +b(\(\))c Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 656 y Fe(history-se)o(ar)o(ch-) +o(fo)o(rwa)o(rd)9 b(\(\))e Fd(:)e(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 +b Fc(45)0 790 y Fj(I)0 856 y Fe(if)8 b Fd(:)d(:)h(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(1)0 915 y Fe(insert-com)o(pl)o +(eti)o(on)o(s)10 b(\(\))s Fd(:)5 b(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +16 b Fc(48)0 973 y Fe(insert-las)o(t-)o(arg)o(um)o(ent)9 +b(\(M-.,)i(M-)p 558 973 12 2 v 13 w(\))5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(49)0 +1031 y(in)o(teraction,)d(readline)t Fd(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)16 b Fc(37)0 1164 y Fj(J)0 +1231 y Fe(jobs)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)17 +b Fc(31)0 1364 y Fj(K)0 1431 y Fe(kill)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(3)0 1489 y(Kill)d(ring)7 +b Fd(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(39)0 1547 +y Fe(kill-line)9 b(\(C-k\))g Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 1605 y Fe(kill-whole)o(-l)o(ine)9 +b(\(\))e Fd(:)e(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 +b Fc(47)0 1663 y Fe(kill-word)9 b(\(M-d\))g Fd(:)d(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 +1721 y(Killing)16 b(text)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b +Fc(39)0 1855 y Fj(L)0 1921 y Fe(let)9 b Fd(:)c(:)h(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)21 b Fc(12,)13 b(26)0 1979 y Fe(local)s Fd(:)t(:)6 +b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(19)0 2038 +y Fe(logout)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 +b Fc(9)0 2171 y Fj(N)0 2238 y Fe(next-histo)o(ry)9 b(\(C-n\))e +Fd(:)t(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 +b Fc(45)0 2296 y Fe(non-increm)o(en)o(tal)o(-f)o(orw)o(ard)o(-s)o(ear)o +(ch)o(-hi)o(st)o(ory)9 b(\(M-n\))82 2354 y Fd(:)d(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 2412 y Fe(non-increm)o(en)o(tal)o +(-r)o(eve)o(rse)o(-s)o(ear)o(ch)o(-hi)o(st)o(ory)9 b(\(M-p\))82 +2470 y Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 +b Fc(45)0 2604 y Fj(O)0 2670 y Fe(operate-an)o(d-)o(get)o(-n)o(ext)9 +b(\(C-o\))c Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(49)1015 183 y +Fj(P)1015 250 y Fe(popd)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)19 b Fc(8)1015 308 y Fe(possible-co)o(mp)o(let)o(ion)o(s)10 +b(\(M-?\))5 b Fd(:)t(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)1015 366 y +Fe(prefix-meta)9 b(\(ESC\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)22 b Fc(49)1015 424 y Fe(previous-hi)o(st)o(ory)9 +b(\(C-p\))g Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(45)1015 +482 y Fe(pushd)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 +b Fc(8)1015 540 y Fe(pwd)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)20 b Fc(3)1015 656 y Fj(Q)1015 722 y Fe(quoted-inse)o +(rt)9 b(\(C-q,)i(C-v\))f Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 +b Fc(46)1015 838 y Fj(R)1015 904 y Fe(re-read-ini)o(t-)o(fil)o(e)10 +b(\(C-x)h(C-r\))c Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(49)1015 962 y +Fe(read)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(3)1015 1020 y(Readline,)d(ho)o(w)d(to)g(use)5 b +Fd(:)h(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fc(35)1015 1078 y Fe(readonly)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(3)1015 1136 y Fe(redraw-curr)o(en)o(t-l)o(ine)9 +b(\(\))h Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(45)1015 +1195 y Fe(return)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 +b Fc(4)1015 1253 y Fe(reverse-sea)o(rc)o(h-h)o(ist)o(or)o(y)10 +b(\(C-r\))f Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)25 b Fc(45)1015 1311 y Fe(revert-line)9 +b(\(M-r\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +22 b Fc(49)1015 1426 y Fj(S)1015 1493 y Fe(self-insert)9 +b(\(a,)j(b,)g(A,)g(1,)g(!,)g(...\))6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)19 b Fc(46)1015 +1551 y Fe(set)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +19 b Fc(20)1015 1609 y Fe(shell-expan)o(d-)o(lin)o(e)10 +b(\(M-C-e\))d Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(49)1015 1667 +y Fe(shift)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 +b Fc(4)1015 1725 y Fe(source)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)25 b Fc(9)1015 1783 y Fe(start-kbd-m)o(ac)o(ro)10 +b(\(C-x)h(\(\))t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)17 +b Fc(48)1015 1841 y Fe(suspend)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 +b Fc(31)1015 1957 y Fj(T)1015 2023 y Fe(tab-insert)9 +b(\(M-TAB\))e Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 +b Fc(46)1015 2081 y Fe(test)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)19 b Fc(4)1015 2139 y Fe(tilde-expan)o(d)10 +b(\(M-~\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 +b Fc(49)1015 2198 y Fe(times)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)17 b Fc(4)1015 2256 y Fe(transpose-c)o(ha)o(rs)10 +b(\(C-t\))s Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)16 +b Fc(46)1015 2314 y Fe(transpose-w)o(or)o(ds)10 b(\(M-t\))s +Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)16 b Fc(46)1015 +2372 y Fe(trap)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)19 b Fc(4)1015 2430 y Fe(type)t Fd(:)5 b(:)h(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)18 b Fc(19)1015 2488 y Fe(typeset)9 b +Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 b Fc(12)1015 2604 +y Fj(U)1015 2670 y Fe(ulimit)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 +b Fc(19)p eop +55 56 bop 0 -58 a Fl(App)q(endix)17 b(B:)e(Concept)h(Index)1347 +b(55)0 183 y Fe(umask)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)17 b Fc(4)0 241 y Fe(unalias)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fc(14)0 299 y Fe(undo)11 b(\(C-)p 153 299 12 2 v 13 +w(,)i(C-x)e(C-u\))c Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)20 b Fc(49)0 358 y Fe(universal-)o(ar)o(gum)o(en)o(t)10 +b(\(\))s Fd(:)5 b(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 +b Fc(48)0 416 y Fe(unix-line-)o(di)o(sca)o(rd)9 b(\(C-u\))g +Fd(:)c(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(47)0 474 y Fe(unix-word-)o(ru)o +(bou)o(t)10 b(\(C-w\))e Fd(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 +b Fc(47)0 532 y Fe(unset)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)17 b Fc(4)0 590 y Fe(until)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)17 b Fc(1)0 648 y Fe(upcase-wor)o(d)10 +b(\(M-u\))e Fd(:)t(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) +21 b Fc(46)1015 183 y Fj(W)1015 250 y Fe(wait)5 b Fd(:)g(:)i(:)f(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(4)1015 308 y +Fe(while)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 +b Fc(1)1015 416 y Fj(Y)1015 482 y Fe(yank)12 b(\(C-y\))d +Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)22 b Fc(47)1015 540 y Fe(yank-last-a)o(rg)9 +b(\(M-.,)i(M-)p 1436 540 V 13 w(\))6 b Fd(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +19 b Fc(46)1015 598 y Fe(yank-nth-ar)o(g)10 b(\(M-C-y\))t +Fd(:)s(:)d(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(46)1015 +656 y Fe(yank-pop)10 b(\(M-y\))t Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(47)1015 715 +y(Y)m(anking)e(text)s Fd(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)16 b Fc(39)p +eop +56 57 bop 0 -58 a Fl(56)1623 b(Bash)15 b(F)l(eatures)p +eop +-1 58 bop 1937 -58 a Fl(i)0 183 y Fh(T)-7 b(able)15 b(of)g(Con)n(ten)n +(ts)0 351 y Fj(1)67 b(Bourne)23 b(Shell)h(St)n(yle)g(F)-6 +b(eatures)14 b Fb(:)c(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)37 b Fj(1)149 +428 y Fl(1.1)45 b(Lo)q(oping)16 b(Constructs)d Fa(:)7 +b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fl(1)149 +491 y(1.2)45 b(Conditional)16 b(Constructs)8 b Fa(:)f(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)22 b Fl(1)149 553 y(1.3)45 b(Shell)17 +b(F)l(unctions)6 b Fa(:)i(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)20 b Fl(2)149 615 y(1.4)45 b(Bourne)16 +b(Shell)h(Builtins)6 b Fa(:)j(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 +b Fl(3)149 677 y(1.5)45 b(Bourne)16 b(Shell)h(V)l(ariables)d +Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fl(4)149 +740 y(1.6)45 b(Other)15 b(Bourne)h(Shell)h(F)l(eatures)5 +b Fa(:)i(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)19 b Fl(5)299 802 y(1.6.1)44 b(Ma)s(jor)13 +b(Di\013erences)j(from)f(the)g(Bourne)g(Shell)6 b Fa(:)j(:)e(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 +b Fl(5)0 927 y Fj(2)67 b(C-Shell)24 b(St)n(yle)g(F)-6 +b(eatures)5 b Fb(:)11 b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)28 b Fj(7)149 1004 y Fl(2.1)45 b(Tilde)17 b(Expansion)6 +b Fa(:)h(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 +b Fl(7)149 1067 y(2.2)45 b(Brace)15 b(Expansion)c Fa(:)d(:)f(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fl(7)149 +1129 y(2.3)45 b(C)15 b(Shell)i(Builtins)11 b Fa(:)e(:)e(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)25 b Fl(8)149 +1191 y(2.4)45 b(C)15 b(Shell)i(V)l(ariables)7 b Fa(:)h(:)f(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)21 b Fl(10)0 1316 +y Fj(3)67 b(Korn)22 b(Shell)j(St)n(yle)e(F)-6 b(eatures)17 +b Fb(:)10 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)39 b Fj(11)149 +1394 y Fl(3.1)45 b(Korn)15 b(Shell)i(Constructs)6 b Fa(:)h(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)21 b Fl(11)149 1456 y(3.2)45 b(Korn)15 +b(Shell)i(Builtins)6 b Fa(:)j(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)20 b Fl(11)149 1518 y(3.3)45 b(Korn)15 b(Shell)i(V)l(ariables)d +Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)28 b Fl(12)149 +1580 y(3.4)45 b(Aliases)7 b Fa(:)h(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)22 +b Fl(13)299 1643 y(3.4.1)44 b(Alias)16 b(Builtins)10 +b Fa(:)f(:)e(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)25 b Fl(14)0 1767 +y Fj(4)67 b(Bash)22 b(Sp)r(eci\014c)h(F)-6 b(eatures)11 +b Fb(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)34 +b Fj(15)149 1845 y Fl(4.1)45 b(In)o(v)o(oking)16 b(Bash)5 +b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +20 b Fl(15)149 1907 y(4.2)45 b(Bash)15 b(Startup)g(Files)c +Fa(:)d(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)26 b +Fl(16)149 1969 y(4.3)45 b(Is)15 b(This)h(Shell)h(In)o(teractiv)o(e?)9 +b Fa(:)f(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b Fl(17)149 2032 y(4.4)45 +b(Bash)15 b(Builtin)j(Commands)13 b Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)28 +b Fl(17)149 2094 y(4.5)45 b(The)15 b(Set)h(Builtin)e +Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 +b Fl(20)149 2156 y(4.6)45 b(Bash)15 b(V)l(ariables)9 +b Fa(:)g(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)24 +b Fl(22)149 2219 y(4.7)45 b(Shell)17 b(Arithmetic)e Fa(:)7 +b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)28 +b Fl(24)299 2281 y(4.7.1)44 b(Arithmetic)16 b(Ev)m(aluation)f +Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)29 +b Fl(24)299 2343 y(4.7.2)44 b(Arithmetic)16 b(Expansion)7 +b Fa(:)h(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)22 b Fl(25)299 2405 y(4.7.3)44 b(Arithmetic)16 b(Builtins)f +Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)27 b Fl(26)149 2468 y(4.8)45 b(Con)o(trolling)16 +b(the)f(Prompt)e Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)28 b +Fl(26)0 2592 y Fj(5)67 b(Job)22 b(Con)n(trol)8 b Fb(:)j(:)f(:)g(:)h(:)f +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)31 b Fj(29)149 2670 y Fl(5.1)45 b(Job)15 b(Con)o(trol)g(Basics) +10 b Fa(:)d(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)24 +b Fl(29)p eop +-2 59 bop 0 -58 a Fl(ii)1645 b(Bash)15 b(F)l(eatures)149 +42 y(5.2)45 b(Job)15 b(Con)o(trol)g(Builtins)h Fa(:)7 +b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)28 b Fl(30)149 104 +y(5.3)45 b(Job)15 b(Con)o(trol)g(V)l(ariables)c Fa(:)d(:)f(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)25 b Fl(31)0 228 y Fj(6)67 b(Using)22 +b(History)h(In)n(teractiv)n(ely)e Fb(:)10 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)41 +b Fj(33)149 306 y Fl(6.1)k(History)15 b(In)o(teraction)8 +b Fa(:)f(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 +b Fl(33)299 368 y(6.1.1)44 b(Ev)o(en)o(t)14 b(Designators)t +Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)19 b Fl(33)299 431 y(6.1.2)44 b(W)l(ord)15 +b(Designators)8 b Fa(:)e(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 b Fl(34)299 493 +y(6.1.3)44 b(Mo)q(di\014ers)13 b Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)28 b Fl(34)0 617 y Fj(7)67 b(Command)22 +b(Line)i(Editing)10 b Fb(:)h(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)33 +b Fj(37)149 695 y Fl(7.1)45 b(In)o(tro)q(duction)16 b(to)f(Line)h +(Editing)t Fa(:)9 b(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)19 b Fl(37)149 758 y(7.2)45 b(Readline)17 +b(In)o(teraction)5 b Fa(:)j(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 +b Fl(37)299 820 y(7.2.1)44 b(Readline)17 b(Bare)e(Essen)o(tials)d +Fa(:)c(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 +b Fl(38)299 882 y(7.2.2)44 b(Readline)17 b(Mo)o(v)o(emen)o(t)d +(Commands)e Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)27 b Fl(38)299 +944 y(7.2.3)44 b(Readline)17 b(Killing)h(Commands)7 b +Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)22 b Fl(39)299 +1007 y(7.2.4)44 b(Readline)17 b(Argumen)o(ts)c Fa(:)8 +b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +28 b Fl(40)149 1069 y(7.3)45 b(Readline)17 b(Init)g(File)c +Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 +b Fl(40)299 1131 y(7.3.1)44 b(Readline)17 b(Init)f(Syn)o(tax)10 +b Fa(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)25 b Fl(40)299 1193 y(7.3.2)44 b(Conditional)16 +b(Init)g(Constructs)c Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +27 b Fl(43)149 1256 y(7.4)45 b(Bindable)17 b(Readline)h(Commands)8 +b Fa(:)e(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)23 b Fl(44)299 1318 y(7.4.1)44 b(Commands)14 b(F)l(or)h(Mo)o +(ving)e Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)28 b Fl(44)299 1380 y(7.4.2)44 b(Commands)14 b(F)l(or)h +(Manipulating)i(The)e(History)8 b Fa(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)23 b Fl(45)299 1443 y(7.4.3)44 +b(Commands)14 b(F)l(or)h(Changing)h(T)l(ext)10 b Fa(:)c(:)i(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)25 b Fl(46)299 1505 y(7.4.4)44 b(Killing)18 +b(And)e(Y)l(anking)10 b Fa(:)e(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) +h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fl(47)299 1567 y(7.4.5)44 +b(Sp)q(ecifying)17 b(Numeric)f(Argumen)o(ts)8 b Fa(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) +g(:)g(:)h(:)22 b Fl(48)299 1629 y(7.4.6)44 b(Letting)15 +b(Readline)j(T)o(yp)q(e)d(F)l(or)g(Y)l(ou)5 b Fa(:)i(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)20 b Fl(48)299 1692 y(7.4.7)44 b(Keyb)q(oard)15 +b(Macros)9 b Fa(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)h(:)f(:)24 b Fl(48)299 1754 y(7.4.8)44 +b(Some)15 b(Miscellaneous)i(Commands)11 b Fa(:)d(:)f(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)27 b Fl(49)149 1816 y(7.5)45 b(Readline)17 b(vi)f(Mo)q(de)d +Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 +b Fl(50)0 1941 y Fj(App)r(endix)d(A)67 b(V)-6 b(ariable)24 +b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)38 b Fj(51)0 +2081 y(App)r(endix)24 b(B)67 b(Concept)22 b(Index)c Fb(:)10 +b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)39 b Fj(53)p eop end +userdict /end-hook known{end-hook}if diff --git a/documentation/features.texi b/documentation/features.texi 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 +#include +.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-, 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 )-.18 E +(#include )-.7 E(typedef int Function \(\);)108 153.6 Q +(char *r)108 170.4 Q(eadline \(pr)-.18 E(ompt\))-.18 E(char *pr)108 182.4 Q +(ompt;)-.18 E(int rl_add_defun \(name, function, k)108 199.2 Q(ey\))-.1 E +(char *name;)108 211.2 Q(Function *function;)108 223.2 Q(int k)108 235.2 Q(ey;) +-.1 E(int rl_bind_k)108 252 Q(ey \(k)-.1 E(ey)-.1 E 2.5(,f)-.55 G(unction\)) +202.26 252 Q(int k)108 264 Q(ey;)-.1 E(Function *function;)108 276 Q +(int rl_unbind_k)108 292.8 Q(ey \(k)-.1 E(ey\))-.1 E(int k)108 304.8 Q(ey;)-.1 +E(int rl_bind_k)108 321.6 Q(ey_in_map \(k)-.1 E(ey)-.1 E 2.5(,f)-.55 G +(unction, k)239.49 321.6 Q(eymap\))-.1 E(int k)108 333.6 Q(ey;)-.1 E +(Function *function;)108 345.6 Q -.25(Ke)108 357.6 S(ymap k).25 E(eymap;)-.1 E +(int rl_unbind_k)108 374.4 Q(ey_in_map \(k)-.1 E(ey)-.1 E 2.5(,k)-.55 G +(eymap\))252.74 374.4 Q(int k)108 386.4 Q(ey;)-.1 E -.25(Ke)108 398.4 S(ymap k) +.25 E(eymap;)-.1 E(int rl_macr)108 415.2 Q(o_bind \(k)-.18 E(eyseq, macr)-.1 E +(o, k)-.18 E(eymap\))-.1 E(char *k)108 427.2 Q(eyseq, *macr)-.1 E(o;)-.18 E +-.25(Ke)108 439.2 S(ymap k).25 E(eymap;)-.1 E(int rl_v)108 456 Q +(ariable_bind \(v)-.1 E(ariable, v)-.1 E(alue\))-.1 E(char *v)108 468 Q +(ariable, *v)-.1 E(alue;)-.1 E(int rl_parse_and_bind \(line\))108 484.8 Q +(char *line;)108 496.8 Q(int rl_translate_k)108 513.6 Q(eyseq \(k)-.1 E +(eyseq, array)-.1 E 2.5(,l)-.55 G(en\))276.68 513.6 Q(char *k)108 525.6 Q +(eyseq, *array;)-.1 E(int *len;)108 537.6 Q +(Function *rl_named_function \(command\))108 554.4 Q(char *command;)108 566.4 Q +(Function *rl_function_of_k)108 583.2 Q(eyseq \(k)-.1 E(eyseq, k)-.1 E +(eymap, type\))-.1 E(char *k)108 595.2 Q(eyseq;)-.1 E -.25(Ke)108 607.2 S +(ymap k).25 E(eymap;)-.1 E(int *type;)108 619.2 Q(char **rl_in)108 636 Q -.1 +(vo)-.4 G(king_k).1 E(eyseqs \(function\))-.1 E(Function *function;)108 648 Q +(char **rl_in)108 664.8 Q -.1(vo)-.4 G(king_k).1 E(eyseqs_in_map \(function, k) +-.1 E(eymap\))-.1 E(Function *function;)108 676.8 Q -.25(Ke)108 688.8 S(ymap k) +.25 E(eymap;)-.1 E -.1(vo)108 705.6 S(id rl_function_dumper \(r).1 E(eadable\)) +-.18 E(int r)108 717.6 Q(eadable;)-.18 E F0 184.005(GNU 1994)72 768 R(July 26) +2.5 E(1)535 768 Q EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 +/Times-Bold@0 SF(char **rl_funmap_names \(\))108 84 Q/F2 9/Times-Bold@0 SF +(COPYRIGHT)72 100.8 Q F0(Readline is Cop)108 112.8 Q +(yright \251 1989, 1991 by the Free Softw)-.1 E(are F)-.1 E(oundation, Inc.) +-.15 E F2(DESCRIPTION)72 129.6 Q F1 -.18(re)108 141.6 S(adline).18 E F0 .49 +(will read a line from the terminal and return it, using)2.99 F F1(pr)2.99 E +(ompt)-.18 E F0 .49(as a prompt.)2.99 F(If)5.49 E F1(pr)2.99 E(ompt)-.18 E F0 +.49(is null, no)2.99 F 1.066(prompt is issued.)108 153.6 R 1.066 +(The line returned is allocated with)6.066 F/F3 10/Times-Italic@0 SF(malloc) +3.566 E F0 1.067(\(3\), so the caller must free it when \214nished.).31 F +(The line returned has the \214nal ne)108 165.6 Q(wline remo)-.25 E -.15(ve) +-.15 G(d, so only the te).15 E(xt of the line remains.)-.15 E F1 -.18(re)108 +182.4 S(adline).18 E F0(of)3.79 E 1.29 +(fers editing capabilities while the user is entering the line.)-.25 F 1.289 +(By def)6.289 F 1.289(ault, the line editing com-)-.1 F +(mands are similar to those of emacs.)108 194.4 Q 2.5(Av)5 G +(i\255style line editing interf)273.53 194.4 Q(ace is also a)-.1 E -.25(va)-.2 +G(ilable.).25 E 6.74(In the follo)108 211.2 R 6.74(wing descriptions,)-.25 F F1 +-.1(ke)9.24 G(ymap).1 E F0 6.74(can be one of)9.24 F F3(emacs_k)9.24 E -.3(ey) +-.1 G 6.74(map, emacs_meta_k).3 F -.3(ey)-.1 G(map,).3 E(emacs_ctlx_k)108 223.2 +Q -.3(ey)-.1 G(map, vi_insertion_k).3 E -.3(ey)-.1 G(map, or vi_mo).3 E +(vement_k)-.1 E -.3(ey)-.1 G(map).3 E F0(.)A F1(rl_add_defun)108 240 Q F0(mak) +3.356 E(es)-.1 E F1(name)3.356 E F0 .856 +(appear as a bindable readline command, and mak)3.356 F(es)-.1 E F1(function) +3.355 E F0 .855(be the function)3.355 F(called when that command is in)108 252 +Q -.2(vo)-.4 G -.1(ke).2 G 2.5(d. If).1 F F1 -.1(ke)2.5 G(y).1 E F0 +(is not \2551, it is bound to)2.5 E F1(function)2.5 E F0(in the current k)2.5 E +-.15(ey)-.1 G(map.).15 E F1(rl_bind_k)108 268.8 Q(ey)-.1 E F0(causes)2.5 E F1 +-.1(ke)2.5 G(y).1 E F0(to in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E +F0 5(.T)C(he binding is made in the current k)296.55 268.8 Q -.15(ey)-.1 G +(map.).15 E F1(rl_unbind_k)108 285.6 Q(ey)-.1 E F0(remo)2.5 E -.15(ve)-.15 G +2.5(st).15 G(he binding for)212.06 285.6 Q F1 -.1(ke)2.5 G(y).1 E F0 +(in the current k)2.5 E -.15(ey)-.1 G(map.).15 E F1(rl_bind_k)108 302.4 Q +(ey_in_map)-.1 E F0(mak)2.5 E(es the)-.1 E F1 -.1(ke)2.5 G(y).1 E F0(entry in) +2.5 E F1 -.1(ke)2.5 G(ymap).1 E F0(in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1 +(function)2.6 E F0(.)A F1(rl_unbind_k)108 319.2 Q(ey_in_map)-.1 E F0(remo)2.5 E +-.15(ve)-.15 G 2.5(st).15 G(he binding for)249.29 319.2 Q F1 -.1(ke)2.5 G(y).1 +E F0(in k)2.5 E -.15(ey)-.1 G(map).15 E F1 -.1(ke)2.5 G(ymap).1 E F0(.)A F1 +(rl_macr)108 336 Q(o_bind)-.18 E F0(mak)2.5 E(es)-.1 E F1 -.1(ke)2.5 G(yseq).1 +E F0(insert the string)2.5 E F1(macr)2.5 E(o)-.18 E F0 5(.T)C +(he binding is performed in)338.81 336 Q F1 -.1(ke)2.5 G(ymap).1 E F0(.)A F1 +(rl_v)108 352.8 Q(ariable_bind)-.1 E F0(sets the v)2.5 E +(alue of the readline v)-.25 E(ariable)-.25 E F1 -.1(va)2.5 G(riable).1 E F0 +(to)2.5 E F1 -.1(va)2.5 G(lue).1 E F0(.)A F1(rl_parse_and_bind)108 369.6 Q F0 +(tak)2.806 E .307(es as an ar)-.1 F .307 +(gument a line of the same form as the readline startup \214le \(see)-.18 F F2 +(INITIAL-)2.807 E(IZA)108 381.6 Q(TION FILE)-.855 E F0(belo)2.25 E(w\) and e) +-.25 E -.15(xe)-.15 G(cutes the commands therein.).15 E F1(rl_translate_k)108 +398.4 Q(eyseq)-.1 E F0(con)2.975 E -.15(ve)-.4 G(rts).15 E F1 -.1(ke)2.975 G +(yseq).1 E F0 .475(into a ne)2.975 F 2.975(ws)-.25 G .475 +(tring, storing the result in)312.05 398.4 R F1(array)2.975 E F0 5.475(.T)C +.475(his translates control)456.28 398.4 R .337(and meta pre\214x)108 410.4 R +.337(es and the readline character escape sequences \(see)-.15 F F2 -.225(Ke) +2.837 G 2.587(yB).225 G(indings)404.423 410.4 Q F0(belo)2.588 E 2.838(w\). The) +-.25 F .338(length of the)2.838 F(translated sequence is returned in)108 422.4 +Q F1(*len)2.5 E F0(.)A F1(rl_named_function)108 439.2 Q F0 2.974 +(returns the function that is e)5.474 F -.15(xe)-.15 G 2.973 +(cuted when the readline command).15 F F1(command)5.473 E F0(is)5.473 E(in)108 +451.2 Q -.2(vo)-.4 G -.1(ke).2 G(d.).1 E F1(rl_function_of_k)108 468 Q(eyseq) +-.1 E F0 .801(returns the function that is e)3.301 F -.15(xe)-.15 G .801 +(cuted when).15 F F1 -.1(ke)3.301 G(yseq).1 E F0 .801(is read and)3.301 F F1 +-.1(ke)3.302 G(ymap).1 E F0 .802(is the cur)3.302 F(-)-.2 E .267(rent k)108 480 +R -.15(ey)-.1 G(map.).15 E F1(type)5.267 E F0 .267 +(is set to indicate whether the return v)2.767 F .266 +(alue corresponds to a function, macro, or auxiliary)-.25 F -.1(ke)108 492 S +(ymap.)-.05 E F1(rl_in)108 508.8 Q -.1(vo)-.4 G(king_k).1 E(eyseqs)-.1 E F0 +(returns all of the k)2.5 E .3 -.15(ey s)-.1 H(equences in the current k).15 E +-.15(ey)-.1 G(map that in).15 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E F0 +(.)A F1(rl_in)108 525.6 Q -.1(vo)-.4 G(king_k).1 E(eyseqs_in_map)-.1 E F0 +(returns all of the k)2.5 E .3 -.15(ey s)-.1 H(equences in).15 E F1 -.1(ke)2.5 +G(ymap).1 E F0(that in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E F0(.)A +F1(rl_function_dumper)108 542.4 Q F0 .117(prints all of the readline functions\ + and their bindings to the readline output stream.)2.617 F(If)5.118 E F1 -.18 +(re)108 554.4 S(adable).18 E F0(is non\255zero, the output is formattted so th\ +at it can be read back in to restore the bindings.)2.5 E F1(rl_funmap_names)108 +571.2 Q F0(returns an array of all kno)2.5 E +(wn readline bindable function names.)-.25 E(The array is sorted.)5 E F2 +(RETURN V)72 588 Q(ALUE)-1.215 E F1 -.18(re)108 600 S(adline).18 E F0 1.09 +(returns the te)3.59 F 1.09(xt of the line read.)-.15 F 3.589(Ab)6.09 G 1.089 +(lank line returns the empty string.)299.949 600 R(If)6.089 E F1(EOF)3.589 E F0 +1.089(is encountered)3.589 F .283(while reading a line, and the line is empty) +108 612 R(,)-.65 E F1(NULL)2.783 E F0 .283(is returned.)2.783 F .283(If an) +5.283 F F1(EOF)2.783 E F0 .283(is read with a non\255empty line, it)2.783 F +(is treated as a ne)108 624 Q(wline.)-.25 E(Unless otherwise stated, the other\ + functions return 0 on success and non\255zero on f)108 640.8 Q(ailure.)-.1 E +F2(NO)72 657.6 Q -.81(TA)-.36 G(TION)-.045 E F0 .037 +(An emacs\255style notation is used to denote k)108 669.6 R -.15(ey)-.1 G +(strok).15 E 2.536(es. Control)-.1 F -.1(ke)2.536 G .036 +(ys are denoted by C\255)-.05 F F3 -.1(ke)C(y)-.2 E F0 2.536(,e)C .036 +(.g., C\255n means)479.568 669.6 R 2.625(Control\255N. Similarly)108 681.6 R(,) +-.65 E F3(meta)2.625 E F0 -.1(ke)2.625 G .125(ys are denoted by M\255)-.05 F F3 +-.1(ke)C(y)-.2 E F0 2.625(,s)C 2.625(oM)341.73 681.6 S .125 +(\255x means Meta\255X.)358.245 681.6 R .126(\(On k)5.126 F -.15(ey)-.1 G .126 +(boards without a).15 F F3(meta)108 693.6 Q F0 -.1(ke)3.309 G 2.109 -.65(y, M) +-.05 H.65 E F3(x)A F0 .809(means ESC)3.309 F F3(x)3.309 E F0 3.309(,i)C +.809(.e., press the Escape k)235.914 693.6 R 1.108 -.15(ey t)-.1 H .808 +(hen the).15 F F3(x)3.308 E F0 -.1(ke)3.308 G 4.608 -.65(y. T)-.05 H .808 +(his mak).65 F .808(es ESC the)-.1 F F3 .808(meta pr)3.308 F(e\214x)-.37 E F0 +(.)A .48(The combination M\255C\255)108 705.6 R F3(x)A F0 .48 +(means ESC\255Control\255)2.98 F F3(x)A F0 2.98(,o)C 2.98(rp)317.4 705.6 S .48 +(ress the Escape k)328.71 705.6 R .78 -.15(ey t)-.1 H .48 +(hen hold the Control k).15 F .78 -.15(ey w)-.1 H(hile).15 E(pressing the)108 +717.6 Q F3(x)2.5 E F0 -.1(ke)2.5 G -.65(y.)-.05 G(\)).65 E 184.005(GNU 1994)72 +768 R(July 26)2.5 E(2)535 768 Q EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R .62 +(Readline commands may be gi)108 84 R -.15(ve)-.25 G 3.119(nn).15 G(umeric) +255.959 84 Q/F1 10/Times-Italic@0 SF(ar)3.119 E(guments)-.37 E F0 3.119(,w).27 +G .619(hich normally act as a repeat count.)341.807 84 R(Sometimes,)5.619 E(ho) +108 96 Q(we)-.25 E -.15(ve)-.25 G 1.418 -.4(r, i).15 H 3.118(ti).4 G 3.119(st) +158.456 96 S .619(he sign of the ar)168.245 96 R .619 +(gument that is signi\214cant.)-.18 F -.15(Pa)5.619 G .619(ssing a ne).15 F +-.05(ga)-.15 G(ti).05 E .919 -.15(ve a)-.25 H -.18(rg).15 G .619 +(ument to a command that).18 F 1.019(acts in the forw)108 108 R 1.018 +(ard direction \(e.g.,)-.1 F/F2 10/Times-Bold@0 SF(kill\255line)3.518 E F0 +3.518(\)c)C 1.018(auses that command to act in a backw)298.478 108 R 1.018 +(ard direction.)-.1 F(Com-)6.018 E(mands whose beha)108 120 Q(vior with ar)-.2 +E(guments de)-.18 E(viates from this are noted.)-.25 E .811 +(When a command is described as)108 136.8 R F1(killing)3.311 E F0(te)3.311 E +.811(xt, the te)-.15 F .811(xt deleted is sa)-.15 F -.15(ve)-.2 G 3.311(df).15 +G .812(or possible future retrie)403.403 136.8 R -.25(va)-.25 G 3.312(l\().25 G +F1(yank-)517.79 136.8 Q(ing)108 148.8 Q F0 3.439(\). The)B .939(killed te)3.439 +F .939(xt is sa)-.15 F -.15(ve)-.2 G 3.439(di).15 G 3.438(na)234.794 148.8 S F1 +(kill\255ring)A F0 5.938(.C)C(onsecuti)302.418 148.8 Q 1.238 -.15(ve k)-.25 H +.938(ills cause the te).15 F .938(xt to be accumulated into one)-.15 F .331 +(unit, which can be yank)108 160.8 R .331(ed all at once.)-.1 F .331 +(Commands which do not kill te)5.331 F .331(xt separate the chunks of te)-.15 F +.331(xt on the)-.15 F(kill\255ring.)108 172.8 Q/F3 9/Times-Bold@0 SF +(INITIALIZA)72 189.6 Q(TION FILE)-.855 E F0 .827 +(Readline is customized by putting commands in an initialization \214le.)108 +201.6 R .827(The name of this \214le is tak)5.827 F .827(en from)-.1 F 1.041 +(the v)108 213.6 R 1.041(alue of the)-.25 F F2(INPUTRC)3.541 E F0 -.25(va)3.542 +G 3.542(riable. If).25 F 1.042(that v)3.542 F 1.042(ariable is unset, the def) +-.25 F 1.042(ault is)-.1 F F1(~/.inputr)3.542 E(c)-.37 E F0 6.042(.W).31 G +1.042(hen a program)480.156 213.6 R 1.159 +(which uses the readline library starts up, the init \214le is read, and the k) +108 225.6 R 1.458 -.15(ey b)-.1 H 1.158(indings and v).15 F 1.158 +(ariables are set.)-.25 F .028(There are only a fe)108 237.6 R 2.528(wb)-.25 G +.028(asic constructs allo)198.13 237.6 R .028(wed in the readline init \214le.) +-.25 F .029(Blank lines are ignored.)5.029 F .029(Lines be)5.029 F(gin-)-.15 E +.554(ning with a)108 249.6 R F2(#)3.054 E F0 .554(are comments.)3.054 F .554 +(Lines be)5.554 F .554(ginning with a)-.15 F F2($)3.054 E F0 .554 +(indicate conditional constructs.)3.054 F .553(Other lines denote)5.553 F -.1 +(ke)108 261.6 S 2.986(yb)-.05 G .486(indings and v)130.176 261.6 R .487 +(ariable settings.)-.25 F .487(Each program using this library may add its o) +5.487 F .487(wn commands and bind-)-.25 F(ings.)108 273.6 Q -.15(Fo)108 290.4 S +2.5(re).15 G(xample, placing)128.53 290.4 Q(M\255Control\255u: uni)144 307.2 Q +-.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(or)108 319.2 Q +(C\255Meta\255u: uni)144 331.2 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E +(into the)108 343.2 Q F1(~/.inputr)4.166 E(c)-.37 E F0 -.1(wo)4.166 G(uld mak) +.1 E 2.5(eM)-.1 G(\255C\255u e)244.092 343.2 Q -.15(xe)-.15 G +(cute the readline command).15 E F1(univer)2.5 E(sal\255ar)-.1 E(gument)-.37 E +F0(.).68 E .978(The follo)108 360 R .978 +(wing symbolic character names are recognized while processing k)-.25 F 1.277 +-.15(ey b)-.1 H(indings:).15 E F1 -.4(RU)3.477 G(BOUT).4 E F0(,)1.27 E F1(DEL) +3.477 E F0(,).53 E F1(ESC)108 372 Q F0(,).72 E F1(LFD)2.984 E F0(,).28 E F1 +(NEWLINE)2.984 E F0(,).73 E F1(RET)2.984 E F0(,)1.27 E F1(RETURN)2.984 E F0(,) +1.1 E F1(SPC)2.984 E F0(,).72 E F1(SP)2.984 E -.3(AC)-.9 G(E).3 E F0 2.984(,a) +.73 G(nd)337.968 372 Q F1 -.5(TA)2.984 G(B).5 E F0 5.484(.I).27 G 2.984(na) +379.816 372 S .485(ddition to command names, readline)392.24 372 R(allo)108 384 +Q(ws k)-.25 E -.15(ey)-.1 G 2.5(st).15 G 2.5(ob)159.72 384 S 2.5(eb)172.22 384 +S(ound to a string that is inserted when the k)184.16 384 Q .3 -.15(ey i)-.1 H +2.5(sp).15 G(ressed \(a)379.73 384 Q F1(macr)2.5 E(o)-.45 E F0(\).)A F2 -.25 +(Ke)87 405.6 S 2.5(yB).25 G(indings)113.14 405.6 Q F0 .724 +(The syntax for controlling k)108 417.6 R 1.024 -.15(ey b)-.1 H .724 +(indings in the).15 F F1(~/.inputr)3.224 E(c)-.37 E F0 .724(\214le is simple.) +3.224 F .723(All that is required is the name of)5.724 F .938 +(the command or the te)108 429.6 R .938(xt of a macro and a k)-.15 F 1.238 -.15 +(ey s)-.1 H .938(equence to which it should be bound. The name may be).15 F +.695(speci\214ed in one of tw)108 441.6 R 3.195(ow)-.1 G .695 +(ays: as a symbolic k)212.095 441.6 R .995 -.15(ey n)-.1 H .695 +(ame, possibly with).15 F F1(Meta\255)3.195 E F0(or)3.195 E F1(Contr)3.194 E +(ol\255)-.45 E F0(pre\214x)3.194 E .694(es, or as a)-.15 F -.1(ke)108 453.6 S +4.143(ys)-.05 G 4.143(equence. When)130.223 453.6 R 1.643(using the form)4.143 +F F2 -.1(ke)4.143 G(yname).1 E F0(:)A F1(function-name)A F0(or)4.143 E F1(macr) +4.143 E(o)-.45 E F0(,)A F1 -.1(ke)4.143 G(yname)-.2 E F0 1.644 +(is the name of a k)4.143 F -.15(ey)-.1 G(spelled out in English.)108 465.6 Q +-.15(Fo)5 G 2.5(re).15 G(xample:)222.98 465.6 Q(Control\255u: uni)144 489.6 Q +-.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(Meta\255Rubout: backw)144 501.6 Q +(ard\255kill\255w)-.1 E(ord)-.1 E(Control\255o: ">&output")144 513.6 Q .229 +(In the abo)108 530.4 R .529 -.15(ve ex)-.15 H(ample,).15 E F1(C\255u)2.729 E +F0 .229(is bound to the function)2.729 F F2(uni)2.729 E -.1(ve)-.1 G +(rsal\255ar).1 E(gument)-.1 E F0(,)A F1(M-DEL)2.729 E F0 .228 +(is bound to the function)2.729 F F2(backward\255kill\255w)108 542.4 Q(ord)-.1 +E F0 3.837(,a)C(nd)208.977 542.4 Q F1(C\255o)3.837 E F0 1.337 +(is bound to run the macro e)3.837 F 1.337 +(xpressed on the right hand side \(that is, to)-.15 F(insert the te)108 554.4 Q +(xt)-.15 E F1(>&output)2.5 E F0(into the line\).)2.5 E .115 +(In the second form,)108 571.2 R F2("k)2.615 E(eyseq")-.1 E F0(:)A F1 +(function\255name)A F0(or)2.615 E F1(macr)2.615 E(o)-.45 E F0(,)A F2 -.1(ke) +2.615 G(yseq).1 E F0(dif)2.615 E .115(fers from)-.25 F F2 -.1(ke)2.615 G(yname) +.1 E F0(abo)2.615 E .415 -.15(ve i)-.15 H 2.615(nt).15 G .115(hat strings) +498.495 571.2 R 1.284(denoting an entire k)108 583.2 R 1.584 -.15(ey s)-.1 H +1.284(equence may be speci\214ed by placing the sequence within double quotes.) +.15 F(Some)6.284 E(GNU Emacs style k)108 595.2 Q .3 -.15(ey e)-.1 H +(scapes can be used, as in the follo).15 E(wing e)-.25 E(xample.)-.15 E +("\\C\255u": uni)144 619.2 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E +("\\C\255x\\C\255r": re\255read\255init\255\214le)144 631.2 Q +("\\e[11~": "Function K)144 643.2 Q .3 -.15(ey 1)-.25 H(").15 E .238(In this e) +108 660 R(xample,)-.15 E F1(C-u)2.738 E F0 .238(is ag)2.738 F .238 +(ain bound to the function)-.05 F F2(uni)2.738 E -.1(ve)-.1 G(rsal\255ar).1 E +(gument)-.1 E F0(.)A F1 .237(C-x C-r)5.238 F F0 .237(is bound to the function) +2.737 F F2 -.18(re)108 672 S.18 E(ead\255init\255\214le)-.18 E F0 3.909 +(,a)C(nd)191.139 672 Q F1 1.409(ESC [ 1 1 ~)3.909 F F0 1.409 +(is bound to insert the te)3.909 F(xt)-.15 E F2 1.41(Function K)3.91 F 1.41 +(ey 1)-.25 F F0 6.41(.T)C 1.41(he full set of escape)454.94 672 R(sequences is) +108 684 Q F2(\\C-)144 700.8 Q F0(control pre\214x)180 700.8 Q F2(\\M-)144 717.6 +Q F0(meta pre\214x)180 717.6 Q 184.005(GNU 1994)72 768 R(July 26)2.5 E(3)535 +768 Q EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 +/Times-Bold@0 SF(\\e)144 84 Q F0(an escape character)180 84 Q F1(\\\\)144 100.8 +Q F0(backslash)180 100.8 Q F1(\\")144 117.6 Q F0(literal ")180 117.6 Q F1(\\') +144 134.4 Q F0(literal ')180 134.4 Q .74(When entering the te)108 151.2 R .74(\ +xt of a macro, single or double quotes should be used to indicate a macro de\ +\214nition.)-.15 F 1.226(Unquoted te)108 163.2 R 1.226 +(xt is assumed to be a function name.)-.15 F 1.227(Backslash will quote an) +6.226 F 3.727(yc)-.15 G 1.227(haracter in the macro te)430.552 163.2 R(xt,)-.15 +E(including " and '.)108 175.2 Q F1(Bash)108 192 Q F0(allo)2.93 E .43 +(ws the current readline k)-.25 F .73 -.15(ey b)-.1 H .429 +(indings to be displayed or modi\214ed with the).15 F F1(bind)2.929 E F0 -.2 +(bu)2.929 G .429(iltin command.).2 F 1.095 +(The editing mode may be switched during interacti)108 204 R 1.395 -.15(ve u) +-.25 H 1.095(se by using the).15 F F13.595 E F0 1.095(option to the)3.595 +F F1(set)3.595 E F0 -.2(bu)3.595 G 1.095(iltin com-).2 F 3.097(mand. Other)108 +216 R .597(programs using this library pro)3.097 F .597 +(vide similar mechanisms.)-.15 F(The)5.597 E/F2 10/Times-Italic@0 SF(inputr) +3.097 E(c)-.37 E F0 .596(\214le may be edited and)3.096 F +(re\255read if a program does not pro)108 228 Q(vide an)-.15 E 2.5(yo)-.15 G +(ther means to incorporate ne)283.85 228 Q 2.5(wb)-.25 G(indings.)412.18 228 Q +F1 -.92(Va)87 244.8 S(riables).92 E F0 .043(Readline has v)108 256.8 R .044 +(ariables that can be used to further customize its beha)-.25 F(vior)-.2 E +5.044(.A)-.55 G -.25(va)413.896 256.8 S .044(riable may be set in the).25 F F2 +(inpu-)2.544 E(tr)108 268.8 Q(c)-.37 E F0(\214le with a statement of the form) +2.5 E F1(set)144 285.6 Q F2(variable\255name value)2.5 E F0 .489 +(Except where noted, readline v)108 302.4 R .489(ariables can tak)-.25 F 2.989 +(et)-.1 G .489(he v)307.123 302.4 R(alues)-.25 E F1(On)2.989 E F0(or)2.989 E F1 +(Off)2.989 E F0 5.489(.T)C .489(he v)404.028 302.4 R .488 +(ariables and their def)-.25 F .488(ault v)-.1 F(al-)-.25 E(ues are:)108 314.4 +Q F1(horizontal\255scr)108 331.2 Q(oll\255mode \(Off\))-.18 E F0 .448 +(When set to)144 343.2 R F1(On)2.948 E F0 2.948(,m)C(ak)222.182 343.2 Q .448 +(es readline use a single line for display)-.1 F 2.948(,s)-.65 G .449 +(crolling the input horizontally on a)398.596 343.2 R 1.194(single screen line\ + when it becomes longer than the screen width rather than wrapping to a ne)144 +355.2 R(w)-.25 E(line.)144 367.2 Q F1(editing\255mode \(emacs\))108 379.2 Q F0 +.252(Controls whether readline be)144 391.2 R .253(gins with a set of k)-.15 F +.553 -.15(ey b)-.1 H .253(indings similar to).15 F F2(emacs)2.753 E F0(or)2.753 +E F2(vi)2.753 E F0(.)A F1(editing\255mode)5.253 E F0(can be set to either)144 +403.2 Q F1(emacs)2.5 E F0(or)2.5 E F1(vi)2.5 E F0(.)A F1 +(mark\255modi\214ed\255lines \(Off\))108 415.2 Q F0(If set to)144 427.2 Q F1 +(On)2.5 E F0 2.5(,h)C(istory lines that ha)200.39 427.2 Q .3 -.15(ve b)-.2 H +(een modi\214ed are displayed with a preceding asterisk \().15 E F1(*)A F0(\).) +A F1(bell\255style \(audible\))108 439.2 Q F0 .011 +(Controls what happens when readline w)144 451.2 R .011 +(ants to ring the terminal bell.)-.1 F .01(If set to)5.01 F F1(none)2.51 E F0 +2.51(,r)C .01(eadline ne)486.8 451.2 R -.15(ve)-.25 G(r).15 E .94 +(rings the bell.)144 463.2 R .94(If set to)5.94 F F1(visible)3.44 E F0 3.44(,r) +C .94(eadline uses a visible bell if one is a)278.91 463.2 R -.25(va)-.2 G 3.44 +(ilable. If).25 F .94(set to)3.44 F F1(audible)3.44 E F0(,)A +(readline attempts to ring the terminal')144 475.2 Q 2.5(sb)-.55 G(ell.)306.21 +475.2 Q F1(comment\255begin \(`)108 487.2 Q(`#')-.63 E('\))-.63 E F0 +(The string that is inserted in)144 499.2 Q F1(vi)2.5 E F0(mode when the)2.5 E +F1(vi\255comment)2.5 E F0(command is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 +(meta\255\215ag \(Off\))108 511.2 Q F0 .228(If set to)144 523.2 R F1(On)2.728 E +F0 2.728(,r)C .227(eadline will enable eight-bit input \(that is, it will not \ +strip the high bit from the char)199.632 523.2 R(-)-.2 E(acters it reads\), re) +144 535.2 Q -.05(ga)-.15 G(rdless of what the terminal claims it can support.) +.05 E F1(con)108 547.2 Q -.1(ve)-.4 G(rt\255meta \(On\)).1 E F0 .612(If set to) +144 559.2 R F1(On)3.112 E F0 3.112(,r)C .613(eadline will con)201.168 559.2 R +-.15(ve)-.4 G .613(rt characters with the eighth bit set to an ASCII k).15 F +.913 -.15(ey s)-.1 H .613(equence by).15 F 1.238 +(stripping the eighth bit and prepending an escape character \(in ef)144 571.2 +R 1.238(fect, using escape as the)-.25 F F2(meta)3.738 E(pr)144 583.2 Q(e\214x) +-.37 E F0(\).)A F1(output\255meta \(Off\))108 595.2 Q F0 .506(If set to)144 +607.2 R F1(On)3.006 E F0 3.006(,r)C .507(eadline will display characters with \ +the eighth bit set directly rather than as a meta-)200.744 607.2 R(pre\214x)144 +619.2 Q(ed escape sequence.)-.15 E F1(completion\255query\255items \(100\))108 +631.2 Q F0 .53(This determines when the user is queried about vie)144 643.2 R +.529(wing the number of possible completions gen-)-.25 F .56(erated by the)144 +655.2 R F1(possible\255completions)3.06 E F0 3.06(command. It)3.06 F .561 +(may be set to an)3.061 F 3.061(yi)-.15 G(nte)428.196 655.2 Q .561(ger v)-.15 F +.561(alue greater than or)-.25 F .783(equal to zero.)144 667.2 R .783 +(If the number of possible completions is greater than or equal to the v)5.783 +F .782(alue of this)-.25 F -.25(va)144 679.2 S .237(riable, the user is ask).25 +F .237(ed whether or not he wishes to vie)-.1 F 2.737(wt)-.25 G .237 +(hem; otherwise the)389.254 679.2 R 2.737(ya)-.15 G .237(re simply listed) +477.855 679.2 R(on the terminal.)144 691.2 Q F1 -.1(ke)108 703.2 S +(ymap \(emacs\)).1 E F0 2.323(Set the current readline k)144 715.2 R -.15(ey) +-.1 G 4.823(map. The).15 F 2.323(set of le)4.823 F -.05(ga)-.15 G 4.823(lk).05 +G -.15(ey)368.478 715.2 S 2.323(map names is).15 F F2 2.323 +(emacs, emacs-standar)4.823 F(d,)-.37 E .808(emacs-meta, emacs-ctlx, vi, vi-mo) +144 727.2 R(ve)-.1 E 3.308(,v)-.1 G(i-command)300.862 727.2 Q F0 3.308(,a)C(nd) +356.1 727.2 Q F2(vi-insert)3.308 E F0(.).68 E F2(vi)5.808 E F0 .808(is equi) +3.308 F -.25(va)-.25 G .809(lent to).25 F F2(vi-command)3.309 E F0(;)A 184.005 +(GNU 1994)72 768 R(July 26)2.5 E(4)535 768 Q EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 +/Times-Italic@0 SF(emacs)144 84 Q F0 1.124(is equi)3.624 F -.25(va)-.25 G 1.124 +(lent to).25 F F1(emacs-standar)3.624 E(d)-.37 E F0 6.124(.T)C 1.124(he def) +317.34 84 R 1.124(ault v)-.1 F 1.124(alue is)-.25 F F1(emacs)3.624 E F0 3.624 +(;t).27 G 1.124(he v)431.47 84 R 1.123(alue of)-.25 F/F2 10/Times-Bold@0 SF +(editing\255mode)3.623 E F0(also af)144 96 Q(fects the def)-.25 E(ault k)-.1 E +-.15(ey)-.1 G(map.).15 E F2(sho)108 108 Q(w\255all\255if\255ambiguous \(Off\)) +-.1 E F0 .477(This alters the def)144 120 R .477(ault beha)-.1 F .477 +(vior of the completion functions.)-.2 F .478(If set to)5.478 F F2(on)2.978 E +F0 2.978(,w)C .478(ords which ha)450.326 120 R .778 -.15(ve m)-.2 H(ore).15 E +1.264(than one possible completion cause the matches to be listed immediately \ +instead of ringing the)144 132 R(bell.)144 144 Q F2(expand\255tilde \(Off\))108 +156 Q F0(If set to)144 168 Q F2(on)2.5 E F0 2.5(,t)C(ilde e)195.39 168 Q +(xpansion is performed when readline attempts w)-.15 E(ord completion.)-.1 E F2 +(Conditional Constructs)87 184.8 Q F0 .05(Readline implements a f)108 196.8 R +.05(acility similar in spirit to the conditional compilation features of the C\ + preprocessor)-.1 F 1.49(which allo)108 208.8 R 1.49(ws k)-.25 F 1.79 -.15 +(ey b)-.1 H 1.49(indings and v).15 F 1.49 +(ariable settings to be performed as the result of tests.)-.25 F 1.49 +(There are three)6.49 F(parser directi)108 220.8 Q -.15(ve)-.25 G 2.5(su).15 G +(sed.)180.91 220.8 Q F2($if)108 237.6 Q F0(The)144 237.6 Q F2($if)2.962 E F0 +.462(construct allo)2.962 F .463 +(ws bindings to be made based on the editing mode, the terminal being used,) +-.25 F .478(or the application using readline.)144 249.6 R .477(The te)5.477 F +.477(xt of the test e)-.15 F .477(xtends to the end of the line; no characters) +-.15 F(are required to isolate it.)144 261.6 Q F2(mode)144 278.4 Q F0(The)180 +278.4 Q F2(mode=)3.711 E F0 1.211(form of the)3.711 F F2($if)3.711 E F0 +(directi)3.711 E 1.511 -.15(ve i)-.25 H 3.711(su).15 G 1.211 +(sed to test whether readline is in emacs or vi)351.628 278.4 R 3.065 +(mode. This)180 290.4 R .565(may be used in conjunction with the)3.065 F F2 +.565(set k)3.065 F(eymap)-.1 E F0 .565(command, for instance, to)3.065 F .029 +(set bindings in the)180 302.4 R F1(emacs-standar)2.529 E(d)-.37 E F0(and)2.529 +E F1(emacs-ctlx)2.529 E F0 -.1(ke)2.529 G .029 +(ymaps only if readline is starting out)-.05 F(in emacs mode.)180 314.4 Q F2 +(term)144 331.2 Q F0(The)180 331.2 Q F2(term=)3.197 E F0 .696 +(form may be used to include terminal-speci\214c k)3.197 F .996 -.15(ey b)-.1 H +.696(indings, perhaps to bind).15 F .654(the k)180 343.2 R .954 -.15(ey s)-.1 H +.654(equences output by the terminal').15 F 3.154(sf)-.55 G .654(unction k) +360.138 343.2 R -.15(ey)-.1 G 3.154(s. The).15 F -.1(wo)3.154 G .654 +(rd on the right side of).1 F(the)180 355.2 Q F2(=)3.004 E F0 .504 +(is tested ag)3.004 F .503 +(ainst the full name of the terminal and the portion of the terminal name)-.05 +F(before the \214rst)180 367.2 Q F22.5 E F0 5(.T)C(his allo)260.13 367.2 Q +(ws)-.25 E F1(sun)2.5 E F0(to match both)2.5 E F1(sun)2.5 E F0(and)2.5 E F1 +(sun\255cmd)2.5 E F0 2.5(,f).77 G(or instance.)456.28 367.2 Q F2(application) +144 384 Q F0(The)180 396 Q F2(application)2.772 E F0 .272 +(construct is used to include application\255speci\214c settings.)2.772 F .272 +(Each program)5.272 F .114(using the readline library sets the)180 408 R F1 +.114(application name)2.614 F F0 2.614(,a)C .114 +(nd an initialization \214le can test for a)395.052 408 R .5(particular v)180 +420 R 3(alue. This)-.25 F .501(could be used to bind k)3 F .801 -.15(ey s)-.1 H +.501(equences to functions useful for a spe-).15 F .397(ci\214c program.)180 +432 R -.15(Fo)5.397 G 2.896(ri).15 G .396(nstance, the follo)261.31 432 R .396 +(wing command adds a k)-.25 F .696 -.15(ey s)-.1 H .396 +(equence that quotes the).15 F(current or pre)180 444 Q(vious w)-.25 E +(ord in Bash:)-.1 E F2($if)180 456 Q F0(bash)2.5 E 2.5(#Q)180 468 S +(uote the current or pre)194.72 468 Q(vious w)-.25 E(ord)-.1 E +("\\C-xq": "\\eb\\"\\ef\\"")180 480 Q F2($endif)180 492 Q($endif)108 508.8 Q F0 +(This command, as you sa)9.33 E 2.5(wi)-.15 G 2.5(nt)257.73 508.8 S(he pre) +268.01 508.8 Q(vious e)-.25 E(xample, terminates an)-.15 E F2($if)2.5 E F0 +(command.)2.5 E F2($else)108 525.6 Q F0(Commands in this branch of the)144 +525.6 Q F2($if)2.5 E F0(directi)2.5 E .3 -.15(ve a)-.25 H(re e).15 E -.15(xe) +-.15 G(cuted if the test f).15 E(ails.)-.1 E/F3 9/Times-Bold@0 SF +(EDITING COMMANDS)72 542.4 Q F0 1.391(The follo)108 554.4 R 1.391 +(wing is a list of the names of the commands and the def)-.25 F 1.391(ault k) +-.1 F 1.691 -.15(ey s)-.1 H 1.391(equences to which the).15 F 3.892(ya)-.15 G +(re)532.23 554.4 Q(bound.)108 566.4 Q F2(Commands f)87 583.2 Q(or Mo)-.25 E +(ving)-.1 E(beginning\255of\255line \(C\255a\))108 595.2 Q F0(Mo)144 607.2 Q .3 +-.15(ve t)-.15 H 2.5(ot).15 G(he start of the current line.)182.59 607.2 Q F2 +(end\255of\255line \(C\255e\))108 619.2 Q F0(Mo)144 631.2 Q .3 -.15(ve t)-.15 H +2.5(ot).15 G(he end of the line.)182.59 631.2 Q F2 -.25(fo)108 643.2 S +(rward\255char \(C\255f\)).25 E F0(Mo)144 655.2 Q .3 -.15(ve f)-.15 H(orw).15 E +(ard a character)-.1 E(.)-.55 E F2(backward\255char \(C\255b\))108 667.2 Q F0 +(Mo)144 679.2 Q .3 -.15(ve b)-.15 H(ack a character).15 E(.)-.55 E F2 -.25(fo) +108 691.2 S(rward\255w).25 E(ord \(M\255f\))-.1 E F0(Mo)144 703.2 Q .823 -.15 +(ve f)-.15 H(orw).15 E .523(ard to the end of the ne)-.1 F .523(xt w)-.15 F +3.023(ord. W)-.1 F .522(ords are composed of alphanumeric characters \(let-)-.8 +F(ters and digits\).)144 715.2 Q 184.005(GNU 1994)72 768 R(July 26)2.5 E(5)535 +768 Q EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 +/Times-Bold@0 SF(backward\255w)108 84 Q(ord \(M\255b\))-.1 E F0(Mo)144 96 Q +.748 -.15(ve b)-.15 H .449(ack to the start of this, or the pre).15 F .449 +(vious, w)-.25 F 2.949(ord. W)-.1 F .449 +(ords are composed of alphanumeric char)-.8 F(-)-.2 E +(acters \(letters and digits\).)144 108 Q F1(clear\255scr)108 120 Q +(een \(C\255l\))-.18 E F0 .993(Clear the screen lea)144 132 R .993 +(ving the current line at the top of the screen.)-.2 F -.4(Wi)5.993 G .993 +(th an ar).4 F .993(gument, refresh the)-.18 F +(current line without clearing the screen.)144 144 Q F1 -.18(re)108 156 S +(draw\255curr).18 E(ent\255line)-.18 E F0(Refresh the current line.)144 168 Q +(By def)5 E(ault, this is unbound.)-.1 E F1(Commands f)87 184.8 Q +(or Manipulating the History)-.25 E(accept\255line \(Newline, Retur)108 196.8 Q +(n\))-.15 E F0 .857(Accept the line re)144 208.8 R -.05(ga)-.15 G .857 +(rdless of where the cursor is.).05 F .857(If this line is non\255empty)5.857 F +3.357(,a)-.65 G .858(dd it to the history)463.228 208.8 R(list. If the line is\ + a modi\214ed history line, then restore the history line to its original stat\ +e.)144 220.8 Q F1(pr)108 232.8 Q -.15(ev)-.18 G(ious\255history \(C\255p\)).15 +E F0(Fetch the pre)144 244.8 Q(vious command from the history list, mo)-.25 E +(ving back in the list.)-.15 E F1(next\255history \(C\255n\))108 256.8 Q F0 +(Fetch the ne)144 268.8 Q(xt command from the history list, mo)-.15 E +(ving forw)-.15 E(ard in the list.)-.1 E F1 +(beginning\255of\255history \(M\255<\))108 280.8 Q F0(Mo)144 292.8 Q .3 -.15 +(ve t)-.15 H 2.5(ot).15 G(he \214rst line in the history)182.59 292.8 Q(.)-.65 +E F1(end\255of\255history \(M\255>\))108 304.8 Q F0(Mo)144 316.8 Q .3 -.15 +(ve t)-.15 H 2.5(ot).15 G(he end of the input history)182.59 316.8 Q 2.5(,i) +-.65 G(.e., the line currently being entered.)294.99 316.8 Q F1 -2.29 -.18 +(re v)108 328.8 T(erse\255sear).08 E(ch\255history \(C\255r\))-.18 E F0 1.471 +(Search backw)144 340.8 R 1.471(ard starting at the current line and mo)-.1 F +1.47(ving `up' through the history as necessary)-.15 F(.)-.65 E +(This is an incremental search.)144 352.8 Q F1 -.25(fo)108 364.8 S +(rward\255sear).25 E(ch\255history \(C\255s\))-.18 E F0 1.131(Search forw)144 +376.8 R 1.131(ard starting at the current line and mo)-.1 F 1.132(ving `do)-.15 +F 1.132(wn' through the history as necessary)-.25 F(.)-.65 E +(This is an incremental search.)144 388.8 Q F1(non\255incr)108 400.8 Q +(emental\255r)-.18 E -2.3 -.15(ev e)-.18 H(rse\255sear).15 E +(ch\255history \(M\255p\))-.18 E F0 1.089(Search backw)144 412.8 R 1.088(ard t\ +hrough the history starting at the current line using a non\255incremental sea\ +rch)-.1 F(for a string supplied by the user)144 424.8 Q(.)-.55 E F1 +(non\255incr)108 436.8 Q(emental\255f)-.18 E(orward\255sear)-.25 E +(ch\255history \(M\255n\))-.18 E F0 1.188(Search forw)144 448.8 R 1.189(ard th\ +rough the history using a non\255incremental search for a string supplied by t\ +he)-.1 F(user)144 460.8 Q(.)-.55 E F1(history\255sear)108 472.8 Q(ch\255f)-.18 +E(orward)-.25 E F0 .249(Search forw)144 484.8 R .249(ard through the history f\ +or the string of characters between the start of the current line)-.1 F +(and the current point.)144 496.8 Q(This is a non-incremental search.)5 E +(By def)5 E(ault, this command is unbound.)-.1 E F1(history\255sear)108 508.8 Q +(ch\255backward)-.18 E F0 .95(Search backw)144 520.8 R .951(ard through the hi\ +story for the string of characters between the start of the current)-.1 F 2.721 +(line and the current point.)144 532.8 R 2.721 +(This is a non-incremental search.)7.721 F 2.72(By def)7.721 F 2.72 +(ault, this command is)-.1 F(unbound.)144 544.8 Q F1(yank\255nth\255ar)108 +556.8 Q 2.5(g\()-.1 G<4dad43ad7929>175.14 556.8 Q F0 .622 +(Insert the \214rst ar)144 568.8 R .622(gument to the pre)-.18 F .622 +(vious command \(usually the second w)-.25 F .622(ord on the pre)-.1 F .622 +(vious line\))-.25 F .682(at point \(the current cursor position\).)144 580.8 R +-.4(Wi)5.682 G .682(th an ar).4 F(gument)-.18 E/F2 10/Times-Italic@0 SF(n)3.182 +E F0 3.182(,i).24 G .682(nsert the)390.17 580.8 R F2(n)3.182 E F0 .682(th w)B +.681(ord from the pre)-.1 F(vious)-.25 E .729(command \(the w)144 592.8 R .729 +(ords in the pre)-.1 F .729(vious command be)-.25 F .729(gin with w)-.15 F .729 +(ord 0\).)-.1 F 3.23(An)5.73 G -2.25 -.15(eg a)441.56 592.8 T(ti).15 E 1.03 +-.15(ve a)-.25 H -.18(rg).15 G .73(ument inserts).18 F(the)144 604.8 Q F2(n)2.5 +E F0(th w)A(ord from the end of the pre)-.1 E(vious command.)-.25 E F1 +(yank\255last\255ar)108 616.8 Q 2.5(g\()-.1 G -1.667(M\255. ,)175.69 616.8 R +-1.667(M\255_ \))2.5 F F0 1.077(Insert the last ar)144 628.8 R 1.077 +(gument to the pre)-.18 F 1.077(vious command \(the last w)-.25 F 1.077 +(ord on the pre)-.1 F 1.077(vious line\).)-.25 F -.4(Wi)6.076 G 1.076(th an).4 +F(ar)144 640.8 Q(gument, beha)-.18 E .3 -.15(ve ex)-.2 H(actly lik).15 E(e)-.1 +E F1(yank-nth-ar)2.5 E(g)-.1 E F0(.)A F1(Commands f)87 657.6 Q(or Changing T) +-.25 E(ext)-.92 E(delete\255char \(C\255d\))108 669.6 Q F0 .486 +(Delete the character under the cursor)144 681.6 R 5.486(.I)-.55 G 2.987(fp) +304.636 681.6 S .487(oint is at the be)315.953 681.6 R .487 +(ginning of the line, there are no charac-)-.15 F +(ters in the line, and the last character typed w)144 693.6 Q(as not)-.1 E F1 +(C\255d)2.5 E F0 2.5(,t)C(hen return)377.34 693.6 Q/F3 9/Times-Bold@0 SF(EOF) +2.5 E/F4 9/Times-Roman@0 SF(.)A F1(backward\255delete\255char \(Rubout\))108 +705.6 Q F0 .553(Delete the character behind the cursor)144 717.6 R 5.553(.W) +-.55 G .553(hen gi)315.598 717.6 R -.15(ve)-.25 G 3.053(nan).15 G .553 +(umeric ar)370.457 717.6 R .552(gument, sa)-.18 F .852 -.15(ve t)-.2 H .552 +(he deleted te).15 F .552(xt on)-.15 F(the kill\255ring.)144 729.6 Q 184.005 +(GNU 1994)72 768 R(July 26)2.5 E(6)535 768 Q EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 +/Times-Bold@0 SF(quoted\255insert \(C\255q, C\255v\))108 84 Q F0 1.228 +(Add the ne)144 96 R 1.228(xt character that you type to the line v)-.15 F +3.728(erbatim. This)-.15 F 1.228(is ho)3.728 F 3.729(wt)-.25 G 3.729(oi)446.163 +96 S 1.229(nsert characters lik)457.672 96 R(e)-.1 E F1(C\255q)144 108 Q F0 2.5 +(,f)C(or e)170.81 108 Q(xample.)-.15 E F1(tab\255insert \(M-T)108 120 Q(AB\)) +-.9 E F0(Insert a tab character)144 132 Q(.)-.55 E F1 +(self\255insert \(a, b, A, 1, !, ...\))108 144 Q F0 +(Insert the character typed.)144 156 Q F1(transpose\255chars \(C\255t\))108 168 +Q F0 .424(Drag the character before point forw)144 180 R .424(ard o)-.1 F -.15 +(ve)-.15 G 2.924(rt).15 G .424(he character at point.)331.218 180 R .424 +(Point mo)5.424 F -.15(ve)-.15 G 2.924(sf).15 G(orw)477.882 180 Q .424 +(ard as well.)-.1 F 1.03 +(If point is at the end of the line, then transpose the tw)144 192 R 3.531(oc) +-.1 G 1.031(haracters before point.)382.266 192 R(Ne)6.031 E -.05(ga)-.15 G(ti) +.05 E 1.331 -.15(ve a)-.25 H -.18(rg).15 G(u-).18 E(ments don')144 204 Q 2.5 +(tw)-.18 G(ork.)200.94 204 Q F1(transpose\255w)108 216 Q(ords \(M\255t\))-.1 E +F0 .683(Drag the w)144 228 R .682(ord behind the cursor past the w)-.1 F .682 +(ord in front of the cursor mo)-.1 F .682(ving the cursor o)-.15 F -.15(ve)-.15 +G 3.182(rt).15 G(hat)527.78 228 Q -.1(wo)144 240 S(rd as well.).1 E F1 +(upcase\255w)108 252 Q(ord \(M\255u\))-.1 E F0 .702 +(Uppercase the current \(or follo)144 264 R .702(wing\) w)-.25 F 3.202(ord. W) +-.1 F .702(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E 1.002 -.15(ve a)-.25 H -.18 +(rg).15 G .702(ument, do the pre).18 F .703(vious w)-.25 F .703(ord, b)-.1 F +(ut)-.2 E(do not mo)144 276 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(do)108 288 Q +(wncase\255w)-.1 E(ord \(M\255l\))-.1 E F0(Lo)144 300 Q .641 +(wercase the current \(or follo)-.25 F .641(wing\) w)-.25 F 3.141(ord. W)-.1 F +.641(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E .941 -.15(ve a)-.25 H -.18(rg).15 G +.64(ument, do the pre).18 F .64(vious w)-.25 F .64(ord, b)-.1 F(ut)-.2 E +(do not mo)144 312 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(capitalize\255w)108 324 +Q(ord \(M\255c\))-.1 E F0 .82(Capitalize the current \(or follo)144 336 R .82 +(wing\) w)-.25 F 3.32(ord. W)-.1 F .82(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E +1.12 -.15(ve a)-.25 H -.18(rg).15 G .82(ument, do the pre).18 F .82(vious w) +-.25 F .82(ord, b)-.1 F(ut)-.2 E(do not mo)144 348 Q .3 -.15(ve p)-.15 H(oint.) +.15 E F1(Killing and Y)87 364.8 Q(anking)-.85 E(kill\255line \(C\255k\))108 +376.8 Q F0(Kill the te)144 388.8 Q +(xt from the current cursor position to the end of the line.)-.15 E F1 +(backward\255kill\255line \(C\255x Rubout\))108 400.8 Q F0(Kill backw)144 412.8 +Q(ard to the be)-.1 E(ginning of the line.)-.15 E F1 +(unix\255line\255discard \(C\255u\))108 424.8 Q F0(Kill backw)144 436.8 Q +(ard from point to the be)-.1 E(ginning of the line.)-.15 E F1 +(kill\255whole\255line)108 448.8 Q F0 +(Kill all characters on the current line, no matter where the cursor is.)144 +460.8 Q(By def)5 E(ault, this is unbound.)-.1 E F1(kill\255w)108 472.8 Q +(ord \(M\255d\))-.1 E F0 1.044 +(Kill from the cursor to the end of the current w)144 484.8 R 1.043 +(ord, or if between w)-.1 F 1.043(ords, to the end of the ne)-.1 F(xt)-.15 E +-.1(wo)144 496.8 S 2.5(rd. W).1 F(ord boundaries are the same as those used by) +-.8 E F1 -.25(fo)2.5 G(rward\255w).25 E(ord)-.1 E F0(.)A F1 +(backward\255kill\255w)108 508.8 Q(ord \(M\255Rubout\))-.1 E F0 3.26 +(Kill the w)144 520.8 R 3.26(ord behind the cursor)-.1 F 8.26(.W)-.55 G 3.26 +(ord boundaries are the same as those used by)304.31 520.8 R F1(back-)5.76 E +(ward\255w)144 532.8 Q(ord)-.1 E F0(.)A F1(unix\255w)108 544.8 Q +(ord\255rubout \(C\255w\))-.1 E F0 .482(Kill the w)144 556.8 R .482 +(ord behind the cursor)-.1 F 2.982(,u)-.4 G .482(sing white space as a w) +281.652 556.8 R .482(ord boundary)-.1 F 5.482(.T)-.65 G .482(he w)445.076 556.8 +R .481(ord boundaries are)-.1 F(dif)144 568.8 Q(ferent from)-.25 E F1 +(backward\255kill\255w)2.5 E(ord)-.1 E F0(.)A F1(delete\255horizontal\255space) +108 580.8 Q F0(Delete all spaces and tabs around point.)144 592.8 Q(By def)5 E +(ault, this is unbound.)-.1 E F1(yank \(C\255y\))108 604.8 Q F0 -1(Ya)144 616.8 +S(nk the top of the kill ring into the b)1 E(uf)-.2 E(fer at the cursor)-.25 E +(.)-.55 E F1(yank\255pop \(M\255y\))108 628.8 Q F0 +(Rotate the kill\255ring, and yank the ne)144 640.8 Q 2.5(wt)-.25 G 2.5 +(op. Only)302.71 640.8 R -.1(wo)2.5 G(rks follo).1 E(wing)-.25 E F1(yank)2.5 E +F0(or)2.5 E F1(yank\255pop)2.5 E F0(.)A F1(Numeric Ar)87 657.6 Q(guments)-.1 E +(digit\255ar)108 669.6 Q(gument \(M\2550, M\2551, ..., M\255\255\))-.1 E F0 +.641(Add this digit to the ar)144 681.6 R .641 +(gument already accumulating, or start a ne)-.18 F 3.141(wa)-.25 G -.18(rg) +425.942 681.6 S 3.142(ument. M\255\255).18 F .642(starts a ne)3.142 F(g-)-.15 E +(ati)144 693.6 Q .3 -.15(ve a)-.25 H -.18(rg).15 G(ument.).18 E F1(uni)108 +705.6 Q -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0 .783(Each time this is e) +144 717.6 R -.15(xe)-.15 G .783(cuted, the ar).15 F .782 +(gument count is multiplied by four)-.18 F 5.782(.T)-.55 G .782(he ar)437.062 +717.6 R .782(gument count is ini-)-.18 F .175(tially one, so e)144 729.6 R -.15 +(xe)-.15 G .175(cuting this function the \214rst time mak).15 F .176(es the ar) +-.1 F .176(gument count four)-.18 F 5.176(.B)-.55 G 2.676(yd)485.028 729.6 S +(ef)497.704 729.6 Q .176(ault, this)-.1 F 184.005(GNU 1994)72 768 R(July 26)2.5 +E(7)535 768 Q EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R +(is not bound to a k)144 84 Q -.15(ey)-.1 G(.)-.5 E/F1 10/Times-Bold@0 SF +(Completing)87 100.8 Q(complete \(T)108 112.8 Q(AB\))-.9 E F0 1.909 +(Attempt to perform completion on the te)144 124.8 R 1.908(xt before point.) +-.15 F 1.908(The actual completion performed is)6.908 F +(application-speci\214c.)144 136.8 Q F1(Bash)5.517 E F0 3.017(,f)C .518 +(or instance, attempts completion treating the te)260.304 136.8 R .518 +(xt as a v)-.15 F .518(ariable \(if the)-.25 F(te)144 148.8 Q .657(xt be)-.15 F +.657(gins with)-.15 F F1($)3.156 E F0 .656(\), username \(if the te)B .656 +(xt be)-.15 F .656(gins with)-.15 F F1(~)3.156 E F0 .656 +(\), hostname \(if the te)B .656(xt be)-.15 F .656(gins with)-.15 F F1(@)3.156 +E F0 .656(\), or)B .929(command \(including aliases and functions\) in turn.) +144 160.8 R .93(If none of these produces a match, \214lename)5.929 F 1.274 +(completion is attempted.)144 172.8 R F1(Gdb)6.273 E F0 3.773(,o)C 3.773(nt) +281.603 172.8 S 1.273(he other hand, allo)293.156 172.8 R 1.273 +(ws completion of program functions and)-.25 F -.25(va)144 184.8 S +(riables, and only attempts \214lename completion under certain circumstances.) +.25 E F1(possible\255completions \(M-?\))108 196.8 Q F0 +(List the possible completions of the te)144 208.8 Q(xt before point.)-.15 E F1 +(insert\255completions)108 220.8 Q F0 3.372(Insert all completions of the te) +144 232.8 R 3.372(xt before point that w)-.15 F 3.372(ould ha)-.1 F 3.672 -.15 +(ve b)-.2 H 3.372(een generated by).15 F F1(possi-)5.873 E(ble\255completions) +144 244.8 Q F0 5(.B)C 2.5(yd)227.76 244.8 S(ef)240.26 244.8 Q +(ault, this is not bound to a k)-.1 E -.15(ey)-.1 G(.)-.5 E F1 -.25(Ke)87 261.6 +S(yboard Macr).25 E(os)-.18 E(start\255kbd\255macr)108 273.6 Q 2.5(o\()-.18 G +(C-x \()188.93 273.6 Q(\)).833 E F0(Be)144 285.6 Q(gin sa)-.15 E +(ving the characters typed into the current k)-.2 E -.15(ey)-.1 G(board macro.) +.15 E F1(end\255kbd\255macr)108 297.6 Q 2.5(o\()-.18 G(C-x \))184.5 297.6 Q(\)) +.833 E F0(Stop sa)144 309.6 Q(ving the characters typed into the current k)-.2 +E -.15(ey)-.1 G(board macro and sa).15 E .3 -.15(ve t)-.2 H(he de\214nition.) +.15 E F1(call\255last\255kbd\255macr)108 321.6 Q 2.5(o\()-.18 G(C-x e\))204.64 +321.6 Q F0(Re-e)144 333.6 Q -.15(xe)-.15 G 1(cute the last k).15 F -.15(ey)-.1 +G .999 +(board macro de\214ned, by making the characters in the macro appear as if).15 +F(typed at the k)144 345.6 Q -.15(ey)-.1 G(board.).15 E F1(Miscellaneous)87 +362.4 Q -.18(re)108 374.4 S(-r).18 E(ead-init-\214le \(C\255x C\255r\))-.18 E +F0 .54(Read in the contents of your init \214le, and incorporate an)144 386.4 R +3.041(yb)-.15 G .541(indings or v)385.876 386.4 R .541 +(ariable assignments found)-.25 F(there.)144 398.4 Q F1(abort \(C\255g\))108 +410.4 Q F0 3.249(Abort the current editing command and ring the terminal')144 +422.4 R 5.748(sb)-.55 G 3.248(ell \(subject to the setting of)414.6 422.4 R F1 +(bell\255style)144 434.4 Q F0(\).)A F1(do\255upper)108 446.4 Q(case\255v)-.18 E +(ersion \(M\255a, M\255b, ...\))-.1 E F0 +(Run the command that is bound to the corresponding uppercase character)144 +458.4 Q(.)-.55 E F1(pr)108 470.4 Q(e\214x\255meta \(ESC\))-.18 E F0 +(Metafy the ne)144 482.4 Q(xt character typed.)-.15 E/F2 9/Times-Bold@0 SF(ESC) +5 E F1(f)2.25 E F0(is equi)2.5 E -.25(va)-.25 G(lent to).25 E F1(Meta\255f)2.5 +E F0(.)A F1(undo \(C\255_, C\255x C\255u\))108 494.4 Q F0 +(Incremental undo, separately remembered for each line.)144 506.4 Q F1 -2.29 +-.18(re v)108 518.4 T(ert\255line \(M\255r\)).08 E F0 .244 +(Undo all changes made to this line.)144 530.4 R .245(This is lik)5.245 F 2.745 +(et)-.1 G .245(yping the)341.895 530.4 R F1(undo)2.745 E F0 .245 +(command enough times to return)2.745 F(the line to its initial state.)144 +542.4 Q F1(tilde\255expand \(M\255~\))108 554.4 Q F0(Perform tilde e)144 566.4 +Q(xpansion on the current w)-.15 E(ord.)-.1 E F1(dump\255functions)108 578.4 Q +F0 .627(Print all of the functions and their k)144 590.4 R .927 -.15(ey b)-.1 H +.626(indings to the readline output stream.).15 F .626(If a numeric ar)5.626 F +(gu-)-.18 E(ment is supplied, the output is formatted in such a w)144 602.4 Q +(ay that it can be made part of an)-.1 E/F3 10/Times-Italic@0 SF(inputr)2.5 E +(c)-.37 E F0(\214le.)2.5 E F1(emacs\255editing\255mode \(C\255e\))108 614.4 Q +F0(When in)144 626.4 Q F1(vi)2.5 E F0(editing mode, this causes a switch to)2.5 +E F1(emacs)2.5 E F0(editing mode.)2.5 E F1 +(vi\255editing\255mode \(M\255C\255j\))108 638.4 Q F0(When in)144 650.4 Q F1 +(emacs)2.5 E F0(editing mode, this causes a switch to)2.5 E F1(vi)2.5 E F0 +(editing mode.)2.5 E F2(DEF)72 667.2 Q -.45(AU)-.81 G 1.656 -.828(LT K).45 H +(EY BINDINGS).828 E F0 .675(The follo)108 679.2 R .675 +(wing is a list of the def)-.25 F .675(ault emacs and vi bindings.)-.1 F .676 +(Characters with the 8th bit set are written as)5.676 F .002 +(M-, and are referred to as)108 691.2 R F3(meta\214ed)2.502 E F0 +2.502(characters. The)2.502 F .002(printable ASCII characters not mentioned in) +2.502 F .444(the list of emacs standard bindings are bound to the)108 703.2 R +F3(self\255insert)2.945 E F0 .445(function, which just inserts the gi)2.945 F +-.15(ve)-.25 G 2.945(nc).15 G(har)524.1 703.2 Q(-)-.2 E 2.021 +(acter into the input line.)108 715.2 R 2.02(In vi insertion mode, all charact\ +ers not speci\214cally mentioned are bound to)7.021 F F3(self\255insert)108 +727.2 Q F0 5.388(.C).68 G .388(haracters assigned to signal generation by) +166.658 727.2 R F3(stty)2.889 E F0 .389(\(1\) or the terminal dri).32 F -.15 +(ve)-.25 G 1.189 -.4(r, s).15 H .389(uch as C-Z or C-C,).4 F 184.005(GNU 1994) +72 768 R(July 26)2.5 E(8)535 768 Q EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R .221 +(retain that function.)108 84 R .221(Upper and lo)5.221 F .221(wer case)-.25 F +/F1 10/Times-Italic@0 SF(meta\214ed)2.721 E F0 .22 +(characters are bound to the same function in the emacs)2.721 F .304 +(mode meta k)108 96 R -.15(ey)-.1 G 2.804(map. The).15 F .305(remaining charac\ +ters are unbound, which causes readline to ring the bell \(subject)2.804 F +(to the setting of the)108 108 Q/F2 10/Times-Bold@0 SF(bell\255style)2.5 E F0 +-.25(va)2.5 G(riable\).).25 E F2(Emacs Mode)87 124.8 Q F0 +(Emacs Standard bindings)151.2 136.8 Q 152.12("C-A" ->)151.2 160.8 R(be)5 E +(ginning-of-line)-.15 E 152.67("C-B" ->)151.2 172.8 R(backw)5 E(ard-char)-.1 E +152.12("C-D" ->)151.2 184.8 R(delete-char)5 E 153.23("C-E" ->)151.2 196.8 R +(end-of-line)5 E 153.78("C-F" ->)151.2 208.8 R(forw)5 E(ard-char)-.1 E 152.12 +("C-G" ->)151.2 220.8 R(abort)5 E 152.12("C-H" ->)151.2 232.8 R(backw)5 E +(ard-delete-char)-.1 E 156.01("C-I" ->)151.2 244.8 R(complete)5 E 155.45 +("C-J" ->)151.2 256.8 R(accept-line)5 E 152.12("C-K" ->)151.2 268.8 R +(kill-line)5 E 153.23("C-L" ->)151.2 280.8 R(clear)5 E(-screen)-.2 E 150.45 +("C-M" ->)151.2 292.8 R(accept-line)5 E 152.12("C-N" ->)151.2 304.8 R(ne)5 E +(xt-history)-.15 E 153.78("C-P" ->)151.2 316.8 R(pre)5 E(vious-history)-.25 E +152.12("C-Q" ->)151.2 328.8 R(quoted-insert)5 E 152.67("C-R" ->)151.2 340.8 R +(re)5 E -.15(ve)-.25 G(rse-search-history).15 E 153.78("C-S" ->)151.2 352.8 R +(forw)5 E(ard-search-history)-.1 E 153.23("C-T" ->)151.2 364.8 R +(transpose-chars)5 E 152.12("C-U" ->)151.2 376.8 R(unix-line-discard)5 E 152.12 +("C-V" ->)151.2 388.8 R(quoted-insert)5 E 149.9("C-W" ->)151.2 400.8 R(unix-w)5 +E(ord-rubout)-.1 E 152.12("C-Y" ->)151.2 412.8 R(yank)5 E 154.34("C-_" ->)151.2 +424.8 R(undo)5 E 3.333("")151.2 436.8 S(to "/")-.833 E 2.5(-> self-insert)331.2 +436.8 R 2.5("0" to)151.2 448.8 R 135.9("9" ->)2.5 F(self-insert)5 E 2.5(":" to) +151.2 460.8 R 139.79("~" ->)2.5 F(self-insert)5 E 154.9("C-?" ->)151.2 472.8 R +(backw)5 E(ard-delete-char)-.1 E(Emacs Meta bindings)151.2 489.6 Q 139.9 +("M-C-H" ->)151.2 513.6 R(backw)5 E(ard-kill-w)-.1 E(ord)-.1 E 143.79 +("M-C-I" ->)151.2 525.6 R(tab-insert)5 E 143.23("M-C-J" ->)151.2 537.6 R +(vi-editing-mode)5 E 138.23("M-C-M" ->)151.2 549.6 R(vi-editing-mode)5 E 140.45 +("M-C-R" ->)151.2 561.6 R(re)5 E -.15(ve)-.25 G(rt-line).15 E 139.9("M-C-Y" ->) +151.2 573.6 R(yank-nth-ar)5 E(g)-.18 E 143.79("M-C-[" ->)151.2 585.6 R +(complete)5 E 149.34("M-&" ->)151.2 597.6 R(tilde-e)5 E(xpand)-.15 E 153.79 +("M--" ->)151.2 609.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-0" ->)151.2 621.6 +R(digit-ar)5 E(gument)-.18 E 152.12("M-1" ->)151.2 633.6 R(digit-ar)5 E(gument) +-.18 E 152.12("M-2" ->)151.2 645.6 R(digit-ar)5 E(gument)-.18 E 152.12 +("M-3" ->)151.2 657.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-4" ->)151.2 669.6 +R(digit-ar)5 E(gument)-.18 E 152.12("M-5" ->)151.2 681.6 R(digit-ar)5 E(gument) +-.18 E 152.12("M-6" ->)151.2 693.6 R(digit-ar)5 E(gument)-.18 E 152.12 +("M-7" ->)151.2 705.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-8" ->)151.2 717.6 +R(digit-ar)5 E(gument)-.18 E 152.12("M-9" ->)151.2 729.6 R(digit-ar)5 E(gument) +-.18 E 184.005(GNU 1994)72 768 R(July 26)2.5 E(9)535 768 Q EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 151.48 +("M-<" ->)151.2 84 R(be)5 E(ginning-of-history)-.15 E 151.48("M->" ->)151.2 96 +R(end-of-history)5 E 152.68("M-?" ->)151.2 108 R(possible-completions)5 E +150.45("M-B" ->)151.2 120 R(backw)5 E(ard-w)-.1 E(ord)-.1 E 150.45("M-C" ->) +151.2 132 R(capitalize-w)5 E(ord)-.1 E 149.9("M-D" ->)151.2 144 R(kill-w)5 E +(ord)-.1 E 151.56("M-F" ->)151.2 156 R(forw)5 E(ard-w)-.1 E(ord)-.1 E 151.01 +("M-L" ->)151.2 168 R(do)5 E(wncase-w)-.25 E(ord)-.1 E 149.9("M-N" ->)151.2 180 +R(non-incremental-forw)5 E(ard-search-history)-.1 E 149.9("M-O" ->)151.2 192 R +(arro)5 E(w-k)-.25 E -.15(ey)-.1 G(-pre\214x).15 E 151.56("M-P" ->)151.2 204 R +(non-incremental-re)5 E -.15(ve)-.25 G(rse-search-history).15 E 150.45 +("M-R" ->)151.2 216 R(re)5 E -.15(ve)-.25 G(rt-line).15 E 151.01("M-T" ->)151.2 +228 R(transpose-w)5 E(ords)-.1 E 149.9("M-U" ->)151.2 240 R(upcase-w)5 E(ord) +-.1 E 149.9("M-Y" ->)151.2 252 R(yank-pop)5 E 139.9("M-C-Y" ->)151.2 264 R +(yank-nth-ar)5 E(g)-.18 E 142.68("M-C-?" ->)151.2 276 R(backw)5 E(ard-delete-w) +-.1 E(ord)-.1 E(Emacs Control-X bindings)151.2 292.8 Q 134.9("C-XC-G" ->)151.2 +316.8 R(abort)5 E 135.45("C-XC-R" ->)151.2 328.8 R(re-read-init-\214le)5 E +134.9("C-XC-U" ->)151.2 340.8 R(undo)5 E 148.79("C-X\(" ->)151.2 352.8 R +(start-kbd-macro)5 E 148.79("C-X\)" ->)151.2 364.8 R(end-kbd-macro)5 E 147.68 +("C-Xe" ->)151.2 376.8 R(call-last-kbd-macro)5 E 137.68("C-XC-?" ->)151.2 388.8 +R(backw)5 E(ard-kill-line)-.1 E/F1 10/Times-Bold@0 SF(VI Mode bindings)87 417.6 +Q F0(VI Insert Mode functions)151.2 429.6 Q 152.12("C-D" ->)151.2 453.6 R +(vi-eof-maybe)5 E 152.12("C-H" ->)151.2 465.6 R(backw)5 E(ard-delete-char)-.1 E +156.01("C-I" ->)151.2 477.6 R(complete)5 E 155.45("C-J" ->)151.2 489.6 R +(accept-line)5 E 152.12("C-K" ->)151.2 501.6 R(kill-line)5 E 153.23("C-L" ->) +151.2 513.6 R(clear)5 E(-screen)-.2 E 150.45("C-M" ->)151.2 525.6 R +(accept-line)5 E 152.12("C-N" ->)151.2 537.6 R(ne)5 E(xt-history)-.15 E 153.78 +("C-P" ->)151.2 549.6 R(pre)5 E(vious-history)-.25 E 152.12("C-Q" ->)151.2 +561.6 R(quoted-insert)5 E 152.67("C-R" ->)151.2 573.6 R(re)5 E -.15(ve)-.25 G +(rse-search-history).15 E 153.78("C-S" ->)151.2 585.6 R(forw)5 E +(ard-search-history)-.1 E 153.23("C-T" ->)151.2 597.6 R(transpose-chars)5 E +152.12("C-U" ->)151.2 609.6 R(unix-line-discard)5 E 152.12("C-V" ->)151.2 621.6 +R(quoted-insert)5 E 149.9("C-W" ->)151.2 633.6 R(unix-w)5 E(ord-rubout)-.1 E +152.12("C-Y" ->)151.2 645.6 R(yank)5 E 156.01("C-[" ->)151.2 657.6 R(vi-mo)5 E +-.15(ve)-.15 G(ment-mode).15 E 3.333("")151.2 669.6 S(to "~")-.833 E 2.5 +(-> self-insert)331.2 669.6 R 154.9("C-?" ->)151.2 681.6 R(backw)5 E +(ard-delete-char)-.1 E(VI Command Mode functions)151.2 698.4 Q 152.12("C-D" ->) +151.2 722.4 R(vi-eof-maybe)5 E 184.005(GNU 1994)72 768 R(July 26)2.5 E(10)530 +768 Q EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 153.23 +("C-E" ->)151.2 84 R(emacs-editing-mode)5 E 152.12("C-G" ->)151.2 96 R(abort)5 +E 152.12("C-H" ->)151.2 108 R(backw)5 E(ard-char)-.1 E 155.45("C-J" ->)151.2 +120 R(accept-line)5 E 152.12("C-K" ->)151.2 132 R(kill-line)5 E 153.23 +("C-L" ->)151.2 144 R(clear)5 E(-screen)-.2 E 150.45("C-M" ->)151.2 156 R +(accept-line)5 E 152.12("C-N" ->)151.2 168 R(ne)5 E(xt-history)-.15 E 153.78 +("C-P" ->)151.2 180 R(pre)5 E(vious-history)-.25 E 152.12("C-Q" ->)151.2 192 R +(quoted-insert)5 E 152.67("C-R" ->)151.2 204 R(re)5 E -.15(ve)-.25 G +(rse-search-history).15 E 153.78("C-S" ->)151.2 216 R(forw)5 E +(ard-search-history)-.1 E 153.23("C-T" ->)151.2 228 R(transpose-chars)5 E +152.12("C-U" ->)151.2 240 R(unix-line-discard)5 E 152.12("C-V" ->)151.2 252 R +(quoted-insert)5 E 149.9("C-W" ->)151.2 264 R(unix-w)5 E(ord-rubout)-.1 E +152.12("C-Y" ->)151.2 276 R(yank)5 E 156.01("C-[" ->)151.2 288 R(abort)5 E +159.341 3.333("" -)151.2 300 T 5(>f)334.53 300 S(orw)348.5 300 Q(ard-char)-.1 E +164.34("#" ->)151.2 312 R(vi-comment)5 E 164.34("$" ->)151.2 324 R(end-of-line) +5 E 161.01("%" ->)151.2 336 R(vi-match)5 E 161.56("&" ->)151.2 348 R +(vi-tilde-e)5 E(xpand)-.15 E 164.34("*" ->)151.2 360 R(vi-complete)5 E 163.7 +("+" ->)151.2 372 R(do)5 E(wn-history)-.25 E 166.84("," ->)151.2 384 R(vi-char) +5 E(-search)-.2 E 166.01("-" ->)151.2 396 R(pre)5 E(vious-history)-.25 E 166.84 +("." ->)151.2 408 R(vi-redo)5 E 166.56("/" ->)151.2 420 R(vi-search)5 E 164.34 +("0" ->)151.2 432 R(be)5 E(ginning-of-line)-.15 E("1" to "9")151.2 444 Q 2.5 +(-> vi-ar)331.2 444 R(g-digit)-.18 E 166.56(";" ->)151.2 456 R(vi-char)5 E +(-search)-.2 E 163.7("=" ->)151.2 468 R(vi-complete)5 E 164.9("?" ->)151.2 480 +R(vi-search)5 E 160.13("@" ->)151.2 492 R(is unde\214ned)5 E 162.12("A" ->) +151.2 504 R(vi-append-eol)5 E 162.67("B" ->)151.2 516 R(vi-pre)5 E(v-w)-.25 E +(ord)-.1 E 162.67("C" ->)151.2 528 R(vi-change-to)5 E 162.12("D" ->)151.2 540 R +(vi-delete-to)5 E 163.23("E" ->)151.2 552 R(vi-end-w)5 E(ord)-.1 E 163.78 +("F" ->)151.2 564 R(vi-char)5 E(-search)-.2 E 166.01("I" ->)151.2 576 R +(vi-insert-be)5 E(g)-.15 E 162.12("N" ->)151.2 588 R(vi-search-ag)5 E(ain)-.05 +E 163.78("P" ->)151.2 600 R(vi-put)5 E 162.67("R" ->)151.2 612 R(vi-replace)5 E +163.78("S" ->)151.2 624 R(vi-subst)5 E 163.23("T" ->)151.2 636 R(vi-char)5 E +(-search)-.2 E 162.12("U" ->)151.2 648 R(re)5 E -.15(ve)-.25 G(rt-line).15 E +159.9("W" ->)151.2 660 R(vi-ne)5 E(xt-w)-.15 E(ord)-.1 E 162.12("X" ->)151.2 +672 R(backw)5 E(ard-delete-char)-.1 E 162.12("Y" ->)151.2 684 R(vi-yank-to)5 E +166.56("\\" ->)151.2 696 R(vi-complete)5 E 166.01("^" ->)151.2 708 R +(vi-\214rst-print)5 E 164.34("_" ->)151.2 720 R(vi-yank-ar)5 E(g)-.18 E 184.005 +(GNU 1994)72 768 R(July 26)2.5 E(11)530 768 Q EP +%%Page: 12 12 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 164.9("a" ->) +151.2 84 R(vi-append-mode)5 E 164.34("b" ->)151.2 96 R(vi-pre)5 E(v-w)-.25 E +(ord)-.1 E 164.9("c" ->)151.2 108 R(vi-change-to)5 E 164.34("d" ->)151.2 120 R +(vi-delete-to)5 E 164.9("e" ->)151.2 132 R(vi-end-w)5 E(ord)-.1 E 166.01 +("f" ->)151.2 144 R(vi-char)5 E(-search)-.2 E 164.34("h" ->)151.2 156 R(backw)5 +E(ard-char)-.1 E 166.56("i" ->)151.2 168 R(vi-insertion-mode)5 E 166.56("j" ->) +151.2 180 R(ne)5 E(xt-history)-.15 E 164.34("k" ->)151.2 192 R(pre)5 E +(v-history)-.25 E 166.56("l" ->)151.2 204 R(forw)5 E(ard-char)-.1 E 164.34 +("n" ->)151.2 216 R(vi-search-ag)5 E(ain)-.05 E 166.01("r" ->)151.2 228 R +(vi-change-char)5 E 165.45("s" ->)151.2 240 R(vi-subst)5 E 166.56("t" ->)151.2 +252 R(vi-char)5 E(-search)-.2 E 164.34("u" ->)151.2 264 R(undo)5 E 162.12 +("w" ->)151.2 276 R(vi-ne)5 E(xt-w)-.15 E(ord)-.1 E 164.34("x" ->)151.2 288 R +(vi-delete)5 E 164.34("y" ->)151.2 300 R(vi-yank-to)5 E 167.34("|" ->)151.2 312 +R(vi-column)5 E 166.01("~" ->)151.2 324 R(vi-change-case)5 E/F1 9/Times-Bold@0 +SF(SEE ALSO)72 340.8 Q/F2 10/Times-Italic@0 SF(The Gnu Readline Libr)108 352.8 +Q(ary)-.15 E F0 2.5(,B)C(rian F)225.35 352.8 Q(ox and Chet Rame)-.15 E(y)-.15 E +F2(The Gnu History Libr)108 364.8 Q(ary)-.15 E F0 2.5(,B)C(rian F)219.8 364.8 Q +(ox and Chet Rame)-.15 E(y)-.15 E F2(bash)108 376.8 Q F0(\(1\))A F1(FILES)72 +393.6 Q F2(~/.inputr)109.666 405.6 Q(c)-.37 E F0(Indi)144 417.6 Q(vidual)-.25 E +/F3 10/Times-Bold@0 SF -.18(re)2.5 G(adline).18 E F0(initialization \214le)2.5 +E F1 -.45(AU)72 434.4 S(THORS).45 E F0(Brian F)144 446.4 Q(ox, Free Softw)-.15 +E(are F)-.1 E(oundation \(primary author\))-.15 E(bfox@ai.MIT)144 458.4 Q(.Edu) +-.74 E(Chet Rame)144 475.2 Q 1.3 -.65(y, C)-.15 H(ase W).65 E(estern Reserv)-.8 +E 2.5(eU)-.15 G(ni)296.66 475.2 Q -.15(ve)-.25 G(rsity).15 E(chet@ins.CWR)144 +487.2 Q(U.Edu)-.4 E F1 -.09(BU)72 504 S 2.25(GR).09 G(EPOR)100.161 504 Q(TS) +-.36 E F0 .691(If you \214nd a b)108 516 R .691(ug in)-.2 F F3 -.18(re)3.191 G +(adline,).18 E F0 .691(you should report it.)3.191 F .69 +(But \214rst, you should mak)5.69 F 3.19(es)-.1 G .69 +(ure that it really is a b)436.35 516 R(ug,)-.2 E +(and that it appears in the latest v)108 528 Q(ersion of the)-.15 E F3 -.18(re) +2.5 G(adline).18 E F0(library that you ha)2.5 E -.15(ve)-.2 G(.).15 E 10.782 +(Once you ha)108 544.8 R 11.082 -.15(ve d)-.2 H 10.782(etermined that a b).15 F +10.782(ug actually e)-.2 F 10.783(xists, mail a b)-.15 F 10.783(ug report to) +-.2 F F2(bash\255maintainer)108 556.8 Q(s)-.1 E F0(@)A F2(pr)A(ep.ai.MIT)-.37 E +(.Edu)-.74 E F0 5.169(.I)C 2.669(fy)267.359 556.8 S .169(ou ha)278.358 556.8 R +.469 -.15(ve a \214)-.2 H .168(x, you are welcome to mail that as well!).15 F +(Suggestions)5.168 E 2(and `philosophical' b)108 568.8 R 2.001 +(ug reports may be mailed to)-.2 F F2 -.2(bu)4.501 G(g-bash).2 E F0(@)A F2(pr)A +(ep.ai.MIT)-.37 E(.Edu)-.74 E F0 2.001(or posted to the Usenet)4.501 F(ne)108 +580.8 Q(wsgroup)-.25 E F3(gnu.bash.b)2.5 E(ug)-.2 E F0(.)A(Comments and b)108 +597.6 Q(ug reports concerning this manual page should be directed to)-.2 E F2 +-.15(ch)2.5 G(et@ins.CWR).15 E -.25(U.)-.4 G(Edu).25 E F0(.).25 E F1 -.09(BU)72 +614.4 S(GS).09 E F0(It')108 626.4 Q 2.5(st)-.55 G(oo big and too slo)126.06 +626.4 Q -.65(w.)-.25 G 184.005(GNU 1994)72 768 R(July 26)2.5 E(12)530 768 Q EP +%%Trailer +end +%%EOF diff --git a/documentation/readline.txt b/documentation/readline.txt 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 + #include + + typedef int Function (); + + char *readline (prompt) + char *prompt; + + int rl_add_defun (name, function, key) + char *name; + Function *function; + int key; + + int rl_bind_key (key, function) + int key; + Function *function; + + int rl_unbind_key (key) + int key; + + int rl_bind_key_in_map (key, function, keymap) + int key; + Function *function; + Keymap keymap; + + int rl_unbind_key_in_map (key, keymap) + int key; + Keymap keymap; + + int rl_macro_bind (keyseq, macro, keymap) + char *keyseq, *macro; + Keymap keymap; + + int rl_variable_bind (variable, value) + char *variable, *value; + + int rl_parse_and_bind (line) + char *line; + + int rl_translate_keyseq (keyseq, array, len) + char *keyseq, *array; + int *len; + + Function *rl_named_function (command) + char *command; + + Function *rl_function_of_keyseq (keyseq, keymap, type) + char *keyseq; + + + +GNU Last change: 1994 July 26 1 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Keymap keymap; + int *type; + + char **rl_invoking_keyseqs (function) + Function *function; + + char **rl_invoking_keyseqs_in_map (function, keymap) + Function *function; + Keymap keymap; + + void rl_function_dumper (readable) + int readable; + + char **rl_funmap_names () + +COPYRIGHT + Readline is Copyright (C) 1989, 1991 by the Free Software + Foundation, Inc. + +DESCRIPTION + readline will read a line from the terminal and return it, + using prompt as a prompt. If prompt is null, no prompt is + issued. The line returned is allocated with _m_a_l_l_o_c(3), so + the caller must free it when finished. The line returned + has the final newline removed, so only the text of the line + remains. + + readline offers editing capabilities while the user is + entering the line. By default, the line editing commands + are similar to those of emacs. A vi-style line editing + interface is also available. + + In the following descriptions, keymap can be one of + _e_m_a_c_s__k_e_y_m_a_p, _e_m_a_c_s__m_e_t_a__k_e_y_m_a_p, _e_m_a_c_s__c_t_l_x__k_e_y_m_a_p, + _v_i__i_n_s_e_r_t_i_o_n__k_e_y_m_a_p, _o_r _v_i__m_o_v_e_m_e_n_t__k_e_y_m_a_p. + + rl_add_defun makes name appear as a bindable readline com- + mand, and makes function be the function called when that + command is invoked. If key is not -1, it is bound to func- + tion in the current keymap. + + rl_bind_key causes key to invoke function. The binding is + made in the current keymap. + + rl_unbind_key removes the binding for key in the current + keymap. + + rl_bind_key_in_map makes the key entry in keymap invoke + function. + + rl_unbind_key_in_map removes the binding for key in keymap + keymap. + + + +GNU Last change: 1994 July 26 2 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + rl_macro_bind makes keyseq insert the string macro. The + binding is performed in keymap. + + rl_variable_bind sets the value of the readline variable + variable to value. + + rl_parse_and_bind takes as an argument a line of the same + form as the readline startup file (see INITIALIZATION FILE + below) and executes the commands therein. + + rl_translate_keyseq converts keyseq into a new string, stor- + ing the result in array. This translates control and meta + prefixes and the readline character escape sequences (see + Key Bindings below). The length of the translated sequence + is returned in *len. + + rl_named_function returns the function that is executed when + the readline command command is invoked. + + rl_function_of_keyseq returns the function that is executed + when keyseq is read and keymap is the current keymap. type + is set to indicate whether the return value corresponds to a + function, macro, or auxiliary keymap. + + rl_invoking_keyseqs returns all of the key sequences in the + current keymap that invoke function. + + rl_invoking_keyseqs_in_map returns all of the key sequences + in keymap that invoke function. + + rl_function_dumper prints all of the readline functions and + their bindings to the readline output stream. If readable + is non-zero, the output is formattted so that it can be read + back in to restore the bindings. + + rl_funmap_names returns an array of all known readline bind- + able function names. The array is sorted. + +RETURN VALUE + readline returns the text of the line read. A blank line + returns the empty string. If EOF is encountered while read- + ing a line, and the line is empty, NULL is returned. If an + EOF is read with a non-empty line, it is treated as a new- + line. + + Unless otherwise stated, the other functions return 0 on + success and non-zero on failure. + +NOTATION + An emacs-style notation is used to denote keystrokes. Con- + trol keys are denoted by C-_k_e_y, e.g., C-n means Control-N. + Similarly, _m_e_t_a keys are denoted by M-_k_e_y, so M-x means + + + +GNU Last change: 1994 July 26 3 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Meta-X. (On keyboards without a _m_e_t_a key, M-_x means ESC _x, + i.e., press the Escape key then the _x key. This makes ESC + the _m_e_t_a _p_r_e_f_i_x. The combination M-C-_x means ESC-Control-_x, + or press the Escape key then hold the Control key while + pressing the _x key.) + + Readline commands may be given numeric _a_r_g_u_m_e_n_t_s, which nor- + mally act as a repeat count. Sometimes, however, it is the + sign of the argument that is significant. Passing a nega- + tive argument to a command that acts in the forward direc- + tion (e.g., kill-line) causes that command to act in a back- + ward direction. Commands whose behavior with arguments + deviates from this are noted. + + When a command is described as _k_i_l_l_i_n_g text, the text + deleted is saved for possible future retrieval (_y_a_n_k_i_n_g). + The killed text is saved in a _k_i_l_l-_r_i_n_g. Consecutive kills + cause the text to be accumulated into one unit, which can be + yanked all at once. Commands which do not kill text separate + the chunks of text on the kill-ring. + +INITIALIZATION FILE + Readline is customized by putting commands in an initializa- + tion file. The name of this file is taken from the value of + the INPUTRC variable. If that variable is unset, the + default is ~/._i_n_p_u_t_r_c. When a program which uses the read- + line library starts up, the init file is read, and the key + bindings and variables are set. There are only a few basic + constructs allowed in the readline init file. Blank lines + are ignored. Lines beginning with a # are comments. Lines + beginning with a $ indicate conditional constructs. Other + lines denote key bindings and variable settings. Each pro- + gram using this library may add its own commands and bind- + ings. + + For example, placing + + M-Control-u: universal-argument + or + C-Meta-u: universal-argument + into the ~/._i_n_p_u_t_r_c would make M-C-u execute the readline + command _u_n_i_v_e_r_s_a_l-_a_r_g_u_m_e_n_t. + + The following symbolic character names are recognized while + processing key bindings: _R_U_B_O_U_T, _D_E_L, _E_S_C, _L_F_D, _N_E_W_L_I_N_E, + _R_E_T, _R_E_T_U_R_N, _S_P_C, _S_P_A_C_E, and _T_A_B. In addition to command + names, readline allows keys to be bound to a string that is + inserted when the key is pressed (a _m_a_c_r_o). + + Key Bindings + The syntax for controlling key bindings in the ~/._i_n_p_u_t_r_c + file is simple. All that is required is the name of the + + + +GNU Last change: 1994 July 26 4 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + command or the text of a macro and a key sequence to which + it should be bound. The name may be specified in one of two + ways: as a symbolic key name, possibly with _M_e_t_a- or _C_o_n_- + _t_r_o_l- prefixes, or as a key sequence. When using the form + keyname:_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, _k_e_y_n_a_m_e is the name of a key + spelled out in English. For example: + + Control-u: universal-argument + Meta-Rubout: backward-kill-word + Control-o: ">&output" + + In the above example, _C-_u is bound to the function + universal-argument, _M-_D_E_L is bound to the function + backward-kill-word, and _C-_o is bound to run the macro + expressed on the right hand side (that is, to insert the + text >&_o_u_t_p_u_t into the line). + + In the second form, "keyseq":_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, keyseq + differs from keyname above in that strings denoting an + entire key sequence may be specified by placing the sequence + within double quotes. Some GNU Emacs style key escapes can + be used, as in the following example. + + "\C-u": universal-argument + "\C-x\C-r": re-read-init-file + "\e[11~": "Function Key 1" + + In this example, _C-_u is again bound to the function + universal-argument. _C-_x _C-_r is bound to the function + re-read-init-file, and _E_S_C [ _1 _1 ~ is bound to insert the + text Function Key 1. The full set of escape sequences is + + \C- control prefix + + \M- meta prefix + + \e an escape character + + \\ backslash + + " \" literal " + + \' literal ' + + When entering the text of a macro, single or double quotes + should be used to indicate a macro definition. Unquoted + text is assumed to be a function name. Backslash will quote + any character in the macro text, including " and '. + + Bash allows the current readline key bindings to be + displayed or modified with the bind builtin command. The + editing mode may be switched during interactive use by using + + + +GNU Last change: 1994 July 26 5 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + the -o option to the set builtin command. Other programs + using this library provide similar mechanisms. The _i_n_p_u_t_r_c + file may be edited and re-read if a program does not provide + any other means to incorporate new bindings. + + Variables + Readline has variables that can be used to further customize + its behavior. A variable may be set in the _i_n_p_u_t_r_c file + with a statement of the form + + set _v_a_r_i_a_b_l_e-_n_a_m_e _v_a_l_u_e + + Except where noted, readline variables can take the values + On or Off. The variables and their default values are: + + horizontal-scroll-mode (Off) + When set to On, makes readline use a single line for + display, scrolling the input horizontally on a single + screen line when it becomes longer than the screen + width rather than wrapping to a new line. + editing-mode (emacs) + Controls whether readline begins with a set of key + bindings similar to _e_m_a_c_s or _v_i. editing-mode can be + set to either emacs or vi. + mark-modified-lines (Off) + If set to On, history lines that have been modified are + displayed with a preceding asterisk (*). + bell-style (audible) + Controls what happens when readline wants to ring the + terminal bell. If set to none, readline never rings + the bell. If set to visible, readline uses a visible + bell if one is available. If set to audible, readline + attempts to ring the terminal's bell. + comment-begin (``#'') + The string that is inserted in vi mode when the + vi-comment command is executed. + meta-flag (Off) + If set to On, readline will enable eight-bit input + (that is, it will not strip the high bit from the char- + acters it reads), regardless of what the terminal + claims it can support. + convert-meta (On) + If set to On, readline will convert characters with the + eighth bit set to an ASCII key sequence by stripping + the eighth bit and prepending an escape character (in + effect, using escape as the _m_e_t_a _p_r_e_f_i_x). + output-meta (Off) + If set to On, readline will display characters with the + eighth bit set directly rather than as a meta-prefixed + escape sequence. + completion-query-items (100) + This determines when the user is queried about viewing + + + +GNU Last change: 1994 July 26 6 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + the number of possible completions generated by the + possible-completions command. It may be set to any + integer value greater than or equal to zero. If the + number of possible completions is greater than or equal + to the value of this variable, the user is asked + whether or not he wishes to view them; otherwise they + are simply listed on the terminal. + keymap (emacs) + Set the current readline keymap. The set of legal key- + map names is _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s- + _c_t_l_x, _v_i, _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is + equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to + _e_m_a_c_s-_s_t_a_n_d_a_r_d. The default value is _e_m_a_c_s; the value + of editing-mode also affects the default keymap. + show-all-if-ambiguous (Off) + This alters the default behavior of the completion + functions. If set to on, words which have more than + one possible completion cause the matches to be listed + immediately instead of ringing the bell. + expand-tilde (Off) + If set to on, tilde expansion is performed when read- + line attempts word completion. + + Conditional Constructs + Readline implements a facility similar in spirit to the con- + ditional compilation features of the C preprocessor which + allows key bindings and variable settings to be performed as + the result of tests. There are three parser directives + used. + + $if The $if construct allows bindings to be made based on + the editing mode, the terminal being used, or the + application using readline. The text of the test + extends to the end of the line; no characters are + required to isolate it. + + mode The mode= form of the $if directive is used to + test whether readline is in emacs or vi mode. + This may be used in conjunction with the set key- + map command, for instance, to set bindings in the + _e_m_a_c_s-_s_t_a_n_d_a_r_d and _e_m_a_c_s-_c_t_l_x keymaps only if + readline is starting out in emacs mode. + + term The term= form may be used to include terminal- + specific key bindings, perhaps to bind the key + sequences output by the terminal's function keys. + The word on the right side of the = is tested + against the full name of the terminal and the por- + tion of the terminal name before the first -. + This allows _s_u_n to match both _s_u_n and _s_u_n-_c_m_d, for + instance. + + + + +GNU Last change: 1994 July 26 7 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + application + The application construct is used to include + application-specific settings. Each program using + the readline library sets the _a_p_p_l_i_c_a_t_i_o_n _n_a_m_e, + and an initialization file can test for a particu- + lar value. This could be used to bind key + sequences to functions useful for a specific pro- + gram. For instance, the following command adds a + key sequence that quotes the current or previous + word in Bash: + $if bash + # Quote the current or previous word + "\C-xq": "\eb\"\ef\"" + $endif + + $endif + This command, as you saw in the previous example, ter- + minates an $if command. + + $else + Commands in this branch of the $if directive are exe- + cuted if the test fails. + +EDITING COMMANDS + The following is a list of the names of the commands and the + default key sequences to which they are bound. + + Commands for Moving + beginning-of-line (C-a) + Move to the start of the current line. + end-of-line (C-e) + Move to the end of the line. + forward-char (C-f) + Move forward a character. + backward-char (C-b) + Move back a character. + forward-word (M-f) + Move forward to the end of the next word. Words are + composed of alphanumeric characters (letters and + digits). + backward-word (M-b) + Move back to the start of this, or the previous, word. + Words are composed of alphanumeric characters (letters + and digits). + clear-screen (C-l) + Clear the screen leaving the current line at the top of + the screen. With an argument, refresh the current line + without clearing the screen. + redraw-current-line + Refresh the current line. By default, this is unbound. + + + + + +GNU Last change: 1994 July 26 8 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Commands for Manipulating the History + accept-line (Newline, Return) + Accept the line regardless of where the cursor is. If + this line is non-empty, add it to the history list. If + the line is a modified history line, then restore the + history line to its original state. + previous-history (C-p) + Fetch the previous command from the history list, mov- + ing back in the list. + next-history (C-n) + Fetch the next command from the history list, moving + forward in the list. + beginning-of-history (M-<) + Move to the first line in the history. + end-of-history (M->) + Move to the end of the input history, i.e., the line + currently being entered. + reverse-search-history (C-r) + Search backward starting at the current line and moving + `up' through the history as necessary. This is an + incremental search. + forward-search-history (C-s) + Search forward starting at the current line and moving + `down' through the history as necessary. This is an + incremental search. + non-incremental-reverse-search-history (M-p) + Search backward through the history starting at the + current line using a non-incremental search for a + string supplied by the user. + non-incremental-forward-search-history (M-n) + Search forward through the history using a + non-incremental search for a string supplied by the + user. + history-search-forward + Search forward through the history for the string of + characters between the start of the current line and + the current point. This is a non-incremental search. + By default, this command is unbound. + history-search-backward + Search backward through the history for the string of + characters between the start of the current line and + the current point. This is a non-incremental search. + By default, this command is unbound. + yank-nth-arg (M-C-y) + Insert the first argument to the previous command (usu- + ally the second word on the previous line) at point + (the current cursor position). With an argument _n, + insert the _nth word from the previous command (the + words in the previous command begin with word 0). A + negative argument inserts the _nth word from the end of + the previous command. + yank-last-arg (M-., M-_) + + + +GNU Last change: 1994 July 26 9 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Insert the last argument to the previous command (the + last word on the previous line). With an argument, + behave exactly like yank-nth-arg. + + Commands for Changing Text + delete-char (C-d) + Delete the character under the cursor. If point is at + the beginning of the line, there are no characters in + the line, and the last character typed was not C-d, + then return EOF. + backward-delete-char (Rubout) + Delete the character behind the cursor. When given a + numeric argument, save the deleted text on the + kill-ring. + quoted-insert (C-q, C-v) + Add the next character that you type to the line verba- + tim. This is how to insert characters like C-q, for + example. + tab-insert (M-TAB) + Insert a tab character. + self-insert (a, b, A, 1, !, ...) + Insert the character typed. + transpose-chars (C-t) + Drag the character before point forward over the char- + acter at point. Point moves forward as well. If point + is at the end of the line, then transpose the two char- + acters before point. Negative arguments don't work. + transpose-words (M-t) + Drag the word behind the cursor past the word in front + of the cursor moving the cursor over that word as well. + upcase-word (M-u) + Uppercase the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + downcase-word (M-l) + Lowercase the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + capitalize-word (M-c) + Capitalize the current (or following) word. With a + negative argument, do the previous word, but do not + move point. + + Killing and Yanking + kill-line (C-k) + Kill the text from the current cursor position to the + end of the line. + backward-kill-line (C-x Rubout) + Kill backward to the beginning of the line. + unix-line-discard (C-u) + Kill backward from point to the beginning of the line. + kill-whole-line + + + +GNU Last change: 1994 July 26 10 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Kill all characters on the current line, no matter + where the cursor is. By default, this is unbound. + kill-word (M-d) + Kill from the cursor to the end of the current word, or + if between words, to the end of the next word. Word + boundaries are the same as those used by forward-word. + backward-kill-word (M-Rubout) + Kill the word behind the cursor. Word boundaries are + the same as those used by backward-word. + unix-word-rubout (C-w) + Kill the word behind the cursor, using white space as a + word boundary. The word boundaries are different from + backward-kill-word. + delete-horizontal-space + Delete all spaces and tabs around point. By default, + this is unbound. + yank (C-y) + Yank the top of the kill ring into the buffer at the + cursor. + yank-pop (M-y) + Rotate the kill-ring, and yank the new top. Only works + following yank or yank-pop. + + Numeric Arguments + digit-argument (M-0, M-1, ..., M--) + Add this digit to the argument already accumulating, or + start a new argument. M-- starts a negative argument. + universal-argument + Each time this is executed, the argument count is mul- + tiplied by four. The argument count is initially one, + so executing this function the first time makes the + argument count four. By default, this is not bound to + a key. + + Completing + complete (TAB) + Attempt to perform completion on the text before point. + The actual completion performed is application- + specific. Bash, for instance, attempts completion + treating the text as a variable (if the text begins + with $), username (if the text begins with ~), hostname + (if the text begins with @), or command (including + aliases and functions) in turn. If none of these pro- + duces a match, filename completion is attempted. Gdb, + on the other hand, allows completion of program func- + tions and variables, and only attempts filename comple- + tion under certain circumstances. + possible-completions (M-?) + List the possible completions of the text before point. + insert-completions + Insert all completions of the text before point that + would have been generated by possible-completions. By + + + +GNU Last change: 1994 July 26 11 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + default, this is not bound to a key. + + Keyboard Macros + start-kbd-macro (C-x () + Begin saving the characters typed into the current key- + board macro. + end-kbd-macro (C-x )) + Stop saving the characters typed into the current key- + board macro and save the definition. + call-last-kbd-macro (C-x e) + Re-execute the last keyboard macro defined, by making + the characters in the macro appear as if typed at the + keyboard. + + Miscellaneous + re-read-init-file (C-x C-r) + Read in the contents of your init file, and incorporate + any bindings or variable assignments found there. + abort (C-g) + Abort the current editing command and ring the + terminal's bell (subject to the setting of bell-style). + do-uppercase-version (M-a, M-b, ...) + Run the command that is bound to the corresponding + uppercase character. + prefix-meta (ESC) + Metafy the next character typed. ESC f is equivalent + to Meta-f. + undo (C-_, C-x C-u) + Incremental undo, separately remembered for each line. + revert-line (M-r) + Undo all changes made to this line. This is like typ- + ing the undo command enough times to return the line to + its initial state. + tilde-expand (M-~) + Perform tilde expansion on the current word. + dump-functions + Print all of the functions and their key bindings to + the readline output stream. If a numeric argument is + supplied, the output is formatted in such a way that it + can be made part of an _i_n_p_u_t_r_c file. + emacs-editing-mode (C-e) + When in vi editing mode, this causes a switch to emacs + editing mode. + vi-editing-mode (M-C-j) + When in emacs editing mode, this causes a switch to vi + editing mode. + +DEFAULT KEY BINDINGS + The following is a list of the default emacs and vi bind- + ings. Characters with the 8th bit set are written as M- + , and are referred to as _m_e_t_a_f_i_e_d characters. + The printable ASCII characters not mentioned in the list of + + + +GNU Last change: 1994 July 26 12 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + emacs standard bindings are bound to the _s_e_l_f-_i_n_s_e_r_t func- + tion, which just inserts the given character into the input + line. In vi insertion mode, all characters not specifically + mentioned are bound to _s_e_l_f-_i_n_s_e_r_t. Characters assigned to + signal generation by _s_t_t_y(1) or the terminal driver, such as + C-Z or C-C, retain that function. Upper and lower case + _m_e_t_a_f_i_e_d characters are bound to the same function in the + emacs mode meta keymap. The remaining characters are + unbound, which causes readline to ring the bell (subject to + the setting of the bell-style variable). + + Emacs Mode + Emacs Standard bindings + + "C-A" -> beginning-of-line + "C-B" -> backward-char + "C-D" -> delete-char + "C-E" -> end-of-line + "C-F" -> forward-char + "C-G" -> abort + "C-H" -> backward-delete-char + "C-I" -> complete + "C-J" -> accept-line + "C-K" -> kill-line + "C-L" -> clear-screen + "C-M" -> accept-line + "C-N" -> next-history + "C-P" -> previous-history + "C-Q" -> quoted-insert + "C-R" -> reverse-search-history + "C-S" -> forward-search-history + "C-T" -> transpose-chars + "C-U" -> unix-line-discard + "C-V" -> quoted-insert + "C-W" -> unix-word-rubout + "C-Y" -> yank + "C-_" -> undo + " " to "/" -> self-insert + "0" to "9" -> self-insert + ":" to "~" -> self-insert + "C-?" -> backward-delete-char + + Emacs Meta bindings + + "M-C-H" -> backward-kill-word + "M-C-I" -> tab-insert + "M-C-J" -> vi-editing-mode + "M-C-M" -> vi-editing-mode + "M-C-R" -> revert-line + "M-C-Y" -> yank-nth-arg + "M-C-[" -> complete + "M-&" -> tilde-expand + + + +GNU Last change: 1994 July 26 13 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + "M--" -> digit-argument + "M-0" -> digit-argument + "M-1" -> digit-argument + "M-2" -> digit-argument + "M-3" -> digit-argument + "M-4" -> digit-argument + "M-5" -> digit-argument + "M-6" -> digit-argument + "M-7" -> digit-argument + "M-8" -> digit-argument + "M-9" -> digit-argument + "M-<" -> beginning-of-history + "M->" -> end-of-history + "M-?" -> possible-completions + "M-B" -> backward-word + "M-C" -> capitalize-word + "M-D" -> kill-word + "M-F" -> forward-word + "M-L" -> downcase-word + "M-N" -> non-incremental-forward-search-history + "M-O" -> arrow-key-prefix + "M-P" -> non-incremental-reverse-search-history + "M-R" -> revert-line + "M-T" -> transpose-words + "M-U" -> upcase-word + "M-Y" -> yank-pop + "M-C-Y" -> yank-nth-arg + "M-C-?" -> backward-delete-word + + Emacs Control-X bindings + + "C-XC-G" -> abort + "C-XC-R" -> re-read-init-file + "C-XC-U" -> undo + "C-X(" -> start-kbd-macro + "C-X)" -> end-kbd-macro + "C-Xe" -> call-last-kbd-macro + "C-XC-?" -> backward-kill-line + + + VI Mode bindings + VI Insert Mode functions + + "C-D" -> vi-eof-maybe + "C-H" -> backward-delete-char + "C-I" -> complete + "C-J" -> accept-line + "C-K" -> kill-line + "C-L" -> clear-screen + "C-M" -> accept-line + "C-N" -> next-history + "C-P" -> previous-history + + + +GNU Last change: 1994 July 26 14 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + "C-Q" -> quoted-insert + "C-R" -> reverse-search-history + "C-S" -> forward-search-history + "C-T" -> transpose-chars + "C-U" -> unix-line-discard + "C-V" -> quoted-insert + "C-W" -> unix-word-rubout + "C-Y" -> yank + "C-[" -> vi-movement-mode + " " to "~" -> self-insert + "C-?" -> backward-delete-char + + VI Command Mode functions + + "C-D" -> vi-eof-maybe + "C-E" -> emacs-editing-mode + "C-G" -> abort + "C-H" -> backward-char + "C-J" -> accept-line + "C-K" -> kill-line + "C-L" -> clear-screen + "C-M" -> accept-line + "C-N" -> next-history + "C-P" -> previous-history + "C-Q" -> quoted-insert + "C-R" -> reverse-search-history + "C-S" -> forward-search-history + "C-T" -> transpose-chars + "C-U" -> unix-line-discard + "C-V" -> quoted-insert + "C-W" -> unix-word-rubout + "C-Y" -> yank + "C-[" -> abort + " " -> forward-char + "#" -> vi-comment + "$" -> end-of-line + "%" -> vi-match + "&" -> vi-tilde-expand + "*" -> vi-complete + "+" -> down-history + "," -> vi-char-search + "-" -> previous-history + "." -> vi-redo + "/" -> vi-search + "0" -> beginning-of-line + "1" to "9" -> vi-arg-digit + ";" -> vi-char-search + "=" -> vi-complete + "?" -> vi-search + "@" -> is undefined + "A" -> vi-append-eol + "B" -> vi-prev-word + + + +GNU Last change: 1994 July 26 15 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + "C" -> vi-change-to + "D" -> vi-delete-to + "E" -> vi-end-word + "F" -> vi-char-search + "I" -> vi-insert-beg + "N" -> vi-search-again + "P" -> vi-put + "R" -> vi-replace + "S" -> vi-subst + "T" -> vi-char-search + "U" -> revert-line + "W" -> vi-next-word + "X" -> backward-delete-char + "Y" -> vi-yank-to + "\" -> vi-complete + "^" -> vi-first-print + "_" -> vi-yank-arg + "a" -> vi-append-mode + "b" -> vi-prev-word + "c" -> vi-change-to + "d" -> vi-delete-to + "e" -> vi-end-word + "f" -> vi-char-search + "h" -> backward-char + "i" -> vi-insertion-mode + "j" -> next-history + "k" -> prev-history + "l" -> forward-char + "n" -> vi-search-again + "r" -> vi-change-char + "s" -> vi-subst + "t" -> vi-char-search + "u" -> undo + "w" -> vi-next-word + "x" -> vi-delete + "y" -> vi-yank-to + "|" -> vi-column + "~" -> vi-change-case + +SEE ALSO + _T_h_e _G_n_u _R_e_a_d_l_i_n_e _L_i_b_r_a_r_y, Brian Fox and Chet Ramey + _T_h_e _G_n_u _H_i_s_t_o_r_y _L_i_b_r_a_r_y, Brian Fox and Chet Ramey + _b_a_s_h(1) + +FILES + ~/._i_n_p_u_t_r_c + Individual readline initialization file + +AUTHORS + Brian Fox, Free Software Foundation (primary author) + bfox@ai.MIT.Edu + + + + +GNU Last change: 1994 July 26 16 + + + + + + +READLINE(3) C LIBRARY FUNCTIONS READLINE(3) + + + + Chet Ramey, Case Western Reserve University + chet@ins.CWRU.Edu + +BUG REPORTS + If you find a bug in readline, you should report it. But + first, you should make sure that it really is a bug, and + that it appears in the latest version of the readline + library that you have. + + Once you have determined that a bug actually exists, mail a + bug report to _b_a_s_h-_m_a_i_n_t_a_i_n_e_r_s@_p_r_e_p._a_i._M_I_T._E_d_u. If you have + a fix, you are welcome to mail that as well! Suggestions + and `philosophical' bug reports may be mailed to _b_u_g- + _b_a_s_h@_p_r_e_p._a_i._M_I_T._E_d_u or posted to the Usenet newsgroup + gnu.bash.bug. + + Comments and bug reports concerning this manual page should + be directed to _c_h_e_t@_i_n_s._C_W_R_U._E_d_u. + +BUGS + It's too big and too slow. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GNU Last change: 1994 July 26 17 + + + diff --git a/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 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 . + % + \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 to achieve this: TeX expands \the only once, +% simply yielding the contents of the . +\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 +#include +#include "bashansi.h" + +/* The name of this program, as taken from argv[0]. */ +char *progname; + +/* The name of the source file that this code is made from. */ +char source_name[256]; + +/* The name of the define. Either "BIG_ENDIAN" or "LITTLE_ENDIAN". */ +char *endian_define; + +char string[9]; +char nstring[9]; + +/* Stuff "1234" into a long, and compare it against a character string + "1234". If the results are EQ, the machine is big endian like a 68000 + or Sparc, otherwise it is little endian, like a Vax, or 386. */ +main (argc, argv) + int argc; + char **argv; +{ +#if defined (__STDC__) + register size_t i; +#else + register int i; +#endif /* !__STDC__ */ + FILE *stream = (FILE *)NULL; + char *stream_name = "stdout"; + union { + unsigned long l; + char s[sizeof (long)]; + } u; + + progname = argv[0]; + + for (i = strlen (progname); i > 0; i--) + if (progname[i] == '/') + { + progname = progname + i + 1; + break; + } + + strcpy (source_name, progname); + for (i = strlen (source_name); i > 0; i--) + if (source_name[i] == '.') + { + source_name[i] = '\0'; + break; + } + + strcat (source_name, ".c"); + + if (argc == 1) + { + stream_name = "stdout"; + stream = stdout; + } + else if (argc == 2) + { + stream_name = argv[1]; + stream = fopen (stream_name, "w"); + } + else + { + fprintf (stderr, "Usage: %s [output-file]\n", progname); + exit (1); + } + + if (!stream) + { + fprintf (stderr, "%s: %s Cannot be opened or written to.\n", + progname, stream_name); + exit (2); + } + + if (sizeof (long int) == 4) + { + u.l = 0x04030201L; + (void) strcpy (string, "4321"); + } + else if (sizeof (long int) == 8) + { +#if defined (__GNUC__) + unsigned long fake_out_gcc; + + fake_out_gcc = (0x08070605L << 31); + fake_out_gcc = (fake_out_gcc << 1); + u.l = fake_out_gcc | 0x04030201L; +#else + u.l = (0x08070605L << 32) | 0x04030201L; +#endif /* !__GNUC__ */ + (void) strcpy (string, "87654321"); + } + else + { + fprintf (stderr, + "%s: sizeof (long int) = %d, which isn't handled here.\n", + progname, sizeof (long int)); + exit (2); + } + + for (i = 0; i < sizeof (long); i++) + nstring[i] = u.s[i] + '0'; + nstring[i] = '\0'; + + if (strcmp (nstring, string) == 0) + endian_define = "BIG_ENDIAN"; + else + endian_define = "LITTLE_ENDIAN"; + + fprintf (stream, "/* %s - Define BIG or LITTLE endian. */\n\n", stream_name); + fprintf (stream, +"/* This file was automatically created by `%s'. You shouldn't\n\ + edit this file, because your changes will be overwritten. Instead,\n\ + edit the source code file `%s'. */\n\n", + progname, source_name); + + fprintf (stream, "#if !defined (%s)\n", endian_define); + fprintf (stream, "# define %s\n", endian_define); + fprintf (stream, "#endif /* %s */\n", endian_define); + + if (stream != stdout) + fclose (stream); + + exit (0); +} diff --git a/error.c b/error.c new file mode 100644 index 0000000..5ffd4ab --- /dev/null +++ b/error.c @@ -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 +#include +#include + +#if defined (HAVE_VFPRINTF) +#include +#endif + +#include +#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 */ diff --git a/error.h b/error.h new file mode 100644 index 0000000..15a5091 --- /dev/null +++ b/error.h @@ -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: +# 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 +# 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" +#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 +#include +#include "bashtypes.h" +#include +#include "filecntl.h" +#include "posixstat.h" +#include + +#if !defined (SIGABRT) +#define SIGABRT SIGIOT +#endif + +#include +#include + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#include "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 +#include + +#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_ */ diff --git a/expr.c b/expr.c new file mode 100644 index 0000000..5f9eb6d --- /dev/null +++ b/expr.c @@ -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 +#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 + +/* 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/flags.c b/flags.c new file mode 100644 index 0000000..b812ec9 --- /dev/null +++ b/flags.c @@ -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); +} diff --git a/flags.h b/flags.h new file mode 100644 index 0000000..bcff4ef --- /dev/null +++ b/flags.h @@ -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 +#include +#include +#include "bashtypes.h" +#include +#if defined (_POSIX_VERSION) +# if defined (amiga) && defined (USGr4) +# define _POSIX_SOURCE +# endif +# include +# if defined (amiga) && defined (USGr4) +# undef _POSIX_SOURCE +# endif +#endif /* _POSIX_VERSION */ +#include "filecntl.h" +#include "bashansi.h" +#include "shell.h" +#include + +#if !defined (USG) || defined (HAVE_RESOURCE) +# include +#endif + +#include +#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 +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 +# 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 +#else +# include +#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 + +#if defined (HAVE_LIMITS_H) +# include +#endif + +#if defined (HAVE_DIRENT_H) +# include +#else +# include +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +#endif /* !HAVE_DIRENT_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "posixstat.h" +#include "maxpath.h" +#include "config.h" + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* !HAVE_STDLIB_H */ + +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#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 +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 */ diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..b955b3f --- /dev/null +++ b/hash.c @@ -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 +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include +#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 + +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: + */ diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..5458787 --- /dev/null +++ b/hash.h @@ -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 */ diff --git a/input.c b/input.c new file mode 100644 index 0000000..852d369 --- /dev/null +++ b/input.c @@ -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 +#include "filecntl.h" +#include "posixstat.h" +#include +#include + +#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 3b_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 diff --git a/input.h b/input.h new file mode 100644 index 0000000..1824b40 --- /dev/null +++ b/input.h @@ -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 */ diff --git a/jobs.c b/jobs.c new file mode 100644 index 0000000..40e7f7d --- /dev/null +++ b/jobs.c @@ -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 +#include +#include + +#if !defined (USG) || defined (HAVE_RESOURCE) +#include +#endif /* USG */ + +#if !defined (_POSIX_VERSION) +# if defined (HAVE_RESOURCE) +# include +# endif +#endif /* _POSIX_VERSION */ + +#include +#include "filecntl.h" +#include +#include + +#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 +#endif + +#if defined (TERMIO_TTY_DRIVER) +#include +#endif + +#if defined (TERMIOS_TTY_DRIVER) +/* For Sun workstations we undefine a couple of defines so that + the inclusion of termios.h won't cause complaints. */ +# if defined (SunOS4) +# undef ECHO +# undef NOFLSH +# undef TOSTOP +# endif /* SunOS4 */ +# include +#endif /* TERMIOS_TTY_DRIVER */ + +/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ + +#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) +# include +#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 (""); + 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 ("")); +} + +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 */ diff --git a/jobs.h b/jobs.h new file mode 100644 index 0000000..18d3d73 --- /dev/null +++ b/jobs.h @@ -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 +#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 +#include +#include +#include "getopt.h" +#include "bashansi.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_UNISTD_H) +# include +#else /* !HAVE_UNISTD_H */ +extern long lseek (); +#endif /* !HAVE_UNISTD_H */ + +extern char *mktemp (); + +#if !defined (HAVE_STRERROR) +extern int sys_nerr; +extern char *sys_errlist[]; +#endif + +#include + +#if defined (_AIX) || !defined (_POSIX_VERSION) +# include +#endif + +#include + +#define TI_NO_ERROR 0 +#define TI_FATAL_ERROR 1 + +#if !defined (SEEK_SET) +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif /* !SEEK_SET */ + +/* When sorting in core, this structure describes one line + and the position and length of its first keyfield. */ +struct lineinfo +{ + char *text; /* The actual text of the line. */ + union { + char *text; /* The start of the key (for textual comparison). */ + long number; /* The numeric value (for numeric comparison). */ + } key; + long keylen; /* Length of KEY field. */ +}; + +/* This structure describes a field to use as a sort key. */ +struct keyfield +{ + int startwords; /* Number of words to skip. */ + int startchars; /* Number of additional chars to skip. */ + int endwords; /* Number of words to ignore at end. */ + int endchars; /* Ditto for characters of last word. */ + char ignore_blanks; /* Non-zero means ignore spaces and tabs. */ + char fold_case; /* Non-zero means case doesn't matter. */ + char reverse; /* Non-zero means compare in reverse order. */ + char numeric; /* Non-zeros means field is ASCII numeric. */ + char positional; /* Sort according to file position. */ + char braced; /* Count balanced-braced groupings as fields. */ +}; + +/* Vector of keyfields to use. */ +struct keyfield keyfields[3]; + +/* Number of keyfields stored in that vector. */ +int num_keyfields = 3; + +/* Vector of input file names, terminated with a null pointer. */ +char **infiles; + +/* Vector of corresponding output file names, or NULL, meaning default it + (add an `s' to the end). */ +char **outfiles; + +/* Length of `infiles'. */ +int num_infiles; + +/* Pointer to the array of pointers to lines being sorted. */ +char **linearray; + +/* The allocated length of `linearray'. */ +long nlines; + +/* Directory to use for temporary files. On Unix, it ends with a slash. */ +char *tempdir; + +/* Start of filename to use for temporary files. */ +char *tempbase; + +/* Number of last temporary file. */ +int tempcount; + +/* Number of last temporary file already deleted. + Temporary files are deleted by `flush_tempfiles' in order of creation. */ +int last_deleted_tempcount; + +/* During in-core sort, this points to the base of the data block + which contains all the lines of data. */ +char *text_base; + +/* Additional command switches .*/ + +/* Nonzero means do not delete tempfiles -- for debugging. */ +int keep_tempfiles; + +/* The name this program was run with. */ +char *program_name; + +/* Forward declarations of functions in this file. */ + +void decode_command (); +void sort_in_core (); +void sort_offline (); +char **parsefile (); +char *find_field (); +char *find_pos (); +long find_value (); +char *find_braced_pos (); +char *find_braced_end (); +void writelines (); +int compare_field (); +int compare_full (); +long readline (); +int merge_files (); +int merge_direct (); +void pfatal_with_name (); +void fatal (); +void error (); +void *xmalloc (), *xrealloc (); +char *concat (); +char *maketempname (); +void flush_tempfiles (); +char *tempcopy (); + +#define MAX_IN_CORE_SORT 500000 + +void +main (argc, argv) + int argc; + char **argv; +{ + int i; + + tempcount = 0; + last_deleted_tempcount = 0; + program_name = argv[0]; + + /* Describe the kind of sorting to do. */ + /* The first keyfield uses the first braced field and folds case. */ + keyfields[0].braced = 1; + keyfields[0].fold_case = 1; + keyfields[0].endwords = -1; + keyfields[0].endchars = -1; + + /* The second keyfield uses the second braced field, numerically. */ + keyfields[1].braced = 1; + keyfields[1].numeric = 1; + keyfields[1].startwords = 1; + keyfields[1].endwords = -1; + keyfields[1].endchars = -1; + + /* The third keyfield (which is ignored while discarding duplicates) + compares the whole line. */ + keyfields[2].endwords = -1; + keyfields[2].endchars = -1; + + decode_command (argc, argv); + + tempbase = mktemp (concat ("txiXXXXXX", "", "")); + + /* Process input files completely, one by one. */ + + for (i = 0; i < num_infiles; i++) + { + int desc; + long ptr; + char *outfile; + + desc = open (infiles[i], O_RDONLY, 0); + if (desc < 0) + pfatal_with_name (infiles[i]); + lseek (desc, 0L, SEEK_END); + ptr = lseek (desc, 0L, SEEK_CUR); + + close (desc); + + outfile = outfiles[i]; + if (!outfile) + { + outfile = concat (infiles[i], "s", ""); + } + + if (ptr < MAX_IN_CORE_SORT) + /* Sort a small amount of data. */ + sort_in_core (infiles[i], ptr, outfile); + else + sort_offline (infiles[i], ptr, outfile); + } + + flush_tempfiles (tempcount); + exit (TI_NO_ERROR); +} + +void +usage () +{ + fprintf (stderr, "\ +Usage: %s [-k] infile [-o outfile] ...\n", program_name); + exit (1); +} + +/* Decode the command line arguments to set the parameter variables + and set up the vector of keyfields and the vector of input files. */ + +void +decode_command (argc, argv) + int argc; + char **argv; +{ + int optc; + char **ip; + char **op; + + /* Store default values into parameter variables. */ + + tempdir = getenv ("TMPDIR"); + if (tempdir == NULL) + tempdir = "/tmp/"; + else + tempdir = concat (tempdir, "/", ""); + + keep_tempfiles = 0; + + /* Allocate ARGC input files, which must be enough. */ + + infiles = (char **) xmalloc (argc * sizeof (char *)); + outfiles = (char **) xmalloc (argc * sizeof (char *)); + ip = infiles; + op = outfiles; + + while ((optc = getopt (argc, argv, "-ko:")) != EOF) + { + switch (optc) + { + case 1: /* Non-option filename. */ + *ip++ = optarg; + *op++ = NULL; + break; + + case 'k': + keep_tempfiles = 1; + break; + + case 'o': + if (op > outfiles) + *(op - 1) = optarg; + break; + + default: + usage (); + } + } + + /* Record number of keyfields and terminate list of filenames. */ + num_infiles = ip - infiles; + *ip = 0; + if (num_infiles == 0) + usage (); +} + +/* Return a name for a temporary file. */ + +char * +maketempname (count) + int count; +{ + char tempsuffix[10]; + sprintf (tempsuffix, "%d", count); + return concat (tempdir, tempbase, tempsuffix); +} + +/* Delete all temporary files up to TO_COUNT. */ + +void +flush_tempfiles (to_count) + int to_count; +{ + if (keep_tempfiles) + return; + while (last_deleted_tempcount < to_count) + unlink (maketempname (++last_deleted_tempcount)); +} + +/* Copy the input file open on IDESC into a temporary file + and return the temporary file name. */ + +#define BUFSIZE 1024 + +char * +tempcopy (idesc) + int idesc; +{ + char *outfile = maketempname (++tempcount); + int odesc; + char buffer[BUFSIZE]; + + odesc = open (outfile, O_WRONLY | O_CREAT, 0666); + + if (odesc < 0) + pfatal_with_name (outfile); + + while (1) + { + int nread = read (idesc, buffer, BUFSIZE); + write (odesc, buffer, nread); + if (!nread) + break; + } + + close (odesc); + + return outfile; +} + +/* Compare LINE1 and LINE2 according to the specified set of keyfields. */ + +int +compare_full (line1, line2) + char **line1, **line2; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; + and so on. */ + + for (i = 0; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], *line1, &length1); + char *start2 = find_field (&keyfields[i], *line2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base, + start2, length2, *line2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Compare LINE1 and LINE2, described by structures + in which the first keyfield is identified in advance. + For positional sorting, assumes that the order of the lines in core + reflects their nominal order. */ + +int +compare_prepared (line1, line2) + struct lineinfo *line1, *line2; +{ + int i; + int tem; + char *text1, *text2; + + /* Compare using the first keyfield, which has been found for us already. */ + if (keyfields->positional) + { + if (line1->text - text_base > line2->text - text_base) + tem = 1; + else + tem = -1; + } + else if (keyfields->numeric) + tem = line1->key.number - line2->key.number; + else + tem = compare_field (keyfields, line1->key.text, line1->keylen, 0, + line2->key.text, line2->keylen, 0); + if (tem) + { + if (keyfields->reverse) + return -tem; + return tem; + } + + text1 = line1->text; + text2 = line2->text; + + /* Compare using the second keyfield; + if that does not distinguish the lines, try the third keyfield; + and so on. */ + + for (i = 1; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], text1, &length1); + char *start2 = find_field (&keyfields[i], text2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base, + start2, length2, text2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Like compare_full but more general. + You can pass any strings, and you can say how many keyfields to use. + POS1 and POS2 should indicate the nominal positional ordering of + the two lines in the input. */ + +int +compare_general (str1, str2, pos1, pos2, use_keyfields) + char *str1, *str2; + long pos1, pos2; + int use_keyfields; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; + and so on. */ + + for (i = 0; i < use_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], str1, &length1); + char *start2 = find_field (&keyfields[i], str2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, pos1, + start2, length2, pos2); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Find the start and length of a field in STR according to KEYFIELD. + A pointer to the starting character is returned, and the length + is stored into the int that LENGTHPTR points to. */ + +char * +find_field (keyfield, str, lengthptr) + struct keyfield *keyfield; + char *str; + long *lengthptr; +{ + char *start; + char *end; + char *(*fun) (); + + if (keyfield->braced) + fun = find_braced_pos; + else + fun = find_pos; + + start = (*fun) (str, keyfield->startwords, keyfield->startchars, + keyfield->ignore_blanks); + if (keyfield->endwords < 0) + { + if (keyfield->braced) + end = find_braced_end (start); + else + { + end = start; + while (*end && *end != '\n') + end++; + } + } + else + { + end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0); + if (end - str < start - str) + end = start; + } + *lengthptr = end - start; + return start; +} + +/* Return a pointer to a specified place within STR, + skipping (from the beginning) WORDS words and then CHARS chars. + If IGNORE_BLANKS is nonzero, we skip all blanks + after finding the specified word. */ + +char * +find_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + char *p = str; + + for (i = 0; i < words; i++) + { + char c; + /* Find next bunch of nonblanks and skip them. */ + while ((c = *p) == ' ' || c == '\t') + p++; + while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) + p++; + if (!*p || *p == '\n') + return p; + } + + while (*p == ' ' || *p == '\t') + p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') + break; + p++; + } + return p; +} + +/* Like find_pos but assumes that each field is surrounded by braces + and that braces within fields are balanced. */ + +char * +find_braced_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + int bracelevel; + char *p = str; + char c; + + for (i = 0; i < words; i++) + { + bracelevel = 1; + while ((c = *p++) != '{' && c != '\n' && c) + /* Do nothing. */ ; + if (c != '{') + return p - 1; + while (bracelevel) + { + c = *p++; + if (c == '{') + bracelevel++; + if (c == '}') + bracelevel--; + if (c == 0 || c == '\n') + return p - 1; + } + } + + while ((c = *p++) != '{' && c != '\n' && c) + /* Do nothing. */ ; + + if (c != '{') + return p - 1; + + if (ignore_blanks) + while ((c = *p) == ' ' || c == '\t') + p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') + break; + p++; + } + return p; +} + +/* Find the end of the balanced-brace field which starts at STR. + The position returned is just before the closing brace. */ + +char * +find_braced_end (str) + char *str; +{ + int bracelevel; + char *p = str; + char c; + + bracelevel = 1; + while (bracelevel) + { + c = *p++; + if (c == '{') + bracelevel++; + if (c == '}') + bracelevel--; + if (c == 0 || c == '\n') + return p - 1; + } + return p - 1; +} + +long +find_value (start, length) + char *start; + long length; +{ + while (length != 0L) + { + if (isdigit (*start)) + return atol (start); + length--; + start++; + } + return 0l; +} + +/* Vector used to translate characters for comparison. + This is how we make all alphanumerics follow all else, + and ignore case in the first sorting. */ +int char_order[256]; + +void +init_char_order () +{ + int i; + for (i = 1; i < 256; i++) + char_order[i] = i; + + for (i = '0'; i <= '9'; i++) + char_order[i] += 512; + + for (i = 'a'; i <= 'z'; i++) + { + char_order[i] = 512 + i; + char_order[i + 'A' - 'a'] = 512 + i; + } +} + +/* Compare two fields (each specified as a start pointer and a character count) + according to KEYFIELD. + The sign of the value reports the relation between the fields. */ + +int +compare_field (keyfield, start1, length1, pos1, start2, length2, pos2) + struct keyfield *keyfield; + char *start1; + long length1; + long pos1; + char *start2; + long length2; + long pos2; +{ + if (keyfields->positional) + { + if (pos1 > pos2) + return 1; + else + return -1; + } + if (keyfield->numeric) + { + long value = find_value (start1, length1) - find_value (start2, length2); + if (value > 0) + return 1; + if (value < 0) + return -1; + return 0; + } + else + { + char *p1 = start1; + char *p2 = start2; + char *e1 = start1 + length1; + char *e2 = start2 + length2; + + while (1) + { + int c1, c2; + + if (p1 == e1) + c1 = 0; + else + c1 = *p1++; + if (p2 == e2) + c2 = 0; + else + c2 = *p2++; + + if (char_order[c1] != char_order[c2]) + return char_order[c1] - char_order[c2]; + if (!c1) + break; + } + + /* Strings are equal except possibly for case. */ + p1 = start1; + p2 = start2; + while (1) + { + int c1, c2; + + if (p1 == e1) + c1 = 0; + else + c1 = *p1++; + if (p2 == e2) + c2 = 0; + else + c2 = *p2++; + + if (c1 != c2) + /* Reverse sign here so upper case comes out last. */ + return c2 - c1; + if (!c1) + break; + } + + return 0; + } +} + +/* A `struct linebuffer' is a structure which holds a line of text. + `readline' reads a line from a stream into a linebuffer + and works regardless of the length of the line. */ + +struct linebuffer +{ + long size; + char *buffer; +}; + +/* Initialize LINEBUFFER for use. */ + +void +initbuffer (linebuffer) + struct linebuffer *linebuffer; +{ + linebuffer->size = 200; + linebuffer->buffer = (char *) xmalloc (200); +} + +/* Read a line of text from STREAM into LINEBUFFER. + Return the length of the line. */ + +long +readline (linebuffer, stream) + struct linebuffer *linebuffer; + FILE *stream; +{ + char *buffer = linebuffer->buffer; + char *p = linebuffer->buffer; + char *end = p + linebuffer->size; + + while (1) + { + int c = getc (stream); + if (p == end) + { + buffer = (char *) xrealloc (buffer, linebuffer->size *= 2); + p += buffer - linebuffer->buffer; + end += buffer - linebuffer->buffer; + linebuffer->buffer = buffer; + } + if (c < 0 || c == '\n') + { + *p = 0; + break; + } + *p++ = c; + } + + return p - buffer; +} + +/* Sort an input file too big to sort in core. */ + +void +sort_offline (infile, nfiles, total, outfile) + char *infile; + int nfiles; + long total; + char *outfile; +{ + /* More than enough. */ + int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT; + char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + FILE *istream = fopen (infile, "r"); + int i; + struct linebuffer lb; + long linelength; + int failure = 0; + + initbuffer (&lb); + + /* Read in one line of input data. */ + + linelength = readline (&lb, istream); + + if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') + { + error ("%s: not a texinfo index file", infile); + return; + } + + /* Split up the input into `ntemps' temporary files, or maybe fewer, + and put the new files' names into `tempfiles' */ + + for (i = 0; i < ntemps; i++) + { + char *outname = maketempname (++tempcount); + FILE *ostream = fopen (outname, "w"); + long tempsize = 0; + + if (!ostream) + pfatal_with_name (outname); + tempfiles[i] = outname; + + /* Copy lines into this temp file as long as it does not make file + "too big" or until there are no more lines. */ + + while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT) + { + tempsize += linelength + 1; + fputs (lb.buffer, ostream); + putc ('\n', ostream); + + /* Read another line of input data. */ + + linelength = readline (&lb, istream); + if (!linelength && feof (istream)) + break; + + if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') + { + error ("%s: not a texinfo index file", infile); + failure = 1; + goto fail; + } + } + fclose (ostream); + if (feof (istream)) + break; + } + + free (lb.buffer); + +fail: + /* Record number of temp files we actually needed. */ + + ntemps = i; + + /* Sort each tempfile into another tempfile. + Delete the first set of tempfiles and put the names of the second + into `tempfiles'. */ + + for (i = 0; i < ntemps; i++) + { + char *newtemp = maketempname (++tempcount); + sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp); + if (!keep_tempfiles) + unlink (tempfiles[i]); + tempfiles[i] = newtemp; + } + + if (failure) + return; + + /* Merge the tempfiles together and indexify. */ + + merge_files (tempfiles, ntemps, outfile); +} + +/* Sort INFILE, whose size is TOTAL, + assuming that is small enough to be done in-core, + then indexify it and send the output to OUTFILE (or to stdout). */ + +void +sort_in_core (infile, total, outfile) + char *infile; + long total; + char *outfile; +{ + char **nextline; + char *data = (char *) xmalloc (total + 1); + char *file_data; + long file_size; + int i; + FILE *ostream = stdout; + struct lineinfo *lineinfo; + + /* Read the contents of the file into the moby array `data'. */ + + int desc = open (infile, O_RDONLY, 0); + + if (desc < 0) + fatal ("failure reopening %s", infile); + for (file_size = 0;;) + { + i = read (desc, data + file_size, total - file_size); + if (i <= 0) + break; + file_size += i; + } + file_data = data; + data[file_size] = 0; + + close (desc); + + if (file_size > 0 && data[0] != '\\' && data[0] != '@') + { + error ("%s: not a texinfo index file", infile); + return; + } + + init_char_order (); + + /* Sort routines want to know this address. */ + + text_base = data; + + /* Create the array of pointers to lines, with a default size + frequently enough. */ + + nlines = total / 50; + if (!nlines) + nlines = 2; + linearray = (char **) xmalloc (nlines * sizeof (char *)); + + /* `nextline' points to the next free slot in this array. + `nlines' is the allocated size. */ + + nextline = linearray; + + /* Parse the input file's data, and make entries for the lines. */ + + nextline = parsefile (infile, nextline, file_data, file_size); + if (nextline == 0) + { + error ("%s: not a texinfo index file", infile); + return; + } + + /* Sort the lines. */ + + /* If we have enough space, find the first keyfield of each line in advance. + Make a `struct lineinfo' for each line, which records the keyfield + as well as the line, and sort them. */ + + lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo)); + + if (lineinfo) + { + struct lineinfo *lp; + char **p; + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + { + lp->text = *p; + lp->key.text = find_field (keyfields, *p, &lp->keylen); + if (keyfields->numeric) + lp->key.number = find_value (lp->key.text, lp->keylen); + } + + qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared); + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + *p = lp->text; + + free (lineinfo); + } + else + qsort (linearray, nextline - linearray, sizeof (char *), compare_full); + + /* Open the output file. */ + + if (outfile) + { + ostream = fopen (outfile, "w"); + if (!ostream) + pfatal_with_name (outfile); + } + + writelines (linearray, nextline - linearray, ostream); + if (outfile) + fclose (ostream); + + free (linearray); + free (data); +} + +/* Parse an input string in core into lines. + DATA is the input string, and SIZE is its length. + Data goes in LINEARRAY starting at NEXTLINE. + The value returned is the first entry in LINEARRAY still unused. + Value 0 means input file contents are invalid. */ + +char ** +parsefile (filename, nextline, data, size) + char *filename; + char **nextline; + char *data; + long size; +{ + char *p, *end; + char **line = nextline; + + p = data; + end = p + size; + *end = 0; + + while (p != end) + { + if (p[0] != '\\' && p[0] != '@') + return 0; + + *line = p; + while (*p && *p != '\n') + p++; + if (p != end) + p++; + + line++; + if (line == linearray + nlines) + { + char **old = linearray; + linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4)); + line += linearray - old; + } + } + + return line; +} + +/* Indexification is a filter applied to the sorted lines + as they are being written to the output file. + Multiple entries for the same name, with different page numbers, + get combined into a single entry with multiple page numbers. + The first braced field, which is used for sorting, is discarded. + However, its first character is examined, folded to lower case, + and if it is different from that in the previous line fed to us + a \initial line is written with one argument, the new initial. + + If an entry has four braced fields, then the second and third + constitute primary and secondary names. + In this case, each change of primary name + generates a \primary line which contains only the primary name, + and in between these are \secondary lines which contain + just a secondary name and page numbers. */ + +/* The last primary name we wrote a \primary entry for. + If only one level of indexing is being done, this is the last name seen. */ +char *lastprimary; +/* Length of storage allocated for lastprimary. */ +int lastprimarylength; + +/* Similar, for the secondary name. */ +char *lastsecondary; +int lastsecondarylength; + +/* Zero if we are not in the middle of writing an entry. + One if we have written the beginning of an entry but have not + yet written any page numbers into it. + Greater than one if we have written the beginning of an entry + plus at least one page number. */ +int pending; + +/* The initial (for sorting purposes) of the last primary entry written. + When this changes, a \initial {c} line is written */ + +char *lastinitial; + +int lastinitiallength; + +/* When we need a string of length 1 for the value of lastinitial, + store it here. */ + +char lastinitial1[2]; + +/* Initialize static storage for writing an index. */ + +static void +xbzero(s, n) + char *s; + int n; +{ + register char *p; + for (p = s; n--; ) + *p++ = '\0'; +} + +void +init_index () +{ + pending = 0; + lastinitial = lastinitial1; + lastinitial1[0] = 0; + lastinitial1[1] = 0; + lastinitiallength = 0; + lastprimarylength = 100; + lastprimary = (char *) xmalloc (lastprimarylength + 1); + xbzero (lastprimary, lastprimarylength + 1); + lastsecondarylength = 100; + lastsecondary = (char *) xmalloc (lastsecondarylength + 1); + xbzero (lastsecondary, lastsecondarylength + 1); +} + +/* Indexify. Merge entries for the same name, + insert headers for each initial character, etc. */ + +void +indexify (line, ostream) + char *line; + FILE *ostream; +{ + char *primary, *secondary, *pagenumber; + int primarylength, secondarylength = 0, pagelength; + int nosecondary; + int initiallength; + char *initial; + char initial1[2]; + register char *p; + + /* First, analyze the parts of the entry fed to us this time. */ + + p = find_braced_pos (line, 0, 0, 0); + if (*p == '{') + { + initial = p; + /* Get length of inner pair of braces starting at `p', + including that inner pair of braces. */ + initiallength = find_braced_end (p + 1) + 1 - p; + } + else + { + initial = initial1; + initial1[0] = *p; + initial1[1] = 0; + initiallength = 1; + + if (initial1[0] >= 'a' && initial1[0] <= 'z') + initial1[0] -= 040; + } + + pagenumber = find_braced_pos (line, 1, 0, 0); + pagelength = find_braced_end (pagenumber) - pagenumber; + if (pagelength == 0) + abort (); + + primary = find_braced_pos (line, 2, 0, 0); + primarylength = find_braced_end (primary) - primary; + + secondary = find_braced_pos (line, 3, 0, 0); + nosecondary = !*secondary; + if (!nosecondary) + secondarylength = find_braced_end (secondary) - secondary; + + /* If the primary is different from before, make a new primary entry. */ + if (strncmp (primary, lastprimary, primarylength)) + { + /* Close off current secondary entry first, if one is open. */ + if (pending) + { + fputs ("}\n", ostream); + pending = 0; + } + + /* If this primary has a different initial, include an entry for + the initial. */ + if (initiallength != lastinitiallength || + strncmp (initial, lastinitial, initiallength)) + { + fprintf (ostream, "\\initial {"); + fwrite (initial, 1, initiallength, ostream); + fprintf (ostream, "}\n", initial); + if (initial == initial1) + { + lastinitial = lastinitial1; + *lastinitial1 = *initial1; + } + else + { + lastinitial = initial; + } + lastinitiallength = initiallength; + } + + /* Make the entry for the primary. */ + if (nosecondary) + fputs ("\\entry {", ostream); + else + fputs ("\\primary {", ostream); + fwrite (primary, primarylength, 1, ostream); + if (nosecondary) + { + fputs ("}{", ostream); + pending = 1; + } + else + fputs ("}\n", ostream); + + /* Record name of most recent primary. */ + if (lastprimarylength < primarylength) + { + lastprimarylength = primarylength + 100; + lastprimary = (char *) xrealloc (lastprimary, + 1 + lastprimarylength); + } + strncpy (lastprimary, primary, primarylength); + lastprimary[primarylength] = 0; + + /* There is no current secondary within this primary, now. */ + lastsecondary[0] = 0; + } + + /* Should not have an entry with no subtopic following one with a subtopic. */ + + if (nosecondary && *lastsecondary) + error ("entry %s follows an entry with a secondary name", line); + + /* Start a new secondary entry if necessary. */ + if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength)) + { + if (pending) + { + fputs ("}\n", ostream); + pending = 0; + } + + /* Write the entry for the secondary. */ + fputs ("\\secondary {", ostream); + fwrite (secondary, secondarylength, 1, ostream); + fputs ("}{", ostream); + pending = 1; + + /* Record name of most recent secondary. */ + if (lastsecondarylength < secondarylength) + { + lastsecondarylength = secondarylength + 100; + lastsecondary = (char *) xrealloc (lastsecondary, + 1 + lastsecondarylength); + } + strncpy (lastsecondary, secondary, secondarylength); + lastsecondary[secondarylength] = 0; + } + + /* Here to add one more page number to the current entry. */ + if (pending++ != 1) + fputs (", ", ostream); /* Punctuate first, if this is not the first. */ + fwrite (pagenumber, pagelength, 1, ostream); +} + +/* Close out any unfinished output entry. */ + +void +finish_index (ostream) + FILE *ostream; +{ + if (pending) + fputs ("}\n", ostream); + free (lastprimary); + free (lastsecondary); +} + +/* Copy the lines in the sorted order. + Each line is copied out of the input file it was found in. */ + +void +writelines (linearray, nlines, ostream) + char **linearray; + int nlines; + FILE *ostream; +{ + char **stop_line = linearray + nlines; + char **next_line; + + init_index (); + + /* Output the text of the lines, and free the buffer space. */ + + for (next_line = linearray; next_line != stop_line; next_line++) + { + /* If -u was specified, output the line only if distinct from previous one. */ + if (next_line == linearray + /* Compare previous line with this one, using only the + explicitly specd keyfields. */ + || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1)) + { + char *p = *next_line; + char c; + + while ((c = *p++) && c != '\n') + /* Do nothing. */ ; + *(p - 1) = 0; + indexify (*next_line, ostream); + } + } + + finish_index (ostream); +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This is the high-level interface that can handle an unlimited + number of files. */ + +#define MAX_DIRECT_MERGE 10 + +int +merge_files (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + char **tempfiles; + int ntemps; + int i; + int value = 0; + int start_tempcount = tempcount; + + if (nfiles <= MAX_DIRECT_MERGE) + return merge_direct (infiles, nfiles, outfile); + + /* Merge groups of MAX_DIRECT_MERGE input files at a time, + making a temporary file to hold each group's result. */ + + ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE; + tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + for (i = 0; i < ntemps; i++) + { + int nf = MAX_DIRECT_MERGE; + if (i + 1 == ntemps) + nf = nfiles - i * MAX_DIRECT_MERGE; + tempfiles[i] = maketempname (++tempcount); + value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]); + } + + /* All temporary files that existed before are no longer needed + since their contents have been merged into our new tempfiles. + So delete them. */ + flush_tempfiles (start_tempcount); + + /* Now merge the temporary files we created. */ + + merge_files (tempfiles, ntemps, outfile); + + free (tempfiles); + + return value; +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This version of merging will not work if the number of + input files gets too high. Higher level functions + use it only with a bounded number of input files. */ + +int +merge_direct (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + struct linebuffer *lb1, *lb2; + struct linebuffer **thisline, **prevline; + FILE **streams; + int i; + int nleft; + int lossage = 0; + int *file_lossage; + struct linebuffer *prev_out = 0; + FILE *ostream = stdout; + + if (outfile) + { + ostream = fopen (outfile, "w"); + } + if (!ostream) + pfatal_with_name (outfile); + + init_index (); + + if (nfiles == 0) + { + if (outfile) + fclose (ostream); + return 0; + } + + /* For each file, make two line buffers. + Also, for each file, there is an element of `thisline' + which points at any time to one of the file's two buffers, + and an element of `prevline' which points to the other buffer. + `thisline' is supposed to point to the next available line from the file, + while `prevline' holds the last file line used, + which is remembered so that we can verify that the file is properly sorted. */ + + /* lb1 and lb2 contain one buffer each per file. */ + lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + + /* thisline[i] points to the linebuffer holding the next available line in file i, + or is zero if there are no lines left in that file. */ + thisline = (struct linebuffer **) + xmalloc (nfiles * sizeof (struct linebuffer *)); + /* prevline[i] points to the linebuffer holding the last used line + from file i. This is just for verifying that file i is properly + sorted. */ + prevline = (struct linebuffer **) + xmalloc (nfiles * sizeof (struct linebuffer *)); + /* streams[i] holds the input stream for file i. */ + streams = (FILE **) xmalloc (nfiles * sizeof (FILE *)); + /* file_lossage[i] is nonzero if we already know file i is not + properly sorted. */ + file_lossage = (int *) xmalloc (nfiles * sizeof (int)); + + /* Allocate and initialize all that storage. */ + + for (i = 0; i < nfiles; i++) + { + initbuffer (&lb1[i]); + initbuffer (&lb2[i]); + thisline[i] = &lb1[i]; + prevline[i] = &lb2[i]; + file_lossage[i] = 0; + streams[i] = fopen (infiles[i], "r"); + if (!streams[i]) + pfatal_with_name (infiles[i]); + + readline (thisline[i], streams[i]); + } + + /* Keep count of number of files not at eof. */ + nleft = nfiles; + + while (nleft) + { + struct linebuffer *best = 0; + struct linebuffer *exch; + int bestfile = -1; + int i; + + /* Look at the next avail line of each file; choose the least one. */ + + for (i = 0; i < nfiles; i++) + { + if (thisline[i] && + (!best || + 0 < compare_general (best->buffer, thisline[i]->buffer, + (long) bestfile, (long) i, num_keyfields))) + { + best = thisline[i]; + bestfile = i; + } + } + + /* Output that line, unless it matches the previous one and we + don't want duplicates. */ + + if (!(prev_out && + !compare_general (prev_out->buffer, + best->buffer, 0L, 1L, num_keyfields - 1))) + indexify (best->buffer, ostream); + prev_out = best; + + /* Now make the line the previous of its file, and fetch a new + line from that file. */ + + exch = prevline[bestfile]; + prevline[bestfile] = thisline[bestfile]; + thisline[bestfile] = exch; + + while (1) + { + /* If the file has no more, mark it empty. */ + + if (feof (streams[bestfile])) + { + thisline[bestfile] = 0; + /* Update the number of files still not empty. */ + nleft--; + break; + } + readline (thisline[bestfile], streams[bestfile]); + if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) + break; + } + } + + finish_index (ostream); + + /* Free all storage and close all input streams. */ + + for (i = 0; i < nfiles; i++) + { + fclose (streams[i]); + free (lb1[i].buffer); + free (lb2[i].buffer); + } + free (file_lossage); + free (lb1); + free (lb2); + free (thisline); + free (prevline); + free (streams); + + if (outfile) + fclose (ostream); + + return lossage; +} + +/* Print error message and exit. */ + +void +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + exit (TI_FATAL_ERROR); +} + +/* Print error message. S1 is printf control string, S2 is arg for it. */ + +void +error (s1, s2) + char *s1, *s2; +{ + printf ("%s: ", program_name); + printf (s1, s2); + printf ("\n"); +} + +#if !defined (HAVE_STRERROR) +static char * +strerror (n) + int n; +{ + static char ebuf[40]; + + if (n < sys_nerr) + return sys_errlist[n]; + else + { + sprintf (ebuf, "Unknown error %d", n); + return ebuf; + } +} +#endif + +void +perror_with_name (name) + char *name; +{ + char *s; + + s = concat ("", strerror (errno), " for %s"); + error (s, name); +} + +void +pfatal_with_name (name) + char *name; +{ + char *s; + + s = concat ("", strerror (errno), " for %s"); + fatal (s, name); +} + +/* Return a newly-allocated string whose contents concatenate those of + S1, S2, S3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +/* Just like malloc, but kills the program in case of fatal error. */ +void * +xmalloc (nbytes) + int nbytes; +{ + void *temp = (void *) malloc (nbytes); + + if (nbytes && temp == (void *)NULL) + memory_error ("xmalloc", nbytes); + + return (temp); +} + +/* Like realloc (), but barfs if there isn't enough memory. */ +void * +xrealloc (pointer, nbytes) + void *pointer; + int nbytes; +{ + void *temp; + + if (!pointer) + temp = (void *)xmalloc (nbytes); + else + temp = (void *)realloc (pointer, nbytes); + + if (nbytes && !temp) + memory_error ("xrealloc", nbytes); + + return (temp); +} + +memory_error (callers_name, bytes_wanted) + char *callers_name; + int bytes_wanted; +{ + char printable_string[80]; + + sprintf (printable_string, + "Virtual memory exhausted in %s ()! Needed %d bytes.", + callers_name, bytes_wanted); + + error (printable_string, ""); + abort (); +} diff --git a/lib/glob/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 +#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 +# else +# include "ansi_stdlib.h" +# endif /* HAVE_STDLIB_H */ +# include +#endif + +#include + +#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) +# if !defined (HAVE_DIRENT_H) +# define HAVE_DIRENT_H +# endif /* !HAVE_DIRENT_H */ +#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ + +#if defined (HAVE_DIRENT_H) +# include +# if !defined (direct) +# define direct dirent +# endif /* !direct */ +# define D_NAMLEN(d) strlen ((d)->d_name) +#else /* !HAVE_DIRENT_H */ +# define D_NAMLEN(d) ((d)->d_namlen) +# if defined (USG) +# if defined (Xenix) +# include +# else /* !Xenix (but USG...) */ +# include "ndir.h" +# endif /* !Xenix */ +# else /* !USG */ +# include +# 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 +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if defined (USG) +# if !defined (isc386) +# include +# endif /* !isc386 */ +# if defined (RISC6000) +extern void bcopy (); +# else /* !RISC6000 */ +# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) +# endif /* !RISC6000 */ +#endif /* USG */ + +#include "fnmatch.h" + +/* If 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 +# 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 @@ +/* -- definitions for 4.2BSD-compatible directory access. + last edit: 09-Jul-1983 D A Gwyn. */ + +#if defined (VMS) +# if !defined (FAB$C_BID) +# include +# endif +# if !defined (NAM$C_BID) +# include +# endif +# if !defined (RMS$_SUC) +# include +# 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 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 +#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 +# if defined (_SC_PAGESIZE) +# define getpagesize() sysconf(_SC_PAGESIZE) +# endif /* _SC_PAGESIZE */ +#endif + +#if !defined (getpagesize) +# include +# if defined (PAGESIZE) +# define getpagesize() PAGESIZE +# else /* !PAGESIZE */ +# if defined (EXEC_PAGESIZE) +# define getpagesize() EXEC_PAGESIZE +# else /* !EXEC_PAGESIZE */ +# if defined (NBPG) +# if !defined (CLSIZE) +# define CLSIZE 1 +# endif /* !CLSIZE */ +# define getpagesize() (NBPG * CLSIZE) +# else /* !NBPG */ +# if defined (NBPC) +# define getpagesize() NBPC +# endif /* NBPC */ +# endif /* !NBPG */ +# endif /* !EXEC_PAGESIZE */ +# endif /* !PAGESIZE */ +#endif /* !getpagesize */ + +#if !defined (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 +#include + +#if !defined (USG) && !defined (USGr4) +# ifndef SIGTSTP +# ifndef USG +# define USG +# endif /* !USG */ +# else /* SIGTSTP */ +# ifdef SIGIO +# define BSD4_2 +# endif /* SIGIO */ +# endif /* SIGTSTP */ +#endif /* !USG && !USGr4 */ + +#ifndef BSD4_2 + /* Define getpagesize () if the system does not. */ +# include "getpagesize.h" +#endif + +#if defined (HAVE_RESOURCE) +# include +# include +#endif /* HAVE_RESOURCE */ + +/* Check for the needed symbols. If they aren't present, this + system's 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 +# 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 , + + 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 + +#if defined (HAVE_STDLIB_H) +# include +#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 +#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 +#endif + +#undef cfree + +#ifdef _LIBC + +#include +#include + +function_alias(cfree, free, void, (ptr), + DEFUN(cfree, (ptr), PTR ptr)) + +#else + +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +#endif diff --git a/lib/malloclib/free.c b/lib/malloclib/free.c 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 +#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 +# if defined (_SC_PAGESIZE) +# define getpagesize() sysconf(_SC_PAGESIZE) +# endif /* _SC_PAGESIZE */ +#endif + +#if !defined (HAVE_GETPAGESIZE) +# include +# if defined (PAGESIZE) +# define getpagesize() PAGESIZE +# else /* !PAGESIZE */ +# if defined (EXEC_PAGESIZE) +# define getpagesize() EXEC_PAGESIZE +# else /* !EXEC_PAGESIZE */ +# if defined (NBPG) +# if !defined (CLSIZE) +# define CLSIZE 1 +# endif /* !CLSIZE */ +# define getpagesize() (NBPG * CLSIZE) +# else /* !NBPG */ +# if defined (NBPC) +# define getpagesize() NBPC +# endif /* NBPC */ +# endif /* !NBPG */ +# endif /* !EXEC_PAGESIZE */ +# endif /* !PAGESIZE */ +#endif /* !getpagesize */ + +#if !defined (HAVE_GETPAGESIZE) && !defined (getpagesize) +# define getpagesize() 4096 /* Just punt and use reasonable value */ +#endif /* !HAVE_GETPAGESIZE && !getpagesize */ diff --git a/lib/malloclib/i386-alloca.s b/lib/malloclib/i386-alloca.s 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 +#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 tries to typedef them on some systems. */ +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef __STDC__ +#include +#else +#undef size_t +#define size_t unsigned int +#undef ptrdiff_t +#define ptrdiff_t int +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((size_t __nmemb, size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +extern __ptr_t memalign __P ((size_t __alignment, size_t __size)); + +/* Allocate SIZE bytes on a page boundary. */ +extern __ptr_t valloc __P ((size_t __size)); + + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG) +#include +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#ifndef memmove +#define memmove(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + + +#if defined(__GNU_LIBRARY__) || defined(__STDC__) +#include +#else +#define CHAR_BIT 8 +#endif + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large block, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + size_t nfree; /* Free fragments in a fragmented block. */ + size_t first; /* First free fragment of the block. */ + } frag; + /* Size (in blocks) of a large cluster. */ + size_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern size_t _heapindex; + +/* Limit of valid info table indices. */ +extern size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Count of blocks for each fragment size. */ +extern int _fragblocks[]; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern size_t _chunks_used; +extern size_t _bytes_used; +extern size_t _chunks_free; +extern size_t _bytes_free; + +/* Internal version of `free' used in `morecore' (malloc.c). */ +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; + +/* Hooks for debugging versions. */ +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); + +/* Activate a standard collection of debugging hooks. */ +extern int mcheck __P ((void (*__bfunc) __P ((char *)), + void (*__afunc) __P ((void)))); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((__const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ diff --git a/lib/malloclib/mcheck.c b/lib/malloclib/mcheck.c 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 +#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 +#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 +#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 +#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 +#endif + +/* Don't #include because did it for us. */ + +#ifndef __GNU_LIBRARY__ +extern char *getenv (); +#else +#include +#endif + +static FILE *mallstream; +static char mallenv[]= "MALLOC_TRACE"; +static char mallbuf[BUFSIZ]; /* Buffer for the output. */ + +/* Address to breakpoint on accesses to... */ +__ptr_t mallwatch; + +/* Old hook values. */ +static void (*tr_old_free_hook) __P ((__ptr_t ptr)); +static __ptr_t (*tr_old_malloc_hook) __P ((size_t size)); +static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, size_t size)); + +/* This function is called when the block being alloc'd, realloc'd, or + freed has an address matching the variable "mallwatch". In a debugger, + set "mallwatch" to the address of interest, then put a breakpoint on + tr_break. */ + +void tr_break __P ((void)); +void +tr_break () +{ +} + +static void tr_freehook __P ((__ptr_t)); +static void +tr_freehook (ptr) + __ptr_t ptr; +{ + fprintf (mallstream, "- %p\n", ptr); /* Be sure to print it first. */ + if (ptr == mallwatch) + tr_break (); + __free_hook = tr_old_free_hook; + free (ptr); + __free_hook = tr_freehook; +} + +static __ptr_t tr_mallochook __P ((size_t)); +static __ptr_t +tr_mallochook (size) + size_t size; +{ + __ptr_t hdr; + + __malloc_hook = tr_old_malloc_hook; + hdr = (__ptr_t) malloc (size); + __malloc_hook = tr_mallochook; + + /* We could be printing a NULL here; that's OK. */ + fprintf (mallstream, "+ %p %x\n", hdr, size); + + if (hdr == mallwatch) + tr_break (); + + return hdr; +} + +static __ptr_t tr_reallochook __P ((__ptr_t, size_t)); +static __ptr_t +tr_reallochook (ptr, size) + __ptr_t ptr; + size_t size; +{ + __ptr_t hdr; + + if (ptr == mallwatch) + tr_break (); + + __free_hook = tr_old_free_hook; + __malloc_hook = tr_old_malloc_hook; + __realloc_hook = tr_old_realloc_hook; + hdr = (__ptr_t) realloc (ptr, size); + __free_hook = tr_freehook; + __malloc_hook = tr_mallochook; + __realloc_hook = tr_reallochook; + if (hdr == NULL) + /* Failed realloc. */ + fprintf (mallstream, "! %p %x\n", ptr, size); + else + fprintf (mallstream, "< %p\n> %p %x\n", ptr, hdr, size); + + if (hdr == mallwatch) + tr_break (); + + return hdr; +} + +/* We enable tracing if either the environment variable MALLOC_TRACE + is set, or if the variable mallwatch has been patched to an address + that the debugging user wants us to stop on. When patching mallwatch, + don't forget to set a breakpoint on tr_break! */ + +void +mtrace () +{ + char *mallfile; + + mallfile = getenv (mallenv); + if (mallfile != NULL || mallwatch != NULL) + { + mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w"); + if (mallstream != NULL) + { + /* Be sure it doesn't malloc its buffer! */ + setbuf (mallstream, mallbuf); + fprintf (mallstream, "= Start\n"); + tr_old_free_hook = __free_hook; + __free_hook = tr_freehook; + tr_old_malloc_hook = __malloc_hook; + __malloc_hook = tr_mallochook; + tr_old_realloc_hook = __realloc_hook; + __realloc_hook = tr_reallochook; + } + } +} diff --git a/lib/malloclib/realloc.c b/lib/malloclib/realloc.c 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 +#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 +#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 , + + 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 + +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 + +/* 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 +# else /* !IBMESA */ +# include +# endif /* !IBMESA */ +# else +extern char *alloca (); +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/lib/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 . + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include + +#if defined (isc386) +# if !defined (S_IFDIR) +# define S_IFDIR 0040000 +# endif /* !S_IFDIR */ +# if !defined (S_IFMT) +# define S_IFMT 0170000 +# endif /* !S_IFMT */ +#endif /* isc386 */ + +/* This text is taken directly from the Cadmus I was trying to + compile on: + the following MACROs are defined for X/OPEN compatibility + however, is the param correct ?? + #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) + + Well, the answer is no. Thus... */ +#if defined (BrainDeath) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 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 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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + 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. + + , 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 is not present +HAVE_UNISTD_H exists +HAVE_STDLIB_H exists +HAVE_VARARGS_H exists and is usable +HAVE_STRING_H exists +HAVE_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 exists and is usable +HAVE_SYS_PTEM_H exists +HAVE_SYS_PTE_H exists +HAVE_SYS_STREAM_H exists + +System-specific options: + +GWINSZ_IN_SYS_IOCTL need to include for TIOCGWINSZ +HAVE_GETPW_DECLS the getpw* functions are declared in 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 +#include +#include +#if !defined (NO_SYS_FILE) +# include +#endif /* !NO_SYS_FILE */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* 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 + +#if defined (HAVE_STRING_H) +# include +#else +# include +#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 +#include +#include +#if !defined (NO_SYS_FILE) +# include +#endif /* !NO_SYS_FILE */ + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include +#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/te. 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 +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "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 new file mode 100644 index 0000000000000000000000000000000000000000..60d737631f82fc45543c090f71b03cee5aff37e1 GIT binary patch literal 47376 zcmeHw4SZZxweKV|p=l`!_|4^kZK1R!Ni#`XXiI@oQd(#b`T-~)OfqMZW9K8xnQ0RR zuRlS(3d!y1d5j|kQk08UD?ZVyJ`@zh>*YOss8`X;yE7P6K&ztU-X9-c<^BI_?|tUX zWReEZca^3;?=77nG`S;wi@O&wR}O{djCY3SV3elbR5sdP>WbSrJCiPi??`mC zwYPYQOx7FkeC(H}4f;=FzFaQaUapzPD_!Ki_(sdhI(Xm1%WWg0M}$JdyBj{af5*A` zkyw$mo%nYhAyU4t|aZ(G{lQ6#mwB6!sN&_f>%H7XvBjJ`P(x`C3y2h;kqq*_uB{`R}WrLFz8 zQwV?Mf_Ubp?s9KFWujV>mD7^=8rzq;92)xslsn3r6IzOv=zs<0-5> z5$m-?mRYMemP~Rm{6D;#Nnj{zhn>kg$srG{7}(Waw&I?hhVr(J?3;(dF39&JZKvOg zbHpADhzCLXdQxe`QruaDP}FA?q1-mS;*{lk@K$%sabmqU-Zih^18KROQ(U{lv(jGP zY8kn0cwH<7-t=Vcc%Rk6NxIj1?H$q1mEN{3Ye()Fz5sJt*_7>2wF-?de8_e@Fa@gx zrMZlkifu1iUMwB=;@|?fo6lJuh1&z&NP#;8wpwZqGQrd7Vm_863yWkRhQMm@P;n@0 z_w|E?w+*K=IlI>)DI8T^6UG=KJoNw-k^G}lVFefpst^9^DcdH{9=`1P8ro&vTG~?? zNFi>|#ehmjAzzBBihiiRmDRMTmDxHV9Tr;%hu*hCc;+*pI0TtPrRLokTs9PmYp34W zSP2%APv)o`7@5`)_jVRD+3g-^u5dQ)Rc3~2r8sFOA-wYHG6_5u-M6876ql?bleQ+Z zC-Q~gOou%=$lghc-A`nTjm2cZ&OFwFt`(%Y@UUTc7C6W)Q^0qB`lO`{d57+xCkVC0^Yi$O^-xhlA}kr1bq^ms!>&{h=7@~x;1fO*Pqjvro^8Njomqh4+pf84`9fAp=Nd4KQ7 z$O!+10mfI&o8NL%5UHJ^X#3BPz!M|x(PuW4qAO2bDHaAGj(Y3&1S}Y13$Rj<0bp(M zHl};qMk<&%E$;;&{efWO@Nj8ee{2AH!f~Uk+(@ak&7q1J$lI94%=kXmo3kN{Y3KSm zsu9-ZE#3f($y*NJ-T`(FALxpU)Ha~7i(|;R?b)=Va0NJz?0YR=eFXtL?)R8C#Z@!YtVPhN(DHsGXw$01}RAGWzzOQ9UnI~tZjhjfDKtLPX4DC~W+~d^`7BrIqVuvKtIwAPl^rs;;P9YAD0Rz!5EpDEf-F@_*K0dPw9 zT5z%WXKyBjU@BfDtI4QbcBn{HgbULOiLV@lk)sQayaO((JP&SY<#)$RTXInOLU{NM zF<%3M+6hOy8+Id(c4t2Z7Fz{TJ3R}Ia`+8&l(C{S05gI&+kIj#*3&}G0TJWJmy>EHOBw9z|KhSlWNKwcf)t0Q16F+ADD#(8X9UCfsgjVU(Nht1}hf zPGx`~2=w)i!wd#b1hWPZ2&#{%AwbK%qad8}yfgF%mzK{cT|P3(T?7{rTu1fbw0@sb zpa{UyPILUq(26AsG@V=fC8D+jHyCdk%9N@4dk@%5B9qa6klvfoZO-Gj;3myksH)G$!eh=7pf`Nubct+BMkE}4{_BgWd?rodw346O*!f`tqh^C?b=Fo}=)G~y$SDk>;@ zCFOn~@18SdB9H}9(!Y|u8uz^(f;BY(yA%Mf!rqwI?k#$^mCY;$c%2Zso2K0k_9oPa z)e2p1FCk3Q;|WxlNR3;~A%^)$?0v+g5~hG5_#c^M41l{V!1(QNP%{}=&;|p<;P?jY z#i-s{O@agsv1}jH47AJD7#_NBBfOKby{JZx6RO`6!_ejc=kQ*tyw-oE?VKzdP zv)s;4L%)5q!OJCPlw`6H{Rg`&cE2<@6Iewqyi;3<5t>88A&ttP**T?4z6UvmIGS_NG=$c4mxkdo2?U z0VP&J5sWeRYesCgQvN0$$r=yaYa8yQ&l`y4`qK>3U}GxkQ$hUCKGFQ_!Nzs+uNkZ?B%AWCEVq?T8so=cI>v?>$>QJ&AoHE8uRsb({n zI~q=<>@3YB<4f`QQU;F_)EOTPFaNb)kKrpf^4X>mGsqlSAc~Q3ui7an^%%n_Zsg=M zN@5PM7ZZE#!5EASV4(A^TAN0|7q^nw_(3a+sTlq#xUJ{r7Ol|u)59=`+FL=>%J9W* zw=9NX-!RRfH{;C}e~$yrjf!g^(Wpm*Z480CfhBlN4reaXZpZ4scB^ zc_VfkEzg!0dL=+SM~r1O9^+awFOyJv_agI$vGKm`^Vn3Zn)*g6NZOdgi1*G zFPtkcR8Mmyb76&gc7IWn9gxL0Qh=12muy#|4@BG#pN~xtw*LekZa6QB` zrT_$hwyPH)v_L3`^2>Doy!rQrMa!lU3i@@5rs<3w3LSHt89g9?4#~+)mG#*jdf}2c zEwAPNQyomb1>S?Ybj#8M2_tZz_2P0c?Y8LW2TQxDyqZ)jkin586@&&)DPCr077(CV zOf8m_*P?IL#L5g95l+#$FvoW96DBDlW?z+M%UMECT9VTy*LKq7CW5QUwJF01Rl?SN|R3WCgeUZ7Y8UgwkVKx#jT5&W9v{kHkDXI zvdrm>=S4Tka%@@ktW32Xz+yO18}7=T zHTb!$n!Azf9K&6cumjk{dXfyLk^YG+_`QT3)&RX1AX0h94EVxPnFd*RWz2B|`We|F zitn-UC`y#5-NlqF;q!HVOFa)5MxrWdznehir`IHdglP>Tk-0L7vRUQm9lAvNF@zqD zNyuR}g~+jP5na9@m{4VTHadI=2&j%@j}R?12#7bJn5A_8C$ z19kn#d7uDW2tNekoLtME@DHB|Fo5LMV}X)F3z94dh;$I4#`UEo!xbgECZcnsTt9L~ zef^XLmw5Eud`4*0QiZm2N1*rS2yiQNOWsq3rr>((!*qUGo#GKHxqBfAWG_`;#*W*F z%W^8=P1mszm5t#LB0s4d10{FAzLM4%tE4|mhJ_5CC-7HiI3XY@$|*KiRW@mASx`dj zBRXK}SZ_AtpvrnjB5ohf%oIZzKeb&Y`_-G|btQG*B#0&`n^y3oo-T0Z;!4uiT*TA~ zScyOg3$8LDM+P;)VrwD%{@ntGjE3cr>BYL(a}s>HIAC!#>+qcM+B zb7e?UBoz8Z*hn~r@4rADo9oIqO8GhQmeuk|w4fNDJD_iRN33bd8bok^l z_(r>sqG=_g&Uge+%V_B8_mf!xE8|81WkuM)bw9;7OcsD!qD-3sN1|N8qIZ#cK;4F* zk!r^4o|8couWgFOTYG>R87AW4ok^97s^V56hU#UDu!$y2N}!c+=&`smWu~aq)>AKE zDYr$}T=S4Z?xkqZ=HH&lsTP^)QOSruYJe&%b28(EZ~B{#6P`r{#5 zL)_{`L4%Z1Bcv|jtQr|Tj%a@DQ`^e9p#f}!5{0I(e;Vcr?DwwV*jHF-q+GrCjNFbs zkYRUG-@aZ%c`lw>LdLEJo2ot}+{%X-^BO+3VdIvqS9G1fb@SU-Pr0%jQuqlkh3dHI zJ2(rN;Eqm3SOM|_AJ${LsWvkS*=Y^_x-7&!>7o1vrly6OvR&OH5-72mXJxJNT7n zKu2W+Cz-+PC>N0`#cD~a)ggq6kx0h+oC#|Gw#{$9V$0UGTf2PCCw{3-@DX^ygM)|o zC09wWqrs@WVGCZ{xPDXD*$DQjMMjQ<9AqHjOi*Pz!a_n}v@83(3g0?w;AFjv-Xs%H z1VDuyLwA7rYU2U$W2+EjR;@?6b;r-In7y@vw=BDO0)YzL2htB>v5-|DDp%q0=vpDK zyQ8gBm4`N_frBx`TmVDR;aAfc7HkpKMN|nCWGho)ELTl;WZ{E#>GqfDn+1vlY8t>Z zMh2o2l*!5}`>3%_70t66L>8%1HgcP60-|mkr(&d0nHEdu#vyCG5(*wI3%4MlySrg@ z?^h+x*OC|+89z-r-Pl#fo;cm<_T-L?jU>g#isP$~d1n4aQe4wtqw%i&3GvCpZs=eB zxvHY+MB5)Vg@sORMpmCVkCvBqTE$# zqtY6N^|B9S>9LNmeX&ll5a3`f#r0RMbXP5;T*WLhd5MttxG(K3Xj8<;6LemWt>Wxh zZ!f9>vfd19YQVaxl)|j(`PT(U8UOmyH~pv7Zu$=hT1e4pgYupPicR=WuLc`N=Y`(w zyIv+|Ufdf{TxIh%TCNaGvKdd|6djkzPX&2_-N_rCMrMVfG;3EWHbzJ%Ukql$O^~JV zfo`7+wXWwZsC&)>Fb6VzZb zoeo3;%1F7Jyz!PYI;#%4NVtFUj-b0|Fu&~VL&Zzt zj^vALSVIWY#MgX7J-wxjpj%ryBPPSL7LQuuN$9Qqo6G44g_cmX6^3@JHlRY|Z$8Q; zRXB=GLOp)=qg;Vb!ZEJh4PSq&%29JnriJ$w1@9FHRhWSEGU$}i9HTeNVHUz~zM1?) zGpE!^a!e~~dsJwU>J8tD9k~VVVO3F-zE_)6&8LFdKlEKu@JSfh| z1z|ku6A~-cFnOZ+Y0XT<1}kjb!YIq2s9_@QzlBO>rQkQkF-m^MFZD<|d<+A*k-l%0 z{EgY9_QaWCNKfR`)1tJ3@VU%DAv{0Mw=_Z-No#xfylN;33eMl}$5QA6V%A1vVHSsI zhy8>ST)Gjy&m0KD2Q8nx@B{Xwgo`jsnvP6KzRox;NF4NGBTWTUWdlx$q>eH zM2}V@JDQH|)O@IkuIuI{;zc`6E356bloI`9y)B;kT2(est3`a>5n0bVCIeWhV{WWu z3h9>C_MohZV;I834bTjAD#AhJI>9^Lk*IhlB@*a;CGQxcDw&}w4J?MER6Az=0}f3- zI=Ft-;Ps?Y6>UPCTisBpY3^HmTZCs!+34#6#0GN_5|pUDzE{#v4ffLZ{m#8Qv6IrT zF4?m&*rLI;E3byPWs!OmF*bN(zyCrK$>^KfD7$S{Gf!uNRzOQ-HC(|+RdCZhz2Iia zRVKJOb^6JJ`q7}#Yiu#H2lbVURk$Ic`({~#=rOseyrE7pDAtN48(mTR-y-yP--%Bi zm?Su(aJE6pR0ic`GR~-TeSQ(9bD3N$S;I%{C2uJYp*5^7Ru{sL z{*DBi7A$5a&^Gz#@1X6HgjGFdI{Y2T+9?)!Dw?OVpnxUj$lw(b3BTtW311BOYR)ND z@lDD>zn3;B#S`gF<~bWu!??)r%hi+V49C)kA2AMMnQn9`jP1b8;vOXBCPQqfbq>g; zBBMVb&}FiORCb+m5&=iwSl>pTp&rR&Xah&lTXNbxP9`bsA81bI zGHEetpzH7@Cc>$qeR2>xOL~E}7sAia%A>#-)ryCDCb%ZmW@EiNT$|v>{FwqX{E09wjrz~DIn-_XpCaFGuJEVI zTi8vAj3euvG+a_NwZ%66_D+K+Dp4#JtGf~zj%zeADkNsgWU3I!Bt&pyi7XTs zE^V=hN4cTEDsMYi=qmQJ8b!(?hu>-re#zMj9t>jyi9oEUh|_2+%CdisA|QXIpGZl> z-!l7vVkirEq&D}kBR;qlYuD?*w5pqlDyslyES3hipfD4M;ifFq$|O0W0a=mmrHXk( ztE!ii+jp{aLhy#q3<(v%1shssPcK00Jl_OpFFpITvNrovH;Xs5qa(5izu?#Ub$GyS zI(dey9A()8KtrP&%9N6J2VP3!h{SdxV#ut&5c$Y|Bclvcs4P0=gAgI|%{hLEpgB50 zl46ADtoU#vf`u`EIPG(N1B^HlJY`Zn0Xt+>O z4Un;lC*4Gw{Ozd5Ls)<;!E9HB6^I+QY1cy!ZcNg^E^^<98Y`6luT)9)zd}0#hoR5B z4HRd0+73@jKY1a~ds5pmk@2r)g&>RKj(M$7eyxHFy5D`R*E}#u06w)=F?{m1ss^bk zqPc_9RW*gHrHY<4UGf1+!f?1+&zin9ce;8u``=e@HA;le8r#tj4un7hyWBwgZL|kJnRSH*)SGkglQ$;ZAT~t-yuw{%ZrCld8s~ zFGP6foGG;Ux1B*PzIjhYi}|8It1&vgR?Wmh8wURA0nU9qBZdOGP_kjPHDxH#BEoqHuAAKf5eY=XiC1HY-kO<`S4RLEfoagFz1 z7Em`gd{@qNsF9Qwkh4i(*q`>0YLIaUM6)394;{K@H* zs?JA2F=*GbenMj~%7nfW_~Bm5!cmY~@99&)mw*Kd8pP)^=m8S$`L5ak8cV=40t?j? z*F*+tw=RfS14uZnPyr;_*#TbsiCO&}!XY!2omwHA4;DRWXf+|sdK;~DI3l z5WaML19%d!7*=cl1DJVHCOglepyzSXD*^JWkEkq zA}=U@smBsYD@|M+?x1@W(pICH6TB184Sar25ESwc?URi$c(l*WC z(n(-rsigG=XM*em+-q;IubM6qabi;d)kD_(e~X9y>EL0-5Q+CfWRhw zmrrd6e7&-^30(vdUY12x;$Jy>$ByelY!9#;VP#VKthQcp?UNzctdTNXL z&TYE*)50Je>cM3&D50@9?=~Of1>~dI4G|S0uiKu2qLfRJ6)fs$!LXlQ|d1jlAWlQjLp}&1+By2gho?;2PQ`DVRkw4APM` zU(usX4Mb@Hn95?dlKpxxu0JR>4Cbo^HmZR`Q#ExuHK;6FhKE;ezv5BjRZpQ;)fNKT zb$6K?Bc#4Fc?!=?4M;shv{){MXvNVvRKScz`#sAqmy>jSGDy6ZX=cl*O2tdmC1Dk= z$r9p)$lh<7aJywsmj@X=>s8btqcI}Qw8^glPCz*A^yxEc88 z^9`8IU?a0#AIHK~2RJ8qi4A<@5=6@WQ5~8iKb2Ny390Ze5{R+mR;!%2vJ#Xhk?&0H&Z`#D+zj6=gYDF(^f>??d=F z1*XcDk9PyU~B;!GyfC_&vSw7ht(^Ii_c5{pQmmB{07Z{tFtG6^pF(rTf zErHClY;kxxSy00q;qz0pRu-fF;OVsxg4x>y($fe(cRe?zR_aDJ{b!|hg_tEH>Qn)1 zIdCNAD!{|15yjz=4R17o+`7uOSJOFS_wVIvqClLgORs2}hI5exPor!P3@U^>e^j6E z_@egy26ZI@4<3B^vtw5&$j!RpKZM9=9AiNxN+Bjz4l(gVIemZztx6VD6-5|Wb6)?1 zE-}aFy6z8$+H*f4btTQt%hJ58DmfoYqZ$)vR6(#t*Xh2+5C3YCfXi3;DO)3QneE7o zSZVZ&2UMH^olf%Bs&XOn)*k@xf*leV1NXHzWRJh%SvS=%;6p;p7Rz zWi>767qJCBhPyV|_sf9k>E})Qp>7vCOB!m~fL&ar2|XF|cG!;1!*ME6rU#=(vy0L2QiJ^ruvmT9Y-XXB>X^**$vI9{ z@Y2XF2hUBa&jcF=wPcI?3W!kk=l~hKK&h%e&ijZ6y-af!Rf5vP>A9kV?2Z+$e_xVH zBTUW|^sm)0gy1jjJ2jshcn(llXngo+3}8!|H|60nOmmWv`feCw>I;C5!kZ+Ir0Pa0 zTrnwjRmb%oJpF2 zIOi`)Sq;|2>zsHmfSeg4?p;})hiuQJnlKG=<*?i|NNs%n)QP0B$+Af3K!C@~V5)9w zV|q#I9wud?@+Xj%%6MTtw=W2+M>EED2nbi=cAZzYFdmjeS!QDIk@6o#3}?$VbA`so z-VO{zR7ffkqW)w9CQ2uq^=yD_jvf4R|D3o-jiO08XM;fmgJ|^^Aa^ zLS*YXa&UkHUaJU3DZ|L&w9N(8?%F$RN7v380vVDRFK zE1vku@*0}S=z9A)ny!6MwR%x}ltaSWe+hef4wds3F2t&ZmUDmp4?@dD@#nE@ zwKQ-a|LrZ(v*9cA;-&l?17Gf~S>v5_S^6XyBlffI9KYe)>Pvjrev&K#<6kqfPdJG6 z*a^i7e{M|GJ1`_vsWr^UEpj za`n{!NZub!K6aQw=g&J98n|5d z(sx~*fnC=ZdA1nKD`OW^rT;;)l_B6MNIG3DYX7l1n(MQFGG5f`m8cN4DK%h(sa1(A zZa11k8&nDq6;*+Xv69Y@;B;YRRRcJ&9oGECRRc&`y=t|_Zm(dHx?;Lh49j$S&9IVT z*E%Vpf9a#rr__up3I*P0abVKHMuf|(v>AF!YDv~`D;o2bBUhLE%6g>~ux7U=6P{a?ls|8@6cpTjV$>ENg%TSu1Gt zaSXLko?a{iM$NKiK&-36aB@M8oDYE$JlwUz-vxM!)DSWwUNS%_mlnu~gOC45UDP>0 z!zyb((l+eNJ~1vBR6Q8kL5G4NNYw7obv+v^cE$Gse5~`W;xFF5hNB4T;BV-a85kd# z)z+nvM^@4(re|@(22y}tpS=Tqgrz7Y4R{i5IA(AoOt?y!6fQgnb+4HY(1k)*Y%@?7 z#T8KpjSPJxMLY9!{>0BT!~4}JdytXS+Ew1VOj@qw-N-cI?uK>ut&T1aV5eNu{uEww zLmyd#Y>~Xzy_UB`RlNy#&tHanjYj_oG01_gwIjFlr#r?QGGDy@+ab0U^8X_EIg*w8 z*{pQ$N@-Sd!*AFseIQ={uJ`;Bap1SMjn7*C{H^o-SMUoaDSPEzt40cuV+Z7cRU^1R z0}sypUCRe|)@T1=|EVLR$A}2JU<3P+*SmKmRhXPcCf{5R?KX^EBwU=~Y&}hKXTR>q z{Ycy@b>1EN_m9u@gMeLEerJYre>NL*XYKwwaDMby=&>6yC5y{IIi92iGSIKhtD#h{*2(+**CuB$q>n@-*vMFxpv1K!Co|MgQ^N~*jeeuV4 z&v1d$`4b;C?m3FvlBVzdkDAWlp-}R4GklHrKWmlxu^4?*iqtMHLSLnn4?G7!csMy<+D~F&OG#4c}ytu=kIH;-XBHaNJ|JpRXbWMhS5Fx!lSJu~~z* zxhEho)VnOy_`~~0+;GC&>ftsl`tgh|PO6Kwk-=pDcAMYf?LS4C{)4fB0oD368P6MM z@0#KHq&#ow0&gXaiZJn5Pm(VDnmT>H5pGE{_}wuo=(Bjw!a0Y-hmy(IpnA6 zj|lRzP{D*6E~BQ6t)|=X?WHpe9&wwW`z4i=oZLW8>Nu)~XXK{p$qDipnL^c*)39Xr zA;?R&`O*i-yW1HcO~N?3CYG+kVTXEmxF!oHg|t}KRRTlR7h2+tOZfIm&c9d zE;$6)?KbcF`jl*<`pE`0?#?*rdK-G9h{j1zsc`;QzXlzZ%7uT_@hVg~ch>mF4yt0j zjAJJ7o=U%ro*nFO3A|688uum!JEp!+tC#2;$yvMBeCbuBm+q|0Rr^;=%^=&E$Ov{U z#odOxdtXJoIG8d`_PyKutK+b{n-uHlHBb%5={y|YS~bJ4$+sc1{>N$s-Ovp`Jp_2@&bs$jN#e6P zO89l4t9xW0o75Ed)ak1rd#HQn^i}Y4lZA1^7yj!Zz`4n6*nE!I`AoGr)@(f=RVKw# zedT44dBGa~%x3wOq!MMbO!uwXeu2++a}^tub28R9+!>uw-3fULxB0PORRHxs*Jhuk zYPjA;UOI3<*kGGjY9mYeCTIrnri6m7(egJV|||py(W>6 zA6&(6v8L>3$AR;3zVEOL50^(o$?@o4@89m+JvSZbijM3%`Wv{9;RO8T3@&GM=Zr7+ z57yLP%;+|(#1Bu0eo-7>dHCL*(}O=L3;wkKjK?2K|5u(+81ReY%-{4e|3CPEpWppd z3At(F0sGF@Vt{e@8;E^as{d5HYR>M!{=Ab=T{0{?wkXQ zAg57v)To0_IB=5@UGYvEzfBalgUD@c#H~YctAC-s);;3xH3zzuBkUK4*`W|tU0*Ce z5E0MI6~?@^0QWIyPr7Tz*Jrfx&#sMb^9#?GmJ<~a%XG8}4hKS+EjTQU+koB11+SeE z#-CjnFBdx8IiFk~5TXEkK#1#kai>1Ji;lK?zCR<%zZg-vbIzJwVlOAAE6UfqC3wdVyuXQitHh=n` ztJc0u$D?=6+o9EdZT%m7-Ia6xiq}1v4&fN@XG*O38(mmVeyB@2@MB+^CA@wzr~__j zPwG|3jLDcZ+2`);<8QBG-U?Bs$`5$SeXxdc>(LvvtD}2{Zzw5$=>sJ;b{nNTg?!U| z;y%2~+^*|3JTenEy!6DJJLl5bB^)pZhb6!kkPGlPc!|2RYr~NP3GB)}eZR09da^hp!AT|P&ffmr63#g3+y<{Kayr$;gH4IVTBbUxE*^9n zF96{G1aWB1?;l5_p3n(Hi$B#ImicrIbv&aTqw{(a9V<`MRiJH5c+|UD``*U)} zoqP40Kp`%NQWsvK_VmYT7N71iwJqD;-O%6q01{QfElkZ1H}Cv;fojpN(yf8_kVq1S)yU8bzmGZ^g{@0L%GSn#8&PwSST#=GR% zKw(NoSRFtqTr_(p?!SSy!kCR1q(XP z5I(J2<{3XFwcwu3RnIzjcE!M*?dMi~n#8A_Lc^T#&QOqsj`MzZ<&gg@Zqmx)(R$Zw U)xBo3-gTYNgYP4akKxb%0}JD;&|$', 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 DI<03F80FFC1C1C380870006000E000E0 +00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 +000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 +700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF +FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF +FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 +1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 +1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> +II<03 +0007800780030000000000000000007F807F800380038003800380038003800380038003800380 +03800380FFFCFFFC0E187D9714>I107 DIII<07C01FF03C78701C701CE00EE00EE00EE0 +0EE00EE00E701C783C3C781FF007C00F107E8F14>II +114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F +14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E +070C03FC00F00F157F9414>IIII<7E3F007E3F001E38000E780007700007E0 +0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>II< +3FFF7FFF700E701C7038007000E001C0038007000E001C0738077007FFFFFFFF10107F8F14>I +E /Fd 1 59 df<60F0F06004047D830B>58 D E /Fe 25 122 df<078018603030303060186018 +E01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01C6018601870383030186007800E187E +9713>48 D<03000700FF0007000700070007000700070007000700070007000700070007000700 +070007000700070007000700FFF00C187D9713>I<0F80106020304038803CC01CE01C401C003C +003800380070006000C001800100020004040804100430083FF87FF8FFF80E187E9713>I<01E0 +06100C1818383038300070006000E000E7C0E860F030F018E018E01CE01CE01C601C601C701830 +183030186007C00E187E9713>54 D<40007FFE7FFC7FFC40088010801080200040004000800180 +01800100030003000300030007000700070007000700070002000F197E9813>I<078018603030 +201860186018601870103C303E600F8007C019F030F86038401CC00CC00CC00CC00C6008201018 +600FC00E187E9713>I<07801860303070306018E018E018E01CE01CE01C601C603C303C185C0F +9C001C00180018003870307060604021801F000E187E9713>I72 +D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 +80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 +707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 +E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 +000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 +E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 +600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 +703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 +E010187F8F13>103 DI<18003C003C001800000000000000000000000000FC00 +1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I110 D<07E01C38300C700E6006E007E007E007E007E007E00760 +06700E381C1C3807E010107F8F13>II114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 +30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C +001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I118 D120 DI E /Ff 2 42 +df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 +00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 +1E000E0007000780038001C000E000700C2E7EA112>40 DI E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F +C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 +7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F +C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 +001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD +F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F +F87F8007E03F8019167E951C>97 DI<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 +FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> +I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 +3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C +003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 +7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 +C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 +003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F +01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 +0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF +807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF +E0001A217F951D>103 DI<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 +0F>I107 +DI< +FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F +801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>II< +00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F +FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>II114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE +003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 +7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF +FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F +C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>IIIIII<7FFFE07FFFE0780FC0701FC0601F80E03F00 +C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 +7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 +F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 +00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 +EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 +FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 +D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 +000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 +0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D +72 DI78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 +7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 +3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 +F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 +0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 +0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A +>I89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A +>95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 +700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 +D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 +007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 +D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F +C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 +C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I +104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 +7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I110 D<01F00007FC001FFF003E0F803C07807803C07001 +C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC +0001F00013157D941A>I114 D<00C00001C00001C00001C00001C00001C00001C0007FFFE0FFFFE0FFFFE001C00001 +C00001C00001C00001C00001C00001C00001C00001C00001C00001C07001C07001C07001C07000 +E0E000FFE0007FC0001F00141C7F9B1A>116 D<7FC7FCFFC7FE7FC7FC0E00E00E00E00F01E007 +01C00701C00783C003838003838003838001C70001C70001C70000EE0000EE0000EE00007C0000 +7C0000380017157F941A>118 D E /Fi 41 123 df<0003FC00003FFE00007E070001F80F8003 +F01F8003E01F8007E01F8007E01F8007E01F8007E0060007E0000007E0000007E0000007E0FFC0 +FFFFFFC0FFFFFFC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00F +C007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E0 +0FC007E00FC007E00FC07FFC7FFC7FFC7FFC1E267FA522>12 D<3C7EFFFFFFFF7E3C08087C8711 +>46 D<001C00003C0000FC00FFFC00FFFC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 +00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 +00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC007FFFFC7FFFFC16237CA21F>49 +D<01FF0007FFC01E07F03803F86001FC7C00FEFE00FEFE00FFFE007FFE007F7C007F3800FF0000 +FF0000FE0000FE0001FC0001F80003F00007E0000780000F00001E00003C0000700000E00301C0 +030380070700060600060FFFFE1FFFFE3FFFFE7FFFFCFFFFFCFFFFFC18237DA21F>I<01FF0007 +FFE01E03F03801F83C01FC7E00FE7E00FE7E00FE3E00FE1C01FE0001FC0001FC0003F80007F000 +0FC001FF0001FF000007E00001F00001F80000FC0000FE0000FF0000FF1000FF7C00FFFE00FFFE +00FFFE00FEFE00FE7C01FC7001F83E07F00FFFC001FF0018237DA21F>I<000038000000780000 +0078000000F8000001F8000003F8000007F8000006F800000CF800001CF8000038F8000030F800 +0060F80000E0F80001C0F8000180F8000300F8000700F8000E00F8001C00F8001800F8003000F8 +007000F800E000F800FFFFFFC0FFFFFFC00001F8000001F8000001F8000001F8000001F8000001 +F8000001F800007FFFC0007FFFC01A237EA21F>I<18000C1F007C1FFFF81FFFF01FFFE01FFFC0 +1FFF801FFE0018000018000018000018000018000018FF001BFFE01F01F01C00F80800FC00007E +00007E00007E00007F00007F78007FFC007FFC007FFC007FFC007EF8007E6000FC7000FC3801F8 +1E07E007FFC001FE0018237DA21F>I<001FC0007FF001F83803E00C07803E0F807E1F007E3F00 +7E3F007E7E003C7E00007E00007E0000FE3FC0FE7FF0FE80F8FF80FCFF007CFF007EFE007EFE00 +7FFE007FFE007FFE007F7E007F7E007F7E007F7E007F3E007E3F007E1F007C0F80F807C1F003FF +C0007F0018237DA21F>I<300000003C0000003FFFFFC03FFFFFC03FFFFF807FFFFF007FFFFE00 +7FFFFC006000180060001800E0003000C0006000C000C000000180000001800000030000000700 +0000060000000E0000001E0000001E0000001E0000003C0000003C0000007C0000007C0000007C +0000007C000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000078000000 +3000001A257DA41F>I<00001C00000000001C00000000003E00000000003E00000000003E0000 +0000007F00000000007F0000000000FF8000000000FF8000000000FF80000000019FC000000001 +9FC0000000031FE0000000030FE0000000030FE00000000607F00000000607F00000000C07F800 +00000C03F80000001C03FC0000001801FC0000001801FC0000003001FE0000003000FE0000007F +FFFF0000007FFFFF00000060007F000000C0007F800000C0003F800001C0003FC0000180001FC0 +000180001FC0000300000FE0000300000FE0000780000FF000FFF801FFFF80FFF801FFFF802925 +7EA42E>65 D +68 DI< +FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 +0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E +000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 +06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 +F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I72 +DI +76 DI<00FF0080 +07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 +80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F +FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 +0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 +D87 +D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 +FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC +017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 DI<007FE003FFF807C07C +1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 +7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 +00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F +8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 +1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E +001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF +C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 +007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 +7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF +FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 +E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< +01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC +007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 +00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 +0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>II<0F00 +1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 +7EA611>I108 DII<007F800003FFF0 +0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 +1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F +C0FC0003FFF000007F80001A187E971F>II114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 +7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 +EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 +0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 +0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E +0013237FA218>III120 DI<3FFF +F83FFFF83E03F03807F0300FE0700FC0701F80603F80603F00607E0000FE0000FC0001F80003F8 +1803F01807E0180FE0180FC0381F80303F80707F00707E01F0FFFFF0FFFFF015187E971B>I +E /Fj 29 122 df<0003F07C001E0DC600380F0F00701E0F00E01E0E00E00C0001C01C0001C01C +0001C01C0001C01C0001C01C00038038007FFFFFC0038038000380380003803800038038000700 +700007007000070070000700700007007000070070000E00E0000E00E0000E00E0000E00E0000E +00E0000E00E0001C01C0001E01E000FF8FFE0020207E9F1B>11 D<0003E0001C1800381800703C +00E03C00E03801C00001C00001C00001C00001C0000380007FFFF0038070038070038070038070 +0700E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C0380 +1E03C0FF0FF816207E9F19>I<0003F03F00001E09E08000380F80C000701F01E000E03E01E000 +E01E01C001C01C000001C01C000001C01C000001C01C000001C01C000003803800007FFFFFFF80 +038038038003803803800380380380038038038007007007000700700700070070070007007007 +00070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E0 +0E001C01C01C001E01E01E00FF8FF8FFC023207E9F26>14 D<0020000060000060000060000060 +007061C03843800E4E0007580001E00001E00006B8001C9C00708700E083800180000180000180 +0001800001000012147AA117>42 D45 D<000C001C00FC0F3800380038 +00380038003800700070007000700070007000E000E000E000E000E000E001C001C001C001C001 +C001C0038003C0FFFE0F1E7C9D17>49 D<003F8000C1E00100F00200780400780400780F007C0F +807C0F807C0F00780600780000F80000F00001E00001C0000380000700000E00001C0000380000 +600000C0000180000300200600200800401000403FFFC07FFF80FFFF80161E7E9D17>I<07F800 +0C0C001E06001E07001C070000070000070000070000FF0007C7001E07003C0E00780E00F00E10 +F00E10F00E10F01E10F02E20784F401F878014147D9317>97 D<01FC07060E0F1C0F380E780070 +00F000F000F000F000E000E000E000E000F0027004300818300FC010147C9314>99 +D<0000700003F00000F00000700000700000E00000E00000E00000E00000E00000E00001C000F9 +C00305C00E03C01C03C03801C0780380700380F00380F00380F00380F00380E00700E00700E007 +00E00700E00700700F00301E00186F000F8FE014207C9F19>I<00F800070E000E07001C070038 +0380780380700380F00380F00380FFFF80F00000E00000E00000E00000E00000F0010070020030 +04001C180007E00011147D9314>I<0007800018C00031E00061E000E1C000C00001C00001C000 +01C00001C00001C0000380007FF800038000038000038000038000070000070000070000070000 +0700000700000E00000E00000E00000E00000E00000E00001C00001E0000FFE00013207E9F0E> +I<00000E003E1100E1A301C1C20381E00780E00701E00F01E00F01E00F01E00703C00703800787 +0004FC000800000800001800001C00000FFF000FFFC007FFE01800F0300030600030C00030C000 +30C000306000603000C01C070007FC00181F809417>I<00E00007E00001E00000E00000E00001 +C00001C00001C00001C00001C00001C000038000038F800390E003A0E003C0600380600780E007 +00E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C03801E03C0FF +CFF815207E9F19>I<01C003E003E003C0018000000000000000000000000003801F8007800380 +03800700070007000700070007000E000E000E000E000E000E001C001E00FF800B1F7F9E0C>I< +00E007E001E000E000E001C001C001C001C001C001C00380038003800380038003800700070007 +000700070007000E000E000E000E000E000E001C001E00FFC00B207F9F0C>108 +D<0387C07C001F9861860007A072070003C0340300038038030007807807000700700700070070 +07000700700700070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00 +E00E000E00E00E001C01C01C001E01E01E00FFCFFCFFC022147E9326>I<038F801F90E007A0E0 +03C0600380600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C0 +0E01C01C03801E03C0FFCFF815147E9319>I<00FC000387000E01801C00C03800E03800E07000 +F0F000F0F000F0F000F0F000F0E001E0E001E0E001C0E003C0F00380700700380E001C1C0007E0 +0014147D9317>I<00E3E007EC3800F01C00E01E00E00E01C00E01C00F01C00F01C00F01C00F01 +C00F03801E03801E03801C03803C0380380380700740E00721C0071F000700000700000700000E +00000E00000E00000E00001E0000FFC000181D809319>I<00F040038CC00E04C01C03C03C03C0 +780380780380F00380F00380F00380F00380E00700E00700E00700F00700F00F00700F00301E00 +186E000F8E00000E00000E00000E00001C00001C00001C00001C00003C0001FF80121D7C9318> +I<038E001FB38007C78003C7800383000780000700000700000700000700000700000E00000E00 +000E00000E00000E00000E00001C00001E0000FFE00011147E9312>I<01F2060E080618061802 +380438001E001FE00FF003F8003C401C400C400C600C6018E010D0608FC00F147E9312>I<0080 +010001000100030007000F001E00FFF80E000E000E000E001C001C001C001C001C001C00380038 +203820382038203840384018800F000D1C7C9B12>I<1C0380FC1F803C07801C03801C03803807 +00380700380700380700380700380700700E00700E00700E00700E00701E00701E00703C00305E +001F9FC012147B9319>II< +FF9FE1FC3E0780701C0300601C0300401C0380401C0380800E0780800E0581000E0981000E09C2 +000E11C2000731C4000721C4000760C8000740C8000780F0000780F0000300E000030060000200 +40001E147C9321>I<1FF0FF03C07801C06001C04000E08000E180007300007600003C00003C00 +001C00002E00004E000087000107000203800603800C01C03E03E0FF07FC18147F9318>I<0FF8 +3F8001E00E0001C00C0001C0080000E0180000E0100000E0200000E0200000F040000070400000 +708000007080000071000000390000003A0000003E0000003C0000003800000018000000100000 +0010000000200000002000000040000070C00000F0800000F1000000E20000007C000000191D80 +9318>I E /Fk 36 122 df<0001C0000003C000000FC000007FC0001FFFC000FFFFC000FFBFC0 +00E03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003F +C000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00000 +3FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000 +003FC000003FC000003FC000003FC000003FC000003FC000003FC0007FFFFFE07FFFFFE07FFFFF +E01B2E7AAD28>49 D<003FE00001FFFE0007FFFF800F80FFC01E003FE038001FF07C000FF87E00 +07FCFF0007FCFF8007FEFF8007FEFF8003FEFF8003FE7F0003FE3E0007FE000007FE000007FC00 +0007FC00000FF800000FF800000FF000001FE000001FC000003F8000007F0000007E000000F800 +0001F0000003E0000007C000000F0000001E000E003C000E0038000E0070001E00E0001C01C000 +1C0300003C07FFFFFC0FFFFFFC1FFFFFFC3FFFFFFC7FFFFFF8FFFFFFF8FFFFFFF8FFFFFFF81F2E +7CAD28>I<0000007800000000000078000000000000FC000000000000FC000000000000FC0000 +00000001FE000000000001FE000000000003FF000000000003FF000000000007FF800000000007 +FF800000000007FF80000000000FFFC0000000000E7FC0000000001E7FE0000000001C3FE00000 +00001C3FE000000000383FF000000000381FF000000000781FF800000000700FF800000000700F +F800000000E00FFC00000000E007FC00000001E007FE00000001C003FE00000001C003FE000000 +038003FF000000038001FF000000078001FF800000070000FF800000070000FF8000000FFFFFFF +C000000FFFFFFFC000001FFFFFFFE000001C00003FE000003C00003FF000003800001FF0000038 +00001FF000007000001FF800007000000FF80000F000000FFC0000E0000007FC0000E0000007FC +0001C0000007FE0003E0000003FE00FFFF8001FFFFFCFFFF8001FFFFFCFFFF8001FFFFFC36317D +B03D>65 DI<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 +003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 +000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F +E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 +0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 +803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 +0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 +001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 +3A>I70 +D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 +0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 +0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 +0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF +C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 +000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF +0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 +00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< +FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F +C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 +7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 +007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF +FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF +8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 +FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 +00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF +FFC03A317EB03F>II78 D80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F +C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 +0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 +0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 +0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F +F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 +00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 +00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 +000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF +000031307DAF38>84 DII<00FFF0000003FFFE00000F803F80000FC00FE0001F +E007F0001FE007F0001FE003F8000FC003FC00078003FC00000003FC00000003FC00000003FC00 +000003FC000000FFFC00001FFFFC0000FFE3FC0003FC03FC000FF003FC001FC003FC003FC003FC +007F8003FC007F8003FC00FF0003FC00FF0003FC00FF0003FC00FF0007FC00FF0007FC007F800D +FC003FC019FE001FE070FFF007FFE07FF000FF803FF024207E9F27>97 D<01F8000000FFF80000 +00FFF8000000FFF80000000FF800000007F800000007F800000007F800000007F800000007F800 +000007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8 +00000007F83FE00007F8FFFC0007FBE07F0007FF001F8007FE000FC007FC000FE007F80007F007 +F80007F807F80007F807F80003FC07F80003FC07F80003FC07F80003FE07F80003FE07F80003FE +07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FC07F80003FC07F80003 +FC07F80007F807F80007F807F80007F007FC000FE007FE000FC007E7003F8007C3C0FE000780FF +F80007003FC00027327EB12D>I<000FFF00007FFFC001FC01F003F003F007E007F80FE007F81F +C007F83FC003F03FC001E07F8000007F8000007F800000FF800000FF800000FF800000FF800000 +FF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC0001C3FC0001C1FC000 +380FE0003807E0007003F001E001FC07C0007FFF00000FF8001E207D9F24>I<0000000FC00000 +07FFC0000007FFC0000007FFC00000007FC00000003FC00000003FC00000003FC00000003FC000 +00003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0 +0000003FC00007F83FC0003FFF3FC000FE07BFC003F801FFC007E0007FC00FE0007FC01FC0003F +C03FC0003FC03FC0003FC07F80003FC07F80003FC07F80003FC0FF80003FC0FF80003FC0FF8000 +3FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC07F80003FC07F80003FC07F80 +003FC03FC0003FC03FC0003FC01FC0003FC00FE0007FC007E000FFC003F003FFE001FC0F3FFE00 +7FFE3FFE000FF03FFE27327DB12D>I<000FFC00007FFF8001FC0FC003F003E007E001F00FE001 +F81FC000FC3FC000FE3FC000FE7F80007E7F80007F7F80007FFF80007FFF80007FFFFFFFFFFFFF +FFFFFF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC000071FC000071F +C0000E0FE0000E07F0001C03F8007800FE03E0003FFFC00007FE0020207E9F25>I<0001FE0000 +0FFF80001FC3C0007F07E000FE0FF001FE0FF001FC0FF003FC0FF003FC07E003FC018003FC0000 +03FC000003FC000003FC000003FC000003FC000003FC000003FC0000FFFFFC00FFFFFC00FFFFFC +0003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC +000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003 +FC000003FC000003FC000003FC000003FC000003FC000003FC00007FFFF0007FFFF0007FFFF000 +1C327EB119>I<001FF007C000FFFE3FE001F83F79F007E00FC3F00FE00FE1F00FC007E0E01FC0 +07F0001FC007F0003FC007F8003FC007F8003FC007F8003FC007F8003FC007F8001FC007F0001F +C007F0000FC007E0000FE00FE00007E00FC00003F83F000006FFFE00000E1FF000000E00000000 +1E000000001E000000001F000000001F800000001FFFFF80000FFFFFF0000FFFFFFC0007FFFFFE +0003FFFFFF0003FFFFFF800FFFFFFFC01F00007FC07E00001FE07C00000FE0FC000007E0FC0000 +07E0FC000007E0FC000007E07E00000FC03E00000F803F00001F800FC0007E0007F803FC0001FF +FFF000001FFF0000242F7E9F28>I<01F8000000FFF8000000FFF8000000FFF80000000FF80000 +0007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F800 +000007F800000007F800000007F800000007F800000007F800000007F807F80007F83FFE0007F8 +783F0007F8C03F8007F9801FC007FB001FC007FE001FE007FC001FE007FC001FE007FC001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 +07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F +E007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF28327DB12D>I<03 +C00007E0000FF0001FF8001FF8001FF8001FF8000FF00007E00003C00000000000000000000000 +000000000000000000000000000000000001F800FFF800FFF800FFF8000FF80007F80007F80007 +F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007 +F80007F80007F80007F80007F80007F80007F80007F80007F800FFFF80FFFF80FFFF8011337DB2 +17>I<01F800FFF800FFF800FFF8000FF80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F800FFFFC0FFFFC0FFFFC012327D +B117>108 D<03F007F8001FE000FFF03FFE00FFF800FFF0783F01E0FC00FFF0C03F8300FE000F +F1801FC6007F0007F3001FCC007F0007F6001FF8007F8007FC001FF0007F8007FC001FF0007F80 +07FC001FF0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F +8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE000 +7F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0 +007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001F +E0007F80FFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFC3E207D9F43>I<03F007F8 +00FFF03FFE00FFF0783F00FFF0C03F800FF1801FC007F3001FC007F6001FE007FC001FE007FC00 +1FE007FC001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8 +001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF +28207D9F2D>I<0007FC0000007FFFC00001FC07F00003F001F80007E000FC000FC0007E001FC0 +007F003FC0007F803F80003F807F80003FC07F80003FC07F80003FC0FF80003FE0FF80003FE0FF +80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE07F80003FC07F80003FC0 +7F80003FC03FC0007F803FC0007F801FC0007F000FE000FE0007E000FC0003F803F80001FE0FF0 +00007FFFC0000007FC000023207E9F28>I<01F83FE000FFF8FFFC00FFFBE07F00FFFF003F8007 +FE001FC007FC000FE007F8000FF007F80007F807F80007F807F80007FC07F80003FC07F80003FC +07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003 +FE07F80003FC07F80007FC07F80007FC07F80007F807F80007F807F8000FF007FC000FE007FE00 +1FC007FF003F8007FBC0FE0007F8FFF80007F83FC00007F800000007F800000007F800000007F8 +00000007F800000007F800000007F800000007F800000007F800000007F800000007F8000000FF +FFC00000FFFFC00000FFFFC00000272E7E9F2D>I<03F03F00FFF07FC0FFF1C3E0FFF187E00FF3 +0FF007F60FF007F60FF007FC07E007FC03C007FC000007FC000007F8000007F8000007F8000007 +F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F80000 +07F8000007F8000007F8000007F8000007F80000FFFFE000FFFFE000FFFFE0001C207E9F21> +114 D<01FF860007FFFE001F00FE003C003E0078001E0078000E00F8000E00F8000E00F8000E00 +FC000000FF800000FFFC00007FFFC0007FFFF0003FFFF8001FFFFC0007FFFE0001FFFF00003FFF +000000FF8000003F8060001F80E0000F80E0000F80F0000F80F0000F00F8000F00FC001E00FE00 +1C00FF807800F3FFF000C07F800019207D9F20>I<001C0000001C0000001C0000001C0000001C +0000003C0000003C0000003C0000007C0000007C000000FC000001FC000003FC000007FC00001F +FFFE00FFFFFE00FFFFFE0003FC000003FC000003FC000003FC000003FC000003FC000003FC0000 +03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC03 +8003FC038003FC038003FC038003FC038003FC038003FC038001FC038001FC070000FE0700007F +0E00003FFC000007F000192E7FAD1F>I<01F80007E0FFF803FFE0FFF803FFE0FFF803FFE00FF8 +003FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 +07F8001FE007F8001FE007F8001FE007F8001FE007F8003FE007F8003FE003F8007FE003F8007F +E001FC00DFF000FE039FFF007FFF1FFF000FFC1FFF28207D9F2D>II< +FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE +00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 +FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 +7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F +FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 +000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 +7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F +E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 +00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 +003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF +FF28207F9F2B>II E /Fl 1 14 df<0001FE00000007FF8000001E01E000007800780000 +E0001C000180000600030000030006000001800C000000C00C000000C018000000603000000030 +30000000303000000030600000001860000000186000000018C00000000CC00000000CC0000000 +0CC00000000CC00000000CC00000000CC00000000CC00000000CC00000000C6000000018600000 +0018600000001830000000303000000030300000003018000000600C000000C00C000000C00600 +0001800300000300018000060000E0001C000078007800001E01E0000007FF80000001FE000026 +2B7DA02D>13 D E /Fm 46 122 df<3C007F00FF80FF80FFC0FFC0FFC07FC03EC000C000C00180 +018001800300030006000E001C00380030000A157B8813>44 D<1C007F007F00FF80FF80FF807F +007F001C0009097B8813>46 D<000E00001E00007E0007FE00FFFE00FFFE00F8FE0000FE0000FE +0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE +0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE +0000FE007FFFFE7FFFFE7FFFFE17277BA622>49 D<00FF800007FFF0000FFFFC001E03FE003800 +FF807C003F80FE003FC0FF001FC0FF001FE0FF000FE0FF000FE07E000FE03C001FE000001FE000 +001FC000001FC000003F8000003F0000007E000000FC000000F8000001F0000003E00000078000 +000F0000001E0000003C00E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFF +C03FFFFFC07FFFFFC0FFFFFF80FFFFFF80FFFFFF801B277DA622>I<007F800003FFF00007FFFC +000F80FE001F007F003F807F003F803F803F803F803F803F801F803F801F003F8000007F000000 +7F0000007E000000FC000001F8000007F00000FFC00000FFC0000001F80000007E0000003F0000 +003F8000001FC000001FC000001FE000001FE03C001FE07E001FE0FF001FE0FF001FE0FF001FC0 +FF003FC0FE003F807C007F003F00FE001FFFFC0007FFF00000FF80001B277DA622>I<00000E00 +00001E0000003E0000007E000000FE000000FE000001FE000003FE0000077E00000E7E00000E7E +00001C7E0000387E0000707E0000E07E0000E07E0001C07E0003807E0007007E000E007E000E00 +7E001C007E0038007E0070007E00E0007E00FFFFFFF8FFFFFFF8FFFFFFF80000FE000000FE0000 +00FE000000FE000000FE000000FE000000FE000000FE00007FFFF8007FFFF8007FFFF81D277EA6 +22>I<180003001F801F001FFFFE001FFFFC001FFFF8001FFFF0001FFFC0001FFF00001C000000 +1C0000001C0000001C0000001C0000001C0000001C0000001C7FC0001DFFF8001F80FC001E003F +0008003F0000001F8000001FC000001FC000001FE000001FE018001FE07C001FE0FE001FE0FE00 +1FE0FE001FE0FE001FC0FC001FC078003F8078003F803C007F001F01FE000FFFFC0003FFF00000 +FF80001B277DA622>I<380000003E0000003FFFFFF03FFFFFF03FFFFFF07FFFFFE07FFFFFC07F +FFFF807FFFFF0070000E0070000E0070001C00E0003800E0007000E000E0000001E0000001C000 +000380000007800000070000000F0000001F0000001E0000003E0000003E0000007E0000007C00 +00007C000000FC000000FC000000FC000000FC000001FC000001FC000001FC000001FC000001FC +000001FC000001FC000000F80000007000001C297CA822>55 D<00000780000000000780000000 +000FC0000000000FC0000000000FC0000000001FE0000000001FE0000000003FF0000000003FF0 +000000003FF00000000077F80000000077F800000000F7FC00000000E3FC00000000E3FC000000 +01C1FE00000001C1FE00000003C1FF0000000380FF0000000380FF00000007007F80000007007F +8000000F007FC000000E003FC000000E003FC000001C001FE000001C001FE000003FFFFFF00000 +3FFFFFF000003FFFFFF00000700007F80000700007F80000F00007FC0000E00003FC0000E00003 +FC0001C00001FE0001C00001FE0003C00001FF00FFFE003FFFFCFFFE003FFFFCFFFE003FFFFC2E +297EA833>65 DI<00007FE0030007FFFC07001FFFFF0F +007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 +0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 +0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 +0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 +F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 +>I69 DI<0000 +7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F +0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 +000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 +00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 +00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF +0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 +FFFE0F0000007FF003002D297CA835>III77 +DI80 +D82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 +3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF +C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 +00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 +E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I85 DII<03FF80000FFFF0001F01FC003F80FE003F +807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 +0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF +803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D +I<003FF00001FFFC0003F03E000FC07F001F807F003F007F003F007F007F003E007E0000007E00 +0000FE000000FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000007F +0000003F0003803F8003801F8007000FE00E0003F83C0001FFF800003FC000191B7E9A1E>I<00 +007FF000007FF000007FF0000007F0000007F0000007F0000007F0000007F0000007F0000007F0 +000007F0000007F0000007F0000007F0000007F0003F87F001FFF7F007F03FF00FC00FF01F8007 +F03F0007F03F0007F07E0007F07E0007F07E0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE00 +07F0FE0007F0FE0007F0FE0007F07E0007F07E0007F03F0007F03F0007F01F800FF00FC01FF007 +E07FFF01FFE7FF007F87FF202A7EA925>I<003FC00001FFF00003E07C000F803E001F801F001F +001F003F000F807E000F807E000FC07E000FC0FE0007C0FE0007C0FFFFFFC0FFFFFFC0FE000000 +FE000000FE0000007E0000007E0000007F0000003F0001C01F0001C00F80038007C0070003F01E +0000FFFC00003FE0001A1B7E9A1F>I<0007F8003FFC007E3E01FC7F03F87F03F07F07F07F07F0 +3E07F00007F00007F00007F00007F00007F00007F000FFFFC0FFFFC0FFFFC007F00007F00007F0 +0007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F00007F00007F00007F0007FFF807FFF807FFF80182A7EA915>I<007F80F001FFE3 +F807C0FE1C0F807C7C1F003E7C1F003E103F003F003F003F003F003F003F003F003F003F003F00 +3F001F003E001F003E000F807C0007C0F80005FFE0000C7F8000180000001C0000001C0000001E +0000001FFFF8001FFFFF000FFFFFC007FFFFE003FFFFF00FFFFFF03E0007F07C0001F8F80000F8 +F80000F8F80000F8F80000F87C0001F07C0001F03F0007E00FC01F8007FFFF00007FF0001E287E +9A22>II<07000F801FC03FE03FE03FE01FC00F80 +07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F +E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I108 DII<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 +07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE +0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 +003FE0001D1B7E9A22>II114 D<03FE300FFFF03E03F0 +7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 +0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> +I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF +E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 +7FA51A>II +IIII E /Fn 75 127 df<70F8F8F8F8F8F8F8F8F8F8F8 +F8F8F8F8F870000000000070F8F8F870051C779B18>33 D<4010E038F078E038E038E038E038E0 +38E038E038E038E038E03860300D0E7B9C18>I<030600078F00078F00078F00078F00078F0007 +8F007FFFC0FFFFE0FFFFE07FFFC00F1E000F1E000F1E000F1E000F1E000F1E007FFFC0FFFFE0FF +FFE07FFFC01E3C001E3C001E3C001E3C001E3C001E3C000C1800131C7E9B18>I<00C00001C000 +01C00001C00003F0000FFC003FFE007DCF0071C700E1C380E1C780E1C780E1C780F1C00079C000 +3DC0001FE0000FF80003FC0001DE0001CF0001C70061C380F1C380F1C380E1C380E1C70071C700 +79DE003FFE001FF80007E00001C00001C00001C00000C00011247D9F18>I<3803007C07807C07 +80EE0F80EE0F00EE0F00EE1F00EE1E00EE1E00EE3E007C3C007C3C00387C0000780000780000F8 +0000F00001F00001E00001E00003E00003C00003C00007C0000783800787C00F87C00F0EE00F0E +E01F0EE01E0EE01E0EE03E0EE03C07C03C07C018038013247E9F18>I<01C00007E0000FF0000E +70001C38001C38001C38001C38001C73F01C73F01CE3F00FE3800FC7000F87000F07001F0E003F +0E007B8E0073DC00E1DC00E0F800E0F800E07070E0787070FC707FFFE03FCFE00F03C0141C7F9B +18>I<387C7C7E3E0E0E0E1C1C38F8F0C0070E789B18>I<007000F001E003C007800F001E001C00 +380038007000700070007000E000E000E000E000E000E000E000E0007000700070007000380038 +001C001E000F00078003C001F000F000700C24799F18>I<6000F00078003C001E000F00078003 +8001C001C000E000E000E000E00070007000700070007000700070007000E000E000E000E001C0 +01C0038007800F001E003C007800F00060000C247C9F18>I<01C00001C00001C00001C000C1C1 +80F1C780F9CF807FFF001FFC0007F00007F0001FFC007FFF00F9CF80F1C780C1C18001C00001C0 +0001C00001C00011147D9718>I<00600000F00000F00000F00000F00000F00000F00000F0007F +FFC0FFFFE0FFFFE07FFFC000F00000F00000F00000F00000F00000F00000F00000600013147E97 +18>I<1C3E7E7F3F1F070E1E7CF860080C788518>I<7FFF00FFFF80FFFF807FFF0011047D8F18> +I<3078FCFC78300606778518>I<000300000780000780000F80000F00001F00001E00001E0000 +3E00003C00007C0000780000780000F80000F00001F00001E00003E00003C00003C00007C00007 +80000F80000F00000F00001F00001E00003E00003C00003C00007C0000780000F80000F00000F0 +000060000011247D9F18>I<01F00007FC000FFE001F1F001C07003803807803C07001C07001C0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07001C07803C0 +3803801C07001F1F000FFE0007FC0001F000131C7E9B18>I<01800380038007800F803F80FF80 +FB80438003800380038003800380038003800380038003800380038003800380038003807FFCFF +FE7FFC0F1C7B9B18>I<03F0000FFE003FFF007C0F807003C0E001C0F000E0F000E06000E00000 +E00000E00001C00001C00003C0000780000F00001E00003C0000780000F00001E00007C0000F80 +001E00E03C00E07FFFE0FFFFE07FFFE0131C7E9B18>I<001F00003F0000770000770000E70001 +E70001C7000387000787000707000E07001E07003C0700380700780700F00700FFFFF8FFFFF8FF +FFF8000700000700000700000700000700000700007FF000FFF8007FF0151C7F9B18>52 +D<007E0001FF0007FF800F83C01E03C01C03C0380180380000700000700000E1F800E7FE00FFFF +00FE0780F803C0F001C0F000E0E000E0F000E07000E07000E07000E03801C03C03C01E07800FFF +0007FE0001F800131C7E9B18>54 D<3078FCFC783000000000000000003078FCFC783006147793 +18>58 D<183C7E7E3C180000000000000000183C7E7E3E1E0E1C3C78F060071A789318>I<0003 +00000780001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000FC00007E00 +003F00001FC00007E00003F00001FC00007E00003F00001F8000078000030011187D9918>I<7F +FFC0FFFFE0FFFFE0FFFFE0000000000000000000000000FFFFE0FFFFE0FFFFE07FFFC0130C7E93 +18>I<600000F00000FC00007E00003F00001FC00007E00003F00001FC00007E00003F00001F80 +001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000F0000060000011187D +9918>I<0FF0003FFC007FFF00700F00F00380F00380600780000F00003E00007C0001F00001E0 +0003C00003C00003C00003C00003C00003800000000000000000000000000000000003800007C0 +0007C00007C000038000111C7D9B18>I<00700000F80000F80000D80000D80001DC0001DC0001 +DC00018C00038E00038E00038E00038E000306000707000707000707000707000FFF800FFF800F +FF800E03800E03801C01C01C01C07F07F0FF8FF87F07F0151C7F9B18>65 +D<7FF800FFFE007FFF001C0F801C03C01C03C01C01E01C00E01C00E01C00F01C00701C00701C00 +701C00701C00701C00701C00701C00701C00F01C00E01C00E01C01E01C01C01C03C01C0F807FFF +00FFFE007FF800141C7F9B18>68 DII<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F +FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F +07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 +0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 +0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E +00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B +18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 +C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D +C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 +E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 +E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>II<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C +0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C +039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 +80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 +E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF +FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 +700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 +1C7F9B18>II89 +D91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 +0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 +007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> +II<018007C01FF07EFCF83EE00E0F067C9B18>I<7FFF00FFFF80FFFF807FFF0011047D7F18>I< +061E3E387070E0E0E0F8FC7C7C38070E789E18>I<1FE0003FF8007FFC00781E00300E00000700 +00070000FF0007FF001FFF007F0700780700E00700E00700E00700F00F00781F003FFFF01FFBF0 +07E1F014147D9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF +800FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E00380F00700F00 +700F80E00FC1E00FFFC00EFF80063E00151C809B18>I<01FE0007FF001FFF803E078038030070 +0000700000E00000E00000E00000E00000E00000E000007000007001C03801C03E03C01FFF8007 +FF0001FC0012147D9318>I<001F80003F80001F8000038000038000038000038000038003E380 +0FFB801FFF803C1F80380F80700780700380E00380E00380E00380E00380E00380E00380700780 +700780380F803C1F801FFFF00FFBF803E3F0151C7E9B18>I<01F00007FC001FFE003E0F003807 +80700380700380E001C0E001C0FFFFC0FFFFC0FFFFC0E000007000007001C03801C03E03C01FFF +8007FF0001FC0012147D9318>I<001F80007FC000FFE000E1E001C0C001C00001C00001C0007F +FFC0FFFFC0FFFFC001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001 +C00001C00001C00001C0007FFF007FFF007FFF00131C7F9B18>I<01E1F007FFF80FFFF81E1E30 +1C0E003807003807003807003807003807001C0E001E1E001FFC001FF80039E0003800001C0000 +1FFE001FFFC03FFFE07801F0700070E00038E00038E00038E000387800F07E03F01FFFC00FFF80 +01FC00151F7F9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF +800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 +E00E00E00E00E07FC3FCFFE7FE7FC3FC171C809B18>I<03800007C00007C00007C00003800000 +00000000000000000000007FC000FFC0007FC00001C00001C00001C00001C00001C00001C00001 +C00001C00001C00001C00001C00001C00001C00001C000FFFF00FFFF80FFFF00111D7C9C18>I< +7FE000FFE0007FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0007FFFC0 +FFFFE07FFFC0131C7E9B18>108 D<7CE0E000FFFBF8007FFFF8001F1F1C001E1E1C001E1E1C00 +1C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C +001C1C1C007F1F1F00FFBFBF807F1F1F001914819318>I<7E3E00FEFF807FFFC00FC1C00F80E0 +0F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E07FC3FC +FFE7FE7FC3FC1714809318>I<01F0000FFE001FFF003E0F803803807001C07001C0E000E0E000 +E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE0001F00013147E9318 +>I<7E3E00FEFF807FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E +00380F00700F00700F80E00FC1E00FFFC00EFF800E3E000E00000E00000E00000E00000E00000E +00000E00007FC000FFE0007FC000151E809318>I<01E38007FB801FFF803E1F80380F80700780 +700780E00380E00380E00380E00380E00380E00380700780700780380F803C1F801FFF800FFB80 +03E380000380000380000380000380000380000380000380003FF8003FF8003FF8151E7E9318> +I<7F87E0FF9FF07FBFF803F87803F03003E00003C00003C0000380000380000380000380000380 +000380000380000380000380007FFE00FFFF007FFE0015147F9318>I<07F7003FFF007FFF0078 +0F00E00700E00700E007007C00007FE0001FFC0003FE00001F00600780E00380E00380F00380F8 +0F00FFFF00FFFC00E7F00011147D9318>I<0180000380000380000380000380007FFFC0FFFFC0 +FFFFC00380000380000380000380000380000380000380000380000380000380400380E00380E0 +0380E001C1C001FFC000FF80003E0013197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E00 +E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E01E00F03E007FFFC03FF +FE01FCFC1714809318>I<7F8FF0FF8FF87F8FF01E03C00E03800E03800E038007070007070007 +0700038E00038E00038E00038E0001DC0001DC0001DC0000F80000F80000700015147F9318>I< +FF8FF8FF8FF8FF8FF83800E03800E03800E01C01C01C01C01C71C01CF9C01CF9C01CD9C01CD9C0 +0DDD800DDD800DDD800D8D800F8F800F8F8007070015147F9318>I<7F8FF07F9FF07F8FF00707 +00078E00039E0001DC0001F80000F80000700000F00000F80001DC00039E00038E000707000F07 +807F8FF0FF8FF87F8FF015147F9318>I<7F8FF0FF8FF87F8FF00E01C00E03800E038007038007 +0700070700038700038600038E0001CE0001CE0000CC0000CC0000DC0000780000780000780000 +700000700000700000F00000E00079E0007BC0007F80003F00001E0000151E7F9318>I<3FFFF0 +7FFFF07FFFF07001E07003C0700780000F00001E00003C0000F80001F00003C0000780000F0070 +1E00703C0070780070FFFFF0FFFFF0FFFFF014147F9318>I<0007E0001FE0007FE000780000E0 +0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00001E0007FC000FF80 +00FF80007FC00001E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0 +0000E000007800007FE0001FE00007E013247E9F18>I<60F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 +F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0600424769F18>I<7C0000FF0000FFC00003C000 +00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000F000007FC0 +003FE0003FE0007FC000F00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00003C000FFC000FF00007C000013247E9F18>I<060C1F1E3FBEFBF8F1F060C00F06 +7C9B18>I E /Fo 75 123 df<001F83E000F06E3001C078780380F8780300F030070070000700 +70000700700007007000070070000700700007007000FFFFFF8007007000070070000700700007 +007000070070000700700007007000070070000700700007007000070070000700700007007000 +07007000070070000700700007007000070070007FE3FF001D20809F1B>11 +D<003F0000E0C001C0C00381E00701E00701E0070000070000070000070000070000070000FFFF +E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700 +E00700E00700E00700E00700E00700E07FC3FE1720809F19>I<003FE000E0E001C1E00381E007 +00E00700E00700E00700E00700E00700E00700E00700E0FFFFE00700E00700E00700E00700E007 +00E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E007 +00E07FE7FE1720809F19>I<001F81F80000F04F040001C07C06000380F80F000300F00F000700 +F00F00070070000007007000000700700000070070000007007000000700700000FFFFFFFF0007 +007007000700700700070070070007007007000700700700070070070007007007000700700700 +070070070007007007000700700700070070070007007007000700700700070070070007007007 +00070070070007007007007FE3FE3FF02420809F26>I<7038F87CFC7EFC7E743A040204020402 +0804080410081008201040200F0E7E9F17>34 D<70F8FCFC74040404080810102040060E7C9F0D +>39 D<0020004000800100020006000C000C00180018003000300030007000600060006000E000 +E000E000E000E000E000E000E000E000E000E000E0006000600060007000300030003000180018 +000C000C000600020001000080004000200B2E7DA112>I<800040002000100008000C00060006 +000300030001800180018001C000C000C000C000E000E000E000E000E000E000E000E000E000E0 +00E000E000C000C000C001C001800180018003000300060006000C00080010002000400080000B +2E7DA112>I<70F8FCFC74040404080810102040060E7C840D>44 DI<70 +F8F8F87005057C840D>I<03F0000E1C001C0E00180600380700700380700380700380700380F0 +03C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C070 +03807003807003807807803807001806001C0E000E1C0003F000121F7E9D17>48 +D<018003800F80F380038003800380038003800380038003800380038003800380038003800380 +03800380038003800380038003800380038007C0FFFE0F1E7C9D17>I<03F0000C1C00100E0020 +0700400780800780F007C0F803C0F803C0F803C02007C00007C0000780000780000F00000E0000 +1C0000380000700000600000C0000180000300000600400C00401800401000803FFF807FFF80FF +FF80121E7E9D17>I<03F0000C1C00100E00200F00780F80780780780780380F80000F80000F00 +000F00000E00001C0000380003F000003C00000E00000F000007800007800007C02007C0F807C0 +F807C0F807C0F00780400780400F00200E001C3C0003F000121F7E9D17>I<000600000600000E +00000E00001E00002E00002E00004E00008E00008E00010E00020E00020E00040E00080E00080E +00100E00200E00200E00400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E +0000FFE0141E7F9D17>I<1803001FFE001FFC001FF8001FE00010000010000010000010000010 +000010000011F000161C00180E001007001007800003800003800003C00003C00003C07003C0F0 +03C0F003C0E00380400380400700200600100E000C380003E000121F7E9D17>I<007C00018200 +0701000E03800C07801C0780380300380000780000700000700000F1F000F21C00F40600F80700 +F80380F80380F003C0F003C0F003C0F003C0F003C07003C07003C0700380380380380700180700 +0C0E00061C0001F000121F7E9D17>I<4000007FFFC07FFF807FFF804001008002008002008004 +0000080000080000100000200000200000400000400000C00000C00001C0000180000380000380 +00038000038000078000078000078000078000078000078000078000030000121F7D9D17>I<03 +F0000C0C001006003003002001806001806001806001807001807803003E03003F06001FC8000F +F00003F80007FC000C7E00103F00300F806003804001C0C001C0C000C0C000C0C000C0C0008060 +01802001001002000C0C0003F000121F7E9D17>I<03F0000E18001C0C00380600380700700700 +700380F00380F00380F003C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C0 +03E3C0000380000380000380000700300700780600780E00700C002018001070000FC000121F7E +9D17>I<70F8F8F8700000000000000000000070F8F8F87005147C930D>I<70F8F8F87000000000 +00000000000070F0F8F878080808101010202040051D7C930D>I<000100000003800000038000 +000380000007C0000007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F0 +0000207800002078000020780000403C0000403C0000403C0000801E0000801E0000FFFE000100 +0F0001000F0001000F00020007800200078002000780040003C00E0003C01F0007E0FFC03FFE1F +207F9F22>65 DI<000FC040007030C001C009C0038005C00700 +03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 +000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 +3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D +9F21>IIII<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 +3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 +00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 +01E0070001E0038002E000E0046000781820000FE0001E217D9F24>III<0FFFC0007C +00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C +00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 +0040780040700030E0000F800012207E9E17>I76 DII<001F800000F0F00001C0380007801E +000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 +01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C +0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 +1C217D9F23>II<001F800000F0F00001C0380007801E000F00 +0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 +0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 +3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 +10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>II<07E0800C1980100780300380600180600180E00180E00080 +E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 +0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D +9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 +10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F +0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 +0F0000001F800007FFFE001C1F7E9E21>IIII91 +D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>II<081020204040808080B8FCFC7C38060E7D9F0D>96 +D<1FE000303000781800781C00300E00000E00000E00000E0000FE00078E001E0E00380E00780E +00F00E10F00E10F00E10F01E10781E103867200F83C014147E9317>I<0E0000FE00000E00000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E3E000EC3800F01C00F00E00E +00E00E00700E00700E00780E00780E00780E00780E00780E00780E00700E00700E00E00F00E00D +01C00CC300083E0015207F9F19>I<03F80E0C1C1E381E380C70007000F000F000F000F000F000 +F00070007000380138011C020E0C03F010147E9314>I<000380003F8000038000038000038000 +038000038000038000038000038000038000038003E380061B801C078038038038038070038070 +0380F00380F00380F00380F00380F00380F003807003807003803803803807801C07800E1B8003 +E3F815207E9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FFFF80 +F00000F00000F000007000007000003800801800800C010007060001F80011147F9314>I<007C +00C6018F038F07060700070007000700070007000700FFF0070007000700070007000700070007 +0007000700070007000700070007000700070007007FF01020809F0E>I<0000E003E3300E3C30 +1C1C30380E00780F00780F00780F00780F00780F00380E001C1C001E380033E000200000200000 +3000003000003FFE001FFF800FFFC03001E0600070C00030C00030C00030C000306000603000C0 +1C038003FC00141F7F9417>I<0E0000FE00000E00000E00000E00000E00000E00000E00000E00 +000E00000E00000E00000E3E000E43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01 +C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16207F9F19>I<1C +003E003E003E001C000000000000000000000000000E007E000E000E000E000E000E000E000E00 +0E000E000E000E000E000E000E000E000E000E00FFC00A1F809E0C>I<00E001F001F001F000E0 +000000000000000000000000007007F000F0007000700070007000700070007000700070007000 +7000700070007000700070007000700070007000706070F060F0C061803F000C28829E0E>I<0E +0000FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0FF00E +03C00E03000E02000E04000E08000E10000E30000E70000EF8000F38000E1C000E1E000E0E000E +07000E07800E03800E03C00E03E0FFCFF815207F9F18>I<0E00FE000E000E000E000E000E000E +000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E00 +0E000E000E000E00FFE00B20809F0C>I<0E1F01F000FE618618000E81C81C000F00F00E000F00 +F00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E +00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E00FFE7FE7FE0 +23147F9326>I<0E3E00FE43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01C00E01 +C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16147F9319>I<01F80007 +0E001C03803801C03801C07000E07000E0F000F0F000F0F000F0F000F0F000F0F000F07000E070 +00E03801C03801C01C0380070E0001F80014147F9317>I<0E3E00FEC3800F01C00F00E00E00E0 +0E00F00E00700E00780E00780E00780E00780E00780E00780E00700E00F00E00E00F01E00F01C0 +0EC3000E3E000E00000E00000E00000E00000E00000E00000E00000E0000FFE000151D7F9319> +I<03E0800619801C05803C0780380380780380700380F00380F00380F00380F00380F00380F003 +807003807803803803803807801C0B800E138003E3800003800003800003800003800003800003 +80000380000380003FF8151D7E9318>I<0E78FE8C0F1E0F1E0F0C0E000E000E000E000E000E00 +0E000E000E000E000E000E000E000E00FFE00F147F9312>I<1F9030704030C010C010C010E000 +78007F803FE00FF00070803880188018C018C018E030D0608F800D147E9312>I<020002000200 +060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E000E000E000E080E080E +080E080E080610031001E00D1C7F9B12>I<0E01C0FE1FC00E01C00E01C00E01C00E01C00E01C0 +0E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E03C00603C0030DC001F1FC +16147F9319>III<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 +7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>II<3FFF380E200E201C40384078407000E001E001C00380078007010E011E +011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF +FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F +C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 +FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 +00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 +C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F +F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 +0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 +0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F +F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 +0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF +C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 +FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 +0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F +C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 +DI76 D78 D85 D<003FFE00000001FFFFE0000007FFFFF800000FE0 +07FC00000FF001FE00001FF800FF00001FF8007F80001FF8007FC0001FF8003FC0000FF0003FE0 +0007E0003FE00003C0003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000 +FFFFE000001FFFFFE000007FF83FE00003FF803FE00007FC003FE0000FF0003FE0001FE0003FE0 +003FE0003FE0007FC0003FE0007FC0003FE000FF80003FE000FF80003FE000FF80003FE000FF80 +003FE000FF80007FE0007FC0007FE0007FC000DFE0003FE0039FF0001FF80F0FFFE007FFFE0FFF +E001FFF807FFE0003FE000FFE02B267DA52F>97 D<00FE00000000FFFE00000000FFFE00000000 +FFFE00000000FFFE0000000007FE0000000003FE0000000003FE0000000003FE0000000003FE00 +00000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE00000000 +03FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE01 +FF000003FE1FFFF00003FE7FFFFC0003FEFC03FE0003FFF000FF0003FFC0003F8003FF00001FC0 +03FE00001FE003FE00000FF003FE00000FF803FE00000FF803FE000007FC03FE000007FC03FE00 +0007FC03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE +03FE000007FE03FE000007FE03FE000007FE03FE000007FC03FE000007FC03FE000007FC03FE00 +000FFC03FE00000FF803FE00000FF003FE00001FF003FF00001FE003FF80003FC003FFC0007F80 +03F9E000FF0003F0FC07FE0003F07FFFF80003E01FFFE00003C003FE00002F3C7DBB36>I<01E0 +0007F8000FFC000FFC001FFE001FFE001FFE001FFE000FFC000FFC0007F80001E0000000000000 +0000000000000000000000000000000000000000000000000000000000FE00FFFE00FFFE00FFFE +00FFFE0007FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE +0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE +0003FE0003FE0003FE0003FE00FFFFF0FFFFF0FFFFF0FFFFF0143D7DBC1A>105 +D<0001FFC00000000FFFF80000007FFFFF000000FF80FF800003FE003FE00007F8000FF0000FF0 +0007F8000FF00007F8001FE00003FC003FE00003FE003FE00003FE007FC00001FF007FC00001FF +007FC00001FF007FC00001FF00FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC0 +0001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF807FC00001FF007FC00001FF +007FC00001FF003FE00003FE003FE00003FE001FE00003FC001FF00007FC000FF00007F80007F8 +000FF00003FE003FE00000FF80FF8000007FFFFF0000000FFFF800000001FFC0000029267DA530 +>111 D<01FC03F000FFFC0FFC00FFFC1FFF00FFFC3C3F80FFFC707F8007FCE0FFC003FCC0FFC0 +03FD80FFC003FD80FFC003FF807F8003FF003F0003FF001E0003FF00000003FE00000003FE0000 +0003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00 +000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE +00000003FE00000003FE00000003FE000000FFFFFC0000FFFFFC0000FFFFFC0000FFFFFC000022 +267DA528>114 D<003FF07003FFFEF007FFFFF01FC01FF03F0003F03E0001F07C0001F07C0000 +F0FC0000F0FC0000F0FE0000F0FF000000FFC00000FFFC00007FFFF0003FFFFE003FFFFF801FFF +FFC00FFFFFE003FFFFF000FFFFF8001FFFFC00007FFC000007FE700001FEF00000FEF000007EF8 +00007EF800007EFC00007EFC00007CFE0000FCFF0000F8FF8001F0FFF00FE0F9FFFFC0F07FFF00 +C01FF8001F267DA526>I<000F0000000F0000000F0000000F0000000F0000001F0000001F0000 +001F0000001F0000003F0000003F0000007F0000007F000000FF000001FF000003FF000007FF00 +001FFFFFF0FFFFFFF0FFFFFFF0FFFFFFF001FF000001FF000001FF000001FF000001FF000001FF +000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001 +FF000001FF000001FF000001FF000001FF003C01FF003C01FF003C01FF003C01FF003C01FF003C +01FF003C01FF003C00FF007800FF8078007F80F0003FC1E0001FFFC0000FFF800001FE001E377E +B626>I121 +D E end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 300dpi +TeXDict begin + +%%EndSetup +%%Page: 1 1 +0 bop 0 1152 a Fp(GNU)33 b(History)f(Library)p 0 1201 1950 +17 v 1035 1250 a Fo(Edition)16 b(2.0,)e(for)h Fn(History)f(Library)g +Fo(V)l(ersion)i(2.0.)1759 1304 y(July)g(1994)0 2443 y Fm(Brian)23 +b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 +b(oundation)0 2509 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 +b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2545 1950 9 +v eop +%%Page: 2 2 +1 bop 0 295 a Fo(This)16 b(do)q(cumen)o(t)g(describ)q(es)h(the)f(GNU)f +(History)g(library)l(,)h(a)g(programming)e(to)q(ol)i(that)f(pro)o(vides)h(a)f +(consisten)o(t)0 358 y(user)g(in)o(terface)h(for)e(recalling)j(lines)g(of)e +(previously)h(t)o(yp)q(ed)g(input.)0 495 y(Published)h(b)o(y)f(the)f(F)l(ree) +g(Soft)o(w)o(are)f(F)l(oundation)0 557 y(675)g(Massac)o(h)o(usetts)g(Av)o(en) +o(ue,)0 619 y(Cam)o(bridge,)h(MA)g(02139)f(USA)0 756 y(P)o(ermission)f(is)g +(gran)o(ted)f(to)f(mak)o(e)h(and)h(distribute)h(v)o(erbatim)e(copies)h(of)f +(this)h(man)o(ual)g(pro)o(vided)g(the)f(cop)o(yrigh)o(t)0 818 +y(notice)k(and)f(this)h(p)q(ermission)h(notice)e(are)g(preserv)o(ed)h(on)f +(all)h(copies.)0 955 y(P)o(ermission)f(is)f(gran)o(ted)f(to)h(cop)o(y)g(and)g +(distribute)h(mo)q(di\014ed)h(v)o(ersions)e(of)f(this)i(man)o(ual)f(under)h +(the)f(conditions)0 1018 y(for)e(v)o(erbatim)g(cop)o(ying,)h(pro)o(vided)h +(that)d(the)i(en)o(tire)g(resulting)h(deriv)o(ed)f(w)o(ork)f(is)h +(distributed)h(under)f(the)g(terms)0 1080 y(of)i(a)g(p)q(ermission)h(notice)g +(iden)o(tical)h(to)e(this)g(one.)0 1217 y(P)o(ermission)20 +b(is)g(gran)o(ted)f(to)g(cop)o(y)h(and)f(distribute)i(translations)f(of)f +(this)h(man)o(ual)f(in)o(to)h(another)f(language,)0 1279 y(under)c(the)f(ab)q +(o)o(v)o(e)g(conditions)h(for)e(mo)q(di\014ed)j(v)o(ersions,)e(except)g(that) +g(this)g(p)q(ermission)i(notice)e(ma)o(y)g(b)q(e)h(stated)0 +1341 y(in)h(a)f(translation)g(appro)o(v)o(ed)g(b)o(y)g(the)g(F)l(oundation.)0 +2636 y(Cop)o(yrigh)o(t)226 2635 y(c)214 2636 y Fl(\015)g Fo(1989,)f(1991)g(F) +l(ree)h(Soft)o(w)o(are)f(F)l(oundation,)h(Inc.)p eop +%%Page: 1 3 +2 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 +b(1)0 158 y Fk(1)41 b(Using)14 b(History)h(In)n(teractiv)n(ely)62 +330 y Fo(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g(the)g(GNU)g +(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g(user's)h(stand-)0 +392 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f(considered)i(a)d(user's)h +(guide.)23 b(F)l(or)15 b(information)h(on)g(using)h(the)f(GNU)g(History)f +(Library)0 454 y(in)h(y)o(our)f(o)o(wn)f(programs,)g(see)i(Chapter)e(2)h +([Programming)f(with)i(GNU)f(History],)f(page)h(5.)0 663 y +Fm(1.1)33 b(History)15 b(In)n(teraction)62 800 y Fo(The)j(History)g(library)g +(pro)o(vides)h(a)e(history)h(expansion)h(feature)e(that)g(is)i(similar)g(to)e +(the)h(history)f(expan-)0 862 y(sion)k(pro)o(vided)h(b)o(y)f +Fn(csh)p Fo(.)36 b(The)22 b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o +(tax)f(used)i(to)e(manipulate)i(the)f(history)0 924 y(information.)62 +1061 y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.)18 +b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e(the)g +(previous)0 1124 y(history)h(should)h(b)q(e)f(used)h(during)f(substitution.) +20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g(of)g(that)f(line)i +(for)f(inclusion)0 1186 y(in)o(to)f(the)h(curren)o(t)f(one.)18 +b(The)12 b(line)h(selected)f(from)f(the)g(previous)h(history)g(is)f(called)i +(the)e Fj(ev)o(en)o(t)p Fo(,)h(and)f(the)h(p)q(ortions)0 1248 +y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h(are)g(called)h +Fj(w)o(ords)p Fo(.)j(The)c(line)h(is)f(brok)o(en)f(in)o(to)h(w)o(ords)f(in)h +(the)f(same)h(fashion)0 1310 y(that)j(Bash)h(do)q(es,)h(so)e(that)g(sev)o +(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f(surrounded)i(b)o(y)f(quotes)f +(are)h(considered)h(as)0 1373 y(one)c(w)o(ord.)0 1565 y Fi(1.1.1)30 +b(Ev)n(en)n(t)16 b(Designators)62 1702 y Fo(An)g(ev)o(en)o(t)f(designator)g +(is)g(a)g(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g +(history)f(list.)0 1847 y Fn(!)216 b Fo(Start)14 b(a)g(history)h +(substitution,)g(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f +(the)h(end)g(of)g(the)g(line,)240 1909 y Fn(=)g Fo(or)g Fn(\()p +Fo(.)0 1989 y Fn(!!)192 b Fo(Refer)16 b(to)e(the)i(previous)f(command.)20 +b(This)c(is)g(a)f(synon)o(ym)g(for)f Fn(!-1)p Fo(.)0 2068 y +Fn(!n)192 b Fo(Refer)16 b(to)e(command)h(line)i Fj(n)p Fo(.)0 +2148 y Fn(!-n)168 b Fo(Refer)16 b(to)e(the)i(command)f Fj(n)g +Fo(lines)i(bac)o(k.)0 2227 y Fn(!string)72 b Fo(Refer)16 b(to)e(the)i(most)e +(recen)o(t)h(command)g(starting)g(with)g Fj(string)p Fo(.)0 +2298 y Fn(!?string)p Fo([)p Fn(?)p Fo(])240 2360 y(Refer)h(to)e(the)i(most)e +(recen)o(t)h(command)g(con)o(taining)h Fj(string)p Fo(.)0 2440 +y Fn(!#)192 b Fo(The)15 b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e +(far.)0 2510 y Fn(^string1^string2^)240 2573 y Fo(Quic)o(k)j(Substitution.)22 +b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h Fj(string1)h +Fo(with)e Fj(string2)p Fo(.)21 b(Equiv-)240 2635 y(alen)o(t)15 +b(to)g Fn(!!:s/string1/string2/)p Fo(.)p eop +%%Page: 2 4 +3 bop 0 -83 a Fo(2)1497 b(GNU)15 b(History)g(Library)0 158 +y Fi(1.1.2)30 b(W)-5 b(ord)15 b(Designators)62 295 y Fo(A)i +Fn(:)g Fo(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j(from)d(the)g +(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted)g(if)g(the)g(w)o +(ord)0 358 y(designator)d(b)q(egins)h(with)f(a)f Fn(^)p Fo(,)h +Fn($)p Fo(,)f Fn(*)h Fo(or)f Fn(\045)p Fo(.)20 b(W)l(ords)13 +b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q(eginning)i(of)d(the)h(line,)i +(with)e(the)0 420 y(\014rst)h(w)o(ord)f(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f +(\(zero\).)0 569 y Fn(0)h(\(zero\))57 b Fo(The)15 b Fn(0)p +Fo(th)g(w)o(ord.)20 b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f +(command)g(w)o(ord.)0 656 y Fn(n)216 b Fo(The)15 b Fj(n)p Fo(th)h(w)o(ord.)0 +744 y Fn(^)216 b Fo(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o(ord)g +(1.)0 831 y Fn($)216 b Fo(The)15 b(last)h(argumen)o(t.)0 918 +y Fn(\045)216 b Fo(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g(most)g +(recen)o(t)g Fn(?string?)f Fo(searc)o(h.)0 1005 y Fn(x-y)168 +b Fo(A)15 b(range)g(of)g(w)o(ords;)f Fn(-)p Fj(y)19 b Fo(abbreviates)c +Fn(0-)p Fj(y)t Fo(.)0 1092 y Fn(*)216 b Fo(All)17 b(of)f(the)g(w)o(ords,)f +(except)i(the)f Fn(0)p Fo(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f +Fn(1-$)p Fo(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 +1155 y Fn(*)f Fo(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g(ev)o(en) +o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e(case.)0 +1242 y Fn(x*)192 b Fo(Abbreviates)16 b Fn(x-$)0 1329 y(x-)192 +b Fo(Abbreviates)16 b Fn(x-$)f Fo(lik)o(e)h Fn(x*)p Fo(,)e(but)i(omits)f(the) +g(last)g(w)o(ord.)0 1537 y Fi(1.1.3)30 b(Mo)r(di\014ers)62 +1674 y Fo(After)20 b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h +(add)g(a)g(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 +1736 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g Fn(:)p +Fo(.)0 1885 y Fn(h)216 b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(pathname)f(comp) +q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 1973 y Fn(r)216 +b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g(the)g(form)g(`)p +Fn(.)p Fo(')p Fj(su\016x)p Fo(,)f(lea)o(ving)i(the)f(basename.)0 +2060 y Fn(e)216 b Fo(Remo)o(v)o(e)15 b(all)h(but)g(the)f(trailing)h(su\016x.) +0 2147 y Fn(t)216 b Fo(Remo)o(v)o(e)15 b(all)h(leading)h(pathname)e(comp)q +(onen)o(ts,)g(lea)o(ving)h(the)f(tail.)0 2234 y Fn(p)216 b +Fo(Prin)o(t)15 b(the)g(new)h(command)f(but)g(do)g(not)g(execute)h(it.)0 +2309 y Fn(s/old/new/)240 2371 y Fo(Substitute)g Fj(new)k Fo(for)15 +b(the)h(\014rst)f(o)q(ccurrence)h(of)g Fj(old)h Fo(in)g(the)e(ev)o(en)o(t)h +(line.)22 b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2433 +y(used)e(in)f(place)h(of)f Fn(/)p Fo(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q +(e)i(quoted)f(in)h Fj(old)h Fo(and)e Fj(new)17 b Fo(with)12 +b(a)g(single)h(bac)o(kslash.)240 2496 y(If)g Fn(&)h Fo(app)q(ears)f(in)h +Fj(new)p Fo(,)f(it)h(is)g(replaced)g(b)o(y)f Fj(old)p Fo(.)20 +b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h Fn(&)p +Fo(.)19 b(The)13 b(\014nal)240 2558 y(delimiter)k(is)f(optional)g(if)f(it)h +(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 +2645 y Fn(&)216 b Fo(Rep)q(eat)16 b(the)f(previous)h(substitution.)p +eop +%%Page: 3 5 +4 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 +b(3)0 158 y Fn(g)216 b Fo(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o +(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 +b(in)g(conjunction)g(with)f Fn(s)p Fo(,)f(as)240 221 y(in)i +Fn(gs/old/new/)p Fo(,)d(or)i(with)h Fn(&)p Fo(.)p eop +%%Page: 4 6 +5 bop 0 -83 a Fo(4)1497 b(GNU)15 b(History)g(Library)p eop +%%Page: 5 7 +6 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(5)0 158 y Fk(2)41 b(Programming)16 b(with)f(GNU)h(History)62 +347 y Fo(This)e(c)o(hapter)f(describ)q(es)i(ho)o(w)d(to)h(in)o(terface)g +(programs)f(that)h(y)o(ou)g(write)g(with)g(the)h(GNU)f(History)g(Library)l(.) +0 409 y(It)j(should)g(b)q(e)g(considered)h(a)f(tec)o(hnical)h(guide.)22 +b(F)l(or)15 b(information)h(on)f(the)h(in)o(teractiv)o(e)g(use)g(of)f(GNU)g +(History)l(,)0 471 y(see)g(Chapter)g(1)g([Using)h(History)f(In)o(teractiv)o +(ely],)g(page)g(1.)0 698 y Fm(2.1)33 b(In)n(tro)r(duction)17 +b(to)e(History)62 835 y Fo(Man)o(y)j(programs)g(read)h(input)h(from)e(the)g +(user)h(a)g(line)h(at)f(a)f(time.)31 b(The)19 b(GNU)g(History)f(library)i(is) +f(able)0 897 y(to)e(k)o(eep)g(trac)o(k)f(of)h(those)g(lines,)i(asso)q(ciate)e +(arbitrary)g(data)g(with)g(eac)o(h)g(line,)j(and)d(utilize)i(information)f +(from)0 960 y(previous)e(lines)h(in)f(comp)q(osing)f(new)h(ones.)62 +1097 y(The)i(programmer)f(using)h(the)g(History)g(library)g(has)g(a)o(v)m +(ailable)h(functions)g(for)e(remem)o(b)q(ering)h(lines)i(on)d(a)0 +1159 y(history)f(list,)g(asso)q(ciating)g(arbitrary)g(data)f(with)h(a)f +(line,)j(remo)o(ving)d(lines)j(from)d(the)h(list,)g(searc)o(hing)g(through)0 +1221 y(the)h(list)h(for)e(a)h(line)h(con)o(taining)g(an)f(arbitrary)f(text)h +(string,)g(and)g(referencing)h(an)o(y)f(line)h(in)g(the)f(list)h(directly)l +(.)0 1284 y(In)d(addition,)h(a)e(history)h Fj(expansion)h Fo(function)g(is)f +(a)o(v)m(ailable)h(whic)o(h)g(pro)o(vides)f(for)f(a)h(consisten)o(t)g(user)g +(in)o(terface)0 1346 y(across)f(di\013eren)o(t)i(programs.)62 +1483 y(The)i(user)g(using)g(programs)f(written)g(with)h(the)g(History)f +(library)i(has)e(the)h(b)q(ene\014t)h(of)e(a)g(consisten)o(t)h(user)0 +1545 y(in)o(terface)d(with)g(a)f(set)h(of)f(w)o(ell-kno)o(wn)h(commands)g +(for)f(manipulating)i(the)f(text)f(of)g(previous)h(lines)h(and)f(using)0 +1608 y(that)g(text)g(in)i(new)e(commands.)22 b(The)15 b(basic)i(history)e +(manipulation)j(commands)d(are)g(similar)i(to)e(the)h(history)0 +1670 y(substitution)g(pro)o(vided)g(b)o(y)f Fn(csh)p Fo(.)62 +1807 y(If)g(the)g(programmer)e(desires,)i(he)g(can)g(use)g(the)f(Readline)j +(library)l(,)e(whic)o(h)h(includes)g(some)f(history)f(manip-)0 +1870 y(ulation)i(b)o(y)f(default,)h(and)f(has)g(the)g(added)h(adv)m(an)o +(tage)f(of)g(command)g(line)h(editing.)0 2096 y Fm(2.2)33 b(History)15 +b(Storage)62 2234 y Fo(The)h(history)f(list)h(is)g(an)f(arra)o(y)f(of)g +(history)i(en)o(tries.)k(A)15 b(history)g(en)o(try)g(is)h(declared)g(as)f +(follo)o(ws:)120 2358 y Fn(typedef)23 b(struct)g(_hist_entry)f({)168 +2408 y(char)h(*line;)168 2458 y(char)g(*data;)120 2508 y(})h(HIST_ENTRY;)62 +2645 y Fo(The)16 b(history)f(list)h(itself)g(migh)o(t)f(therefore)g(b)q(e)h +(declared)g(as)p eop +%%Page: 6 8 +7 bop 0 -83 a Fo(6)1497 b(GNU)15 b(History)g(Library)120 158 +y Fn(HIST_ENTRY)22 b(**the_history_list;)62 302 y Fo(The)16 +b(state)e(of)h(the)g(History)g(library)h(is)g(encapsulated)g(in)o(to)f(a)g +(single)i(structure:)120 434 y Fn(/*)24 b(A)f(structure)g(used)g(to)h(pass)f +(the)h(current)f(state)g(of)g(the)h(history)f(stuff)g(around.)g(*/)120 +484 y(typedef)g(struct)g(_hist_state)f({)168 534 y(HIST_ENTRY)g(**entries;) +214 b(/*)23 b(Pointer)g(to)h(the)f(entries)g(themselves.)f(*/)168 +584 y(int)h(offset;)453 b(/*)23 b(The)h(location)e(pointer)h(within)g(this)h +(array.)f(*/)168 633 y(int)g(length;)453 b(/*)23 b(Number)g(of)h(elements)f +(within)g(this)g(array.)g(*/)168 683 y(int)g(size;)501 b(/*)23 +b(Number)g(of)h(slots)f(allocated)g(to)g(this)h(array.)f(*/)168 +733 y(int)g(flags;)120 783 y(})h(HISTORY_STATE;)62 927 y Fo(If)16 +b(the)f(\015ags)g(mem)o(b)q(er)g(includes)j Fn(HS_STIFLED)p +Fo(,)13 b(the)i(history)h(has)f(b)q(een)h(sti\015ed.)0 1215 +y Fm(2.3)33 b(History)15 b(F)-6 b(unctions)62 1359 y Fo(This)16 +b(section)g(describ)q(es)h(the)e(calling)i(sequence)f(for)f(the)g(v)m(arious) +h(functions)g(presen)o(t)f(in)h(GNU)f(History)l(.)0 1631 y +Fi(2.3.1)30 b(Initializing)15 b(History)g(and)g(State)g(Managemen)n(t)62 +1775 y Fo(This)j(section)g(describ)q(es)h(functions)f(used)g(to)e(initialize) +21 b(and)c(manage)g(the)g(state)g(of)g(the)g(History)g(library)0 +1837 y(when)f(y)o(ou)f(w)o(an)o(t)f(to)g(use)i(the)f(history)g(functions)h +(in)g(y)o(our)f(program.)1725 2021 y(F)l(unction)-1899 b Fh(void)20 +b Fg(using)p 258 2021 18 3 v 20 w(history)j Ff(\(\))120 2083 +y Fo(Begin)g(a)f(session)g(in)h(whic)o(h)g(the)f(history)g(functions)g(migh)o +(t)g(b)q(e)h(used.)40 b(This)23 b(initializes)i(the)120 2145 +y(in)o(teractiv)o(e)16 b(v)m(ariables.)1725 2328 y(F)l(unction)-1899 +b Fh(HISTORY_STATE)21 b(*)e Fg(history)p 582 2328 V 21 w(get)p +680 2328 V 21 w(history)p 876 2328 V 21 w(state)j Ff(\(\))120 +2391 y Fo(Return)16 b(a)f(structure)g(describing)i(the)e(curren)o(t)g(state)f +(of)h(the)g(input)i(history)l(.)1725 2574 y(F)l(unction)-1899 +b Fh(void)20 b Fg(history)p 302 2574 V 20 w(set)p 393 2574 +V 21 w(history)p 589 2574 V 21 w(state)j Ff(\()p Fn(HISTORY_STATE)13 +b(*state)p Ff(\))120 2636 y Fo(Set)i(the)h(state)e(of)h(the)g(history)g(list) +h(according)g(to)e Fj(state)p Fo(.)p eop +%%Page: 7 9 +8 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(7)0 158 y Fi(2.3.2)30 b(History)15 b(List)g(Managemen)n(t)62 +295 y Fo(These)i(functions)h(manage)e(individual)k(en)o(tries)d(on)f(the)h +(history)g(list,)g(or)f(set)h(parameters)e(managing)i(the)0 +358 y(list)f(itself.)1725 520 y(F)l(unction)-1899 b Fh(void)20 +b Fg(add)p 219 520 18 3 v 20 w(history)j Ff(\()p Fn(char)14 +b(*string)p Ff(\))120 582 y Fo(Place)j Fj(string)k Fo(at)16 +b(the)g(end)i(of)e(the)g(history)h(list.)25 b(The)17 b(asso)q(ciated)g(data)f +(\014eld)h(\(if)g(an)o(y\))f(is)h(set)g(to)120 644 y Fn(NULL)p +Fo(.)1725 806 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e +Fg(remo)n(v)n(e)p 509 806 V 20 w(history)k Ff(\()p Fn(int)14 +b(which)p Ff(\))120 868 y Fo(Remo)o(v)o(e)d(history)g(en)o(try)g(at)g +(o\013set)f Fj(whic)o(h)i Fo(from)f(the)g(history)l(.)19 b(The)11 +b(remo)o(v)o(ed)g(elemen)o(t)h(is)g(returned)120 930 y(so)j(y)o(ou)g(can)g +(free)g(the)h(line,)g(data,)e(and)i(con)o(taining)g(structure.)1725 +1092 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e Fg(replace)p +505 1092 V 22 w(history)p 702 1092 V 20 w(en)n(try)24 b Ff(\()p +Fn(int)14 b(which,)g(char)h(*line,)f(char)208 1155 y(*data)p +Ff(\))120 1217 y Fo(Mak)o(e)d(the)i(history)f(en)o(try)g(at)f(o\013set)h +Fj(whic)o(h)h Fo(ha)o(v)o(e)e Fj(line)17 b Fo(and)12 b Fj(data)p +Fo(.)19 b(This)12 b(returns)g(the)h(old)g(en)o(try)e(so)120 +1279 y(y)o(ou)i(can)g(disp)q(ose)h(of)e(the)h(data.)19 b(In)13 +b(the)g(case)g(of)f(an)h(in)o(v)m(alid)i Fj(whic)o(h)p Fo(,)f(a)f +Fn(NULL)f Fo(p)q(oin)o(ter)i(is)f(returned.)1725 1441 y(F)l(unction)-1899 +b Fh(void)20 b Fg(sti\015e)p 245 1441 V 21 w(history)j Ff(\()p +Fn(int)14 b(max)p Ff(\))120 1503 y Fo(Sti\015e)i(the)f(history)h(list,)f +(remem)o(b)q(ering)h(only)g(the)f(last)g Fj(max)j Fo(en)o(tries.)1725 +1665 y(F)l(unction)-1899 b Fh(int)20 b Fg(unsti\015e)p 283 +1665 V 21 w(history)i Ff(\(\))120 1728 y Fo(Stop)13 b(sti\015ing)h(the)f +(history)l(.)19 b(This)14 b(returns)f(the)g(previous)h(amoun)o(t)e(the)h +(history)g(w)o(as)g(sti\015ed.)20 b(The)120 1790 y(v)m(alue)c(is)g(p)q +(ositiv)o(e)g(if)g(the)f(history)g(w)o(as)g(sti\015ed,)h(negativ)o(e)f(if)g +(it)h(w)o(asn't.)1725 1952 y(F)l(unction)-1899 b Fh(int)20 +b Fg(history)p 276 1952 V 20 w(is)p 334 1952 V 21 w(sti\015ed)k +Ff(\(\))120 2014 y Fo(Returns)16 b(non-zero)f(if)h(the)f(history)g(is)h +(sti\015ed,)g(zero)f(if)g(it)h(is)g(not.)0 2222 y Fi(2.3.3)30 +b(Information)14 b(Ab)r(out)h(the)g(History)g(List)62 2359 +y Fo(These)h(functions)g(return)f(information)g(ab)q(out)g(the)h(en)o(tire)f +(history)g(list)h(or)f(individual)j(list)f(en)o(tries.)1725 +2521 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(**)e Fg(history)p +530 2521 V 21 w(list)24 b Ff(\(\))120 2583 y Fo(Return)e(a)e +Fn(NULL)h Fo(terminated)g(arra)o(y)f(of)g Fn(HIST_ENTRY)g Fo(whic)o(h)i(is)f +(the)g(curren)o(t)g(input)h(history)l(.)120 2645 y(Elemen)o(t)16 +b(0)f(of)f(this)i(list)g(is)g(the)f(b)q(eginning)i(of)e(time.)20 +b(If)c(there)f(is)h(no)f(history)l(,)g(return)g Fn(NULL)p Fo(.)p +eop +%%Page: 8 10 +9 bop 0 -83 a Fo(8)1497 b(GNU)15 b(History)g(Library)1725 158 +y(F)l(unction)-1899 b Fh(int)20 b Fg(where)p 250 158 18 3 v +20 w(history)j Ff(\(\))120 221 y Fo(Returns)16 b(the)f(o\013set)f(of)h(the)g +(curren)o(t)g(history)g(elemen)o(t.)1725 378 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(curren)n(t)p 512 378 V 21 w(history)k +Ff(\(\))120 440 y Fo(Return)14 b(the)g(history)g(en)o(try)f(at)h(the)g +(curren)o(t)f(p)q(osition,)i(as)e(determined)j(b)o(y)d Fn(where_history)h +(\(\))p Fo(.)120 502 y(If)h(there)h(is)f(no)h(en)o(try)e(there,)h(return)g(a) +g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 660 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(history)p 504 660 V 21 w(get)j +Ff(\()p Fn(int)15 b(offset)p Ff(\))120 722 y Fo(Return)g(the)g(history)f(en)o +(try)g(at)g(p)q(osition)i Fj(o\013set)p Fo(,)d(starting)h(from)g +Fn(history_base)p Fo(.)k(If)c(there)h(is)g(no)120 784 y(en)o(try)g(there,)g +(or)f(if)i Fj(o\013set)f Fo(is)h(greater)e(than)h(the)h(history)f(length,)g +(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 942 y(F)l(unction)-1899 +b Fh(int)20 b Fg(history)p 276 942 V 20 w(total)p 412 942 V +22 w(b)n(ytes)j Ff(\(\))120 1004 y Fo(Return)17 b(the)f(n)o(um)o(b)q(er)g(of) +g(b)o(ytes)g(that)f(the)h(primary)g(history)g(en)o(tries)h(are)e(using.)23 +b(This)17 b(function)120 1066 y(returns)e(the)g(sum)h(of)e(the)i(lengths)f +(of)g(all)h(the)g(lines)g(in)g(the)g(history)l(.)0 1265 y Fi(2.3.4)30 +b(Mo)n(ving)15 b(Around)h(the)f(History)g(List)62 1402 y Fo(These)h +(functions)g(allo)o(w)f(the)g(curren)o(t)h(index)g(in)o(to)f(the)h(history)f +(list)h(to)e(b)q(e)i(set)f(or)g(c)o(hanged.)1725 1559 y(F)l(unction)-1899 +b Fh(int)20 b Fg(history)p 276 1559 V 20 w(set)p 367 1559 V +21 w(p)r(os)h Ff(\()p Fn(int)15 b(pos)p Ff(\))120 1621 y Fo(Set)g(the)h(p)q +(osition)g(in)g(the)f(history)g(list)h(to)f Fj(p)q(os)p Fo(,)g(an)g(absolute) +g(index)i(in)o(to)e(the)g(list.)1725 1779 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(previous)p 540 1779 V 20 w(history)k +Ff(\(\))120 1841 y Fo(Bac)o(k)16 b(up)h(the)g(curren)o(t)f(history)h +(o\013set)e(to)h(the)h(previous)g(history)g(en)o(try)l(,)f(and)h(return)f(a)g +(p)q(oin)o(ter)120 1903 y(to)f(that)f(en)o(try)l(.)20 b(If)15 +b(there)g(is)h(no)f(previous)h(en)o(try)l(,)f(return)g(a)g +Fn(NULL)g Fo(p)q(oin)o(ter.)1725 2061 y(F)l(unction)-1899 b +Fh(HIST_ENTRY)21 b(*)e Fg(next)p 439 2061 V 21 w(history)k +Ff(\(\))120 2123 y Fo(Mo)o(v)o(e)c(the)h(curren)o(t)g(history)f(o\013set)g +(forw)o(ard)g(to)g(the)h(next)g(history)g(en)o(try)l(,)g(and)g(return)g(the)g +(a)120 2185 y(p)q(oin)o(ter)c(to)e(that)h(en)o(try)l(.)k(If)d(there)f(is)h +(no)f(next)g(en)o(try)l(,)g(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)0 +2384 y Fi(2.3.5)30 b(Searc)n(hing)15 b(the)h(History)f(List)62 +2521 y Fo(These)e(functions)g(allo)o(w)f(searc)o(hing)h(of)f(the)g(history)g +(list)h(for)f(en)o(tries)h(con)o(taining)g(a)f(sp)q(eci\014c)i(string.)19 +b(Searc)o(h-)0 2583 y(ing)e(ma)o(y)g(b)q(e)g(p)q(erformed)g(b)q(oth)g(forw)o +(ard)f(and)h(bac)o(kw)o(ard)f(from)g(the)h(curren)o(t)f(history)h(p)q +(osition.)26 b(The)17 b(searc)o(h)0 2645 y(ma)o(y)d(b)q(e)i +Fj(anc)o(hored)p Fo(,)f(meaning)h(that)f(the)g(string)g(m)o(ust)g(matc)o(h)f +(at)h(the)g(b)q(eginning)i(of)e(the)h(history)f(en)o(try)l(.)p +eop +%%Page: 9 11 +10 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(9)1725 158 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 158 18 3 v 20 w(searc)n(h)j Ff(\()p Fn(char)14 b(*string,)g(int)h +(direction)p Ff(\))120 221 y Fo(Searc)o(h)k(the)g(history)g(for)f +Fj(string)p Fo(,)i(starting)e(at)g(the)h(curren)o(t)g(history)g(o\013set.)30 +b(If)19 b Fj(direction)h Fn(<)f Fo(0,)120 283 y(then)14 b(the)f(searc)o(h)g +(is)h(through)e(previous)i(en)o(tries,)g(else)g(through)f(subsequen)o(t.)20 +b(If)13 b Fj(string)k Fo(is)d(found,)120 345 y(then)f(the)g(curren)o(t)g +(history)g(index)i(is)e(set)g(to)f(that)h(history)g(en)o(try)l(,)f(and)i(the) +f(v)m(alue)h(returned)f(is)h(the)120 407 y(o\013set)h(in)i(the)f(line)i(of)d +(the)h(en)o(try)g(where)g Fj(string)k Fo(w)o(as)c(found.)22 +b(Otherwise,)17 b(nothing)f(is)h(c)o(hanged,)120 470 y(and)e(a)g(-1)g(is)h +(returned.)1725 659 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 659 V 20 w(searc)n(h)p 452 659 V 21 w(pre\014x)i Ff(\()p +Fn(char)15 b(*string,)f(int)g(direction)p Ff(\))120 721 y Fo(Searc)o(h)22 +b(the)h(history)f(for)f Fj(string)p Fo(,)j(starting)e(at)f(the)i(curren)o(t)f +(history)g(o\013set.)40 b(The)22 b(searc)o(h)g(is)120 783 y(anc)o(hored:)i +(matc)o(hing)18 b(lines)h(m)o(ust)d(b)q(egin)j(with)f Fj(string)p +Fo(.)26 b(If)17 b Fj(direction)i Fn(<)e Fo(0,)g(then)h(the)f(searc)o(h)g(is) +120 845 y(through)e(previous)h(en)o(tries,)f(else)i(through)d(subsequen)o(t.) +21 b(If)16 b Fj(string)j Fo(is)d(found,)f(then)h(the)f(curren)o(t)120 +908 y(history)20 b(index)i(is)e(set)g(to)g(that)f(en)o(try)l(,)i(and)f(the)g +(return)h(v)m(alue)g(is)g(0.)34 b(Otherwise,)22 b(nothing)e(is)120 +970 y(c)o(hanged,)15 b(and)h(a)e(-1)h(is)h(returned.)1725 1159 +y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 1159 V 20 +w(searc)n(h)p 452 1159 V 21 w(p)r(os)h Ff(\()p Fn(char)15 b(*string,)f(int)g +(direction,)g(int)h(pos)p Ff(\))120 1221 y Fo(Searc)o(h)d(for)f +Fj(string)k Fo(in)d(the)g(history)f(list,)i(starting)e(at)g +Fj(p)q(os)p Fo(,)h(an)f(absolute)h(index)h(in)o(to)e(the)h(list.)19 +b(If)12 b Fj(di-)120 1283 y(rection)g Fo(is)h(negativ)o(e,)f(the)g(searc)o(h) +g(pro)q(ceeds)h(bac)o(kw)o(ard)e(from)g Fj(p)q(os)p Fo(,)i(otherwise)f(forw)o +(ard.)17 b(Returns)120 1345 y(the)e(absolute)h(index)g(of)f(the)g(history)h +(elemen)o(t)f(where)h Fj(string)j Fo(w)o(as)14 b(found,)h(or)g(-1)g +(otherwise.)0 1634 y Fi(2.3.6)30 b(Managing)14 b(the)i(History)f(File)62 +1780 y Fo(The)f(History)g(library)h(can)f(read)g(the)g(history)g(from)f(and)i +(write)f(it)g(to)f(a)h(\014le.)20 b(This)15 b(section)g(do)q(cumen)o(ts)f +(the)0 1842 y(functions)i(for)f(managing)g(a)f(history)i(\014le.)1725 +2031 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p 211 2031 V +20 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 2093 +y Fo(Add)i(the)f(con)o(ten)o(ts)g(of)g Fj(\014lename)k Fo(to)c(the)h(history) +f(list,)h(a)f(line)i(at)e(a)g(time.)24 b(If)17 b Fj(\014lename)j +Fo(is)d Fn(NULL)p Fo(,)120 2155 y(then)f(read)f(from)f(`)p +Fn(~/.history)p Fo('.)k(Returns)e(0)e(if)i(successful,)g(or)f(errno)g(if)h +(not.)1725 2344 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p +211 2344 V 20 w(history)p 406 2344 V 20 w(range)i Ff(\()p Fn(char)15 +b(*filename,)e(int)i(from,)g(int)f(to)p Ff(\))120 2407 y Fo(Read)j(a)e(range) +h(of)f(lines)j(from)d Fj(\014lename)p Fo(,)i(adding)f(them)g(to)f(the)h +(history)g(list.)23 b(Start)15 b(reading)i(at)120 2469 y(line)f +Fj(from)f Fo(and)g(end)g(at)f Fj(to)p Fo(.)19 b(If)d Fj(from)e +Fo(is)h(zero,)f(start)g(at)g(the)h(b)q(eginning.)22 b(If)15 +b Fj(to)i Fo(is)e(less)g(than)g Fj(from)p Fo(,)120 2531 y(then)i(read)g(un)o +(til)h(the)f(end)g(of)g(the)g(\014le.)25 b(If)17 b Fj(\014lename)k +Fo(is)c Fn(NULL)p Fo(,)f(then)i(read)e(from)g(`)p Fn(~/.history)p +Fo('.)120 2593 y(Returns)g(0)f(if)g(successful,)h(or)f Fn(errno)g +Fo(if)g(not.)p eop +%%Page: 10 12 +11 bop 0 -83 a Fo(10)1474 b(GNU)15 b(History)g(Library)1725 +158 y(F)l(unction)-1899 b Fh(int)20 b Fg(write)p 229 158 18 +3 v 22 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 +221 y Fo(W)l(rite)20 b(the)g(curren)o(t)f(history)h(to)f Fj(\014lename)p +Fo(,)i(o)o(v)o(erwriting)f Fj(\014lename)j Fo(if)d(necessary)l(.)34 +b(If)20 b Fj(\014lename)120 283 y Fo(is)d Fn(NULL)p Fo(,)g(then)g(write)g +(the)g(history)g(list)h(to)e(`)p Fn(~/.history)p Fo('.)23 b(V)l(alues)18 +b(returned)g(are)e(as)h(in)h Fn(read_)120 345 y(history)c(\(\))p +Fo(.)1725 504 y(F)l(unction)-1899 b Fh(int)20 b Fg(app)r(end)p +285 504 V 19 w(history)j Ff(\()p Fn(int)14 b(nelements,)g(char)h(*filename)p +Ff(\))120 566 y Fo(App)q(end)i(the)e(last)g Fj(nelemen)o(ts)j +Fo(of)d(the)g(history)g(list)h(to)f Fj(\014lename)p Fo(.)1725 +724 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 724 +V 20 w(truncate)p 507 724 V 21 w(\014le)k Ff(\()p Fn(char)14 +b(*filename,)g(int)h(nlines)p Ff(\))120 787 y Fo(T)l(runcate)g(the)h(history) +f(\014le)h Fj(\014lename)p Fo(,)g(lea)o(ving)g(only)g(the)f(last)g +Fj(nlines)k Fo(lines.)0 988 y Fi(2.3.7)30 b(History)15 b(Expansion)62 +1125 y Fo(These)h(functions)g(implemen)o(t)g Fn(csh)p Fo(-lik)o(e)g(history)g +(expansion.)1725 1283 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 1283 V 20 w(expand)j Ff(\()p Fn(char)14 b(*string,)g(char)h(**output)p +Ff(\))120 1345 y Fo(Expand)20 b Fj(string)p Fo(,)f(placing)i(the)e(result)h +(in)o(to)f Fj(output)p Fo(,)h(a)f(p)q(oin)o(ter)h(to)e(a)h(string)h(\(see)f +(Section)h(1.1)120 1408 y([History)15 b(In)o(teraction],)f(page)h(1\).)20 +b(Returns:)120 1555 y Fn(0)216 b Fo(If)21 b(no)g(expansions)h(to)q(ok)e +(place)h(\(or,)g(if)h(the)f(only)g(c)o(hange)g(in)h(the)f(text)f(w)o(as)g +(the)360 1618 y(de-slashifying)d(of)e(the)g(history)h(expansion)g(c)o +(haracter\);)120 1701 y Fn(1)216 b Fo(if)16 b(expansions)g(did)g(tak)o(e)e +(place;)120 1785 y Fn(-1)192 b Fo(if)16 b(there)f(w)o(as)f(an)h(error)g(in)h +(expansion;)120 1869 y Fn(2)216 b Fo(if)14 b(the)f(returned)h(line)h(should)f +(only)g(b)q(e)f(displa)o(y)o(ed,)i(but)e(not)g(executed,)h(as)f(with)h(the) +360 1931 y Fn(:p)h Fo(mo)q(di\014er)h(\(see)f(Section)h(1.1.3)e([Mo)q +(di\014ers],)h(page)g(2\).)120 2079 y(If)g(an)h(error)e(o)q(curred)i(in)g +(expansion,)f(then)h Fj(output)g Fo(con)o(tains)f(a)g(descriptiv)o(e)i(error) +d(message.)1725 2238 y(F)l(unction)-1899 b Fh(char)20 b(*)f +Fg(history)p 347 2238 V 21 w(arg)p 449 2238 V 19 w(extract)24 +b Ff(\()p Fn(int)14 b(first,)h(int)g(last,)f(char)h(*string)p +Ff(\))120 2300 y Fo(Extract)10 b(a)h(string)g(segmen)o(t)g(consisting)h(of)f +(the)g Fj(\014rst)h Fo(through)f Fj(last)h Fo(argumen)o(ts)e(presen)o(t)h(in) +h Fj(string)p Fo(.)120 2362 y(Argumen)o(ts)j(are)g(brok)o(en)g(up)g(as)g(in)h +(Bash.)1725 2521 y(F)l(unction)-1899 b Fh(char)20 b(*)f Fg(get)p +249 2521 V 21 w(history)p 445 2521 V 20 w(ev)n(en)n(t)25 b +Ff(\()p Fn(char)14 b(*string,)g(int)h(*cindex,)f(int)h(qchar)p +Ff(\))120 2583 y Fo(Returns)e(the)f(text)f(of)h(the)g(history)g(ev)o(en)o(t)f +(b)q(eginning)k(at)c Fj(string)16 b Fn(+)c Fj(*cindex)p Fo(.)20 +b Fj(*cindex)c Fo(is)d(mo)q(di\014ed)120 2645 y(to)h(p)q(oin)o(t)h(to)f +(after)h(the)f(ev)o(en)o(t)h(sp)q(eci\014er.)21 b(A)o(t)15 +b(function)g(en)o(try)l(,)f Fj(cindex)20 b Fo(p)q(oin)o(ts)15 +b(to)f(the)h(index)h(in)o(to)p eop +%%Page: 11 13 +12 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 +b(11)120 158 y Fj(string)17 b Fo(where)d(the)f(history)h(ev)o(en)o(t)f(sp)q +(eci\014cation)i(b)q(egins.)20 b Fj(qc)o(har)d Fo(is)c(a)g(c)o(haracter)g +(that)g(is)h(allo)o(w)o(ed)120 221 y(to)h(end)g(the)h(ev)o(en)o(t)f(sp)q +(eci\014cation)i(in)f(addition)g(to)f(the)g(\\normal")g(terminating)g(c)o +(haracters.)1725 394 y(F)l(unction)-1899 b Fh(char)20 b(**)f +Fg(history)p 373 394 18 3 v 21 w(tok)n(enize)25 b Ff(\()p Fn(char)14 +b(*string)p Ff(\))120 456 y Fo(Return)k(an)f(arra)o(y)f(of)h(tok)o(ens)f +(parsed)i(out)e(of)h Fj(string)p Fo(,)g(m)o(uc)o(h)h(as)e(the)i(shell)g(migh) +o(t.)26 b(The)17 b(tok)o(ens)120 519 y(are)c(split)h(on)f(white)g(space)h +(and)f(on)g(the)g(c)o(haracters)f Fn(\(\)<>;&|$)p Fo(,)g(and)h(shell)i +(quoting)e(con)o(v)o(en)o(tions)120 581 y(are)i(ob)q(ey)o(ed.)0 +840 y Fm(2.4)33 b(History)15 b(V)-6 b(ariables)62 981 y Fo(This)16 +b(section)g(describ)q(es)h(the)e(externally)h(visible)i(v)m(ariables)e(exp)q +(orted)g(b)o(y)f(the)g(GNU)g(History)g(Library)l(.)1736 1155 +y(V)l(ariable)-1899 b Fh(int)20 b Fg(history)p 276 1155 V 20 +w(base)120 1217 y Fo(The)15 b(logical)i(o\013set)d(of)h(the)g(\014rst)g(en)o +(try)g(in)h(the)f(history)g(list.)1736 1390 y(V)l(ariable)-1899 +b Fh(int)20 b Fg(history)p 276 1390 V 20 w(length)120 1453 +y Fo(The)15 b(n)o(um)o(b)q(er)h(of)f(en)o(tries)g(curren)o(tly)h(stored)f(in) +h(the)f(history)g(list.)1736 1626 y(V)l(ariable)-1899 b Fh(int)20 +b Fg(max)p 208 1626 V 19 w(input)p 360 1626 V 21 w(history)120 +1689 y Fo(The)12 b(maxim)o(um)g(n)o(um)o(b)q(er)g(of)f(history)h(en)o(tries.) +19 b(This)12 b(m)o(ust)f(b)q(e)h(c)o(hanged)g(using)h Fn(stifle_history)120 +1751 y(\(\))p Fo(.)1736 1924 y(V)l(ariable)-1899 b Fh(char)20 +b Fg(history)p 302 1924 V 20 w(expansion)p 569 1924 V 21 w(c)n(har)120 +1987 y Fo(The)15 b(c)o(haracter)g(that)f(starts)g(a)h(history)g(ev)o(en)o(t.) +20 b(The)15 b(default)h(is)g(`)p Fn(!)p Fo('.)1736 2160 y(V)l(ariable)-1899 +b Fh(char)20 b Fg(history)p 302 2160 V 20 w(subst)p 454 2160 +V 20 w(c)n(har)120 2222 y Fo(The)13 b(c)o(haracter)e(that)h(in)o(v)o(ok)o(es) +g(w)o(ord)g(substitution)h(if)g(found)g(at)e(the)i(start)e(of)h(a)g(line.)21 +b(The)12 b(default)120 2285 y(is)k(`)p Fn(^)p Fo('.)1736 2458 +y(V)l(ariable)-1899 b Fh(char)20 b Fg(history)p 302 2458 V +20 w(commen)n(t)p 552 2458 V 19 w(c)n(har)120 2521 y Fo(During)12 +b(tok)o(enization,)h(if)f(this)h(c)o(haracter)e(is)i(seen)f(as)g(the)g +(\014rst)f(c)o(haracter)g(of)h(a)g(w)o(ord,)f(then)i(it)f(and)120 +2583 y(all)19 b(subsequen)o(t)g(c)o(haracters)e(up)h(to)g(a)f(newline)j(are)e +(ignored,)h(suppressing)g(history)f(expansion)120 2645 y(for)d(the)g +(remainder)h(of)f(the)g(line.)21 b(This)16 b(is)g(disabled)h(b)o(y)e +(default.)p eop +%%Page: 12 14 +13 bop 0 -83 a Fo(12)1474 b(GNU)15 b(History)g(Library)1736 +158 y(V)l(ariable)-1899 b Fh(char)20 b(*)f Fg(history)p 347 +158 18 3 v 21 w(no)p 429 158 V 20 w(expand)p 629 158 V 20 w(c)n(hars)120 +221 y Fo(The)f(list)g(of)g(c)o(haracters)e(whic)o(h)j(inhibit)h(history)d +(expansion)i(if)f(found)g(immediately)h(follo)o(wing)120 283 +y Fj(history)p 261 283 14 2 v 16 w(expansion)p 472 283 V 18 +w(c)o(har)p Fo(.)g(The)d(default)f(is)h(whitespace)g(and)g(`)p +Fn(=)p Fo('.)0 575 y Fm(2.5)33 b(History)15 b(Programming)h(Example)62 +720 y Fo(The)g(follo)o(wing)g(program)e(demonstrates)g(simple)j(use)e(of)g +(the)g(GNU)g(History)g(Library)l(.)120 852 y Fn(main)23 b(\(\))120 +902 y({)168 951 y(char)g(line[1024],)f(*t;)168 1001 y(int)h(len,)g(done)h(=)g +(0;)168 1101 y(line[0])f(=)g(0;)168 1201 y(using_history)f(\(\);)168 +1250 y(while)h(\(!done\))215 1300 y({)263 1350 y(printf)g(\("history$)g("\);) +263 1400 y(fflush)g(\(stdout\);)263 1450 y(t)h(=)g(fgets)f(\(line,)g(sizeof)g +(\(line\))g(-)h(1,)f(stdin\);)263 1499 y(if)h(\(t)f(&&)h(*t\))311 +1549 y({)359 1599 y(len)f(=)h(strlen)f(\(t\);)359 1649 y(if)g(\(t[len)g(-)h +(1])g(==)f('\\n'\))406 1699 y(t[len)h(-)f(1])h(=)g('\\0';)311 +1748 y(})263 1848 y(if)g(\(!t\))311 1898 y(strcpy)f(\(line,)g("quit"\);)263 +1998 y(if)h(\(line[0]\))311 2047 y({)359 2097 y(char)f(*expansion;)359 +2147 y(int)g(result;)359 2247 y(result)g(=)g(history_expand)f(\(line,)h +(&expansion\);)359 2296 y(if)g(\(result\))406 2346 y(fprintf)g(\(stderr,)g +("\045s\\n",)g(expansion\);)359 2446 y(if)g(\(result)g(<)h(0)g(||)f(result)g +(==)h(2\))406 2496 y({)454 2545 y(free)f(\(expansion\);)454 +2595 y(continue;)406 2645 y(})p eop +%%Page: 13 15 +14 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 +b(13)359 208 y Fn(add_history)22 b(\(expansion\);)359 258 y(strncpy)h +(\(line,)g(expansion,)f(sizeof)h(\(line\))g(-)h(1\);)359 308 +y(free)f(\(expansion\);)311 358 y(})263 457 y(if)h(\(strcmp)f(\(line,)g +("quit"\))g(==)g(0\))311 507 y(done)g(=)h(1;)263 557 y(else)f(if)h(\(strcmp)f +(\(line,)g("save"\))g(==)h(0\))311 607 y(write_history)e(\("history_file"\);) +263 656 y(else)h(if)h(\(strcmp)f(\(line,)g("read"\))g(==)h(0\))311 +706 y(read_history)e(\("history_file"\);)263 756 y(else)h(if)h(\(strcmp)f +(\(line,)g("list"\))g(==)h(0\))311 806 y({)359 856 y(register)e(HIST_ENTRY)h +(**the_list;)359 906 y(register)f(int)i(i;)359 1005 y(the_list)e(=)i +(history_list)e(\(\);)359 1055 y(if)h(\(the_list\))406 1105 +y(for)h(\(i)f(=)h(0;)g(the_list[i];)e(i++\))454 1155 y(printf)h(\("\045d:)g +(\045s\\n",)g(i)h(+)g(history_base,)e(the_list[i]->line\);)311 +1204 y(})263 1254 y(else)h(if)h(\(strncmp)f(\(line,)g("delete",)g(6\))g(==)h +(0\))311 1304 y({)359 1354 y(int)f(which;)359 1404 y(if)g(\(\(sscanf)g +(\(line)g(+)h(6,)f("\045d",)h(&which\)\))e(==)i(1\))406 1453 +y({)454 1503 y(HIST_ENTRY)f(*entry)g(=)g(remove_history)f(\(which\);)454 +1553 y(if)i(\(!entry\))502 1603 y(fprintf)f(\(stderr,)f("No)i(such)f(entry)g +(\045d\\n",)g(which\);)454 1653 y(else)502 1703 y({)550 1752 +y(free)g(\(entry->line\);)550 1802 y(free)g(\(entry\);)502 +1852 y(})406 1902 y(})359 1952 y(else)406 2001 y({)454 2051 +y(fprintf)g(\(stderr,)g("non-numeric)f(arg)h(given)h(to)f(`delete'\\n"\);)406 +2101 y(})311 2151 y(})215 2201 y(})120 2250 y(})p eop +%%Page: 14 16 +15 bop 0 -83 a Fo(14)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: 15 17 +16 bop 0 -83 a Fo(App)q(endix)17 b(A:)e(Concept)g(Index)1346 +b(15)0 158 y Fk(App)r(endix)13 b(A)41 b(Concept)15 b(Index)0 +405 y Fm(A)0 471 y Fe(anc)o(hored)f(searc)o(h)5 b Fd(:)i(:)f(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(8)0 +579 y Fm(E)0 646 y Fe(ev)o(en)o(t)13 b(designators)g Fd(:)6 +b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)23 +b Fe(1)1015 405 y(expansion)5 b Fd(:)k(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(1)1015 +521 y Fm(H)1015 587 y Fe(history)d(ev)o(en)o(ts)5 b Fd(:)i(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b +Fe(1)1015 646 y(History)c(Searc)o(hing)7 b Fd(:)h(:)e(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)p eop +%%Page: 16 18 +17 bop 0 -83 a Fo(16)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: 17 19 +18 bop 0 -83 a Fo(App)q(endix)17 b(B:)e(F)l(unction)h(and)g(V)l(ariable)g +(Index)1069 b(17)0 158 y Fk(App)r(endix)13 b(B)41 b(F)-7 b(unction)15 +b(and)g(V)-7 b(ariable)14 b(Index)0 405 y Fm(A)0 471 y Fc(add)p +62 471 12 2 v 13 w(history)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(7)0 529 y Fc(append)p +122 529 V 12 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)24 b Fe(10)0 654 y Fm(C)0 720 y Fc(current)p +142 720 V 11 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)24 b Fe(8)0 845 y Fm(G)0 911 y Fc(get)p 62 911 +V 13 w(history)p 215 911 V 11 w(event)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)23 b Fe(10)0 1036 y Fm(H)0 1102 y Fc(history)p +142 1102 V 11 w(arg)p 213 1102 V 13 w(extract)8 b Fd(:)t(:)e(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)21 b Fe(10)0 1160 y Fc(history)p 142 1160 +V 11 w(base)e Fd(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)20 b Fe(11)0 1218 y Fc(history)p 142 1218 V 11 w(comment)p +293 1218 V 12 w(char)g Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 +b Fe(11)0 1276 y Fc(history)p 142 1276 V 11 w(expand)10 b Fd(:)c(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fe(10)0 +1335 y Fc(history)p 142 1335 V 11 w(expansion)p 333 1335 V +11 w(char)17 b Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fe(11)0 +1393 y Fc(history)p 142 1393 V 11 w(get)8 b Fd(:)d(:)h(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(8)0 +1451 y Fc(history)p 142 1451 V 11 w(get)p 213 1451 V 13 w(history)p +366 1451 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fe(6)0 +1509 y Fc(history)p 142 1509 V 11 w(is)p 193 1509 V 14 w(stifled)7 +b Fd(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b +Fe(7)0 1567 y Fc(history)p 142 1567 V 11 w(length)16 b Fd(:)6 +b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 +b Fe(11)0 1625 y Fc(history)p 142 1625 V 11 w(list)7 b Fd(:)t(:)g(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(7)0 1683 y Fc(history)p 142 1683 V 11 w(no)p 193 1683 +V 14 w(expand)p 327 1683 V 12 w(chars)f Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 +b Fe(12)0 1741 y Fc(history)p 142 1741 V 11 w(search)t Fd(:)t(:)6 +b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(9)0 1800 y Fc(history)p 142 1800 V 11 w(search)p 273 1800 +V 12 w(pos)9 b Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 +b Fe(9)0 1858 y Fc(history)p 142 1858 V 11 w(search)p 273 1858 +V 12 w(prefix)6 b Fd(:)t(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(9)0 1916 y Fc(history)p 142 1916 V 11 w(set)p 213 1916 +V 13 w(history)p 366 1916 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(6)0 1974 y Fc(history)p 142 1974 V 11 w(set)p 213 1974 +V 13 w(pos)5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)18 b Fe(8)0 2032 y Fc(history)p 142 2032 V 11 w(subst)p +253 2032 V 13 w(char)k Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 +b Fe(11)1015 405 y Fc(history)p 1157 405 V 12 w(tokenize)9 +b Fd(:)s(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 +b Fe(11)1015 463 y Fc(history)p 1157 463 V 12 w(total)p 1269 +463 V 12 w(bytes)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fe(8)1015 521 y Fc(history)p 1157 521 V 12 w(truncate)p 1329 +521 V 11 w(file)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(10)1015 629 y Fm(M)1015 695 y Fc(max)p 1077 695 V 13 w(input)p +1190 695 V 13 w(history)14 b Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)17 b Fe(11)1015 803 y Fm(N)1015 870 y Fc(next)p 1097 +870 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)1015 978 y Fm(P)1015 1044 +y Fc(previous)p 1177 1044 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fe(8)1015 1152 y Fm(R)1015 +1218 y Fc(read)p 1097 1218 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(9)1015 +1276 y Fc(read)p 1097 1276 V 13 w(history)p 1250 1276 V 11 +w(range)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 +b Fe(9)1015 1335 y Fc(remove)p 1137 1335 V 12 w(history)t Fd(:)t(:)6 +b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(7)1015 1393 y Fc(replace)p 1157 1393 V 12 w(history)p +1309 1393 V 11 w(entry)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 +b Fe(7)1015 1501 y Fm(S)1015 1567 y Fc(stifle)p 1137 1567 V +12 w(history)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)17 b Fe(7)1015 1675 y Fm(U)1015 1741 y Fc(unstifle)p +1177 1741 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)23 b Fe(7)1015 1800 y Fc(using)p 1117 1800 V +13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)18 b Fe(6)1015 1907 y Fm(W)1015 1974 y Fc(where)p +1117 1974 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(8)1015 2032 y Fc(write)p +1117 2032 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(9)p eop +%%Page: 18 20 +19 bop 0 -83 a Fo(18)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: -1 21 +20 bop 1937 -83 a Fo(i)0 158 y Fk(T)-7 b(able)15 b(of)g(Con)n(ten)n(ts)0 +333 y Fm(1)67 b(Using)22 b(History)h(In)n(teractiv)n(ely)9 +b Fb(:)k(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)31 b Fm(1)149 411 y Fo(1.1)45 +b(History)15 b(In)o(teraction)9 b Fa(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)23 +b Fo(1)299 473 y(1.1.1)44 b(Ev)o(en)o(t)14 b(Designators)6 +b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)20 b Fo(1)299 535 y(1.1.2)44 b(W)l(ord)15 b(Designators)9 +b Fa(:)d(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)23 b Fo(2)299 597 y(1.1.3)44 b(Mo)q(di\014ers)14 +b Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)28 b Fo(2)0 722 +y Fm(2)67 b(Programming)23 b(with)g(GNU)f(History)13 b Fb(:)e(:)f(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)36 b +Fm(5)149 800 y Fo(2.1)45 b(In)o(tro)q(duction)16 b(to)f(History)6 +b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(5)149 862 y(2.2)45 b(History)15 +b(Storage)d Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 +b Fo(5)149 924 y(2.3)45 b(History)15 b(F)l(unctions)c Fa(:)d(:)f(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(6)299 986 y(2.3.1)44 b(Initializing)18 +b(History)d(and)h(State)e(Managemen)o(t)f Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 b Fo(6)299 1049 y(2.3.2)44 b(History)15 +b(List)h(Managemen)o(t)c Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)28 b Fo(7)299 1111 y(2.3.3)44 b(Information)15 b(Ab)q(out)g(the)h(History) +f(List)5 b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fo(7)299 1173 y(2.3.4)44 b(Mo)o(ving)15 +b(Around)g(the)g(History)g(List)6 b Fa(:)i(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 +b Fo(8)299 1236 y(2.3.5)44 b(Searc)o(hing)16 b(the)f(History)g(List)7 +b Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b +Fo(8)299 1298 y(2.3.6)44 b(Managing)15 b(the)g(History)g(File)5 +b Fa(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)19 b +Fo(9)299 1360 y(2.3.7)44 b(History)15 b(Expansion)d Fa(:)7 +b(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 +b Fo(10)149 1422 y(2.4)45 b(History)15 b(V)l(ariables)5 b Fa(:)k(:)e(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(11)149 1485 y(2.5)45 b(History)15 +b(Programming)f(Example)8 b Fa(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)23 b Fo(12)0 1609 y Fm(App)r(endix)h(A)67 b(Concept)22 +b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)37 b Fm(15)0 1749 +y(App)r(endix)24 b(B)67 b(F)-6 b(unction)25 b(and)e(V)-6 b(ariable)24 +b(Index)8 b Fb(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)31 +b Fm(17)p eop +%%Page: -2 22 +21 bop 0 -83 a Fo(ii)1496 b(GNU)15 b(History)g(Library)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/lib/readline/doc/hstech.texinfo b/lib/readline/doc/hstech.texinfo 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 new file mode 100644 index 0000000000000000000000000000000000000000..aea321a2b76a74a9e8f22fdf6da61ab744575a32 GIT binary patch literal 154240 zcmc$n34B~vb^jgDC?Ob_Kn%nSlJSxdvH`YY6O+gZwww@>V2`AcHL;`-Gb7td z8rpxMECs7k-k)K>P(#T-5GZL2U4XC@+EPlx(v~(9kcvy8l&yjE&rbM%f9Kr$-kXu+ zC~iOfyG!hO@7;Uuxo1D;p8KQaC%odeKRffHW&A08^GQ$bFTePy)yc-hWaFvpFSy{` zwd&2Aa0 zG%D5cX5o(E4QtnRC&SfRa{tDE{?^3@(>Iy0(OAE3u5+Sf_Uf5mKE7P8)fph+>$THI zPFuF@&}}EY^Y`|@aB_5NhCzjo>9?J5`t`3mbpIAx$0LS^+t#sVbFESuZ*~n2Z$13L z9mCaIUw_ZR?qqALRxT$ytHX^qy#Ag8NvT$z(HpJm~p_4kyMUE`JgEkWC8fux7sbI)s+Eq5eMA9=#E zWv|y>@xzk-tZCn?zrOGDhi3anD)nYz@ZO>7oBQSlC&$X;x4!S}Mlw{c57sIJ0F*RF z$_cwRQyBbYCo+Y}?wP{NR+f^$M zjjDca?XL`#lTtER9UCi+4<$xSmGM>>Ywh%%XEXd&lLMob`bc?5V-FZ~TFzDh9=ED> zpv6Y{Z`nq@{m`?|KkqPK^_A-N(%>83clLzoh9ZI94Vam1hU@u(%lMdKz-cH!Zs!TRiIh6sOZrS;H@WT$} zT7Z4rdASbguyM1n?AP}j&Qb)lrYhrmp|Z2@ircPbK@D1a8BA7K2@9DVZSW$LTNB3& zB?ns7+P(ysGt3Sp*~}2im?o_b8{H)fA_*EZey9wBbqLSUSsgFWM^Ewn-&+cL8ti?2 z)MUYYw1|AGAhgQLYRPD6eD7olvI0m0yII&Xsx_AeVAU!V2_5P;m@DAW1mRe<74WZp zH91!YedGJe2M5a&LYv_ZXeXevK$?*%#!7rNmB9E(y-|WlnY?0xwv^;xPf8PPhJ!F9 zE*VIsTENya&PusxEkgAC?>*&EZ*_uqjYgBkA^yyq_=l(e&U=1iaC&-L|6+jqFFboi z_nY(LyFRsk-Pcd!jp>=wpMS#a`U{?OfpHkZd400=aE^l++k~w)GAC@ilWpUJYo{|g zxg?#2aQ#P}+q4Hdjb>nHCz~d)o;stM{%4%%}t3gt{~>z>C5t4BM9<2uPp(jPD(qK`sWde8=!0yx>4Ykt|+zp*&Ek zR|b>ea;Y&1`8$)DsBRaEWf2FAkr$3fwjP)|bm-e#)~{VZ^ROqrY1=sZt5K`oTHiP{ zIT%!HAGFvG-t8;CFc`rzX+2yW9jyZ40gXRVs+ACJ6C-e(YY%~HTna@S$xDKo*sGOI z^g!sSLMI;wNRUu-#^0eH$1gbKG;a+dV4NUW}(&^CPPxHCwqFUrZj5R(Voj! z&J=EVgo)2=O2-Z=2!ICJK8Z^SrO81_g%M=8xQJ0&Ogm}-Oy6nB2u*m$@Q}eKKsByj zodbY<5=v7NCjdJ+*xJ_y>jO7BtbLuZ_LUnYgYto$IVj=Zu!n=NTOQ6<2b5!cpX?JO zPbI4=!${>RsJ%LQxcJCTBc%ih&_W!oZdK~76z=Ys;_8FUW(+xZd24oGQl8Qq26?h? z?aYZ!sBRl>p^7J4L)8|$1FmeWQcDxI^nvSkMiN^~4kqZ8(kKw@1A?$;2%zF0e`2sS zo($M#?=6p)YZ4ntP`0h93DL&fmYu!H{m-7bYuyXmSbTK-x}&Go>Wx`o{z)s~o0;Ng zm(Q-9dDtoUZK(i6+{eK(1_JxAZ@k(%fX=D|(oumuEJZO>Y`%P!x3!bDZ-zT9rftIx zzbbCnJo2(F%hA}rm9FEKNMHltH3J9OM8LCg@@>e{@7_=va)FIl{^c33ZMCcbb|StenbLV5`dhYBI*$rCY9;?KU*)KUZwMRR7s| zRj>ZDV@p5(0l70wJ=ec!GeFJqd9!f#mk{z0x$I}A8>^Q`_X}TjXOnuFT{jC3bPHd= zd+`mt%WrIXWxUczP8}^Lt9UWlSvJ9utY5n^xh^#nx9Od&mC^DI-OM_HI@89S>n8hH z70q24AFi&(2u~%_21%qi0IH$Sr4w{z6HEsgF?;1O_GGj0`3Ht3YoalO2-1Y(^`qb#FTEg>1L^4+LpxhyPS;FoW&j*m`B*#|=@wKYVjEaHGhs$o%< zzrnbmE!duzXP9}mKcl1Np|vx`Pu;24@X7PS)9@gZ6Ls7`|flReza{ zXNj6{F#id5x4&j2$n;~SnPrFXzOhI;V~Kk%Vlb&UX=crj7m#1%2w z32!ubuuKABCxer<$=>x-k;it`w3$fzXc*lG}isd0)`Ez>=a2&-)$>!O+B)86aT z2RpN7{9z;s&y@ycu>ohTyth;v8WkLIK&iAr*Q#;tj#I5ExLq12ZvZXPQ9SX1XaH@v z?Sz5b-z1+Mu1yI!`s|%1PoJ4Qr#n3V11jl4_oSW*4;eX zsFX(Q({kBva{EGJ@)_)L z4&_FX9V>BAs+q{EmE9|4&}QNNe-MaN3}2E7{ilUYLor}@>{QLhAV%sFM#v79yJXNy z*N3+aJ4YfRA{g>rQxnAo7mpy^(5AvRrc&VaT7pF5U)k&8n}HHWNHRGQl#}s=kdd1r zzfyTDGOc!2QI!?c37*3jf+QI$p|d2s3`gSRJZ#RF#=v;WART%X;)9R?^zn}hFOnre zWa?!>U8~ku(B!zJa%J>z;pfw4a|C0fk(e|p54BK%TH|QTJfGGe4CSVqnE0!^wlOKP zp*08=VA0c`V55L1%ts%hg_7Oenr&2DV^uR`z(mXU2LKw?X5rJjgq+dxu$0)}UzKiT z5Ev<{g+BS@OuX&RO{kcf!UIFv{=dJ{zehmgkjGMhNU!p4NhJ5D}RyXcni|h|l&+OezSH z1dpw@QV;l&=mWHk_bg#j9gB8=!)4;w00;(2Wn3axn(d^k*IZEnNe3#nA@BXN3s|RL zm(k7QIYTCx%`ikDxhd^%v58xU+_ee&yx=+_hlM3bt2)`Q)a$2$6~`Ux9l%@O*DRi~ z&pD9bQQit==WAu{*~~A8F2&9Y0#oo|3}5iwO*6$awi75aO)NTb*J?l$BXcdtfP^yq zMD@mNA}xjxw`$vD5fM#wbHH39G|mB>nj=qN_Mf=9qEVdL3qF7UY+u+3bDc|r7=B2P z9Nn*-zWs6Wo2?6cgU*)6J2daJw`(4Z!SKzcrY{AcR@LTg1i}$VM11(>$W%38FMaSq zEG{t)u1$-E{bIqVBghY3g;{2tk5vu?Ij+XjmA@raY%`)tA%q+w?{^6JBq-GmAa@5K zca0Ch<-X3*5<4j+D3gTG0>=$iWR%U$M&&I=W&uQ8pd{f3PDc>BU5=n@5pi1W*x;!NW(VIq&1omk%%h(nv|%5ca;+C=HC3aoa4? z`Ubg#=CO@c(Gf;~t%-zSXhm#^6d>)4`_^Yl_lm z6}K`0Xi*#fCZ9xd*PIpGiOUGWx6AWWtOxp|Xu z*QO3mF?w+Mh)~B`41Dk3WgNC;@$bsO+xC_5Mqke{nX=S6fQdR37^!b@u6G_zU(X^{ zg(b!Fmp#(6FAphFwXri&rA>wkEUDSdsvfUTw29x@Wrf4w5}U4bFk$1>aUw7dAfm zF%#QxdoYo4;>1(+V7fuY$Q&3EHdM&nL;?`Pk6j*4B zQFVM_@JPmAdd)MVaM+j^4nWX%IT~EJ%f!N+PdoYd4NphIvze~TA31B-mMylBAJTl$34NM3gbmO!3~`M3I0d z$gl|^yv1yY(I75bbzlhMigEVr0}=I=L2sH|;Pccumq7M7Qk{rqklpf<^-jAs^STER9l~E}& zQK4_1fvOCQ?Gg~!CfIK0S0v*~g9^|z=V1=3>r5#Jv9DrJtSXvksUi|t3s!wE90uWI zrpx6)qF>JQD9+j$$VC`B2GQVtvqeV8vnpD|S~TZ8>3`=F5pT@U*AtB+pW)Weq?{Q> zn?HijC?RC2sUe8%4NqYWm0`zQgG8hPZZ1*mY1<$mQU()nX+`6rnga@HNYUI8fJzNN z2kV9_=Yhql+H_&u;Ut8$n0McIj|J7f?*^#iFzs+<jZXCdt7zC0)a?|i-;;q!q+8hE-kxg%4&xk=v^6Mdnn6WgFsqNbFr+qQr!{>f zCG0rI4&`jX#Z|WoYz=6l4=k1LmKCRPnnaSGj+YO>G83%-P1ryLX>4iT}gD{4X z^b6vBd_{z})R+k0_K3u~K>6tr+C80*O?OiO6~qPtCZ#=~tBfrUyKQHJTg%Dl?#NdVsNy zy~`PHv=cyrT2qb>0f6;5RM}f$U&*P1AH;_R4gxwzZ+&t9w&7;+C*KouD8-QMu@6>8 zw>2tWw|2+y^(K8QlT~v)v#T+hw||~*QCbXO6flnfgma-<)YRziF4d-pmB;Zh{dk;}{P^R)QJd=d)b)R!i*QkQ-c#TeDey(7)SAKoRXQ&x|89)MCN zO(}*n&9h~!G+6H$t$5r``Mv>Af(fH|HhAB0Rc7} z12K>`7K4_>s7f1FW#%(uW*CPQQ+_s>>!V-Ii|RoVMb)v&ODgM24cC|KT*;vBzf8Gz;l-qQIV1<07 z1)~oB^j`_Xia^Jc)KUoHyUFmrRsZa-)T-kIU9kW6A69gax;$BCc&L5>s8#;16G_?F$IE=@qWpGxzdmt+kLzZE$vFn+s9=^_R#rw#qcC zc7qzNI?OHA6jPB9j6axf0#g5zdo`J`WT{iYs8QF@9dq9y*AEntE~FV{Dg$c-g6v3f zCqH<6FVrin z0Zb@5VDK@-C=3)r_+zD^vVu+(S>G=(<{><`aelf7`fVgTr!3i1I+*eh1R#6seJ|4r z%~~i?&~hNeU*$}x*g{H?%q9Z)0NF*o4q*w6DW>DP*z6O2v01TT3r+AHchfz@l?cOJ?=HNZQkJNDg=oE*J z8bJ$X2V#acw0A6bTm@TRFCtQiM3gtCx|U)}EnBwYPopul^eU+HI$}#!Y8yCC;Oq== zx_KjSCN-vh<4rQAJSPC<+4jOW3d<-XBBIDI+2l>S{i?Z`tZOSp6?32?WdP8jc|0lF zEWG-sdLtv3;@^Kzex`J5u=h<*1c@5m+ko159T*}VvuOzeDmzebq(?zLx zA%X65KX7Q~>JMHfsHAH`aJFZxO8x5o%JiM5>jglZ-2rPsTMkFU8iF;P+QyRwso}R z6O~)44G8ecxem_6SfUv(RNxw*=JMd`<@(#dp@=5&d@;cbD?_ls0OGUV=4rMs2Fmo%hA4}zFMB=G90tu`-CdUb z6;JdDXCstK+*BP$oA(eyrAE#+JHsCOt@z0AE^Ue{WzgdiT{%3ADm(Fv`cCH|nf*XA zr{}@VbWttzvG``;rC%`vIoMh*Jn~k9_5)(Z8h0RJ00W!6gsggt|A?nhrXC3n3(!c- zizOIvB+aHs9bxJa9=F{$_vp{q=P=?g%jVUvt zj8jo6kqxOk>pLJJMmedul|-0rosqwk{=$s1HCpsgEX4BgIM8WE{}yC?U$SjDEDaRl zvQ3B%$8i*9<(_>Z9dEpBW_m5rXfh?ptI7k>D8-Mw4x22Zcz?x=TJW5HjL8}Isnjf< z_{Q)`96?btxh7yl70bSZ9*9I^KJc>K;HAkSrO=YuRe~Vk47aIx);r>CVL7EnLkT|% zMzE%NNLYyz7Zwny%WZ{5&wz}BjIQvq9`{|;xv8Wo!b+L*NE|jsv?X%v>DwV7Q7b)R zYYr2eT5+U^rATvCVxGG8y%n?G0waSF;u-?SD3}Ewmv(P*zwczs^ zXjHg@R@kO&M&V7v?KMtDs=`G|frF!^3I{?XlUC^aoHzAO>w>avPtD!F)^nclNJ-#;%%rzNSA|5Y}7ed4x_}6 z%4#F@c0?tV%|P7G{UxBP6s9K2uvvWSO^iqGNP!%q1O_|xAVK<2TpWQw$6WEm91_Fu z&S210Aiz1$lgb@GMb?SS!b#6-!)0ORW7~1*f>d&~J?|!mIV@fXwdHFh_a7~DCE$j+! z&=WL-2x}Dk5P63rUB7M}L~`WuZ@HaJi*4e*^3+&qf`B}q%KtsdOWE;m7E zvGL#f6#qL00K<@4SLwGIsK%Jtzv94+(Sv+feCDNS8$Ctmj8*re#8dUdIQ)zM-z+}r z5B1#jnC#FqKgPf9SO%7`LW2%xw+6p2hGK|u!1b7LDkZasPTgyV zvMKNpVI-3cW2FYlOC?89KUqkmS=d{5u1G3GL53>uD$YR8YL`u8W(`|HOvH@2PaSRB zAg{6uHb|S=EgzhKoO&n*9kMi?ct_Fi_n+UUDvCecXRl!A@V?dWLoO!EYsAojtHX4S zmRrn-X0#UsZIt}t>afSg*AcqQIq<@x%^?`8@3E+jobGPbr_72j9W<^*uiC*OT#3C_ z84_98ViFC|62l9c!6Xe)_J=*Wv9+S;zQq?}nB8#CM4V+o4<2Y1uDnG9WHHe+7%q7k zK6X1@Y!n8#n^esItDdd{dbkT-7w*>dxu{v%CK* zcaiPXNMU&GZL{#_e@CPmHhuOAp*{b3u;~=cGCN-+tn&kqEaPM`d8;*4Rq@~SaBxdV zay5X_=JAp^AKOLLRS8~}0`c1(8X@|D2BFr7^{DTcfSFnL){|!Kz~a#;RC?_9V(%Ey z1X21?LKn5_v}S<`9qRNI&&P@u;?leZD%6iyk^-YoE80SU0OT8gb>wOk{6c8nw(Qp5 zx@fMKcnG18p2-Vm2!c&=svY@AfFxv*8q>GaCcxkAlcTa@a)24^Wm0_m4xrF_ED3!8 z@dwm4Y8e$^t2phAug;2GHFnrM}XXh{n4b|_}8bpNw) zWL)C7IEOauL|6G>kDpT26rK!k!pBzs2T8El^TGXlntQ- z`b-;fU(MeQxh2fPN~33(vdzesE3PkJw|@Q0S6rxo_lm8-u1Qd` z$@&%3REOV^@@L^uR$tP_pZu2cXJPHDkBdK}2w0^kceAkOSA|xun92}r>Gm*{f)Kr1 zG*?Wb&1YrtUM3V+ewYQ9W+=mg;wVQy4L2Vy{KLQRk&mv8x-MDI|Ga#5r93jJ2FVA@ zomp_mj56_cYtLLnSQtInChN&U&Yal&gnrq$kNaHP+3WePuJ3tAiJry#BBj`IS!Y8R zmywt17wYuEPvz)9YIE%O^z?1Z-dp=8((EQ?kmFJz7C~Uk<9mJSdkQct^hP-jO9HjM!Y`0AF4d)oM3uB&bT5xUy*)u{mSr@icAIm>@_-eQ+V-8_b`aohAdGGjuSMH zCS=d{ex}YtSQP7gC@)K7^eDmZ3SEpEc1E_wTdqxWfMF;Ms8itx+UC;`Ow0I)q_+Z#gmJ~R?DeZ}++0$ac%QAiSv>do7OuD95Tzkc>nCWU%y2EE z#UV_t`4iH+qr^X1^IWPGOe%&?b2fUVpvIlNJ0$rz|R7NWF2bow7j5`)TQt zN;&(sDU-}^Az6x;KU?C2^CYv;`)(HA@hTnN)L{(Jr}S|`_DcZ_Mc6{p2O(RZsBow? zs(YwAP9$4vf^f1GgLZaU=w*Eh#o4JTokmyNlB<7|#`Kk|ZXMu&dd|HE1hl*R$(>1C zaAUrg_2UTc4Khl5faORLi1~`N1~M}m_E!eWivk)W>S9CZ1%*dKHd9Z9Q`vHxHiq*5v@{Mo#ckQ0NUzCk}k8 zlEG<-zlVvug^Pw2eO<&^xi%f>qOhiD17!gEyi%{KCK-j`XEZFJql9b-=Lko|SG{vi zKV6c{YEPoS?s&_iT6UwBXK)G55T?piC+I-4gi(c#QD=P40~RrDs8bGD0z<0Ax(MOU zXt^dVHZYXRM%@_IsFf>dwR@CP4nuorXqJ8XI`eOU9nqj@3Ws`7H^ld- zA&*-e42=*ciZPckM}hdGf2RQJ{S;*MX+?>Rgr<={5mmnIAhtVo~&O?Z^x=S=Cip=e4S8<2^6!$bD+U(7^hb}U+#6wRoL^%RsYfrJ4 z^8h?FL1qna?YFKK<3#_nBgPNbtmPUepK1!SS%?@$C18RBUUvm1S}eTjWuZJfGGI7o zYVJbdkv(&lxWyu7fgDSFar_}i%`!Ymnm77#{1C>D4BIUJ>a!%D^s2>s*+UpJWxkLD zv;nYHp(z08T`yOp3K7fXq}>;Yc*Dq&fr@CD_j#QIy$ z;F!XVd4g5g?frl3VYi&bh^oC`Y})^eqq#?Uk(T4jxTm={*;aYoItwA5u=<&Z^DS0X zI?^nTeIS;3W#uJNP$6u*p95dJv~B}L$WmLABd=$H0b&n(Gz%ZRRaU%G%a-=|VxrtrpI?Phvp zRs0*{CRCXrKLh+u%u+tlR)h@j^W5b!lJHPB)p&q_lC;w!exyMb%4Y00>3=rW!vbg_ z#RE_-Be@8`)8se2NPb*y%#I;*VE}VWUKVYL^1$`@AH&zLkX2~2JYBJs;py8SzxPIr z)$p&V4L#NoMW(8+LvV_-KL?^!m98ZEC2XEC1$!u`HfmGrMdvzY?&;-G&La3Uz2Wqv zP-ik1+JtzI&9Swvg=p% z_LNpn?pL7Mx4bhW*Z`nE#<}-Sa1y9ga_vh5MfYQ%3$d0c@P-F89ElE zlpeTh=`2q;GO85zHP&2&AitG;L7C!X4mjHTWy?%udHltf}C~5{d1nT`_i(?=vj@CxauIN<7hJ ztnuJ9Od!{Q4+laD?JFw}&DjJ8di>Ky##brj?I=?ZQKz;%oZPnqxAJA2ffg)>lD_j2 zK!p|%4;Ord!)iL+a&GjbOg>2`XAGZfHI($jxR+JxDpV5x3sP@EV-O0MRolx4w9am< zKHAQWrvPuVRyEDS%0~;AhKkODj#!q*s&Sbxn^8yaA0^M#kkMP z5dQqvqJf^HQfHJubN!I(`2%o2p+ z{*IwCw8o(%#rANL>cIF)_|rx+J`JO_3&liHdD^`0Lz3ejNe-4 zv`k*dpG6COJag7>HItOnB?fl;o`;5HyP&=KRP5W8YVEAn!<2emUFvmhXV|%HgfX;y2T2>%H)iT#~g^m8pN#;TSZh83$CKRz$yy2^rTwrA*^8m z649yy=EFKlW|c3z8hNwFUWynru2dzi$Jn60o{TB}M>j~E=N3Dqq&avcL9?APUjsYY z>-1DeHcE|X>Y8Cs+tEwaHny$!7@OJGlksl0;{U|OEI<{qVWTu!0#0gArz9ZBw;Nkagh_lOe&HYL-+YmhFX&^;ZOf7 zqD`}Y-EAk_u;!ObYpgccu@TW`4Ljj!NSVz!g8TX}b29M1aXSKDz!p_${Ux5un z)IJ@29bgqd*S%?`aMKIY1HTbE7|3CY^lvj!Ea1>V{dhSUd^rW*Ikzc2+YU8j(teor z*w=&3@9Wt;Z%h97H}qbF!>|+#lg^Qq9mi(S+m5afl1|@q+y`6<{hAq-mfL}DM@^{0 z!KWv-snUF6EJ+&?spjvJ@++bhZH-;p+~&jXHshmsRaAcqYYy9ag~-vnxAf#(%b|4P zp)=R=ub-&p)6&q5 z7c8r0@x~h!8wb772~LT}zbPKRG4ilsSOrEQzZ4J6iuSRpl}+yLQO5f4jZ7nRTK+(o zY|E8fjRK;mqQ*rH3NuuAdB;3#9QmMOBL`sEsTfX0;;?=&@~Z8dW|kj0p!O^A*nL98 z#*b+D@o?cagu@+tx+J3kS{W~!v%sueF4lEXETcp0)+)3(cYdH zg-B_LM;Yi;1_ii-?4#9h3iP&gK{RqN4YX05eNFG*;ry~oFiCf^sXJNUot)jBtX;dd zV=PVLB}ka(qr(n@+S^YMtFWD}8yvkojr7Y)X%XHmyz>bQ?=mJr8t@a9%bp+xLf}VL zC7w9Sb~JK;lLYks&P&x@O0g@acqVBU_x-a!x51z*4F~zsYGssTC?~CbL0~N3a7DdS z6T(bkkDuoxU0{^AUd-_Flu}#4+T({%jcu0}X+qIjr#C{&VO61_Q?5a2R1b`If=|%ONqY8*a0)sA|57U# zT>|ib`SoK0KgzTQ%W(rwgn-i)6-;ZYi}I)+OkwX$pEnCbk6R+v|LPOR1pH+${;vXl zWW(@jQNLRcn9Dg5i4cLT`!-?eU8~5r_w!LqOj~4ih+^9y-}a?T)VIzLiqs#Zxpr*W z=6i(rrjB#z{iYPqX{&zJtU)UsOgfaPCYOxi3s}=Ts;IySO#8v$U?#+{vk4x>jHqrr zXc4|1j^qp?A;Y@hnm~3w^ri>ehSu6_a9_}|rt;N?s0+OG;qp$ua6qsLodmaquP9nV z-@aVmA(MT2v**A_b+o)d$W$;k3!l4@)MJN<6D&jr0s*ImQw{u2@4*-%B}uSJIs10q zqv&MUi~l|6i?GyG)>lmKcKCx}(gDm;0hzt$(EWez6PC{|cor60lk@qZLQpKJ=6O<( zb5g#Lg0Zq4_3EI+oOGrCRvV>64oF*XDZk#KeoW)Vd;%dCg{&8WB;^22>7W?J>YqI| zs}l|cd!Pf1Gyhymih5}wEr{TL&I>(KMEwr=#=3Rz1_7nuUPOOC3;X^4&-)owTdksx zjA|>K${;fuIx(s@uW^Ubgv!p0go7cRKO(LfZ2>9t!8u?w5wn4$s2sDE2KWo%U;ZBK z6zMEOW{yXz_lcq-Z{>uHg{>5qt(-;qft6u``o8VKliAeXcWlMv0gM8*kVaNPtB-D^mT5ENCzTtA2(K2lKa#GjY@ZVpn~ zUNK8ouUYRf5UjMdHBRI8=_8L3^z*Cd+sU1B3qGXWV$Da?(k!LknEM8%%l}TCoQ_OH zgj5&N3W}wGyiv&_x5M-s0?r%lNK*Pi068{MYZmWY$G0k6=IR0Kc7Vs+wfT2B4d%1D zQ^-59%EHVeiy0Y=Rs-o}AB#=`|2i}aH7{Uj*@02KXoLKag(VlJk38?}4bd!lw&>*w zuTc@Dq{;n$lJzvehmN=q%OerjB1xyE)Ri}u&uysAdxD!}gxEp%W^v_fnHCEwylh23 zp8hfG#mfIWyfScG+7cbt_Iett*B`VZ8p4q;u)Bajt`@`=?)mi!C%rDZESKq#i!4N! z)CpsvGh6d#r&1b?R-QZ_R0D}>8?c;WZl z((RQ>xTzsO2(FP;z_6(L)EJ~{n>I@3@qM801($A)-NhVI-f^iLO0F`9nc>VWi_Oqh z9U2y;0%K04Q60k+3cq0N@}RfO=G$OQlng zD=KLh7%v0!Z*nLiD>`h9;N;QDO2J(Eo5XildfrUwG$9nx^@6gQY8gQ7gUe_z+T%>I zYaeDNxDtBvgy5YibsX{B%~M>I=_E0?(5fkVHg*(Z!$~)#AtenKJj-_x0KBm5TmJ>X~@#**7rMV>Q_(v^iXmtV$8FS+zC#-MWh?a$&g5LLA7K zv=N_@8m@j*J63TbBSi%@Y!bsi!HNZ@U7b$569wNayyBVvZL>PLS*v7QfYra-`CmB3 z>flWvvD-b0hb#bGR{FD}+!Mrpv-q-Y68aWG@yfII#af-c9h$lQ1eH@Fk{3du)mzcT z(9XL#VIa0dUEb;(TMw4BdIL@z5gqc7j~9Dln1bBAg}`O8OZihhJ6Z@2A(FANBa#v9 zh3A;Ppi@N%|2|waVppYc?jNe>I*K1T`%BlWu*BNE5y%Tia#FJ6)K1<)kPe|v{;q%> zk{bAo)K^<0fOp&lo4Y`zPD2IvNMB6l+b@t2O7b^r8HZBVL4>rT7}KFmG?kDcd&eU& z#J*~R3e_l!R*siqAA-I#!1=~tpYBcRb(7Q(51NIGz9xcj`ZrfP)}cpXF7V7;)q9~t zZ&Ynt6z=1mvdICv%8KLO(I5(?pFv_&hc$bykHHbQ2i3khRuv4sa_);(8sZgAD%0|Wrm5b9I_Xnu&6;LI?ddOTgT zijzetlKQ+`Vzcn_%e8h7OsCOr&hKvCV{I9C+&2)iY{Ukb{JR-D04f~h&lQ;h1DqJ>a6<23?a6$OVbxW zeS#??*`eO~&<;JA#AVkkR5J6h%kGLu3cWVNYJ_pDT-0*fiIgsVRQ!ZF!i7s#9I5uH zc(jmj+O*bmSP0G-xOVs*IjF<(#twZwFHhn1D}`C)n2^zVPQEkNVZmJ+bZByHq9Zl5==c*oUWz}#TQse@0|jjSh2d9T#vL;1!?S>llmkPbgD4zas%9Js(Luo zgNf)7u7Gdtosa{CSU4NI>}Y7^Ia9pqM)fAeH@W1!7h_>_2kLp9&0cA3K_M)cp;Etl zr{t;~FSHQhrZ_~CGfPQ!opO;p_&6j5+0g?}S3tm29U z&X)CrkLXo`6dO{O9dnKaYroS?i7gCZ-RuMkN0s6N>`-9w#?yi?qWA?%@r$>FhJZ7m z*YT#}n}2AcQ$9g-nyn*&o$23`rjAyoO$hag+ZFcVh@~Cv1h7I5>S22KKSGpy<|;Zm z(REh$RVabFmG^DvKC zitVy&*@50@y{xB|`jX=tBEV*G=XubB7duA6i3r8UAZ3IVkTeeSp6;1t*NZQ&#B1BC zY2|UOS+hbtni?@AM`QQRuC(`|Ap`^LfQlmFXV*z-b_++?^n2!Rm7jy^Sdi=9w02svcxY?~gIbn^~gG6)X+ zIE4Taj%v1|N(eeQqtu?S`)zID;o@Vz7g*djk0Kc}OjU)TJ6%(Z)rOa5d3NM!1KRuO}}+XrA|@kR&A7S-)1D`t*^g_ z6D&2fz>4#Jb-d^8@?@lWDJ>H@^3Hj8J@LQcS9mAn7ertlRWFe@~O=GfhO{d?K z1L9`S?rEWhA0Q8^~~ zG;Um&CA2!3)ooN#kc!cR8EVC&d7>&5^|}^?dOeEXkzB==wH=W_jCr|$%)%4iXqBEb z#k*R}?eC?NCbMxMuxa|&u3g2UNu zTXi!2p467~3Tb{fw{<8rs5H<;(?j*;#;TK5n}Z6*+O&P=wxpM^#q{k@5p|yV&0TYY z)a&T*)S8I2WR-qO)*N+A-FnHgxz!h;#%Fg{EhVjK)ze$nAITq&owSW)c)P?fYkys} zV#|1@EiX(~_;`wB{Pg!yn?UnNg_=jY=_bc_*O&ev#kV6Ftd5{Ig{f23bd)ZzHYEmr zxHM03yhnbtUUgZe6R1Lk2NX;lsE> z+uSR8vu17S+6SldYsl|xcI(07?}h?Q2tSQ2-3j$iDOM598OiKNP6wGC+e3j9;aLWn z2?=`Out@$T55(XPwC>k49WJi^;wq=<-kz)M&@-WMYc#StyF`P#C&=_b^I9gSGIk?f z?G%PFfF1IT39z^^27Y!S881S+rQ~S%(k^V*@dcU3h&$Hij++j+rF5N}O6LVvX;7!T zt%r3LvsIy(p-m%1osNqKWu=raa~PAL`&x1yU0apvbv39ORGTw}&?Hy59W8GtJZdRs z!m?%m>*3K*SWiF5C0k5JrHy9c=DQ#f`S)1QVVm5Cs8(nra`Rnv(&f-*OXP?0)$;2x z!59$9k98HIyz&AB9`aY4UvJeAF7yo#P2x(e0gCh($oWT?M>Y$u{UJnAEAu|vVi&0f zf4BIBfy!g)Qr8=B7JAZvn%wPYmlN}Qka zYyCT{JhGmcJV2bQLQ-%Lga8OlExKM4{#_g0ZP*j3o0HBvmUdgU_fDT3w_0LpU~(9e zF&swEWI&CiO)H70b$z1>Gwp4{Bs$uqz{ef$#HD0-4I&i<$kovZ5wrNYT;nsthC#9M z8^16po;Um=eUoyczj2WU=2414jo*nxUSX75)o_oM%0@Fr(;a*kA6y4 zt#I{|4Hgh%Peod#aSqx`}vcl9T?ok4oK5 z`c;q#QGIpF!?27n-}VN-aqlAHraU#rnKAyg zYE9bHZf^Ce)usf5#@uHvbm&Ze(QLRx22^sp9vRk{ny!PS_g-cV%w~$`?UaHRva{3+ z|3pW+n`3>^O^*UO>wodPCAU&AAbY;2lF*n5!jLZ?v5;=6&P$O>`v@s&{KA%-YSL+)8`*xaGCw|-WoVU@Tu#e4oTkLdWFQ=~#v z<2^T(YsjWykSkJ~nkf!GTabtlP&MAcvoe&V?Wzm)N9T|;=)sp{74ammZbj$-%R23` zkh9^u^DJ_%o$2?hW=!C-9%{^7#ewfg)4tf?%ZRdTel#$v!!%E(Olzu)UUEBb9J})R z1`dCUEhr;%_aD79E&ke#QH%HD&LF|Ho+Z2c^P0ig;vtRYZ+vmYSZpOl@Vy+GxWip| z?!h8M9eK>snNv*^%$dDtX8HHuZ{#RzozjN`bS{#@P6%KoW$_?F#U3RnKIgreeOYZ)NqOuz}vWz$GF9W&` zEGzWy9dZ?x{qj#-d`5xQEd1@cAPaJqE3Pg&3JRp3m;;ps4T7DYi;|fFg1f)`Zz|J8 zLsaTiUVE8UJzTn_eywICVvJFBYX z@-k4h3+Yu=b>>t?Ri;{Fmjo%AOy9?2VgoQ zMY|-Ld4Z|osBFarwiSJBg*S}ow?_`}EwTMWVRUN2rJb%;S;+lc9S)Msr zrKGnN(a2gNLPV2M_{r%*k9ZjXD@s%B^S$k@agj(yU5GQ+n3^afvNW7jQTlvUs)alf z{lQyVcs)4nzEX*F<1kw;L`vO`vT*Pm`(hGZG{eF{Hn{ruVA0w}D&D!kWu}xk}I~ZWA4U?Ht}r(5#cHKYr?A3RFNzI6{Ga zfEU0WD9kv+2=SrlBj-1(Ia#>B{sOzk^r$Hj8adAY3E_rNG22qmttG^$t zR7qH&BI_9~+7()a2bQA{ix6Lo)gW^8Bmy4~c$s?2!pD?f zlT7xj?e{7FY&I|f5n)oa$a6D#B!?8!!n4s|F{@XL3N0(t?0UxXqcPw$(>1VM7M=jl zpPHlU6wKM>>FZ?>29vBj#AQaZa%I5JocOpi;g!=8?(9EGB9|BQ&$aeh#*34ZYp&^RJD=aZZ~^ z2C`JnpJEdli@g&fBsRG(arhtVx{%UdIIXnTyMde8V~|*QLl!Ov+3=)c&~fdq(+pG0+56znuo_UTe%gv3*GI#aecu$UcVK@B> zn0`{P#-`Ce6ABp1%L$ zfBx3R2bZbJTs;F$92{#j*01|F$@FINO|3P_{TH3_gB4fjUl=&Je%&`}qlade{r&%a z?XqRB`K@Ker+sm{S^UvwBxE{%_AnV}l8o@cLh6C_{Zofo?V?jEwAy3ck6D_@@W$^% zlcD!GyyOcyli~|8%CR?pj63~Y#|JvcrTE%E=vVyBPwBeDB^04 z<{E;A5Dn(W#&vqdMw0eR$pE#82j-Pb(E3q&TVZSvzPj@n4-}4vex=(YaqNtx{pb9^ zTm(ctqAUh!Qj-yZXA(VHN3KxP;BJo8wXP(0e~TX}c*uMvAtOG6U|`u!QDX&F^OjKc zLnpR`408M%$rUPXUEW)HqAUrb=dvJBj3tG?{^q8BMIrcK9lz2giwsn6OrFBO>%ibQ z8?piU+s@=WXm9-799P#bn{8aZK$U(;@vq$w(Ay)>5rVRBe zrA}>PvEjDG;!}lJL$*;yRJSY&udi&63N0?f9}FPvyQsC3xMYZD0I39K-`4Mm@bb^x=@cNB_K90Z{NR;OVOKMMEKH`z2|K2~wLiK;onA~)kcw81 zZH*8VU#KRuz(u;$ zT~C(eic+LNbWSWx=tAT8S9X|{mG{5ltu#zc8XaqschIr6jn}sgUKI_() zrNhYB^>HL%%{-4G-F)Mi>bSN%{bG6*)npFn~Eo%v5SzIDO~J>;BNp%Oh{QJ0Ag`o?hHSmMlb!b;t?@ zb|%MXx~ATI|M_E2`^b)E55Iq7bVBR(_3Qp+l^2fz+Zt)#?kv1*p;rah(iqdf#G-`R zO*(1(2X8;BPiDIM-laD0LSU@u(eGKJK`D`+Pjgm9Ta;x`b)mI_;cXjgF(y?(1W6;I zWI57VySbRIWS$qc0wRcAsY@M)W)R{6+AJBH)%+~Zf%(*^=b)VicS*rF3x9H*$;`OR z1b{@|vNybzQe5fDBwfmuvoRETKke>q4U6f60$sMm9g0@dl^U~b4C~=a>*r1kx5YgJ z-eN{HPA^_4qZD}UbvXI7^V`_AL}NR|orx-tL3560+;!cm^bQJR)Y z+}45d2$<5QAKpC3F|R42e3iNoz^tBoXC;2gn@y&JYH>fzXd)XEm&aBCVYDUYiv-8! z!a);B1-W4u5}lG^fWS}ZZ(&Nwi+@Q=khoz-?j}-l{hwLl4uaYCSk9C?U7m83)RsE-^eP7&>v2U5|=>+TQw~_OR|p)xES41;tE_zg&sd< z*cvc1bxbVG1@rpl>H0z(kxcH=AlM5jL1UO++=Q$C|P|8B2H0nq>Ti)1wY^Q zEP|g0-@mMI*^j4Z3g2Jp6)~{Y+c9xbH*i}xHwjfIkMbmKWCI_76XNPqD^6`PN}XcDtOev6x)JoK&;aksa@l zRdD<~jIHn>s7kGtRE{}bvb+rmDuV=zI;?DQc#ge!L?<2unqzDn7Lu~!)==oEPD!yZ zGlie+)ggkkg*j!t@lZ^7WpP*^OfxKmJE;my+_?<=l+K^r`je_KBT^h-Mr1~cK}Z%S zj*1X75$RU~iT%xlluEzk%3w{N_Dv-nWqk#T39TR8Sd2$TAx6ZjU4`YG?_407=k7UT z8?`~pQ?!>N5vNJ6ixi%0lPj|oCoSeB&Q&SW+PhAPZlZO5-Rz}#tga7y)=6xit%_jP za0VlwS@@j~<(Vri6dyq1E;E_(7Xm~&n<;*IdkRqCH$>Wk+;$;C&JQ;3ChB2lGgVP3 z?(J@No&Klc8JW6L`g=GDxm)*m<$l~>*{y5eu~Qq_uMDXfc;<2zD=I$3$ld+kh3BRM z>pd||9PC&m=~r%vk~HKu6>>uKv$bi#J(Gbpa=M}%Sy-ZEuN@4DxD0oEBpK!gT-tcx zm|}L(Op=TuS(=^nyw5~zkgt3#VgkPl`9v9si##xm-g0JIQ~COH1TEiO@oZq2o=e9$johlbIjj=8~)<0jt8zx>lG(VJh zY)o|Gr!wC8iv*O}iYoFs2D-X+3oI|Q_c;?vsMAL&=9({`k2yD-6o_~b1bJ|xH6JTk zRO<0dv$_884bkS>@R0g^k>019u|wj`Q7vkl)?!T?o5sND&Mx?~y^6h(65IcdmNjUoK+X9Fysex!g_^ zES1_G0%eH{=OgFX6lP61FyO<|kI7<-ZL<|?R0ca&C>fM(vN%C?Y28*4maJjJDHDqS z8Y(sDIpS;8mTXwIYyn>Sj9uyGdKSx#{D_K-V`Pyues<3V;d|4+qBP!|DL!I#q@Pl4 zph90`YBTbcfJX%aLdMnYQTf(W)=+1r*f?jlP8lC!@ZP6bLC-!`Ca*`I$n~>~szNB9 z)>7XdAC9w=|8cWvg{-b47o}J=w{7RvUE6zSbx-rx`mCh{LeN_)6;FJLp7(9)-J$2j zv#!DCq?;P^xUkXF%lkH6MJj)$>lYuiu&ep%gpG*81Ql%2x{hm6?CnVUA?s!0Egc)- z9Ly7BJ+T+fNgXpnF%RdNbsegof;P;hD-Hw!jKWY`x(@A5 zDib3EP$(bq!{MEYvj;QCjth-iQ76i@kDb4 zp!Xow=0KIi9nK!#9AoY>uDZ^COjHmanSru1pN)9F-R0`cED0g!&+Gmy>5vQV&X1O{ z96P@s3NMwZAHW?fwbYrVGDy$KT1&nQ2lQP+EpEANT|x#>2%fjuadDly+qtu{xlHn+ z8sax@x9iR5o-ArvEd{m(#T5lc!tx_uw_}_wyP8`iMA6pQ12f~cE zBEpVkUHuQ^&%IpWjbY=(bl|arQE_D*s7cflOa)#XKDOYEY<6}{I#aphOp;uMi72bB zS$y;}L=$?$Y69ZOrVCuvEI>0(2IlbQBfGpg1}O!SQC=>sCQ)*B^RrZ}@mKd!ZRhaJ z6o=+qYWM+0Ou^4@)O40@L`29mv0h=45%ozw8z2BXkq_$F*v?<2Yyvx{;Ywj&hLb?ma_t=nNdl~9eOaPk#!1_rklpg* zqdBZjA6fTzUyUY&HKN|6lBecT^-*H)`$Bm8x^Eo|J(n+yQ3j=etM$qHdxmjUgj-*?~0)^yqDL6AwxS1xG z$siZ-Xhbq*rMeXYHt<8z%%+UjkgD_}Ar@tp?_iKw7nRTb+P0a(&E(y5r#5;>fdP9O zfe^tkC+iVv36Co(4z&A#x`tPf#-T)rAOBNNv}S8atTE0M#70#JmY$y`#L=Rf;8U+h z_jtGW`~#it5hye!OHZoq)_3ANCAJJ8J@aqvnSiqvGUj0D6gv?6Qoyul)WjoG-bRK+ z#hh?ylCyqlpa7*z#o9py*0i8^pB@m%PR2IcWV&rJMEnT7)^fiaJo=fPefQ6KWalfP zfEISJCt9IM08^04YrE`Me_y);rag~Gaov%~i>bBmCL_@Xftd+rDFtZJw1$B9JAh>Xl1 z)ii)cx{-6pXN7JM6lP71=`4-`F<7My)XmAR?U!D;n|l$q^l$0*e{9>nbIXqY@Q=+~ zUa)O@`1_XamnOI9B%B43w^!LLa?w{j!sedK4V27|mAPKYb*~7{n8An+pLgXXJ;@LU>iDe4YR(Reh;T}_opdbW;Oc^iO&9%9mvNW%)Y2GG! z)kYT0qcO)){`_TX&24xnUF}r){}7{j15&CGW~Xo$_BwxavJH9mTvSirQ}?>%%XK?) zB1X5JsEoUoQ)L5Mu9P?@QLKsyM`0XJ(+IFb8F9bm!N;BO2PKVE1jWeJk%={iLTX zViF!Rj0kUcqVqvf?5m&c9pzLN>+kur$Uav*Z%B5WT16>DYT28`r46>qiH(PYauk^h zxUl@xzL3<=@}oj-mq|wH655n4!ww^DuP(qA$B6GA+X?~c3!y6*e(EEV_xw?_>mVu8a1D@9>P0n9t;F+9X= zhr;T(oPf6!jH#nd2X;I#Kc8h~%{kIi6Rk7V9;$CbmZRCk?QDA6u;<#cc=z5|=rsn9>MKh?`#TD*aW^;sWaqC8MD9Z*S81v| ztX{QBdvyd(vLIbuG|e8OuF*+2#u!);*Ot0*wn^$Gk}_?^qWzi;)!tnG{x7CZ1JKmN z(JB2dy0H})A7|xrJPMq*{Jt-mRuJFK6jrQJKslb$agyU)2HL22sIU#ci-(rsm02eB zBb*4xV1gdtIwdeV;DJE%6jS6l{%jwnk38o^*G2cm?nT)_x6nGpfw~H1I*ZQDF11=# zDC9h(k3k7o2WRzK$x5^9=^vAPqLsYAsgy^;NpgMe>et1$8 zDPL`Oz=oebL`-Ey%@dbm(kxr{*?a#hA*%D16rwt&fP!xZ=SN*96;~kX(ZPV zn9gh-+cOQh2c6a|_)3rcmi7&$i4(uf@N#nO#?7Ip%sr1*6z0wr1WH9|#3YDV73 zH4f5iP~WM5_^|P8r-)H*ryBBOMNzhO?gx&?CaKP|`baT#C>C2-2c@N4S!}#YV1hx6 zaMqjPDN!JY%V=`MPUw=fQO^Sei2g%}o*FtkHApsVmG`JzZIj>`yz8`hfptmeG{VC1 zz9t*0yVJU@I#0+xP9>$|3iIL{8n1KRC~dAJ3dU}*#CGW8W})YETD9+o+%c-vw0K+A zAVBS6#p#E%OVa3O}K9jM8H7Gi9z~}atcGEGZo-=y-RX$u< z8>;?*o?w6kJ@U|#tH{QMitMIcMzf3E_{mTpNaz@ z1RO0}s0#`p3?Os#w?C_a%EVXvH;)m}i9*qM;nYV0fAf1mNR3HCgJ{zt9A9^{G=zwc zlSZ_MwN84#1<4Sb8dJS`RdZ`?;T8Eh`e)g@GuTR1qor7~ALX$tdHR$Ni`tNIR==+A z#8@~U)gbfFjg(HXrHcYFC}b^@VvT;wbnLd!lnuMoUY4EeA=G$2LV<)vJNZJ#c0^sl zwz{1>JWgD@J#`GIAvoLHMJ$9%?Yi!`16qKeS2C2xkY z_)3JqW1Z`xa$4%*_*WBR_9o|4=q=&mp{l%zqXJ_5k|nK*gHFdOO+-^V{B-=Q>Gc&f zi^+ZBhur40ub}w(`!f5iYx(B(eF-a&D9|VZ$!^X;Uwm!{hgu*(>^fvnR2OW~&3{g6 zD0>pW^$VIbfV&fZV^a(b2hW0P480M4MbzDJe}9BN6K_U#Itczp`xT&Evp(*|-t~(6 zhv+h@z@5Frh2E1>9LU0qaMSm+W#?YhW0?~32(_Ib(%80W0UnkY;1b1Wt`Oo|K-1gR zt3)D>lKLp71@lRm=1sOUmS(cu`+L!3+wf3&1qU%_w?XaV-j_;4HZQWLts`5V$o;Cl z-;S2clI>s-reesQgqbge%vYU7rn<_yUiy7Qa2C8wNh97J_K9_o^hPOc>BqNO1Q&aH zNWE07v?Ta|s3cXCJ1P1DbWL`sd4Gjc{;#!;=4j8}nkhcD)m}`op{=a$E zsOMJD-o7+6w}KOREx&Cq{Zx50PWC7$7%-z(g&B9apT;al*rt3Awl`I_54dXynF4&$kA= z)57k~GLsC(=JGdvFk)L^4wXxpTJo>e<3NU>M2+l0Yzcn=wRE0{(L^(aXaAY}a2JaH zYS=t)8ZWUfe0k`EYguSNv@UCKvv`=hG&(U-vamM!iA9Mr3WYm{t(TZ6lk1iwnF&<; z2mrtc^DZ|#cHl#Oe!TbBaZH^ka~(Q|=?IDw?t>G7v|k6&?cgV&FOOe$PNgQQ@Q|I2 z)Z?&o+R^-da+)@mc(Mk!fT!%Mc?@>bhP7mqpQ{r2!CDn5Zq_+W$u2 zI0{BcAP%a{Iu_w&;g%;YO?MyN9d$R6p@-TbctdB0;A2z0-Q2viJ&0w)){8V8iGAIYcED07+x2B zxHLK$;}!FHTRVdTmx<@3tuvX~KRKY?l4C%X&%^>TSsR>gJaYb+uFL4uxvD#_bjq!9KR(^Jtv+Yc%+cq566yc@PXMwYu zXRMaZ7T;3a9m$tw;k#Sf?KlR^%|(&H`))GN007eh5o?5N<{cRhc|5wga!|LB6(0Bn za-N_>?n+A@#5j*MjprnIi$0Ba35KZO^Kd9uj=iiUkrvQRO$O+w5}Q^7 zg+Nl6z#|B`v9q4(EPTCnWY15BE+M)?k9B1r&{HAi5Te-T%VkP3ZVFz`k+ZaqgoWn9 z1r+1lgBs!&x!HTK+_k-*vKoqtOsC1PHiw{YS1jC4>q8p_nhb_X#Rl3f^jJvT+M23a zC#ef;M+*vZT?HTLN%kNf61N*ExJyDU+3MIwdW)B3>M8qS>B`T-m~BJ5_cMn z?zY}|Hk4g@VUx$7ljqtijIet8P6M2)E1WItT8DKs5++oZeQ3ZX7bok~gH`uj+^qj{ zC5ET7$k_Y5J?pLBg9r9S_|g7u4{|qTlt(#ud&?T3Ml8hMV6M^HDBqyV<^7o&cfBk0d6uTX0SbkMqV zWoA=eMj^LvnLcvvt6QjQ?pClHZ?n4sAaBpRtDWl2f4#=c3G*p{M~ni z?nq8;qCM;ItV+;u+C_?m;8?hrD713K6C&$SQoZ2bNeB!D6vA%YU`NrwA--=GKJiyN zDuxo=cmm4Uv%~2v7z(;sai9h8>bjHsufNJd;68d+4k?IyD)A{eTB;sN&EVxo21-Ebj5@pkjdbZ!4Z9VCez)B zx)YILgN9`1Q^1gCO0a;O{ge!#SJ&C5U_YJbw=7&{)wt+<+L-woK-4u#V^nMVi0;8` zI&rS%&+powwo(u4#qYG%y+rK6&AWc8jj(Icl&=!qc}G;g&LYDRekLonQV3RP^=9qC zyMH~cUy_AFL15=>QgP(*Y=ttcX1CPi{TQ5Q#-L!?D%-XDtFiU$un)l(WiA2OggPlr zZ{==|FCr`iu?_)<;dZ}omWxI%oU{d zGRYlv>6NtQT1%K3d=p;##+#v`R-^+iWV3rYbRQ|Vw?RR6Tt74Rf|Epu_hkXep_#7#_{RFR(=(5|Ye;gSP`g$8L_`sq4Lg;N zXXUEl`*5ueIoIMnO7*Vkwm`g4aciZD-#kl9xKgj` z8c0bdfdj0~t}}j3sSq)&Y%#0Ah>P|T46Tkj_6(D|)y;zfa7B_ry}Ea&Cy%cS-hv3C zA-u_pFj@A!I;cJ8r8)ud7c+psZPs2XrY}9Hxrq2e*4=Zar)tA{agN+Rs}TL3GfnIp z$_E>?zxE46J(?xD@Xs@l6nW#SO-qGIeM=gEl@T=+<9=Yj4M1BBdsnDQp>E{SPddx# zX+uU&#jEd%q@*x(+}UFxk6n#tCXNOyR!Iju<=)x!YxX6@FZc@h6tb?8}Y-SyfH1&h^LDF@@~wz;=aiE07d)ts~>p{yxuH+)^5^TV3#9> z`n|dmF7aMn8B>W)mX{V5L}8*;tDD6WmeV}R3ocZc!~by|kDWbAnM5ho3QRXz9#$0Q zyMM5&ZW5v$Wf>uhf+rE0_FP;SrlSV5IQR8*SdPwTv`!t61Y6k3uA9FTw~|Wwo}y41 zSIa()nXwDdr9_k{`IBOi{fYCL97X|s=sjBk=@u^jTqqrC+wBbWI0+esQs8nO^+7

$IR`xE0-KuN??v%KSE5O#@RWAUav8m@>@mil_AA0jRBWIY`m`lOs5ojZLU2;G z2)v!&j{+~$+SPIWMk_2tBcyC*L^Y&?V~zsR0Nz&MmuBI#Px|fYhGl6E@gUbUdXR;z z*xo8vCyk7Gd#c4{7M&}K@BT$UQ-{_{aUzqrNDO@UVEg6BEe4V2-9++lTbFR2J|o+X zECh}x899V@=kF0M0XSL)t9Sd_&%>taZDOKaB*Wq|R5D|6M6fjn&IlD8X<$0c2j_L2 zaoI7oi`^49w<<2bU79GIn_)QOGYpTcNd38wnO2&|<0?XlE9@jK()f^^rSaRdG;$_(69*cq!thxlEZ~=v!)M;N zM4m6c;q7(|rNdfo(r?l-VEL3g{5Df~$#2l^rbW9O<`5VnY8{q?p^cETJ&E0NHq9*m z+BZ|OZ7%=UCt{}UnR_0I13%qoR$@b{Gq+}T zWwS8S^zp-~3#cY_xiRgdk(dFD%~$;E-aT_?r_*R{UM4ToAU{AfwgaQ&2C+;M0aq4; zc!h>d<03Q1rP^@u(1*wa#W4A+mhAmyBqU?lAR7+FvHJ9X`v0Ohy2dswk%%6?VeBC* zj(|93XcoTpv!FXLY~-T;7Zpc#bZ_47bOj&-F%tQLM_l@xtd>h$aKidTPW&lrty4?i9DY+=U9r7{`0u{mI-nxQEkEjxI)S zHh0_P3ZMLQ#Eg5cWizQ;lag~DtsrWu%?I(&aTD5ASmS5n3@~t&QL0YrPgURtA<6% ztZ{p+EhLVA_8;7DmOrJ*l5A!h=M4sRt(JK_Q~32a;q-B5f)p%+l z1%@gHhbq<;pPe{IjMzx#^)$brd9%&G?^!|NIlEqKd zDP6)cyBdeHfSLjurc_> z(`2$nSW8A=n=hFIXhBTli_brVejV;yG-Gg1tVQ#Oy^Fi>4VhLNF#?A1iE!{^@{G_F zkCu@pl%QENJR=Gmo01m32b>D;j_<%8IYw>-=ryI-DiwjMmsxA2ZRS~eEls`%P+?`m zgIZW3vWo}&`IXNXZn-v1tExKbdKX6HRVNKQ$R-G8XF^ZsLQ&3jh$?UcU5KqB_DIGP&JT9Dw6=tV3YxN+cUI@-vE3{UO-Ev+u}} z9B@g|-|O-K^yqhRU-ooLSID;C8*$|HhQX#9m=^O)5YXbB;76^V?_*6dIk1|TpYJ;I zoO(VLv`hg(er>ReA$~CW-A4e|KYZDMi};J|uBy8i0bJB*%)!iZ{FQx?wn`Kk3E-WM za8SXY{UbS(^972vRt1)u8` zoeQ&eRv>*4K*=6=v7iAX8(V$`1QL@QZ)i_LDlQ%({Ee)1OK@ly@z0MrZ+&h8$dD75 zF_BHGy`*X@Lmc0Q&xC>W^x2cjU$vZ1JBNZ-0*!K^We~>GSv2z)d z)+neuVL->O_+*=-;FzyS&q8K#k5@kZTVuRw%NO|w?m*DMLhq%(pcQM34)-hGElGJn zX+A=n(`y^Adek&=6EO=jopMN+p-x|MX&E8SzxddY?For8KtyT519kR(1Xi7$iDPeb zo4xA(YfDr2U;GuT?zhbJn1-2?S6b?+&~ZDjh8tS+DZ|L2arJe<;zw_of@J8J5RPH^ zmkT|50sj3yHbXKA7h1qDI8Di-wS=luZh!;FvDer&{OvK&i8Q~G#2w*Q4$e3#1c>Zg zlUJmYJ5mt{Fln1f5yf~qgmr2JAj;n zr1ie9m7qRk#))Bz2*K*^?^qpwd#;K0V zGUFAg7od;b=(cNL;RbSJTpblGZ+)ycg1#RV>P^LE@sx`w?Bj5DD&N6jvX%^}C%2eG z=f|toPZ)!OGL}=-O-ZCZrky#hLhDi#fE-xG?vkZP5M?~EG<{QvwgIMzPk0`B0rE1`gWERkZOG}2kf z$vYa_67EUuIO(%J zvM>VJG*Y@+#~<5kyx&QnXB)hyl$=^h76rhCE&cFWr87!BE2F=R|r z^Ob&?!Yj-dMA*?K=(W#b6wgXGE`mCoEyPeB_UmjnGZ7bWDt~s{?C?gQ!p^vqc|FM? zo?I-~EY{TWpy~Y|r{Tvm3{W04=P;NtAQO$B5|yX<@__Dz6G7I=K%H$#kq2%Y>e?_Fw3`)^q?vv@(c zApPT|_Iktqs>}Zb+eKG1H|zt*j3uu7zd$dxi?u=K}-47|~ zvhb63Jk|w9DK0GJ_ec?UwicOFk`sIN%4;Wqj#`Bshz!RE*p7hV3{mp{RHSvAPq3lo z&ws#W*d;IpbMg2J!7~d?k=p2bzzG3cgiBjZ!_JD@S&Ai+NKFNhjc<}!wfuK{C*2ETRo-~Fg#~&&zH>(|Vo~fu zz@QQw3d@amL(drCp}CAb6s3S zpaWLcg4(!c8=BBOYQ-`@CDj?!G?0Y4@@emOY877mr||U9tM;k;!Lr9I@4bton(#)H zrWe{|Lp5S`2bH?(pD;BF=@m>1!^@4R3C1q|;Uhx3C;(tehj-GbZ~#(BeF)Iar2vr% zqGe+gMBfl!VC^oe{LrqFLOI(DT?_6XT;>xfy+N`rF@tji=Y=PEL|iA{&8{h7t1Bu3 zwWr(7Zkb81Y)^r(v;J&2oNYw{YXSzKXR~Mn_j$Gq0PIWZe&S+@#71?oaO1gKv2`qg z^KV_FI{EEg0#@(1P>@Y&1dEW!1$IjgUP_1zqk+3(FaR|^hy#e=DdtSI9Ra|hz8sZ~ zAaNEy-XlfB-~eaG6Vd*mo)~NDUYE}F#FLGE7aQ)7dv7GY!Zhb7dY|8$;&p};r?`#d z=MwUD6oUC@24N|6peyVzMaHqWR~RheV|qAbt|OL308zck)}u53?jEEvO4=_z=f6Kp zB1}f*2|a=-O9cvQnF~f}xip0z%n3LWbY3+Q*NCdlR)7cF>PLJE8!7Wh4#1g?%;eg- z1}Xs8?TWL>rTGIal{Gc?Pr}amV=!mtp5e5ZbDk4x*Nzb7YW0U8HaVEow_-keVXb89 zXtPeYt43jHl3J1Ul+H3$n@hudNxjDK1*y~CCf)!KsrdoUQvOe4Syz5)AQFY(`{I55 zxvW&pqPCOU!pm~L?uFSE_1SH72ulx1@$w5i0Caxd0^ULu?>q9DWAMI=VXu;VXji}F zd~uAoCc8baJD=}K>NnRXqpW5E+$ljBsLN0pcD_s+1tn=gdJE~N?edO})-CHTSk0ei zs|8wDUyBlAyWpF6rzYA{qcj)J8kpY3l^&I5fyf=u? z<|Y1$uWTlUYeobyQfMvx>D)JRKEqM+KLY|V@8CClgy+a;YaaeWP!4MPP*W-vmjz?q zR7nJ85dMl$-bAv{hS~-#_k)1GZqy`GATFE-Zl?sm!=%lS6bx&ggDbC zNG+>9nxJ%lz^qL7hbtL_v}Q9sXjs{f{$w{yCF@o&h2^**XR&BJlm`t6WUbylBU~+? zwXGezKrnj<&m8uH57wqV4M%t(Z6%-OM-Bi}vhggpCx^Ny>xe=O1=kk}I_l6^qe+WS zJci5B!4W=Nn?ffB=eiDZ%EwcVoV~@!W9G8SE7-{>b{G5Un;>t<9MQ^iG9$b{-daPVA791tlL_ViF7Z-9!E9#>Pu z<|Jz2`6?L=kvTRTi?XBj4$)?zoF&lBQV3LHn`AQ%$zXPnDe}SWg?h`;{9xsUS${VP zvC(87>@2gjHRMknk;J-ejh5oQ+OR87 zA%#QYp<#s)GM0wfEQEL1K*VJsvK+evv&MRj%UGb`?)IK%@YU;#%4d*Wa0GYE zcO-4WdkZfMD&ng=AVY4MZ(*LEb{9xV$jDvO6$eyiaacpNU3ML|k5!6f_hnUXe%G?n z7*O+TEdy$qNe5N2P9Oq}Wq~Q?EnC*cE$~tkFZzke-)<-_4**>a4<{_@4g0pY9P(tW z(y}AGq5-r?*I*k-rTIP|v>T5H<9g%Kr3N#^-@wFvY28xGDWY9U_MCIP=xHzOE-Kh9 zv|(}H#n5^N%*Rrx{`0)^uGL>W_nMXG+OHWH=^MF1 zkE_>&%e5QAHP73TZz3p&ow|!UhpB~u1}h1Ye|dUcb_=RwhG1!0QA!on@P)=}63`UP zSM)F*W*j!GJFn%=M#K!jBt`8Ng;@(}g!JL_N$569{{1NtdYnt)P0={gMwbUw8AreN z^yrb4S^+?9J^DEb28A!?lXZ33T3IHbiJ9fmCRp@NG)&7<9}^A2qh2`ls=W*vK%ipj zOase9SeT9v(x}m&71O-anNUOyd39a^oa9UKbmCkVx7w|tI%2UMbM#V@nYI@{gxl~H zK?N_pYPCi$RPY1nQ-EGI!dmgdwndODW-e(EQ=^RIZC&KFcuGal!l{<`#VXNOi+Q7t z?Rn4wEDxd1@r;d)aJk;{(zxE5J1p0mjoRhyJ?S*v(z~f~#(>*syO^M(MBU;#LNpp~ zrR4E48b=O7L5CMlq&yXa-t5+{&P`i3dho$T9YP2w1BNUf8S|t;XzahkF3sk<@=ms% ze^Ev9G{M09VGspc^A3|g9{{j9t`<8bjzIBZ|4Kkqy)l>gjKT2a3@a8vxdj)}jbUhNopdJ~;+z0i<|THp|!#xdpb@2ac+>!9Z?|0sO% zC?{EOG*N>}GNK{D>zn|w$NC~(=+Dv+2Tgl=RODM=%tRn3hI7(go^dK$PbR)5O0l5- zm2enEXn#ZJgTDel>}^8`x;>zoq4A!9Rf=%~4N};CJOw`iSvkGUyh6#!W>&O^Ic@SJ z>*>_ki7rhZrdmLq7itnZ0;DX#XhLtL`xNs;eIETgu)`3YkQlA;FuiR>qx2Y0Mdj=E zLu9!9j=dmFunF0VvQ{Opv1FmYBVFvc919YJWhD?5Q1WCZe$cH$dYf9^+|G-Jz&AuVikb+lV~L8hF&Km8$80)g%2f@5csag18smv#0%K|>Fe=C^9u>iLQ{y9w zfvZay5*DSp-iU+zZR9L#b&Z_JA>E&lk9)NPJ|G*8i;z8h$$i>lf+Yh-2GyJCdOC@k zD+b53RME~O83i<;k$aP&VNJF$1;GQb2U=7bI?`l}%hJk@_M+89%*JA}T1;9B5ddF~ zH&SxQ1&m3mB@e8PDA3@{wGX`_Ht{Ii&^qu)@7dnH=VQq2s2WVYc`)cp84!SVGS zsF<`|h=y0Jw>KV*qYP|BTNBQ>^o;NwnYcmHT_)*T#!F^bTHp$z3LY&Lc!=nN+9mLS zDM)9yh5+BBR?h)>18s)nidDb}VU2`&Mqa02tISCbHxa6W6$eYwluseLXzP5 zy@#_nFE|Oeh(x_H}BI_YvUByYl+q`LOS3`FDruHjEwdic8g>E>g!D{9pK`FPvJeTc==)>@M z?&_wM&8xKU7(7rdl-Rz z9CVCdHI>&mN@m*Y9Flp$IfRyB;SFv5JF?3eS>pgQcrH>|py|~avcdPQ#NwP8W}4ZY z1z(r$0z>V&4jU3ob_bsvPY?bfj)3OUWeBcZac9RMen% z2B@$`4?>4K$ixAr+%pa}ANYtzGx;W%H{$OEA>V{afR5D`Hik9kgO-n)UCsw>Ehpx( z!P?T;;H9szY;aYnEs-34=df@rpcebxkUdA%A-o%oN2Bz4gc_P;r`Z1yAa+m{vcSa; zSp+~XlFaFL??L>Ut<)2A@RYLn`sL|!*NF$z84%m$ePKCLau82k-a{*M=W>&01hJ1R z-6NS8?!z9?VqW`FxfC;Z1QldSjS$8OzAvG9T&>N$EVOF+S=ZE{m30lsk+|a>AdPdL z>_zu|UM=*xgL~e^Y)T-lC%ZWUUIekl^nplbou+;CyJrrG-U7~7E*N6>!9>;E@+TR@ zq+1mq1i*%Gvfy0Q>CfIRgGf_#_LM6=%s}oio(=a#S{x}yhNLqc99$tVy#^3A$?lo}#gYv)EW@c27@*T&qzEX8L^mpL9W*}PEJ;jG|} zqLc<*mK_z!2nUWjlT{V)`D&hI%sxR60AEzZnR|mp2D$p!QU+bKH{XoFFCxA450e^P zRWH{)EL_MFn)9OS@-%7!Gt1MOrYx+iM>=;%7?Q?kq#ltFti_^PuH~ zb|Kz5AZ%hktaUNr7os{`A#If6IHDGM8VZ=aOvL4)b)|99j&m#*orN;F%G;_zm@Bs9 z3E&!WsCH_PzE&YUJK)7(u(fo27!c?m8b~<7Xn@!-ZUaEth-(CjkzaHO6bGVrn0vyQ zjO}5s>JU~9n6BP4yk&jscKh_92#8!=W0GKUV+%sK_SsmEcdM;&AQa-=VXRT_tlV+G zE|NkMgon7jTm?gd^fX`$(}W^PbcCij>>>bmv3oz@{l|RCq^bxag3RuIJ1v5J8*(MMF`Fj#qTqPIu?jF+Mv_AyK`4&=1rA$;P$iKz?(iv0Ghd)fp+YJTEA?eRR+?zKEYd{N zsYP6~?4yjSb1hv-cz&(sFa9~GP=GHA9$|T+%mi8W0O^%z@x$yDPBw+Mx4k0M%vfeh z_T$#3(rfS34j7va=4uLXjf&;u#^9-3w6$*D+};U~FAjUr*|7WwGzy(%E6l?=OPujZ zy#vzo%0tH>9KHt#=2~Zh|9ZaKR^(HLx_PhO-lGy=7bNruaxlcY)aVDIDEMV>(foy0 zYaiM=9-|dNn~E8JkVC+=hN*cNp$FN#s+&uY=aoi~+yB-QWLq*3jSb3?k(=mh+#7h; z4?nvqug2pk_qh&vZgliu#XGO5-LvPwXHnB}xP8;;oiD~OM*_+F-uFmFHKxJ;RndXe z+6nYldtj}}Z+E1?=MSrY8d0^dW zc7gs>!M(qjXc|3$GpPaR%Yd#Em!VCGKoQPX6}apJ0+}+j9^Q8ButbG!*)-8Idf+td z0>Mwn1CQyeRe^?Ily~5HqfZt3s{?@asOBttE1v%QQx3OxYW5<3O<3k3oWw?!RG{v| z>?J>Z-3OqzZ68(+WeIk-z<$%TJu?-VtFy?`Arou-BhkJ>{ z9%p1jX`=ZpXIRm^s-${7=S;0|Y2!!!$&SBaKPo0|K{+bdsY`8l`Xd=_p!G|gt5$pR z{F(Bw=cx_*pN(vEUqzH8?^Ue))E{k!e$cS&^dI{<#b zzT%fZDZ~D_!QN6qv7ajR%Ka1Pj~+M+O-c{9w<3ObDAJ88cM8qgw(yQR6?oC(<^7uV zeyLFFtrJZxM1DqN1~XwO*yz*%=x&Ma=I;$i&19qLI#uzxAI||utKi|=Cf3S=`Um?W z-7zHgsEYS*o&!@aMg%9ybrpOdIMKYuQsX70#%|=4vRX4tFRY=;Zs5w{)&&f36*}ur zTB11M(Xl`mN}WU9i1LAb-Pdpe0!oE``Rj?Mm82qP1v_DUyWF8IJe+mb@SAf_fHkP< zGk-SG)RaGGCXEVac7)frZw79v|8W9Lccw(Gf)Dlim*-hondV%YL-uxp$5(`tyay-MYQ2q@Xs;Hv*pWrSKeHqFt*0rwaZ4DPgMJW37)M zj1x|0;N2eSkBz&8y$nnMekEyAea#V;~~CW_+y zR2a$ru^5h6l%4IzzOMc50szBw;8UTU9}rH=93OP0L!d1zoC(551-|u}GKfkxN>%lu z8^Bsfd8XP=kPQbk){QM&S_b5_fK1QtlgE3 zr841xSSB)7^R@*H7eAb4`?m^qt#$RL_0*gEzJRuH52WgbgJo!ss?hM&#_?dFgr27H z8`&Qa3O^eLiD;MyMto0vM?8bh!@6`u^yZH6%7$!5xTzuA*w~0)!dPZ@_yxcU6@0kG z=)y8hOu^4Q2ghEv`~{fVY^iXrzNdoge=^a0K4n?4oj{h|P)t?)`X%MCw7c&`?!wkgvWO!&0bz5wh5Z)C--wYmFE3UiEs|P6dConw|n=j4{_lGMf(d z3=Is1ZEhG&almGkl^bT-t~1I_%ji9?iu}r^gtdQa`_G|(OM;C?Q6$+E@L1M?jGq`<0A#E}FJ7s&I~N>zk&=r6joa^C0MPI= zO%?pNxcK#Qfa3|U(6jw+9_RD$wlZOAw)XiN3Csw@^qCrA^rJH=V9PV?(FUf&EdzyB^anDov9pR`REu z^nxhMVF}SO5SCyvV=k!D2;@Zja-!jF;dI^Dnk{o+|1FDF!MAlpe* zGZzgI!SnF|G6)=;k@Q`b=2xoX&QHxDys-Fjynm|T_jgV-uW}jlrC!EtGEc&W^lToL z^Grn;5@)3725is%X^Gdnn7RsrIGl6ObBbWty{?HC@R>`G!aKv zG3BWmPjI9ygG;VnV*CRODY2s2g$+we1uzpkfl0BEfyf{{NwxEUT8=j-p6&Nk@bRBR zv-bD~oGe%2UTxu>P%MA`wepta88NE*74Oh#LYlS(aJ&1G{V_=rwqov&r!HXFsZia& z=EKNMM`qZ!j9dkZ$1QR>Vq~+Y4EYcmYU_{yP|IucGN}U`v>XX50MSx8q>hAnoDCh0 zkQ#`jb{ZuoeoCxI$ULnAi_Tua6z&JB3bjl!+k@4d!WWrH6FxP9ZV?}dl;M;oMf~ua z?cXZ&l~;My&Mg*e53%*I&+ma+wz9KGdu}C%)mtpzSXwcA_seWC`>IlpkGlDr=a{1O zL+nU|zSk+9@J$2CdU6VQsXD^kt=*0Wrrf?XDs;~~V3O&|Y5$O^7{kReYklXIfecPF zBqGlVbd*h@axgHwxJyR;_^>3hiY?N{^@u}+9-$dD=`Oce25;qJbGtg?akIK|B-O!M23-1Cj zDxRJPz);oApVY~{ zs}~=u_t4!c%5;R$64 znkzw5{a`O%FBAi-I3?J36{ndaDN+SmzhCA?Gd3qwD6J-%r5#17;AUuB1;&nLTJW*r zttZO3D)itohPTP#3L?2abuX5O>aI=UCjy%ntSWD*dI9M`1wXWNqD5MT6kJ(%Bpr|X z=gu?}|1~-G+<%dsa3WE(-A${ihyMEuxJ*AHsnCm8%cfv%2=h5lSq@E=q-aU z4}2EERp^PO6U}R->9iE87gk3sH2o-w^9W)ooV%Xb|&2a>Q3V!VGN?2NclZz~(YpD_c zR=PTPV&FKg!cw#UrwYFJyAE|vA$@dbm;#HGJ}3S~>b579AAIZtSfPK#rT(pg|9HXF z`#zYrxzIF4qbcWamyiRa^S6t;6{5*}0PAxn%3hoj!0X3z?Zqjq4$*0*8-DmHSpZ(H zM<}HNR^#&&0Jdk2`C(k#VbhmP?o?IxUvUDnQ5E{m{Sz(HxUZly2ghke(V*DBX2U51 zkE}R>*XAdoWA!&WX8m?5+b_RNNc&fx_){5pMeUYSH%nE&`2J!ZC7Ovm`%YC(%!ewP zQbBUOpHsnqO-wXN*Z4dh!Yx3@09E;4@-jRfcoxHH6}tQVnycs%nSwwr zQoqlmqX+wOctu|8N<@;=P~>`4)tU7t&?czR8l}~+SuB=5Cp2vLABdfmT{{ zyQ^#7I6VZCsc3%0bZD?AlJ9hb<~rCP85w)yi4;UEw)#@9tKiKSX{Y#9cw&w?%R>k> zmx`s3lzsagz=u*HGSlZ&=;K#TH1o`!SwJw!NJEal7lu$ec7qD6nM>W;X9_d>ybA63 z!$dQU#VKI7BbH$9zaLPH?2c{!%LR;i7K+7wqI2I5OMq^kPGP;4N7~B3omQ)`z*nJV z&uW`}N>nZa>^$Vob0xE>kP1AhKR3TSU8(AqY?&66@g0d|DnBq*TumDq?2ktw*3snP z8@HVRh^>OZes)^@r0^=!$-D+r9tAb+M=?#4O=o6$uRel&1Rm^4n{n+q!Z(QXz_$oq)5Q&~ZauQ0I6agNd@ zpY&Z~oTCUzYI;v+Py{lds@{I2OztJa)>429-TszoeHZb>t|X5z_Y=N0DbO3BzIp+I z9Pr#U9@)&W1NM;vHGb(S3SenMNzq=p_|S#$)GPIYsU|B8erg|@A|g|1acMn z%zLI~3Imay`3M@xx6N#be*xDiFuAFSl0;-I1WD_RDW{N?kmICNZkV=M1jxo%j77Cz?M*%g-mOP zpzF{>)3OLOd$OLIrt8Z67K`UT<|!NrI~oc;Wadcd0lkFNN+>!IMj;u-0s6IzJ{$zD-$Y z$VKH6bOxkC>pa=Ai(yvCTat?*6-&qRcyFOVQ96T+rv=>_XqxC+K}e!Q#Xy`rD$33p z*I6?SA1#28Hgr+WBlQ@v)2V4C<&mZbV^L(!`DK=FvWzHY)q@Kurw)zOI;TuHqy`I4 zn92<0MRlcqs`7Ww0hDD6H`l^dp_6-Q7mtY9DY!w*I_z? z1PDL&vnh_MC^MTGGaGZ_R^i4(Ru=l9UDl8DT*J!osTBt0P@-5j!ZOx+?TpeyWbqag zMd9qn;lgQruld~q6b35zrh6EWyXQFDT{=!&C_R2^Q(I51%oQw@`j1qTyRAO#?Y+qY>MtHHx=Kt{s=U-b4oAkXB>zfPT-dL)VN!PKDpF;T(vBmtRPDKLS@&+74EBv@<{=`e(4X(i zS^r=(0)aya7)=z+qI`s)j?fHWt&Lv8YpDehS_L?5`AF_uH}`Z}kN>_slH1`&Y4)?v zYskQugPW%1+lQ=82Ok?ceGX8r3f}b?TVFfpzhC7Q>?4r`>S-X5+QK6s$iF%f+L-${ zZLa;TLSwaF-bWaR`y=TLRRGbVI>L<&*^aOev8YNxgS!3Ya{#MK-4hl3pO1Q(o4_KG z=_4qNARy+Az2(>QXwlOFM+M*i_jy1WOb!}=036GfE+BAB2d-lGRdCynNoU>|=gN{| zoQnd3HpaQ?g1v!j>z~`WWg8=$ok*2rDo%EDygL<1jo7&6fio&9-v7Sm@UOJ-U)^QK z-y8V$XKtU2+i~_B{PW$6k3Q9h91ns64^|8bo4;Ic=DUn zi(8u8k^=*9;EgZt?cL0&wfCU=4ywQw1y9;cMs&LpwJE-c5cW@*xI_8nP!^1<$lE0!E-saWEGa^)`o$*Rd8$rHNl z>^J+$KS`BS!2yXK_f9sA-uWV6GB>2Dv6=f}DNJD(^xnjH!XNfURou$Nm*4Cw!+R>Y zP6zkd-dELU)?mNx*rP6$&C=v!w~It`3HkzL+tcZokQ7pw(rVFJKPhjS`obEolp^Q!P z0A4MN@=$RT3SzPwPywSBT{T*Uufx-(gX^)rua-=HP4AnCrIviLBs;ftM1)dgSOp%s zs=R$AZ=YJSQRRSFL>8-5gvUB z`dAw)&b1v~Y1Uf10O2%Sj-aX^zJ8KzXS5Vtr77J4lX$p6As;!J%623n2zNno7(1DT zjb)3WuqCEKAGkdSpoX@!u9XAONFqKs)E}W=A=}j#%U&8!XObz@FrI(f2>@VK{Vy9P zd7_ZT43XYBn88eSU`AVCB!Pq1v50-K;fxBzdA{m=!w*&czn`9z3@-~0;YCK7=DxNf zQU59u3p~$&h6=plW{f?^s z@JA=Hk=kZ$))APtA?Wr4+(@yfOnoPgm3Z&P<*j_dw^CJ~HZ<8JZU#8Kuw|O~V3d*1 zdw0yEals>VZh7xY-aB}5uFHk7SjJbbbx(+Sx1)5p6EZ-lG{G%-K?DO62p@4?drH> zA|6XbWBa^p27=+p#xmyTF&9<6`|Xp>th1wO+}vpVm0KdB-wFTlf^qDXuPg&G4~WxI zjtcF+JQv8qskg@ZW5^lN9*9U5W;f1!P=S}9QwDL#AXe4;uFVCl@Nh;n=rRNX1FUdf z{L6>RKrI=l)8VuKzFPA7Z%sB^mm`^o@aEQZn$|qp1X(2avXU%#Oe~#cHx{#7;L-np zEUOnxJ5kl=oj)lZ!7VQo4@GN#KO;4}4L)r{5gC82_}YBTcJXiRvHDw8zY$qAHd}-! zBQDua)4GpdSftVX@&&|(W3}?RGA`12&YEnNToa=ih;vvw=*$rgV6R=&kR?j>{U4Nf z>v?0bYRT27P0G1kmKTY?cpI7_#4|!2fW4QUf_Z-8l=21~^#-8(^ZLnV_9n4_UrR@Q zYl6B&`*37n5Xn`6hgjBDwxYEaeXKYdvU+ZxM5BdKr*7fd66+T3vvm>i_})NwXmXmm z2-GwD%{QTSiw{6#zUy5?d>%WF7GzK&-?^i_>qkvsGsPCQB>0iZ<_k;;zKEjL+M9T( zsAY6=nN5OPmc3GE*X+c0ZJ$rUvzda;|GcVx{M`hjZz@4W>xSiuDS6CfnpPgU@XY_L+3vlH5mp{qx3s3=!`|}9 z^a!pNESfxW{=nH^?96#Kjc3;k-n;URIam8}wMFLODZ7+8G+*`~*N-^QE{+bQ@aU_b zymL!MMKz$t|G1dRtUVH3{me&dycY-JYmWqy_r32C=VBFJU;9kOqBlRg=t=zh|5wdi A*Z=?k literal 0 HcmV?d00001 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 DI<03F80FFC1C1C380870006000E000E0 +00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 +000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 +700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF +FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF +FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 +1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 +1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> +II<03 +0007800780030000000000000000007F807F800380038003800380038003800380038003800380 +03800380FFFCFFFC0E187D9714>I107 DIII<07C01FF03C78701C701CE00EE00EE00EE0 +0EE00EE00E701C783C3C781FF007C00F107E8F14>II +114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F +14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E +070C03FC00F00F157F9414>IIII<7E3F007E3F001E38000E780007700007E0 +0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>II< +3FFF7FFF700E701C7038007000E001C0038007000E001C0738077007FFFFFFFF10107F8F14>I +E /Fd 1 59 df<60F0F06004047D830B>58 D E /Fe 25 122 df<078018603030303060186018 +E01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01C6018601870383030186007800E187E +9713>48 D<03000700FF0007000700070007000700070007000700070007000700070007000700 +070007000700070007000700FFF00C187D9713>I<0F80106020304038803CC01CE01C401C003C +003800380070006000C001800100020004040804100430083FF87FF8FFF80E187E9713>I<01E0 +06100C1818383038300070006000E000E7C0E860F030F018E018E01CE01CE01C601C601C701830 +183030186007C00E187E9713>54 D<40007FFE7FFC7FFC40088010801080200040004000800180 +01800100030003000300030007000700070007000700070002000F197E9813>I<078018603030 +201860186018601870103C303E600F8007C019F030F86038401CC00CC00CC00CC00C6008201018 +600FC00E187E9713>I<07801860303070306018E018E018E01CE01CE01C601C603C303C185C0F +9C001C00180018003870307060604021801F000E187E9713>I72 +D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 +80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 +707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 +E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 +000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 +E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 +600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 +703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 +E010187F8F13>103 DI<18003C003C001800000000000000000000000000FC00 +1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I110 D<07E01C38300C700E6006E007E007E007E007E007E00760 +06700E381C1C3807E010107F8F13>II114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 +30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C +001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I118 D120 DI E /Ff 2 42 +df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 +00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 +1E000E0007000780038001C000E000700C2E7EA112>40 DI E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F +C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 +7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F +C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 +0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F +800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 +001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD +F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F +F87F8007E03F8019167E951C>97 DI<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 +FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> +I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 +3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C +003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 +7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 +C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 +003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F +01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 +0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF +807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF +E0001A217F951D>103 DI<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 +0F>I107 +DI< +FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F +801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 +1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F +801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>II< +00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F +FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>II114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE +003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 +7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF +FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F +C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>IIIIII<7FFFE07FFFE0780FC0701FC0601F80E03F00 +C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 +7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 +F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 +00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 +EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 +FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 +D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 +000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 +0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D +72 DI78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 +7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 +3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 +F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 +0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 +0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A +>I89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A +>95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 +700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 +D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 +007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 +D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F +C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 +C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I +104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 +7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I110 D<01F00007FC001FFF003E0F803C07807803C07001 +C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC +0001F00013157D941A>I114 D<00C00001C00001C00001C00001C00001C00001C0007FFFE0FFFFE0FFFFE001C00001 +C00001C00001C00001C00001C00001C00001C00001C00001C00001C07001C07001C07001C07000 +E0E000FFE0007FC0001F00141C7F9B1A>116 D<7FC7FCFFC7FE7FC7FC0E00E00E00E00F01E007 +01C00701C00783C003838003838003838001C70001C70001C70000EE0000EE0000EE00007C0000 +7C0000380017157F941A>118 D E /Fi 41 123 df<0003FC00003FFE00007E070001F80F8003 +F01F8003E01F8007E01F8007E01F8007E01F8007E0060007E0000007E0000007E0000007E0FFC0 +FFFFFFC0FFFFFFC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00F +C007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E0 +0FC007E00FC007E00FC07FFC7FFC7FFC7FFC1E267FA522>12 D<3C7EFFFFFFFF7E3C08087C8711 +>46 D<001C00003C0000FC00FFFC00FFFC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 +00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 +00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC007FFFFC7FFFFC16237CA21F>49 +D<01FF0007FFC01E07F03803F86001FC7C00FEFE00FEFE00FFFE007FFE007F7C007F3800FF0000 +FF0000FE0000FE0001FC0001F80003F00007E0000780000F00001E00003C0000700000E00301C0 +030380070700060600060FFFFE1FFFFE3FFFFE7FFFFCFFFFFCFFFFFC18237DA21F>I<01FF0007 +FFE01E03F03801F83C01FC7E00FE7E00FE7E00FE3E00FE1C01FE0001FC0001FC0003F80007F000 +0FC001FF0001FF000007E00001F00001F80000FC0000FE0000FF0000FF1000FF7C00FFFE00FFFE +00FFFE00FEFE00FE7C01FC7001F83E07F00FFFC001FF0018237DA21F>I<000038000000780000 +0078000000F8000001F8000003F8000007F8000006F800000CF800001CF8000038F8000030F800 +0060F80000E0F80001C0F8000180F8000300F8000700F8000E00F8001C00F8001800F8003000F8 +007000F800E000F800FFFFFFC0FFFFFFC00001F8000001F8000001F8000001F8000001F8000001 +F8000001F800007FFFC0007FFFC01A237EA21F>I<18000C1F007C1FFFF81FFFF01FFFE01FFFC0 +1FFF801FFE0018000018000018000018000018000018FF001BFFE01F01F01C00F80800FC00007E +00007E00007E00007F00007F78007FFC007FFC007FFC007FFC007EF8007E6000FC7000FC3801F8 +1E07E007FFC001FE0018237DA21F>I<001FC0007FF001F83803E00C07803E0F807E1F007E3F00 +7E3F007E7E003C7E00007E00007E0000FE3FC0FE7FF0FE80F8FF80FCFF007CFF007EFE007EFE00 +7FFE007FFE007FFE007F7E007F7E007F7E007F7E007F3E007E3F007E1F007C0F80F807C1F003FF +C0007F0018237DA21F>I<300000003C0000003FFFFFC03FFFFFC03FFFFF807FFFFF007FFFFE00 +7FFFFC006000180060001800E0003000C0006000C000C000000180000001800000030000000700 +0000060000000E0000001E0000001E0000001E0000003C0000003C0000007C0000007C0000007C +0000007C000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000078000000 +3000001A257DA41F>I<00001C00000000001C00000000003E00000000003E00000000003E0000 +0000007F00000000007F0000000000FF8000000000FF8000000000FF80000000019FC000000001 +9FC0000000031FE0000000030FE0000000030FE00000000607F00000000607F00000000C07F800 +00000C03F80000001C03FC0000001801FC0000001801FC0000003001FE0000003000FE0000007F +FFFF0000007FFFFF00000060007F000000C0007F800000C0003F800001C0003FC0000180001FC0 +000180001FC0000300000FE0000300000FE0000780000FF000FFF801FFFF80FFF801FFFF802925 +7EA42E>65 D +68 DI< +FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 +0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E +000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 +06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 +F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I72 +DI +76 DI<00FF0080 +07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 +80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F +FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 +0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 +D87 +D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 +FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC +017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 DI<007FE003FFF807C07C +1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 +7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 +00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F +8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 +1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E +001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF +C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 +007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 +7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF +FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 +E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< +01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC +007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 +00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 +0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>II<0F00 +1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F +C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 +7EA611>I108 DII<007F800003FFF0 +0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 +1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F +C0FC0003FFF000007F80001A187E971F>II114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 +7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 +EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 +0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 +0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E +0013237FA218>III120 DI<3FFF +F83FFFF83E03F03807F0300FE0700FC0701F80603F80603F00607E0000FE0000FC0001F80003F8 +1803F01807E0180FE0180FC0381F80303F80707F00707E01F0FFFFF0FFFFF015187E971B>I +E /Fj 29 122 df<0003F07C001E0DC600380F0F00701E0F00E01E0E00E00C0001C01C0001C01C +0001C01C0001C01C0001C01C00038038007FFFFFC0038038000380380003803800038038000700 +700007007000070070000700700007007000070070000E00E0000E00E0000E00E0000E00E0000E +00E0000E00E0001C01C0001E01E000FF8FFE0020207E9F1B>11 D<0003E0001C1800381800703C +00E03C00E03801C00001C00001C00001C00001C0000380007FFFF0038070038070038070038070 +0700E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C0380 +1E03C0FF0FF816207E9F19>I<0003F03F00001E09E08000380F80C000701F01E000E03E01E000 +E01E01C001C01C000001C01C000001C01C000001C01C000001C01C000003803800007FFFFFFF80 +038038038003803803800380380380038038038007007007000700700700070070070007007007 +00070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E0 +0E001C01C01C001E01E01E00FF8FF8FFC023207E9F26>14 D<0020000060000060000060000060 +007061C03843800E4E0007580001E00001E00006B8001C9C00708700E083800180000180000180 +0001800001000012147AA117>42 D45 D<000C001C00FC0F3800380038 +00380038003800700070007000700070007000E000E000E000E000E000E001C001C001C001C001 +C001C0038003C0FFFE0F1E7C9D17>49 D<003F8000C1E00100F00200780400780400780F007C0F +807C0F807C0F00780600780000F80000F00001E00001C0000380000700000E00001C0000380000 +600000C0000180000300200600200800401000403FFFC07FFF80FFFF80161E7E9D17>I<07F800 +0C0C001E06001E07001C070000070000070000070000FF0007C7001E07003C0E00780E00F00E10 +F00E10F00E10F01E10F02E20784F401F878014147D9317>97 D<01FC07060E0F1C0F380E780070 +00F000F000F000F000E000E000E000E000F0027004300818300FC010147C9314>99 +D<0000700003F00000F00000700000700000E00000E00000E00000E00000E00000E00001C000F9 +C00305C00E03C01C03C03801C0780380700380F00380F00380F00380F00380E00700E00700E007 +00E00700E00700700F00301E00186F000F8FE014207C9F19>I<00F800070E000E07001C070038 +0380780380700380F00380F00380FFFF80F00000E00000E00000E00000E00000F0010070020030 +04001C180007E00011147D9314>I<0007800018C00031E00061E000E1C000C00001C00001C000 +01C00001C00001C0000380007FF800038000038000038000038000070000070000070000070000 +0700000700000E00000E00000E00000E00000E00000E00001C00001E0000FFE00013207E9F0E> +I<00000E003E1100E1A301C1C20381E00780E00701E00F01E00F01E00F01E00703C00703800787 +0004FC000800000800001800001C00000FFF000FFFC007FFE01800F0300030600030C00030C000 +30C000306000603000C01C070007FC00181F809417>I<00E00007E00001E00000E00000E00001 +C00001C00001C00001C00001C00001C000038000038F800390E003A0E003C0600380600780E007 +00E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C03801E03C0FF +CFF815207E9F19>I<01C003E003E003C0018000000000000000000000000003801F8007800380 +03800700070007000700070007000E000E000E000E000E000E001C001E00FF800B1F7F9E0C>I< +00E007E001E000E000E001C001C001C001C001C001C00380038003800380038003800700070007 +000700070007000E000E000E000E000E000E001C001E00FFC00B207F9F0C>108 +D<0387C07C001F9861860007A072070003C0340300038038030007807807000700700700070070 +07000700700700070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00 +E00E000E00E00E001C01C01C001E01E01E00FFCFFCFFC022147E9326>I<038F801F90E007A0E0 +03C0600380600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C0 +0E01C01C03801E03C0FFCFF815147E9319>I<00FC000387000E01801C00C03800E03800E07000 +F0F000F0F000F0F000F0F000F0E001E0E001E0E001C0E003C0F00380700700380E001C1C0007E0 +0014147D9317>I<00E3E007EC3800F01C00E01E00E00E01C00E01C00F01C00F01C00F01C00F01 +C00F03801E03801E03801C03803C0380380380700740E00721C0071F000700000700000700000E +00000E00000E00000E00001E0000FFC000181D809319>I<00F040038CC00E04C01C03C03C03C0 +780380780380F00380F00380F00380F00380E00700E00700E00700F00700F00F00700F00301E00 +186E000F8E00000E00000E00000E00001C00001C00001C00001C00003C0001FF80121D7C9318> +I<038E001FB38007C78003C7800383000780000700000700000700000700000700000E00000E00 +000E00000E00000E00000E00001C00001E0000FFE00011147E9312>I<01F2060E080618061802 +380438001E001FE00FF003F8003C401C400C400C600C6018E010D0608FC00F147E9312>I<0080 +010001000100030007000F001E00FFF80E000E000E000E001C001C001C001C001C001C00380038 +203820382038203840384018800F000D1C7C9B12>I<1C0380FC1F803C07801C03801C03803807 +00380700380700380700380700380700700E00700E00700E00700E00701E00701E00703C00305E +001F9FC012147B9319>II< +FF9FE1FC3E0780701C0300601C0300401C0380401C0380800E0780800E0581000E0981000E09C2 +000E11C2000731C4000721C4000760C8000740C8000780F0000780F0000300E000030060000200 +40001E147C9321>I<1FF0FF03C07801C06001C04000E08000E180007300007600003C00003C00 +001C00002E00004E000087000107000203800603800C01C03E03E0FF07FC18147F9318>I<0FF8 +3F8001E00E0001C00C0001C0080000E0180000E0100000E0200000E0200000F040000070400000 +708000007080000071000000390000003A0000003E0000003C0000003800000018000000100000 +0010000000200000002000000040000070C00000F0800000F1000000E20000007C000000191D80 +9318>I E /Fk 36 122 df<0001C0000003C000000FC000007FC0001FFFC000FFFFC000FFBFC0 +00E03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003F +C000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00000 +3FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000 +003FC000003FC000003FC000003FC000003FC000003FC000003FC0007FFFFFE07FFFFFE07FFFFF +E01B2E7AAD28>49 D<003FE00001FFFE0007FFFF800F80FFC01E003FE038001FF07C000FF87E00 +07FCFF0007FCFF8007FEFF8007FEFF8003FEFF8003FE7F0003FE3E0007FE000007FE000007FC00 +0007FC00000FF800000FF800000FF000001FE000001FC000003F8000007F0000007E000000F800 +0001F0000003E0000007C000000F0000001E000E003C000E0038000E0070001E00E0001C01C000 +1C0300003C07FFFFFC0FFFFFFC1FFFFFFC3FFFFFFC7FFFFFF8FFFFFFF8FFFFFFF8FFFFFFF81F2E +7CAD28>I<0000007800000000000078000000000000FC000000000000FC000000000000FC0000 +00000001FE000000000001FE000000000003FF000000000003FF000000000007FF800000000007 +FF800000000007FF80000000000FFFC0000000000E7FC0000000001E7FE0000000001C3FE00000 +00001C3FE000000000383FF000000000381FF000000000781FF800000000700FF800000000700F +F800000000E00FFC00000000E007FC00000001E007FE00000001C003FE00000001C003FE000000 +038003FF000000038001FF000000078001FF800000070000FF800000070000FF8000000FFFFFFF +C000000FFFFFFFC000001FFFFFFFE000001C00003FE000003C00003FF000003800001FF0000038 +00001FF000007000001FF800007000000FF80000F000000FFC0000E0000007FC0000E0000007FC +0001C0000007FE0003E0000003FE00FFFF8001FFFFFCFFFF8001FFFFFCFFFF8001FFFFFC36317D +B03D>65 DI<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 +003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 +000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F +E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 +0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 +803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 +0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 +001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 +3A>I70 +D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 +0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 +0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 +0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF +C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 +0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 +000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF +0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 +00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< +FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F +C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 +7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 +007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF +FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF +8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 +FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 +00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 +0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF +FFC03A317EB03F>II78 D80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F +C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 +0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 +0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 +0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F +F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 +00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 +00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 +000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF +000031307DAF38>84 DII<00FFF0000003FFFE00000F803F80000FC00FE0001F +E007F0001FE007F0001FE003F8000FC003FC00078003FC00000003FC00000003FC00000003FC00 +000003FC000000FFFC00001FFFFC0000FFE3FC0003FC03FC000FF003FC001FC003FC003FC003FC +007F8003FC007F8003FC00FF0003FC00FF0003FC00FF0003FC00FF0007FC00FF0007FC007F800D +FC003FC019FE001FE070FFF007FFE07FF000FF803FF024207E9F27>97 D<01F8000000FFF80000 +00FFF8000000FFF80000000FF800000007F800000007F800000007F800000007F800000007F800 +000007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8 +00000007F83FE00007F8FFFC0007FBE07F0007FF001F8007FE000FC007FC000FE007F80007F007 +F80007F807F80007F807F80003FC07F80003FC07F80003FC07F80003FE07F80003FE07F80003FE +07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FC07F80003FC07F80003 +FC07F80007F807F80007F807F80007F007FC000FE007FE000FC007E7003F8007C3C0FE000780FF +F80007003FC00027327EB12D>I<000FFF00007FFFC001FC01F003F003F007E007F80FE007F81F +C007F83FC003F03FC001E07F8000007F8000007F800000FF800000FF800000FF800000FF800000 +FF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC0001C3FC0001C1FC000 +380FE0003807E0007003F001E001FC07C0007FFF00000FF8001E207D9F24>I<0000000FC00000 +07FFC0000007FFC0000007FFC00000007FC00000003FC00000003FC00000003FC00000003FC000 +00003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0 +0000003FC00007F83FC0003FFF3FC000FE07BFC003F801FFC007E0007FC00FE0007FC01FC0003F +C03FC0003FC03FC0003FC07F80003FC07F80003FC07F80003FC0FF80003FC0FF80003FC0FF8000 +3FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC07F80003FC07F80003FC07F80 +003FC03FC0003FC03FC0003FC01FC0003FC00FE0007FC007E000FFC003F003FFE001FC0F3FFE00 +7FFE3FFE000FF03FFE27327DB12D>I<000FFC00007FFF8001FC0FC003F003E007E001F00FE001 +F81FC000FC3FC000FE3FC000FE7F80007E7F80007F7F80007FFF80007FFF80007FFFFFFFFFFFFF +FFFFFF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC000071FC000071F +C0000E0FE0000E07F0001C03F8007800FE03E0003FFFC00007FE0020207E9F25>I<0001FE0000 +0FFF80001FC3C0007F07E000FE0FF001FE0FF001FC0FF003FC0FF003FC07E003FC018003FC0000 +03FC000003FC000003FC000003FC000003FC000003FC000003FC0000FFFFFC00FFFFFC00FFFFFC +0003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC +000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003 +FC000003FC000003FC000003FC000003FC000003FC000003FC00007FFFF0007FFFF0007FFFF000 +1C327EB119>I<001FF007C000FFFE3FE001F83F79F007E00FC3F00FE00FE1F00FC007E0E01FC0 +07F0001FC007F0003FC007F8003FC007F8003FC007F8003FC007F8003FC007F8001FC007F0001F +C007F0000FC007E0000FE00FE00007E00FC00003F83F000006FFFE00000E1FF000000E00000000 +1E000000001E000000001F000000001F800000001FFFFF80000FFFFFF0000FFFFFFC0007FFFFFE +0003FFFFFF0003FFFFFF800FFFFFFFC01F00007FC07E00001FE07C00000FE0FC000007E0FC0000 +07E0FC000007E0FC000007E07E00000FC03E00000F803F00001F800FC0007E0007F803FC0001FF +FFF000001FFF0000242F7E9F28>I<01F8000000FFF8000000FFF8000000FFF80000000FF80000 +0007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F800 +000007F800000007F800000007F800000007F800000007F800000007F807F80007F83FFE0007F8 +783F0007F8C03F8007F9801FC007FB001FC007FE001FE007FC001FE007FC001FE007FC001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 +07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F +E007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF28327DB12D>I<03 +C00007E0000FF0001FF8001FF8001FF8001FF8000FF00007E00003C00000000000000000000000 +000000000000000000000000000000000001F800FFF800FFF800FFF8000FF80007F80007F80007 +F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007 +F80007F80007F80007F80007F80007F80007F80007F80007F800FFFF80FFFF80FFFF8011337DB2 +17>I<01F800FFF800FFF800FFF8000FF80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 +07F80007F80007F80007F80007F80007F80007F80007F80007F800FFFFC0FFFFC0FFFFC012327D +B117>108 D<03F007F8001FE000FFF03FFE00FFF800FFF0783F01E0FC00FFF0C03F8300FE000F +F1801FC6007F0007F3001FCC007F0007F6001FF8007F8007FC001FF0007F8007FC001FF0007F80 +07FC001FF0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F +8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE000 +7F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0 +007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001F +E0007F80FFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFC3E207D9F43>I<03F007F8 +00FFF03FFE00FFF0783F00FFF0C03F800FF1801FC007F3001FC007F6001FE007FC001FE007FC00 +1FE007FC001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8 +001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF +28207D9F2D>I<0007FC0000007FFFC00001FC07F00003F001F80007E000FC000FC0007E001FC0 +007F003FC0007F803F80003F807F80003FC07F80003FC07F80003FC0FF80003FE0FF80003FE0FF +80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE07F80003FC07F80003FC0 +7F80003FC03FC0007F803FC0007F801FC0007F000FE000FE0007E000FC0003F803F80001FE0FF0 +00007FFFC0000007FC000023207E9F28>I<01F83FE000FFF8FFFC00FFFBE07F00FFFF003F8007 +FE001FC007FC000FE007F8000FF007F80007F807F80007F807F80007FC07F80003FC07F80003FC +07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003 +FE07F80003FC07F80007FC07F80007FC07F80007F807F80007F807F8000FF007FC000FE007FE00 +1FC007FF003F8007FBC0FE0007F8FFF80007F83FC00007F800000007F800000007F800000007F8 +00000007F800000007F800000007F800000007F800000007F800000007F800000007F8000000FF +FFC00000FFFFC00000FFFFC00000272E7E9F2D>I<03F03F00FFF07FC0FFF1C3E0FFF187E00FF3 +0FF007F60FF007F60FF007FC07E007FC03C007FC000007FC000007F8000007F8000007F8000007 +F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F80000 +07F8000007F8000007F8000007F8000007F80000FFFFE000FFFFE000FFFFE0001C207E9F21> +114 D<01FF860007FFFE001F00FE003C003E0078001E0078000E00F8000E00F8000E00F8000E00 +FC000000FF800000FFFC00007FFFC0007FFFF0003FFFF8001FFFFC0007FFFE0001FFFF00003FFF +000000FF8000003F8060001F80E0000F80E0000F80F0000F80F0000F00F8000F00FC001E00FE00 +1C00FF807800F3FFF000C07F800019207D9F20>I<001C0000001C0000001C0000001C0000001C +0000003C0000003C0000003C0000007C0000007C000000FC000001FC000003FC000007FC00001F +FFFE00FFFFFE00FFFFFE0003FC000003FC000003FC000003FC000003FC000003FC000003FC0000 +03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC03 +8003FC038003FC038003FC038003FC038003FC038003FC038001FC038001FC070000FE0700007F +0E00003FFC000007F000192E7FAD1F>I<01F80007E0FFF803FFE0FFF803FFE0FFF803FFE00FF8 +003FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 +F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 +07F8001FE007F8001FE007F8001FE007F8001FE007F8003FE007F8003FE003F8007FE003F8007F +E001FC00DFF000FE039FFF007FFF1FFF000FFC1FFF28207D9F2D>II< +FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE +00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 +FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 +7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F +FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 +000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 +7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F +E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 +00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 +003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF +FF28207F9F2B>II E /Fl 1 14 df<0001FE00000007FF8000001E01E000007800780000 +E0001C000180000600030000030006000001800C000000C00C000000C018000000603000000030 +30000000303000000030600000001860000000186000000018C00000000CC00000000CC0000000 +0CC00000000CC00000000CC00000000CC00000000CC00000000CC00000000C6000000018600000 +0018600000001830000000303000000030300000003018000000600C000000C00C000000C00600 +0001800300000300018000060000E0001C000078007800001E01E0000007FF80000001FE000026 +2B7DA02D>13 D E /Fm 46 122 df<3C007F00FF80FF80FFC0FFC0FFC07FC03EC000C000C00180 +018001800300030006000E001C00380030000A157B8813>44 D<1C007F007F00FF80FF80FF807F +007F001C0009097B8813>46 D<000E00001E00007E0007FE00FFFE00FFFE00F8FE0000FE0000FE +0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE +0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE +0000FE007FFFFE7FFFFE7FFFFE17277BA622>49 D<00FF800007FFF0000FFFFC001E03FE003800 +FF807C003F80FE003FC0FF001FC0FF001FE0FF000FE0FF000FE07E000FE03C001FE000001FE000 +001FC000001FC000003F8000003F0000007E000000FC000000F8000001F0000003E00000078000 +000F0000001E0000003C00E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFF +C03FFFFFC07FFFFFC0FFFFFF80FFFFFF80FFFFFF801B277DA622>I<007F800003FFF00007FFFC +000F80FE001F007F003F807F003F803F803F803F803F803F801F803F801F003F8000007F000000 +7F0000007E000000FC000001F8000007F00000FFC00000FFC0000001F80000007E0000003F0000 +003F8000001FC000001FC000001FE000001FE03C001FE07E001FE0FF001FE0FF001FE0FF001FC0 +FF003FC0FE003F807C007F003F00FE001FFFFC0007FFF00000FF80001B277DA622>I<00000E00 +00001E0000003E0000007E000000FE000000FE000001FE000003FE0000077E00000E7E00000E7E +00001C7E0000387E0000707E0000E07E0000E07E0001C07E0003807E0007007E000E007E000E00 +7E001C007E0038007E0070007E00E0007E00FFFFFFF8FFFFFFF8FFFFFFF80000FE000000FE0000 +00FE000000FE000000FE000000FE000000FE000000FE00007FFFF8007FFFF8007FFFF81D277EA6 +22>I<180003001F801F001FFFFE001FFFFC001FFFF8001FFFF0001FFFC0001FFF00001C000000 +1C0000001C0000001C0000001C0000001C0000001C0000001C7FC0001DFFF8001F80FC001E003F +0008003F0000001F8000001FC000001FC000001FE000001FE018001FE07C001FE0FE001FE0FE00 +1FE0FE001FE0FE001FC0FC001FC078003F8078003F803C007F001F01FE000FFFFC0003FFF00000 +FF80001B277DA622>I<380000003E0000003FFFFFF03FFFFFF03FFFFFF07FFFFFE07FFFFFC07F +FFFF807FFFFF0070000E0070000E0070001C00E0003800E0007000E000E0000001E0000001C000 +000380000007800000070000000F0000001F0000001E0000003E0000003E0000007E0000007C00 +00007C000000FC000000FC000000FC000000FC000001FC000001FC000001FC000001FC000001FC +000001FC000001FC000000F80000007000001C297CA822>55 D<00000780000000000780000000 +000FC0000000000FC0000000000FC0000000001FE0000000001FE0000000003FF0000000003FF0 +000000003FF00000000077F80000000077F800000000F7FC00000000E3FC00000000E3FC000000 +01C1FE00000001C1FE00000003C1FF0000000380FF0000000380FF00000007007F80000007007F +8000000F007FC000000E003FC000000E003FC000001C001FE000001C001FE000003FFFFFF00000 +3FFFFFF000003FFFFFF00000700007F80000700007F80000F00007FC0000E00003FC0000E00003 +FC0001C00001FE0001C00001FE0003C00001FF00FFFE003FFFFCFFFE003FFFFCFFFE003FFFFC2E +297EA833>65 DI<00007FE0030007FFFC07001FFFFF0F +007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 +0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 +0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 +0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 +F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 +>I69 DI<0000 +7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F +0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 +000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 +00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 +00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF +0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 +FFFE0F0000007FF003002D297CA835>III77 +DI80 +D82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 +3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF +C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 +00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 +E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I85 DII<03FF80000FFFF0001F01FC003F80FE003F +807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 +0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF +803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D +I<003FF00001FFFC0003F03E000FC07F001F807F003F007F003F007F007F003E007E0000007E00 +0000FE000000FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000007F +0000003F0003803F8003801F8007000FE00E0003F83C0001FFF800003FC000191B7E9A1E>I<00 +007FF000007FF000007FF0000007F0000007F0000007F0000007F0000007F0000007F0000007F0 +000007F0000007F0000007F0000007F0000007F0003F87F001FFF7F007F03FF00FC00FF01F8007 +F03F0007F03F0007F07E0007F07E0007F07E0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE00 +07F0FE0007F0FE0007F0FE0007F07E0007F07E0007F03F0007F03F0007F01F800FF00FC01FF007 +E07FFF01FFE7FF007F87FF202A7EA925>I<003FC00001FFF00003E07C000F803E001F801F001F +001F003F000F807E000F807E000FC07E000FC0FE0007C0FE0007C0FFFFFFC0FFFFFFC0FE000000 +FE000000FE0000007E0000007E0000007F0000003F0001C01F0001C00F80038007C0070003F01E +0000FFFC00003FE0001A1B7E9A1F>I<0007F8003FFC007E3E01FC7F03F87F03F07F07F07F07F0 +3E07F00007F00007F00007F00007F00007F00007F000FFFFC0FFFFC0FFFFC007F00007F00007F0 +0007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F00007F00007F00007F0007FFF807FFF807FFF80182A7EA915>I<007F80F001FFE3 +F807C0FE1C0F807C7C1F003E7C1F003E103F003F003F003F003F003F003F003F003F003F003F00 +3F001F003E001F003E000F807C0007C0F80005FFE0000C7F8000180000001C0000001C0000001E +0000001FFFF8001FFFFF000FFFFFC007FFFFE003FFFFF00FFFFFF03E0007F07C0001F8F80000F8 +F80000F8F80000F8F80000F87C0001F07C0001F03F0007E00FC01F8007FFFF00007FF0001E287E +9A22>II<07000F801FC03FE03FE03FE01FC00F80 +07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F +E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I108 DII<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 +07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE +0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 +003FE0001D1B7E9A22>II114 D<03FE300FFFF03E03F0 +7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 +0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> +I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF +E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 +0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 +7FA51A>II +IIII E /Fn 75 127 df<70F8F8F8F8F8F8F8F8F8F8F8 +F8F8F8F8F870000000000070F8F8F870051C779B18>33 D<4010E038F078E038E038E038E038E0 +38E038E038E038E038E03860300D0E7B9C18>I<030600078F00078F00078F00078F00078F0007 +8F007FFFC0FFFFE0FFFFE07FFFC00F1E000F1E000F1E000F1E000F1E000F1E007FFFC0FFFFE0FF +FFE07FFFC01E3C001E3C001E3C001E3C001E3C001E3C000C1800131C7E9B18>I<00C00001C000 +01C00001C00003F0000FFC003FFE007DCF0071C700E1C380E1C780E1C780E1C780F1C00079C000 +3DC0001FE0000FF80003FC0001DE0001CF0001C70061C380F1C380F1C380E1C380E1C70071C700 +79DE003FFE001FF80007E00001C00001C00001C00000C00011247D9F18>I<3803007C07807C07 +80EE0F80EE0F00EE0F00EE1F00EE1E00EE1E00EE3E007C3C007C3C00387C0000780000780000F8 +0000F00001F00001E00001E00003E00003C00003C00007C0000783800787C00F87C00F0EE00F0E +E01F0EE01E0EE01E0EE03E0EE03C07C03C07C018038013247E9F18>I<01C00007E0000FF0000E +70001C38001C38001C38001C38001C73F01C73F01CE3F00FE3800FC7000F87000F07001F0E003F +0E007B8E0073DC00E1DC00E0F800E0F800E07070E0787070FC707FFFE03FCFE00F03C0141C7F9B +18>I<387C7C7E3E0E0E0E1C1C38F8F0C0070E789B18>I<007000F001E003C007800F001E001C00 +380038007000700070007000E000E000E000E000E000E000E000E0007000700070007000380038 +001C001E000F00078003C001F000F000700C24799F18>I<6000F00078003C001E000F00078003 +8001C001C000E000E000E000E00070007000700070007000700070007000E000E000E000E001C0 +01C0038007800F001E003C007800F00060000C247C9F18>I<01C00001C00001C00001C000C1C1 +80F1C780F9CF807FFF001FFC0007F00007F0001FFC007FFF00F9CF80F1C780C1C18001C00001C0 +0001C00001C00011147D9718>I<00600000F00000F00000F00000F00000F00000F00000F0007F +FFC0FFFFE0FFFFE07FFFC000F00000F00000F00000F00000F00000F00000F00000600013147E97 +18>I<1C3E7E7F3F1F070E1E7CF860080C788518>I<7FFF00FFFF80FFFF807FFF0011047D8F18> +I<3078FCFC78300606778518>I<000300000780000780000F80000F00001F00001E00001E0000 +3E00003C00007C0000780000780000F80000F00001F00001E00003E00003C00003C00007C00007 +80000F80000F00000F00001F00001E00003E00003C00003C00007C0000780000F80000F00000F0 +000060000011247D9F18>I<01F00007FC000FFE001F1F001C07003803807803C07001C07001C0 +E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07001C07803C0 +3803801C07001F1F000FFE0007FC0001F000131C7E9B18>I<01800380038007800F803F80FF80 +FB80438003800380038003800380038003800380038003800380038003800380038003807FFCFF +FE7FFC0F1C7B9B18>I<03F0000FFE003FFF007C0F807003C0E001C0F000E0F000E06000E00000 +E00000E00001C00001C00003C0000780000F00001E00003C0000780000F00001E00007C0000F80 +001E00E03C00E07FFFE0FFFFE07FFFE0131C7E9B18>I<001F00003F0000770000770000E70001 +E70001C7000387000787000707000E07001E07003C0700380700780700F00700FFFFF8FFFFF8FF +FFF8000700000700000700000700000700000700007FF000FFF8007FF0151C7F9B18>52 +D<007E0001FF0007FF800F83C01E03C01C03C0380180380000700000700000E1F800E7FE00FFFF +00FE0780F803C0F001C0F000E0E000E0F000E07000E07000E07000E03801C03C03C01E07800FFF +0007FE0001F800131C7E9B18>54 D<3078FCFC783000000000000000003078FCFC783006147793 +18>58 D<183C7E7E3C180000000000000000183C7E7E3E1E0E1C3C78F060071A789318>I<0003 +00000780001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000FC00007E00 +003F00001FC00007E00003F00001FC00007E00003F00001F8000078000030011187D9918>I<7F +FFC0FFFFE0FFFFE0FFFFE0000000000000000000000000FFFFE0FFFFE0FFFFE07FFFC0130C7E93 +18>I<600000F00000FC00007E00003F00001FC00007E00003F00001FC00007E00003F00001F80 +001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000F0000060000011187D +9918>I<0FF0003FFC007FFF00700F00F00380F00380600780000F00003E00007C0001F00001E0 +0003C00003C00003C00003C00003C00003800000000000000000000000000000000003800007C0 +0007C00007C000038000111C7D9B18>I<00700000F80000F80000D80000D80001DC0001DC0001 +DC00018C00038E00038E00038E00038E000306000707000707000707000707000FFF800FFF800F +FF800E03800E03801C01C01C01C07F07F0FF8FF87F07F0151C7F9B18>65 +D<7FF800FFFE007FFF001C0F801C03C01C03C01C01E01C00E01C00E01C00F01C00701C00701C00 +701C00701C00701C00701C00701C00701C00F01C00E01C00E01C01E01C01C01C03C01C0F807FFF +00FFFE007FF800141C7F9B18>68 DII<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F +FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F +07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 +0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 +0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E +00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B +18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 +C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D +C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 +E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 +E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>II<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C +0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C +039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 +80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 +E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF +FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 +700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 +1C7F9B18>II89 +D91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 +0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 +007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> +II<018007C01FF07EFCF83EE00E0F067C9B18>I<7FFF00FFFF80FFFF807FFF0011047D7F18>I< +061E3E387070E0E0E0F8FC7C7C38070E789E18>I<1FE0003FF8007FFC00781E00300E00000700 +00070000FF0007FF001FFF007F0700780700E00700E00700E00700F00F00781F003FFFF01FFBF0 +07E1F014147D9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF +800FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E00380F00700F00 +700F80E00FC1E00FFFC00EFF80063E00151C809B18>I<01FE0007FF001FFF803E078038030070 +0000700000E00000E00000E00000E00000E00000E000007000007001C03801C03E03C01FFF8007 +FF0001FC0012147D9318>I<001F80003F80001F8000038000038000038000038000038003E380 +0FFB801FFF803C1F80380F80700780700380E00380E00380E00380E00380E00380E00380700780 +700780380F803C1F801FFFF00FFBF803E3F0151C7E9B18>I<01F00007FC001FFE003E0F003807 +80700380700380E001C0E001C0FFFFC0FFFFC0FFFFC0E000007000007001C03801C03E03C01FFF +8007FF0001FC0012147D9318>I<001F80007FC000FFE000E1E001C0C001C00001C00001C0007F +FFC0FFFFC0FFFFC001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001 +C00001C00001C00001C0007FFF007FFF007FFF00131C7F9B18>I<01E1F007FFF80FFFF81E1E30 +1C0E003807003807003807003807003807001C0E001E1E001FFC001FF80039E0003800001C0000 +1FFE001FFFC03FFFE07801F0700070E00038E00038E00038E000387800F07E03F01FFFC00FFF80 +01FC00151F7F9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF +800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 +E00E00E00E00E07FC3FCFFE7FE7FC3FC171C809B18>I<03800007C00007C00007C00003800000 +00000000000000000000007FC000FFC0007FC00001C00001C00001C00001C00001C00001C00001 +C00001C00001C00001C00001C00001C00001C00001C000FFFF00FFFF80FFFF00111D7C9C18>I< +7FE000FFE0007FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0007FFFC0 +FFFFE07FFFC0131C7E9B18>108 D<7CE0E000FFFBF8007FFFF8001F1F1C001E1E1C001E1E1C00 +1C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C +001C1C1C007F1F1F00FFBFBF807F1F1F001914819318>I<7E3E00FEFF807FFFC00FC1C00F80E0 +0F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E07FC3FC +FFE7FE7FC3FC1714809318>I<01F0000FFE001FFF003E0F803803807001C07001C0E000E0E000 +E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE0001F00013147E9318 +>I<7E3E00FEFF807FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E +00380F00700F00700F80E00FC1E00FFFC00EFF800E3E000E00000E00000E00000E00000E00000E +00000E00007FC000FFE0007FC000151E809318>I<01E38007FB801FFF803E1F80380F80700780 +700780E00380E00380E00380E00380E00380E00380700780700780380F803C1F801FFF800FFB80 +03E380000380000380000380000380000380000380000380003FF8003FF8003FF8151E7E9318> +I<7F87E0FF9FF07FBFF803F87803F03003E00003C00003C0000380000380000380000380000380 +000380000380000380000380007FFE00FFFF007FFE0015147F9318>I<07F7003FFF007FFF0078 +0F00E00700E00700E007007C00007FE0001FFC0003FE00001F00600780E00380E00380F00380F8 +0F00FFFF00FFFC00E7F00011147D9318>I<0180000380000380000380000380007FFFC0FFFFC0 +FFFFC00380000380000380000380000380000380000380000380000380000380400380E00380E0 +0380E001C1C001FFC000FF80003E0013197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E00 +E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E01E00F03E007FFFC03FF +FE01FCFC1714809318>I<7F8FF0FF8FF87F8FF01E03C00E03800E03800E038007070007070007 +0700038E00038E00038E00038E0001DC0001DC0001DC0000F80000F80000700015147F9318>I< +FF8FF8FF8FF8FF8FF83800E03800E03800E01C01C01C01C01C71C01CF9C01CF9C01CD9C01CD9C0 +0DDD800DDD800DDD800D8D800F8F800F8F8007070015147F9318>I<7F8FF07F9FF07F8FF00707 +00078E00039E0001DC0001F80000F80000700000F00000F80001DC00039E00038E000707000F07 +807F8FF0FF8FF87F8FF015147F9318>I<7F8FF0FF8FF87F8FF00E01C00E03800E038007038007 +0700070700038700038600038E0001CE0001CE0000CC0000CC0000DC0000780000780000780000 +700000700000700000F00000E00079E0007BC0007F80003F00001E0000151E7F9318>I<3FFFF0 +7FFFF07FFFF07001E07003C0700780000F00001E00003C0000F80001F00003C0000780000F0070 +1E00703C0070780070FFFFF0FFFFF0FFFFF014147F9318>I<0007E0001FE0007FE000780000E0 +0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00001E0007FC000FF80 +00FF80007FC00001E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0 +0000E000007800007FE0001FE00007E013247E9F18>I<60F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 +F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0600424769F18>I<7C0000FF0000FFC00003C000 +00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000F000007FC0 +003FE0003FE0007FC000F00000E00000E00000E00000E00000E00000E00000E00000E00000E000 +00E00000E00003C000FFC000FF00007C000013247E9F18>I<060C1F1E3FBEFBF8F1F060C00F06 +7C9B18>I E /Fo 75 123 df<001F83E000F06E3001C078780380F8780300F030070070000700 +70000700700007007000070070000700700007007000FFFFFF8007007000070070000700700007 +007000070070000700700007007000070070000700700007007000070070000700700007007000 +07007000070070000700700007007000070070007FE3FF001D20809F1B>11 +D<003F0000E0C001C0C00381E00701E00701E0070000070000070000070000070000070000FFFF +E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700 +E00700E00700E00700E00700E00700E07FC3FE1720809F19>I<003FE000E0E001C1E00381E007 +00E00700E00700E00700E00700E00700E00700E00700E0FFFFE00700E00700E00700E00700E007 +00E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E007 +00E07FE7FE1720809F19>I<001F81F80000F04F040001C07C06000380F80F000300F00F000700 +F00F00070070000007007000000700700000070070000007007000000700700000FFFFFFFF0007 +007007000700700700070070070007007007000700700700070070070007007007000700700700 +070070070007007007000700700700070070070007007007000700700700070070070007007007 +00070070070007007007007FE3FE3FF02420809F26>I<7038F87CFC7EFC7E743A040204020402 +0804080410081008201040200F0E7E9F17>34 D<70F8FCFC74040404080810102040060E7C9F0D +>39 D<0020004000800100020006000C000C00180018003000300030007000600060006000E000 +E000E000E000E000E000E000E000E000E000E000E0006000600060007000300030003000180018 +000C000C000600020001000080004000200B2E7DA112>I<800040002000100008000C00060006 +000300030001800180018001C000C000C000C000E000E000E000E000E000E000E000E000E000E0 +00E000E000C000C000C001C001800180018003000300060006000C00080010002000400080000B +2E7DA112>I<70F8FCFC74040404080810102040060E7C840D>44 DI<70 +F8F8F87005057C840D>I<03F0000E1C001C0E00180600380700700380700380700380700380F0 +03C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C070 +03807003807003807807803807001806001C0E000E1C0003F000121F7E9D17>48 +D<018003800F80F380038003800380038003800380038003800380038003800380038003800380 +03800380038003800380038003800380038007C0FFFE0F1E7C9D17>I<03F0000C1C00100E0020 +0700400780800780F007C0F803C0F803C0F803C02007C00007C0000780000780000F00000E0000 +1C0000380000700000600000C0000180000300000600400C00401800401000803FFF807FFF80FF +FF80121E7E9D17>I<03F0000C1C00100E00200F00780F80780780780780380F80000F80000F00 +000F00000E00001C0000380003F000003C00000E00000F000007800007800007C02007C0F807C0 +F807C0F807C0F00780400780400F00200E001C3C0003F000121F7E9D17>I<000600000600000E +00000E00001E00002E00002E00004E00008E00008E00010E00020E00020E00040E00080E00080E +00100E00200E00200E00400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E +0000FFE0141E7F9D17>I<1803001FFE001FFC001FF8001FE00010000010000010000010000010 +000010000011F000161C00180E001007001007800003800003800003C00003C00003C07003C0F0 +03C0F003C0E00380400380400700200600100E000C380003E000121F7E9D17>I<007C00018200 +0701000E03800C07801C0780380300380000780000700000700000F1F000F21C00F40600F80700 +F80380F80380F003C0F003C0F003C0F003C0F003C07003C07003C0700380380380380700180700 +0C0E00061C0001F000121F7E9D17>I<4000007FFFC07FFF807FFF804001008002008002008004 +0000080000080000100000200000200000400000400000C00000C00001C0000180000380000380 +00038000038000078000078000078000078000078000078000078000030000121F7D9D17>I<03 +F0000C0C001006003003002001806001806001806001807001807803003E03003F06001FC8000F +F00003F80007FC000C7E00103F00300F806003804001C0C001C0C000C0C000C0C000C0C0008060 +01802001001002000C0C0003F000121F7E9D17>I<03F0000E18001C0C00380600380700700700 +700380F00380F00380F003C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C0 +03E3C0000380000380000380000700300700780600780E00700C002018001070000FC000121F7E +9D17>I<70F8F8F8700000000000000000000070F8F8F87005147C930D>I<70F8F8F87000000000 +00000000000070F0F8F878080808101010202040051D7C930D>I<000100000003800000038000 +000380000007C0000007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F0 +0000207800002078000020780000403C0000403C0000403C0000801E0000801E0000FFFE000100 +0F0001000F0001000F00020007800200078002000780040003C00E0003C01F0007E0FFC03FFE1F +207F9F22>65 DI<000FC040007030C001C009C0038005C00700 +03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 +000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 +3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D +9F21>IIII<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 +3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 +00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 +01E0070001E0038002E000E0046000781820000FE0001E217D9F24>III<0FFFC0007C +00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C +00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 +0040780040700030E0000F800012207E9E17>I76 DII<001F800000F0F00001C0380007801E +000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 +01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C +0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 +1C217D9F23>II<001F800000F0F00001C0380007801E000F00 +0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 +0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 +3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 +10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>II<07E0800C1980100780300380600180600180E00180E00080 +E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 +0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D +9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 +10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F +0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 +0F0000001F800007FFFE001C1F7E9E21>IIII91 +D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>II<081020204040808080B8FCFC7C38060E7D9F0D>96 +D<1FE000303000781800781C00300E00000E00000E00000E0000FE00078E001E0E00380E00780E +00F00E10F00E10F00E10F01E10781E103867200F83C014147E9317>I<0E0000FE00000E00000E +00000E00000E00000E00000E00000E00000E00000E00000E00000E3E000EC3800F01C00F00E00E +00E00E00700E00700E00780E00780E00780E00780E00780E00780E00700E00700E00E00F00E00D +01C00CC300083E0015207F9F19>I<03F80E0C1C1E381E380C70007000F000F000F000F000F000 +F00070007000380138011C020E0C03F010147E9314>I<000380003F8000038000038000038000 +038000038000038000038000038000038000038003E380061B801C078038038038038070038070 +0380F00380F00380F00380F00380F00380F003807003807003803803803807801C07800E1B8003 +E3F815207E9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FFFF80 +F00000F00000F000007000007000003800801800800C010007060001F80011147F9314>I<007C +00C6018F038F07060700070007000700070007000700FFF0070007000700070007000700070007 +0007000700070007000700070007000700070007007FF01020809F0E>I<0000E003E3300E3C30 +1C1C30380E00780F00780F00780F00780F00780F00380E001C1C001E380033E000200000200000 +3000003000003FFE001FFF800FFFC03001E0600070C00030C00030C00030C000306000603000C0 +1C038003FC00141F7F9417>I<0E0000FE00000E00000E00000E00000E00000E00000E00000E00 +000E00000E00000E00000E3E000E43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01 +C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16207F9F19>I<1C +003E003E003E001C000000000000000000000000000E007E000E000E000E000E000E000E000E00 +0E000E000E000E000E000E000E000E000E000E00FFC00A1F809E0C>I<00E001F001F001F000E0 +000000000000000000000000007007F000F0007000700070007000700070007000700070007000 +7000700070007000700070007000700070007000706070F060F0C061803F000C28829E0E>I<0E +0000FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0FF00E +03C00E03000E02000E04000E08000E10000E30000E70000EF8000F38000E1C000E1E000E0E000E +07000E07800E03800E03C00E03E0FFCFF815207F9F18>I<0E00FE000E000E000E000E000E000E +000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E00 +0E000E000E000E00FFE00B20809F0C>I<0E1F01F000FE618618000E81C81C000F00F00E000F00 +F00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E +00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E00FFE7FE7FE0 +23147F9326>I<0E3E00FE43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01C00E01 +C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16147F9319>I<01F80007 +0E001C03803801C03801C07000E07000E0F000F0F000F0F000F0F000F0F000F0F000F07000E070 +00E03801C03801C01C0380070E0001F80014147F9317>I<0E3E00FEC3800F01C00F00E00E00E0 +0E00F00E00700E00780E00780E00780E00780E00780E00780E00700E00F00E00E00F01E00F01C0 +0EC3000E3E000E00000E00000E00000E00000E00000E00000E00000E0000FFE000151D7F9319> +I<03E0800619801C05803C0780380380780380700380F00380F00380F00380F00380F00380F003 +807003807803803803803807801C0B800E138003E3800003800003800003800003800003800003 +80000380000380003FF8151D7E9318>I<0E78FE8C0F1E0F1E0F0C0E000E000E000E000E000E00 +0E000E000E000E000E000E000E000E00FFE00F147F9312>I<1F9030704030C010C010C010E000 +78007F803FE00FF00070803880188018C018C018E030D0608F800D147E9312>I<020002000200 +060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E000E000E000E080E080E +080E080E080610031001E00D1C7F9B12>I<0E01C0FE1FC00E01C00E01C00E01C00E01C00E01C0 +0E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E03C00603C0030DC001F1FC +16147F9319>III<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 +7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>II<3FFF380E200E201C40384078407000E001E001C00380078007010E011E +011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF +FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F +C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 +FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 +00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 +C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F +F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 +0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 +0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F +F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 +0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF +C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 +FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 +0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F +C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 +DI76 D78 D85 D<003FFE00000001FFFFE0000007FFFFF800000FE0 +07FC00000FF001FE00001FF800FF00001FF8007F80001FF8007FC0001FF8003FC0000FF0003FE0 +0007E0003FE00003C0003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000 +FFFFE000001FFFFFE000007FF83FE00003FF803FE00007FC003FE0000FF0003FE0001FE0003FE0 +003FE0003FE0007FC0003FE0007FC0003FE000FF80003FE000FF80003FE000FF80003FE000FF80 +003FE000FF80007FE0007FC0007FE0007FC000DFE0003FE0039FF0001FF80F0FFFE007FFFE0FFF +E001FFF807FFE0003FE000FFE02B267DA52F>97 D<00FE00000000FFFE00000000FFFE00000000 +FFFE00000000FFFE0000000007FE0000000003FE0000000003FE0000000003FE0000000003FE00 +00000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE00000000 +03FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE01 +FF000003FE1FFFF00003FE7FFFFC0003FEFC03FE0003FFF000FF0003FFC0003F8003FF00001FC0 +03FE00001FE003FE00000FF003FE00000FF803FE00000FF803FE000007FC03FE000007FC03FE00 +0007FC03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE +03FE000007FE03FE000007FE03FE000007FE03FE000007FC03FE000007FC03FE000007FC03FE00 +000FFC03FE00000FF803FE00000FF003FE00001FF003FF00001FE003FF80003FC003FFC0007F80 +03F9E000FF0003F0FC07FE0003F07FFFF80003E01FFFE00003C003FE00002F3C7DBB36>I<01E0 +0007F8000FFC000FFC001FFE001FFE001FFE001FFE000FFC000FFC0007F80001E0000000000000 +0000000000000000000000000000000000000000000000000000000000FE00FFFE00FFFE00FFFE +00FFFE0007FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE +0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE +0003FE0003FE0003FE0003FE00FFFFF0FFFFF0FFFFF0FFFFF0143D7DBC1A>105 +D<0001FFC00000000FFFF80000007FFFFF000000FF80FF800003FE003FE00007F8000FF0000FF0 +0007F8000FF00007F8001FE00003FC003FE00003FE003FE00003FE007FC00001FF007FC00001FF +007FC00001FF007FC00001FF00FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC0 +0001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF807FC00001FF007FC00001FF +007FC00001FF003FE00003FE003FE00003FE001FE00003FC001FF00007FC000FF00007F80007F8 +000FF00003FE003FE00000FF80FF8000007FFFFF0000000FFFF800000001FFC0000029267DA530 +>111 D<01FC03F000FFFC0FFC00FFFC1FFF00FFFC3C3F80FFFC707F8007FCE0FFC003FCC0FFC0 +03FD80FFC003FD80FFC003FF807F8003FF003F0003FF001E0003FF00000003FE00000003FE0000 +0003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00 +000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE +00000003FE00000003FE00000003FE000000FFFFFC0000FFFFFC0000FFFFFC0000FFFFFC000022 +267DA528>114 D<003FF07003FFFEF007FFFFF01FC01FF03F0003F03E0001F07C0001F07C0000 +F0FC0000F0FC0000F0FE0000F0FF000000FFC00000FFFC00007FFFF0003FFFFE003FFFFF801FFF +FFC00FFFFFE003FFFFF000FFFFF8001FFFFC00007FFC000007FE700001FEF00000FEF000007EF8 +00007EF800007EFC00007EFC00007CFE0000FCFF0000F8FF8001F0FFF00FE0F9FFFFC0F07FFF00 +C01FF8001F267DA526>I<000F0000000F0000000F0000000F0000000F0000001F0000001F0000 +001F0000001F0000003F0000003F0000007F0000007F000000FF000001FF000003FF000007FF00 +001FFFFFF0FFFFFFF0FFFFFFF0FFFFFFF001FF000001FF000001FF000001FF000001FF000001FF +000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001 +FF000001FF000001FF000001FF000001FF003C01FF003C01FF003C01FF003C01FF003C01FF003C +01FF003C01FF003C00FF007800FF8078007F80F0003FC1E0001FFFC0000FFF800001FE001E377E +B626>I121 +D E end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 300dpi +TeXDict begin + +%%EndSetup +%%Page: 1 1 +0 bop 0 1152 a Fp(GNU)33 b(History)f(Library)p 0 1201 1950 +17 v 1035 1250 a Fo(Edition)16 b(2.0,)e(for)h Fn(History)f(Library)g +Fo(V)l(ersion)i(2.0.)1759 1304 y(July)g(1994)0 2443 y Fm(Brian)23 +b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 +b(oundation)0 2509 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 +b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2545 1950 9 +v eop +%%Page: 2 2 +1 bop 0 295 a Fo(This)16 b(do)q(cumen)o(t)g(describ)q(es)h(the)f(GNU)f +(History)g(library)l(,)h(a)g(programming)e(to)q(ol)i(that)f(pro)o(vides)h(a)f +(consisten)o(t)0 358 y(user)g(in)o(terface)h(for)e(recalling)j(lines)g(of)e +(previously)h(t)o(yp)q(ed)g(input.)0 495 y(Published)h(b)o(y)f(the)f(F)l(ree) +g(Soft)o(w)o(are)f(F)l(oundation)0 557 y(675)g(Massac)o(h)o(usetts)g(Av)o(en) +o(ue,)0 619 y(Cam)o(bridge,)h(MA)g(02139)f(USA)0 756 y(P)o(ermission)f(is)g +(gran)o(ted)f(to)f(mak)o(e)h(and)h(distribute)h(v)o(erbatim)e(copies)h(of)f +(this)h(man)o(ual)g(pro)o(vided)g(the)f(cop)o(yrigh)o(t)0 818 +y(notice)k(and)f(this)h(p)q(ermission)h(notice)e(are)g(preserv)o(ed)h(on)f +(all)h(copies.)0 955 y(P)o(ermission)f(is)f(gran)o(ted)f(to)h(cop)o(y)g(and)g +(distribute)h(mo)q(di\014ed)h(v)o(ersions)e(of)f(this)i(man)o(ual)f(under)h +(the)f(conditions)0 1018 y(for)e(v)o(erbatim)g(cop)o(ying,)h(pro)o(vided)h +(that)d(the)i(en)o(tire)g(resulting)h(deriv)o(ed)f(w)o(ork)f(is)h +(distributed)h(under)f(the)g(terms)0 1080 y(of)i(a)g(p)q(ermission)h(notice)g +(iden)o(tical)h(to)e(this)g(one.)0 1217 y(P)o(ermission)20 +b(is)g(gran)o(ted)f(to)g(cop)o(y)h(and)f(distribute)i(translations)f(of)f +(this)h(man)o(ual)f(in)o(to)h(another)f(language,)0 1279 y(under)c(the)f(ab)q +(o)o(v)o(e)g(conditions)h(for)e(mo)q(di\014ed)j(v)o(ersions,)e(except)g(that) +g(this)g(p)q(ermission)i(notice)e(ma)o(y)g(b)q(e)h(stated)0 +1341 y(in)h(a)f(translation)g(appro)o(v)o(ed)g(b)o(y)g(the)g(F)l(oundation.)0 +2636 y(Cop)o(yrigh)o(t)226 2635 y(c)214 2636 y Fl(\015)g Fo(1989,)f(1991)g(F) +l(ree)h(Soft)o(w)o(are)f(F)l(oundation,)h(Inc.)p eop +%%Page: 1 3 +2 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 +b(1)0 158 y Fk(1)41 b(Using)14 b(History)h(In)n(teractiv)n(ely)62 +330 y Fo(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g(the)g(GNU)g +(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g(user's)h(stand-)0 +392 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f(considered)i(a)d(user's)h +(guide.)23 b(F)l(or)15 b(information)h(on)g(using)h(the)f(GNU)g(History)f +(Library)0 454 y(in)h(y)o(our)f(o)o(wn)f(programs,)g(see)i(Chapter)e(2)h +([Programming)f(with)i(GNU)f(History],)f(page)h(5.)0 663 y +Fm(1.1)33 b(History)15 b(In)n(teraction)62 800 y Fo(The)j(History)g(library)g +(pro)o(vides)h(a)e(history)h(expansion)h(feature)e(that)g(is)i(similar)g(to)e +(the)h(history)f(expan-)0 862 y(sion)k(pro)o(vided)h(b)o(y)f +Fn(csh)p Fo(.)36 b(The)22 b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o +(tax)f(used)i(to)e(manipulate)i(the)f(history)0 924 y(information.)62 +1061 y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.)18 +b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e(the)g +(previous)0 1124 y(history)h(should)h(b)q(e)f(used)h(during)f(substitution.) +20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g(of)g(that)f(line)i +(for)f(inclusion)0 1186 y(in)o(to)f(the)h(curren)o(t)f(one.)18 +b(The)12 b(line)h(selected)f(from)f(the)g(previous)h(history)g(is)f(called)i +(the)e Fj(ev)o(en)o(t)p Fo(,)h(and)f(the)h(p)q(ortions)0 1248 +y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h(are)g(called)h +Fj(w)o(ords)p Fo(.)j(The)c(line)h(is)f(brok)o(en)f(in)o(to)h(w)o(ords)f(in)h +(the)f(same)h(fashion)0 1310 y(that)j(Bash)h(do)q(es,)h(so)e(that)g(sev)o +(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f(surrounded)i(b)o(y)f(quotes)f +(are)h(considered)h(as)0 1373 y(one)c(w)o(ord.)0 1565 y Fi(1.1.1)30 +b(Ev)n(en)n(t)16 b(Designators)62 1702 y Fo(An)g(ev)o(en)o(t)f(designator)g +(is)g(a)g(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g +(history)f(list.)0 1847 y Fn(!)216 b Fo(Start)14 b(a)g(history)h +(substitution,)g(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f +(the)h(end)g(of)g(the)g(line,)240 1909 y Fn(=)g Fo(or)g Fn(\()p +Fo(.)0 1989 y Fn(!!)192 b Fo(Refer)16 b(to)e(the)i(previous)f(command.)20 +b(This)c(is)g(a)f(synon)o(ym)g(for)f Fn(!-1)p Fo(.)0 2068 y +Fn(!n)192 b Fo(Refer)16 b(to)e(command)h(line)i Fj(n)p Fo(.)0 +2148 y Fn(!-n)168 b Fo(Refer)16 b(to)e(the)i(command)f Fj(n)g +Fo(lines)i(bac)o(k.)0 2227 y Fn(!string)72 b Fo(Refer)16 b(to)e(the)i(most)e +(recen)o(t)h(command)g(starting)g(with)g Fj(string)p Fo(.)0 +2298 y Fn(!?string)p Fo([)p Fn(?)p Fo(])240 2360 y(Refer)h(to)e(the)i(most)e +(recen)o(t)h(command)g(con)o(taining)h Fj(string)p Fo(.)0 2440 +y Fn(!#)192 b Fo(The)15 b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e +(far.)0 2510 y Fn(^string1^string2^)240 2573 y Fo(Quic)o(k)j(Substitution.)22 +b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h Fj(string1)h +Fo(with)e Fj(string2)p Fo(.)21 b(Equiv-)240 2635 y(alen)o(t)15 +b(to)g Fn(!!:s/string1/string2/)p Fo(.)p eop +%%Page: 2 4 +3 bop 0 -83 a Fo(2)1497 b(GNU)15 b(History)g(Library)0 158 +y Fi(1.1.2)30 b(W)-5 b(ord)15 b(Designators)62 295 y Fo(A)i +Fn(:)g Fo(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j(from)d(the)g +(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted)g(if)g(the)g(w)o +(ord)0 358 y(designator)d(b)q(egins)h(with)f(a)f Fn(^)p Fo(,)h +Fn($)p Fo(,)f Fn(*)h Fo(or)f Fn(\045)p Fo(.)20 b(W)l(ords)13 +b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q(eginning)i(of)d(the)h(line,)i +(with)e(the)0 420 y(\014rst)h(w)o(ord)f(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f +(\(zero\).)0 569 y Fn(0)h(\(zero\))57 b Fo(The)15 b Fn(0)p +Fo(th)g(w)o(ord.)20 b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f +(command)g(w)o(ord.)0 656 y Fn(n)216 b Fo(The)15 b Fj(n)p Fo(th)h(w)o(ord.)0 +744 y Fn(^)216 b Fo(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o(ord)g +(1.)0 831 y Fn($)216 b Fo(The)15 b(last)h(argumen)o(t.)0 918 +y Fn(\045)216 b Fo(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g(most)g +(recen)o(t)g Fn(?string?)f Fo(searc)o(h.)0 1005 y Fn(x-y)168 +b Fo(A)15 b(range)g(of)g(w)o(ords;)f Fn(-)p Fj(y)19 b Fo(abbreviates)c +Fn(0-)p Fj(y)t Fo(.)0 1092 y Fn(*)216 b Fo(All)17 b(of)f(the)g(w)o(ords,)f +(except)i(the)f Fn(0)p Fo(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f +Fn(1-$)p Fo(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 +1155 y Fn(*)f Fo(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g(ev)o(en) +o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e(case.)0 +1242 y Fn(x*)192 b Fo(Abbreviates)16 b Fn(x-$)0 1329 y(x-)192 +b Fo(Abbreviates)16 b Fn(x-$)f Fo(lik)o(e)h Fn(x*)p Fo(,)e(but)i(omits)f(the) +g(last)g(w)o(ord.)0 1537 y Fi(1.1.3)30 b(Mo)r(di\014ers)62 +1674 y Fo(After)20 b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h +(add)g(a)g(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 +1736 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g Fn(:)p +Fo(.)0 1885 y Fn(h)216 b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(pathname)f(comp) +q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 1973 y Fn(r)216 +b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g(the)g(form)g(`)p +Fn(.)p Fo(')p Fj(su\016x)p Fo(,)f(lea)o(ving)i(the)f(basename.)0 +2060 y Fn(e)216 b Fo(Remo)o(v)o(e)15 b(all)h(but)g(the)f(trailing)h(su\016x.) +0 2147 y Fn(t)216 b Fo(Remo)o(v)o(e)15 b(all)h(leading)h(pathname)e(comp)q +(onen)o(ts,)g(lea)o(ving)h(the)f(tail.)0 2234 y Fn(p)216 b +Fo(Prin)o(t)15 b(the)g(new)h(command)f(but)g(do)g(not)g(execute)h(it.)0 +2309 y Fn(s/old/new/)240 2371 y Fo(Substitute)g Fj(new)k Fo(for)15 +b(the)h(\014rst)f(o)q(ccurrence)h(of)g Fj(old)h Fo(in)g(the)e(ev)o(en)o(t)h +(line.)22 b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2433 +y(used)e(in)f(place)h(of)f Fn(/)p Fo(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q +(e)i(quoted)f(in)h Fj(old)h Fo(and)e Fj(new)17 b Fo(with)12 +b(a)g(single)h(bac)o(kslash.)240 2496 y(If)g Fn(&)h Fo(app)q(ears)f(in)h +Fj(new)p Fo(,)f(it)h(is)g(replaced)g(b)o(y)f Fj(old)p Fo(.)20 +b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h Fn(&)p +Fo(.)19 b(The)13 b(\014nal)240 2558 y(delimiter)k(is)f(optional)g(if)f(it)h +(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 +2645 y Fn(&)216 b Fo(Rep)q(eat)16 b(the)f(previous)h(substitution.)p +eop +%%Page: 3 5 +4 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 +b(3)0 158 y Fn(g)216 b Fo(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o +(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 +b(in)g(conjunction)g(with)f Fn(s)p Fo(,)f(as)240 221 y(in)i +Fn(gs/old/new/)p Fo(,)d(or)i(with)h Fn(&)p Fo(.)p eop +%%Page: 4 6 +5 bop 0 -83 a Fo(4)1497 b(GNU)15 b(History)g(Library)p eop +%%Page: 5 7 +6 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(5)0 158 y Fk(2)41 b(Programming)16 b(with)f(GNU)h(History)62 +347 y Fo(This)e(c)o(hapter)f(describ)q(es)i(ho)o(w)d(to)h(in)o(terface)g +(programs)f(that)h(y)o(ou)g(write)g(with)g(the)h(GNU)f(History)g(Library)l(.) +0 409 y(It)j(should)g(b)q(e)g(considered)h(a)f(tec)o(hnical)h(guide.)22 +b(F)l(or)15 b(information)h(on)f(the)h(in)o(teractiv)o(e)g(use)g(of)f(GNU)g +(History)l(,)0 471 y(see)g(Chapter)g(1)g([Using)h(History)f(In)o(teractiv)o +(ely],)g(page)g(1.)0 698 y Fm(2.1)33 b(In)n(tro)r(duction)17 +b(to)e(History)62 835 y Fo(Man)o(y)j(programs)g(read)h(input)h(from)e(the)g +(user)h(a)g(line)h(at)f(a)f(time.)31 b(The)19 b(GNU)g(History)f(library)i(is) +f(able)0 897 y(to)e(k)o(eep)g(trac)o(k)f(of)h(those)g(lines,)i(asso)q(ciate)e +(arbitrary)g(data)g(with)g(eac)o(h)g(line,)j(and)d(utilize)i(information)f +(from)0 960 y(previous)e(lines)h(in)f(comp)q(osing)f(new)h(ones.)62 +1097 y(The)i(programmer)f(using)h(the)g(History)g(library)g(has)g(a)o(v)m +(ailable)h(functions)g(for)e(remem)o(b)q(ering)h(lines)i(on)d(a)0 +1159 y(history)f(list,)g(asso)q(ciating)g(arbitrary)g(data)f(with)h(a)f +(line,)j(remo)o(ving)d(lines)j(from)d(the)h(list,)g(searc)o(hing)g(through)0 +1221 y(the)h(list)h(for)e(a)h(line)h(con)o(taining)g(an)f(arbitrary)f(text)h +(string,)g(and)g(referencing)h(an)o(y)f(line)h(in)g(the)f(list)h(directly)l +(.)0 1284 y(In)d(addition,)h(a)e(history)h Fj(expansion)h Fo(function)g(is)f +(a)o(v)m(ailable)h(whic)o(h)g(pro)o(vides)f(for)f(a)h(consisten)o(t)g(user)g +(in)o(terface)0 1346 y(across)f(di\013eren)o(t)i(programs.)62 +1483 y(The)i(user)g(using)g(programs)f(written)g(with)h(the)g(History)f +(library)i(has)e(the)h(b)q(ene\014t)h(of)e(a)g(consisten)o(t)h(user)0 +1545 y(in)o(terface)d(with)g(a)f(set)h(of)f(w)o(ell-kno)o(wn)h(commands)g +(for)f(manipulating)i(the)f(text)f(of)g(previous)h(lines)h(and)f(using)0 +1608 y(that)g(text)g(in)i(new)e(commands.)22 b(The)15 b(basic)i(history)e +(manipulation)j(commands)d(are)g(similar)i(to)e(the)h(history)0 +1670 y(substitution)g(pro)o(vided)g(b)o(y)f Fn(csh)p Fo(.)62 +1807 y(If)g(the)g(programmer)e(desires,)i(he)g(can)g(use)g(the)f(Readline)j +(library)l(,)e(whic)o(h)h(includes)g(some)f(history)f(manip-)0 +1870 y(ulation)i(b)o(y)f(default,)h(and)f(has)g(the)g(added)h(adv)m(an)o +(tage)f(of)g(command)g(line)h(editing.)0 2096 y Fm(2.2)33 b(History)15 +b(Storage)62 2234 y Fo(The)h(history)f(list)h(is)g(an)f(arra)o(y)f(of)g +(history)i(en)o(tries.)k(A)15 b(history)g(en)o(try)g(is)h(declared)g(as)f +(follo)o(ws:)120 2358 y Fn(typedef)23 b(struct)g(_hist_entry)f({)168 +2408 y(char)h(*line;)168 2458 y(char)g(*data;)120 2508 y(})h(HIST_ENTRY;)62 +2645 y Fo(The)16 b(history)f(list)h(itself)g(migh)o(t)f(therefore)g(b)q(e)h +(declared)g(as)p eop +%%Page: 6 8 +7 bop 0 -83 a Fo(6)1497 b(GNU)15 b(History)g(Library)120 158 +y Fn(HIST_ENTRY)22 b(**the_history_list;)62 302 y Fo(The)16 +b(state)e(of)h(the)g(History)g(library)h(is)g(encapsulated)g(in)o(to)f(a)g +(single)i(structure:)120 434 y Fn(/*)24 b(A)f(structure)g(used)g(to)h(pass)f +(the)h(current)f(state)g(of)g(the)h(history)f(stuff)g(around.)g(*/)120 +484 y(typedef)g(struct)g(_hist_state)f({)168 534 y(HIST_ENTRY)g(**entries;) +214 b(/*)23 b(Pointer)g(to)h(the)f(entries)g(themselves.)f(*/)168 +584 y(int)h(offset;)453 b(/*)23 b(The)h(location)e(pointer)h(within)g(this)h +(array.)f(*/)168 633 y(int)g(length;)453 b(/*)23 b(Number)g(of)h(elements)f +(within)g(this)g(array.)g(*/)168 683 y(int)g(size;)501 b(/*)23 +b(Number)g(of)h(slots)f(allocated)g(to)g(this)h(array.)f(*/)168 +733 y(int)g(flags;)120 783 y(})h(HISTORY_STATE;)62 927 y Fo(If)16 +b(the)f(\015ags)g(mem)o(b)q(er)g(includes)j Fn(HS_STIFLED)p +Fo(,)13 b(the)i(history)h(has)f(b)q(een)h(sti\015ed.)0 1215 +y Fm(2.3)33 b(History)15 b(F)-6 b(unctions)62 1359 y Fo(This)16 +b(section)g(describ)q(es)h(the)e(calling)i(sequence)f(for)f(the)g(v)m(arious) +h(functions)g(presen)o(t)f(in)h(GNU)f(History)l(.)0 1631 y +Fi(2.3.1)30 b(Initializing)15 b(History)g(and)g(State)g(Managemen)n(t)62 +1775 y Fo(This)j(section)g(describ)q(es)h(functions)f(used)g(to)e(initialize) +21 b(and)c(manage)g(the)g(state)g(of)g(the)g(History)g(library)0 +1837 y(when)f(y)o(ou)f(w)o(an)o(t)f(to)g(use)i(the)f(history)g(functions)h +(in)g(y)o(our)f(program.)1725 2021 y(F)l(unction)-1899 b Fh(void)20 +b Fg(using)p 258 2021 18 3 v 20 w(history)j Ff(\(\))120 2083 +y Fo(Begin)g(a)f(session)g(in)h(whic)o(h)g(the)f(history)g(functions)g(migh)o +(t)g(b)q(e)h(used.)40 b(This)23 b(initializes)i(the)120 2145 +y(in)o(teractiv)o(e)16 b(v)m(ariables.)1725 2328 y(F)l(unction)-1899 +b Fh(HISTORY_STATE)21 b(*)e Fg(history)p 582 2328 V 21 w(get)p +680 2328 V 21 w(history)p 876 2328 V 21 w(state)j Ff(\(\))120 +2391 y Fo(Return)16 b(a)f(structure)g(describing)i(the)e(curren)o(t)g(state)f +(of)h(the)g(input)i(history)l(.)1725 2574 y(F)l(unction)-1899 +b Fh(void)20 b Fg(history)p 302 2574 V 20 w(set)p 393 2574 +V 21 w(history)p 589 2574 V 21 w(state)j Ff(\()p Fn(HISTORY_STATE)13 +b(*state)p Ff(\))120 2636 y Fo(Set)i(the)h(state)e(of)h(the)g(history)g(list) +h(according)g(to)e Fj(state)p Fo(.)p eop +%%Page: 7 9 +8 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(7)0 158 y Fi(2.3.2)30 b(History)15 b(List)g(Managemen)n(t)62 +295 y Fo(These)i(functions)h(manage)e(individual)k(en)o(tries)d(on)f(the)h +(history)g(list,)g(or)f(set)h(parameters)e(managing)i(the)0 +358 y(list)f(itself.)1725 520 y(F)l(unction)-1899 b Fh(void)20 +b Fg(add)p 219 520 18 3 v 20 w(history)j Ff(\()p Fn(char)14 +b(*string)p Ff(\))120 582 y Fo(Place)j Fj(string)k Fo(at)16 +b(the)g(end)i(of)e(the)g(history)h(list.)25 b(The)17 b(asso)q(ciated)g(data)f +(\014eld)h(\(if)g(an)o(y\))f(is)h(set)g(to)120 644 y Fn(NULL)p +Fo(.)1725 806 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e +Fg(remo)n(v)n(e)p 509 806 V 20 w(history)k Ff(\()p Fn(int)14 +b(which)p Ff(\))120 868 y Fo(Remo)o(v)o(e)d(history)g(en)o(try)g(at)g +(o\013set)f Fj(whic)o(h)i Fo(from)f(the)g(history)l(.)19 b(The)11 +b(remo)o(v)o(ed)g(elemen)o(t)h(is)g(returned)120 930 y(so)j(y)o(ou)g(can)g +(free)g(the)h(line,)g(data,)e(and)i(con)o(taining)g(structure.)1725 +1092 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e Fg(replace)p +505 1092 V 22 w(history)p 702 1092 V 20 w(en)n(try)24 b Ff(\()p +Fn(int)14 b(which,)g(char)h(*line,)f(char)208 1155 y(*data)p +Ff(\))120 1217 y Fo(Mak)o(e)d(the)i(history)f(en)o(try)g(at)f(o\013set)h +Fj(whic)o(h)h Fo(ha)o(v)o(e)e Fj(line)17 b Fo(and)12 b Fj(data)p +Fo(.)19 b(This)12 b(returns)g(the)h(old)g(en)o(try)e(so)120 +1279 y(y)o(ou)i(can)g(disp)q(ose)h(of)e(the)h(data.)19 b(In)13 +b(the)g(case)g(of)f(an)h(in)o(v)m(alid)i Fj(whic)o(h)p Fo(,)f(a)f +Fn(NULL)f Fo(p)q(oin)o(ter)i(is)f(returned.)1725 1441 y(F)l(unction)-1899 +b Fh(void)20 b Fg(sti\015e)p 245 1441 V 21 w(history)j Ff(\()p +Fn(int)14 b(max)p Ff(\))120 1503 y Fo(Sti\015e)i(the)f(history)h(list,)f +(remem)o(b)q(ering)h(only)g(the)f(last)g Fj(max)j Fo(en)o(tries.)1725 +1665 y(F)l(unction)-1899 b Fh(int)20 b Fg(unsti\015e)p 283 +1665 V 21 w(history)i Ff(\(\))120 1728 y Fo(Stop)13 b(sti\015ing)h(the)f +(history)l(.)19 b(This)14 b(returns)f(the)g(previous)h(amoun)o(t)e(the)h +(history)g(w)o(as)g(sti\015ed.)20 b(The)120 1790 y(v)m(alue)c(is)g(p)q +(ositiv)o(e)g(if)g(the)f(history)g(w)o(as)g(sti\015ed,)h(negativ)o(e)f(if)g +(it)h(w)o(asn't.)1725 1952 y(F)l(unction)-1899 b Fh(int)20 +b Fg(history)p 276 1952 V 20 w(is)p 334 1952 V 21 w(sti\015ed)k +Ff(\(\))120 2014 y Fo(Returns)16 b(non-zero)f(if)h(the)f(history)g(is)h +(sti\015ed,)g(zero)f(if)g(it)h(is)g(not.)0 2222 y Fi(2.3.3)30 +b(Information)14 b(Ab)r(out)h(the)g(History)g(List)62 2359 +y Fo(These)h(functions)g(return)f(information)g(ab)q(out)g(the)h(en)o(tire)f +(history)g(list)h(or)f(individual)j(list)f(en)o(tries.)1725 +2521 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(**)e Fg(history)p +530 2521 V 21 w(list)24 b Ff(\(\))120 2583 y Fo(Return)e(a)e +Fn(NULL)h Fo(terminated)g(arra)o(y)f(of)g Fn(HIST_ENTRY)g Fo(whic)o(h)i(is)f +(the)g(curren)o(t)g(input)h(history)l(.)120 2645 y(Elemen)o(t)16 +b(0)f(of)f(this)i(list)g(is)g(the)f(b)q(eginning)i(of)e(time.)20 +b(If)c(there)f(is)h(no)f(history)l(,)g(return)g Fn(NULL)p Fo(.)p +eop +%%Page: 8 10 +9 bop 0 -83 a Fo(8)1497 b(GNU)15 b(History)g(Library)1725 158 +y(F)l(unction)-1899 b Fh(int)20 b Fg(where)p 250 158 18 3 v +20 w(history)j Ff(\(\))120 221 y Fo(Returns)16 b(the)f(o\013set)f(of)h(the)g +(curren)o(t)g(history)g(elemen)o(t.)1725 378 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(curren)n(t)p 512 378 V 21 w(history)k +Ff(\(\))120 440 y Fo(Return)14 b(the)g(history)g(en)o(try)f(at)h(the)g +(curren)o(t)f(p)q(osition,)i(as)e(determined)j(b)o(y)d Fn(where_history)h +(\(\))p Fo(.)120 502 y(If)h(there)h(is)f(no)h(en)o(try)e(there,)h(return)g(a) +g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 660 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(history)p 504 660 V 21 w(get)j +Ff(\()p Fn(int)15 b(offset)p Ff(\))120 722 y Fo(Return)g(the)g(history)f(en)o +(try)g(at)g(p)q(osition)i Fj(o\013set)p Fo(,)d(starting)h(from)g +Fn(history_base)p Fo(.)k(If)c(there)h(is)g(no)120 784 y(en)o(try)g(there,)g +(or)f(if)i Fj(o\013set)f Fo(is)h(greater)e(than)h(the)h(history)f(length,)g +(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 942 y(F)l(unction)-1899 +b Fh(int)20 b Fg(history)p 276 942 V 20 w(total)p 412 942 V +22 w(b)n(ytes)j Ff(\(\))120 1004 y Fo(Return)17 b(the)f(n)o(um)o(b)q(er)g(of) +g(b)o(ytes)g(that)f(the)h(primary)g(history)g(en)o(tries)h(are)e(using.)23 +b(This)17 b(function)120 1066 y(returns)e(the)g(sum)h(of)e(the)i(lengths)f +(of)g(all)h(the)g(lines)g(in)g(the)g(history)l(.)0 1265 y Fi(2.3.4)30 +b(Mo)n(ving)15 b(Around)h(the)f(History)g(List)62 1402 y Fo(These)h +(functions)g(allo)o(w)f(the)g(curren)o(t)h(index)g(in)o(to)f(the)h(history)f +(list)h(to)e(b)q(e)i(set)f(or)g(c)o(hanged.)1725 1559 y(F)l(unction)-1899 +b Fh(int)20 b Fg(history)p 276 1559 V 20 w(set)p 367 1559 V +21 w(p)r(os)h Ff(\()p Fn(int)15 b(pos)p Ff(\))120 1621 y Fo(Set)g(the)h(p)q +(osition)g(in)g(the)f(history)g(list)h(to)f Fj(p)q(os)p Fo(,)g(an)g(absolute) +g(index)i(in)o(to)e(the)g(list.)1725 1779 y(F)l(unction)-1899 +b Fh(HIST_ENTRY)21 b(*)e Fg(previous)p 540 1779 V 20 w(history)k +Ff(\(\))120 1841 y Fo(Bac)o(k)16 b(up)h(the)g(curren)o(t)f(history)h +(o\013set)e(to)h(the)h(previous)g(history)g(en)o(try)l(,)f(and)h(return)f(a)g +(p)q(oin)o(ter)120 1903 y(to)f(that)f(en)o(try)l(.)20 b(If)15 +b(there)g(is)h(no)f(previous)h(en)o(try)l(,)f(return)g(a)g +Fn(NULL)g Fo(p)q(oin)o(ter.)1725 2061 y(F)l(unction)-1899 b +Fh(HIST_ENTRY)21 b(*)e Fg(next)p 439 2061 V 21 w(history)k +Ff(\(\))120 2123 y Fo(Mo)o(v)o(e)c(the)h(curren)o(t)g(history)f(o\013set)g +(forw)o(ard)g(to)g(the)h(next)g(history)g(en)o(try)l(,)g(and)g(return)g(the)g +(a)120 2185 y(p)q(oin)o(ter)c(to)e(that)h(en)o(try)l(.)k(If)d(there)f(is)h +(no)f(next)g(en)o(try)l(,)g(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)0 +2384 y Fi(2.3.5)30 b(Searc)n(hing)15 b(the)h(History)f(List)62 +2521 y Fo(These)e(functions)g(allo)o(w)f(searc)o(hing)h(of)f(the)g(history)g +(list)h(for)f(en)o(tries)h(con)o(taining)g(a)f(sp)q(eci\014c)i(string.)19 +b(Searc)o(h-)0 2583 y(ing)e(ma)o(y)g(b)q(e)g(p)q(erformed)g(b)q(oth)g(forw)o +(ard)f(and)h(bac)o(kw)o(ard)f(from)g(the)h(curren)o(t)f(history)h(p)q +(osition.)26 b(The)17 b(searc)o(h)0 2645 y(ma)o(y)d(b)q(e)i +Fj(anc)o(hored)p Fo(,)f(meaning)h(that)f(the)g(string)g(m)o(ust)g(matc)o(h)f +(at)h(the)g(b)q(eginning)i(of)e(the)h(history)f(en)o(try)l(.)p +eop +%%Page: 9 11 +10 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 +b(9)1725 158 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 158 18 3 v 20 w(searc)n(h)j Ff(\()p Fn(char)14 b(*string,)g(int)h +(direction)p Ff(\))120 221 y Fo(Searc)o(h)k(the)g(history)g(for)f +Fj(string)p Fo(,)i(starting)e(at)g(the)h(curren)o(t)g(history)g(o\013set.)30 +b(If)19 b Fj(direction)h Fn(<)f Fo(0,)120 283 y(then)14 b(the)f(searc)o(h)g +(is)h(through)e(previous)i(en)o(tries,)g(else)g(through)f(subsequen)o(t.)20 +b(If)13 b Fj(string)k Fo(is)d(found,)120 345 y(then)f(the)g(curren)o(t)g +(history)g(index)i(is)e(set)g(to)f(that)h(history)g(en)o(try)l(,)f(and)i(the) +f(v)m(alue)h(returned)f(is)h(the)120 407 y(o\013set)h(in)i(the)f(line)i(of)d +(the)h(en)o(try)g(where)g Fj(string)k Fo(w)o(as)c(found.)22 +b(Otherwise,)17 b(nothing)f(is)h(c)o(hanged,)120 470 y(and)e(a)g(-1)g(is)h +(returned.)1725 659 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 659 V 20 w(searc)n(h)p 452 659 V 21 w(pre\014x)i Ff(\()p +Fn(char)15 b(*string,)f(int)g(direction)p Ff(\))120 721 y Fo(Searc)o(h)22 +b(the)h(history)f(for)f Fj(string)p Fo(,)j(starting)e(at)f(the)i(curren)o(t)f +(history)g(o\013set.)40 b(The)22 b(searc)o(h)g(is)120 783 y(anc)o(hored:)i +(matc)o(hing)18 b(lines)h(m)o(ust)d(b)q(egin)j(with)f Fj(string)p +Fo(.)26 b(If)17 b Fj(direction)i Fn(<)e Fo(0,)g(then)h(the)f(searc)o(h)g(is) +120 845 y(through)e(previous)h(en)o(tries,)f(else)i(through)d(subsequen)o(t.) +21 b(If)16 b Fj(string)j Fo(is)d(found,)f(then)h(the)f(curren)o(t)120 +908 y(history)20 b(index)i(is)e(set)g(to)g(that)f(en)o(try)l(,)i(and)f(the)g +(return)h(v)m(alue)g(is)g(0.)34 b(Otherwise,)22 b(nothing)e(is)120 +970 y(c)o(hanged,)15 b(and)h(a)e(-1)h(is)h(returned.)1725 1159 +y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 1159 V 20 +w(searc)n(h)p 452 1159 V 21 w(p)r(os)h Ff(\()p Fn(char)15 b(*string,)f(int)g +(direction,)g(int)h(pos)p Ff(\))120 1221 y Fo(Searc)o(h)d(for)f +Fj(string)k Fo(in)d(the)g(history)f(list,)i(starting)e(at)g +Fj(p)q(os)p Fo(,)h(an)f(absolute)h(index)h(in)o(to)e(the)h(list.)19 +b(If)12 b Fj(di-)120 1283 y(rection)g Fo(is)h(negativ)o(e,)f(the)g(searc)o(h) +g(pro)q(ceeds)h(bac)o(kw)o(ard)e(from)g Fj(p)q(os)p Fo(,)i(otherwise)f(forw)o +(ard.)17 b(Returns)120 1345 y(the)e(absolute)h(index)g(of)f(the)g(history)h +(elemen)o(t)f(where)h Fj(string)j Fo(w)o(as)14 b(found,)h(or)g(-1)g +(otherwise.)0 1634 y Fi(2.3.6)30 b(Managing)14 b(the)i(History)f(File)62 +1780 y Fo(The)f(History)g(library)h(can)f(read)g(the)g(history)g(from)f(and)i +(write)f(it)g(to)f(a)h(\014le.)20 b(This)15 b(section)g(do)q(cumen)o(ts)f +(the)0 1842 y(functions)i(for)f(managing)g(a)f(history)i(\014le.)1725 +2031 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p 211 2031 V +20 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 2093 +y Fo(Add)i(the)f(con)o(ten)o(ts)g(of)g Fj(\014lename)k Fo(to)c(the)h(history) +f(list,)h(a)f(line)i(at)e(a)g(time.)24 b(If)17 b Fj(\014lename)j +Fo(is)d Fn(NULL)p Fo(,)120 2155 y(then)f(read)f(from)f(`)p +Fn(~/.history)p Fo('.)k(Returns)e(0)e(if)i(successful,)g(or)f(errno)g(if)h +(not.)1725 2344 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p +211 2344 V 20 w(history)p 406 2344 V 20 w(range)i Ff(\()p Fn(char)15 +b(*filename,)e(int)i(from,)g(int)f(to)p Ff(\))120 2407 y Fo(Read)j(a)e(range) +h(of)f(lines)j(from)d Fj(\014lename)p Fo(,)i(adding)f(them)g(to)f(the)h +(history)g(list.)23 b(Start)15 b(reading)i(at)120 2469 y(line)f +Fj(from)f Fo(and)g(end)g(at)f Fj(to)p Fo(.)19 b(If)d Fj(from)e +Fo(is)h(zero,)f(start)g(at)g(the)h(b)q(eginning.)22 b(If)15 +b Fj(to)i Fo(is)e(less)g(than)g Fj(from)p Fo(,)120 2531 y(then)i(read)g(un)o +(til)h(the)f(end)g(of)g(the)g(\014le.)25 b(If)17 b Fj(\014lename)k +Fo(is)c Fn(NULL)p Fo(,)f(then)i(read)e(from)g(`)p Fn(~/.history)p +Fo('.)120 2593 y(Returns)g(0)f(if)g(successful,)h(or)f Fn(errno)g +Fo(if)g(not.)p eop +%%Page: 10 12 +11 bop 0 -83 a Fo(10)1474 b(GNU)15 b(History)g(Library)1725 +158 y(F)l(unction)-1899 b Fh(int)20 b Fg(write)p 229 158 18 +3 v 22 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 +221 y Fo(W)l(rite)20 b(the)g(curren)o(t)f(history)h(to)f Fj(\014lename)p +Fo(,)i(o)o(v)o(erwriting)f Fj(\014lename)j Fo(if)d(necessary)l(.)34 +b(If)20 b Fj(\014lename)120 283 y Fo(is)d Fn(NULL)p Fo(,)g(then)g(write)g +(the)g(history)g(list)h(to)e(`)p Fn(~/.history)p Fo('.)23 b(V)l(alues)18 +b(returned)g(are)e(as)h(in)h Fn(read_)120 345 y(history)c(\(\))p +Fo(.)1725 504 y(F)l(unction)-1899 b Fh(int)20 b Fg(app)r(end)p +285 504 V 19 w(history)j Ff(\()p Fn(int)14 b(nelements,)g(char)h(*filename)p +Ff(\))120 566 y Fo(App)q(end)i(the)e(last)g Fj(nelemen)o(ts)j +Fo(of)d(the)g(history)g(list)h(to)f Fj(\014lename)p Fo(.)1725 +724 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 724 +V 20 w(truncate)p 507 724 V 21 w(\014le)k Ff(\()p Fn(char)14 +b(*filename,)g(int)h(nlines)p Ff(\))120 787 y Fo(T)l(runcate)g(the)h(history) +f(\014le)h Fj(\014lename)p Fo(,)g(lea)o(ving)g(only)g(the)f(last)g +Fj(nlines)k Fo(lines.)0 988 y Fi(2.3.7)30 b(History)15 b(Expansion)62 +1125 y Fo(These)h(functions)g(implemen)o(t)g Fn(csh)p Fo(-lik)o(e)g(history)g +(expansion.)1725 1283 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p +276 1283 V 20 w(expand)j Ff(\()p Fn(char)14 b(*string,)g(char)h(**output)p +Ff(\))120 1345 y Fo(Expand)20 b Fj(string)p Fo(,)f(placing)i(the)e(result)h +(in)o(to)f Fj(output)p Fo(,)h(a)f(p)q(oin)o(ter)h(to)e(a)h(string)h(\(see)f +(Section)h(1.1)120 1408 y([History)15 b(In)o(teraction],)f(page)h(1\).)20 +b(Returns:)120 1555 y Fn(0)216 b Fo(If)21 b(no)g(expansions)h(to)q(ok)e +(place)h(\(or,)g(if)h(the)f(only)g(c)o(hange)g(in)h(the)f(text)f(w)o(as)g +(the)360 1618 y(de-slashifying)d(of)e(the)g(history)h(expansion)g(c)o +(haracter\);)120 1701 y Fn(1)216 b Fo(if)16 b(expansions)g(did)g(tak)o(e)e +(place;)120 1785 y Fn(-1)192 b Fo(if)16 b(there)f(w)o(as)f(an)h(error)g(in)h +(expansion;)120 1869 y Fn(2)216 b Fo(if)14 b(the)f(returned)h(line)h(should)f +(only)g(b)q(e)f(displa)o(y)o(ed,)i(but)e(not)g(executed,)h(as)f(with)h(the) +360 1931 y Fn(:p)h Fo(mo)q(di\014er)h(\(see)f(Section)h(1.1.3)e([Mo)q +(di\014ers],)h(page)g(2\).)120 2079 y(If)g(an)h(error)e(o)q(curred)i(in)g +(expansion,)f(then)h Fj(output)g Fo(con)o(tains)f(a)g(descriptiv)o(e)i(error) +d(message.)1725 2238 y(F)l(unction)-1899 b Fh(char)20 b(*)f +Fg(history)p 347 2238 V 21 w(arg)p 449 2238 V 19 w(extract)24 +b Ff(\()p Fn(int)14 b(first,)h(int)g(last,)f(char)h(*string)p +Ff(\))120 2300 y Fo(Extract)10 b(a)h(string)g(segmen)o(t)g(consisting)h(of)f +(the)g Fj(\014rst)h Fo(through)f Fj(last)h Fo(argumen)o(ts)e(presen)o(t)h(in) +h Fj(string)p Fo(.)120 2362 y(Argumen)o(ts)j(are)g(brok)o(en)g(up)g(as)g(in)h +(Bash.)1725 2521 y(F)l(unction)-1899 b Fh(char)20 b(*)f Fg(get)p +249 2521 V 21 w(history)p 445 2521 V 20 w(ev)n(en)n(t)25 b +Ff(\()p Fn(char)14 b(*string,)g(int)h(*cindex,)f(int)h(qchar)p +Ff(\))120 2583 y Fo(Returns)e(the)f(text)f(of)h(the)g(history)g(ev)o(en)o(t)f +(b)q(eginning)k(at)c Fj(string)16 b Fn(+)c Fj(*cindex)p Fo(.)20 +b Fj(*cindex)c Fo(is)d(mo)q(di\014ed)120 2645 y(to)h(p)q(oin)o(t)h(to)f +(after)h(the)f(ev)o(en)o(t)h(sp)q(eci\014er.)21 b(A)o(t)15 +b(function)g(en)o(try)l(,)f Fj(cindex)20 b Fo(p)q(oin)o(ts)15 +b(to)f(the)h(index)h(in)o(to)p eop +%%Page: 11 13 +12 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 +b(11)120 158 y Fj(string)17 b Fo(where)d(the)f(history)h(ev)o(en)o(t)f(sp)q +(eci\014cation)i(b)q(egins.)20 b Fj(qc)o(har)d Fo(is)c(a)g(c)o(haracter)g +(that)g(is)h(allo)o(w)o(ed)120 221 y(to)h(end)g(the)h(ev)o(en)o(t)f(sp)q +(eci\014cation)i(in)f(addition)g(to)f(the)g(\\normal")g(terminating)g(c)o +(haracters.)1725 394 y(F)l(unction)-1899 b Fh(char)20 b(**)f +Fg(history)p 373 394 18 3 v 21 w(tok)n(enize)25 b Ff(\()p Fn(char)14 +b(*string)p Ff(\))120 456 y Fo(Return)k(an)f(arra)o(y)f(of)h(tok)o(ens)f +(parsed)i(out)e(of)h Fj(string)p Fo(,)g(m)o(uc)o(h)h(as)e(the)i(shell)g(migh) +o(t.)26 b(The)17 b(tok)o(ens)120 519 y(are)c(split)h(on)f(white)g(space)h +(and)f(on)g(the)g(c)o(haracters)f Fn(\(\)<>;&|$)p Fo(,)g(and)h(shell)i +(quoting)e(con)o(v)o(en)o(tions)120 581 y(are)i(ob)q(ey)o(ed.)0 +840 y Fm(2.4)33 b(History)15 b(V)-6 b(ariables)62 981 y Fo(This)16 +b(section)g(describ)q(es)h(the)e(externally)h(visible)i(v)m(ariables)e(exp)q +(orted)g(b)o(y)f(the)g(GNU)g(History)g(Library)l(.)1736 1155 +y(V)l(ariable)-1899 b Fh(int)20 b Fg(history)p 276 1155 V 20 +w(base)120 1217 y Fo(The)15 b(logical)i(o\013set)d(of)h(the)g(\014rst)g(en)o +(try)g(in)h(the)f(history)g(list.)1736 1390 y(V)l(ariable)-1899 +b Fh(int)20 b Fg(history)p 276 1390 V 20 w(length)120 1453 +y Fo(The)15 b(n)o(um)o(b)q(er)h(of)f(en)o(tries)g(curren)o(tly)h(stored)f(in) +h(the)f(history)g(list.)1736 1626 y(V)l(ariable)-1899 b Fh(int)20 +b Fg(max)p 208 1626 V 19 w(input)p 360 1626 V 21 w(history)120 +1689 y Fo(The)12 b(maxim)o(um)g(n)o(um)o(b)q(er)g(of)f(history)h(en)o(tries.) +19 b(This)12 b(m)o(ust)f(b)q(e)h(c)o(hanged)g(using)h Fn(stifle_history)120 +1751 y(\(\))p Fo(.)1736 1924 y(V)l(ariable)-1899 b Fh(char)20 +b Fg(history)p 302 1924 V 20 w(expansion)p 569 1924 V 21 w(c)n(har)120 +1987 y Fo(The)15 b(c)o(haracter)g(that)f(starts)g(a)h(history)g(ev)o(en)o(t.) +20 b(The)15 b(default)h(is)g(`)p Fn(!)p Fo('.)1736 2160 y(V)l(ariable)-1899 +b Fh(char)20 b Fg(history)p 302 2160 V 20 w(subst)p 454 2160 +V 20 w(c)n(har)120 2222 y Fo(The)13 b(c)o(haracter)e(that)h(in)o(v)o(ok)o(es) +g(w)o(ord)g(substitution)h(if)g(found)g(at)e(the)i(start)e(of)h(a)g(line.)21 +b(The)12 b(default)120 2285 y(is)k(`)p Fn(^)p Fo('.)1736 2458 +y(V)l(ariable)-1899 b Fh(char)20 b Fg(history)p 302 2458 V +20 w(commen)n(t)p 552 2458 V 19 w(c)n(har)120 2521 y Fo(During)12 +b(tok)o(enization,)h(if)f(this)h(c)o(haracter)e(is)i(seen)f(as)g(the)g +(\014rst)f(c)o(haracter)g(of)h(a)g(w)o(ord,)f(then)i(it)f(and)120 +2583 y(all)19 b(subsequen)o(t)g(c)o(haracters)e(up)h(to)g(a)f(newline)j(are)e +(ignored,)h(suppressing)g(history)f(expansion)120 2645 y(for)d(the)g +(remainder)h(of)f(the)g(line.)21 b(This)16 b(is)g(disabled)h(b)o(y)e +(default.)p eop +%%Page: 12 14 +13 bop 0 -83 a Fo(12)1474 b(GNU)15 b(History)g(Library)1736 +158 y(V)l(ariable)-1899 b Fh(char)20 b(*)f Fg(history)p 347 +158 18 3 v 21 w(no)p 429 158 V 20 w(expand)p 629 158 V 20 w(c)n(hars)120 +221 y Fo(The)f(list)g(of)g(c)o(haracters)e(whic)o(h)j(inhibit)h(history)d +(expansion)i(if)f(found)g(immediately)h(follo)o(wing)120 283 +y Fj(history)p 261 283 14 2 v 16 w(expansion)p 472 283 V 18 +w(c)o(har)p Fo(.)g(The)d(default)f(is)h(whitespace)g(and)g(`)p +Fn(=)p Fo('.)0 575 y Fm(2.5)33 b(History)15 b(Programming)h(Example)62 +720 y Fo(The)g(follo)o(wing)g(program)e(demonstrates)g(simple)j(use)e(of)g +(the)g(GNU)g(History)g(Library)l(.)120 852 y Fn(main)23 b(\(\))120 +902 y({)168 951 y(char)g(line[1024],)f(*t;)168 1001 y(int)h(len,)g(done)h(=)g +(0;)168 1101 y(line[0])f(=)g(0;)168 1201 y(using_history)f(\(\);)168 +1250 y(while)h(\(!done\))215 1300 y({)263 1350 y(printf)g(\("history$)g("\);) +263 1400 y(fflush)g(\(stdout\);)263 1450 y(t)h(=)g(fgets)f(\(line,)g(sizeof)g +(\(line\))g(-)h(1,)f(stdin\);)263 1499 y(if)h(\(t)f(&&)h(*t\))311 +1549 y({)359 1599 y(len)f(=)h(strlen)f(\(t\);)359 1649 y(if)g(\(t[len)g(-)h +(1])g(==)f('\\n'\))406 1699 y(t[len)h(-)f(1])h(=)g('\\0';)311 +1748 y(})263 1848 y(if)g(\(!t\))311 1898 y(strcpy)f(\(line,)g("quit"\);)263 +1998 y(if)h(\(line[0]\))311 2047 y({)359 2097 y(char)f(*expansion;)359 +2147 y(int)g(result;)359 2247 y(result)g(=)g(history_expand)f(\(line,)h +(&expansion\);)359 2296 y(if)g(\(result\))406 2346 y(fprintf)g(\(stderr,)g +("\045s\\n",)g(expansion\);)359 2446 y(if)g(\(result)g(<)h(0)g(||)f(result)g +(==)h(2\))406 2496 y({)454 2545 y(free)f(\(expansion\);)454 +2595 y(continue;)406 2645 y(})p eop +%%Page: 13 15 +14 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 +b(13)359 208 y Fn(add_history)22 b(\(expansion\);)359 258 y(strncpy)h +(\(line,)g(expansion,)f(sizeof)h(\(line\))g(-)h(1\);)359 308 +y(free)f(\(expansion\);)311 358 y(})263 457 y(if)h(\(strcmp)f(\(line,)g +("quit"\))g(==)g(0\))311 507 y(done)g(=)h(1;)263 557 y(else)f(if)h(\(strcmp)f +(\(line,)g("save"\))g(==)h(0\))311 607 y(write_history)e(\("history_file"\);) +263 656 y(else)h(if)h(\(strcmp)f(\(line,)g("read"\))g(==)h(0\))311 +706 y(read_history)e(\("history_file"\);)263 756 y(else)h(if)h(\(strcmp)f +(\(line,)g("list"\))g(==)h(0\))311 806 y({)359 856 y(register)e(HIST_ENTRY)h +(**the_list;)359 906 y(register)f(int)i(i;)359 1005 y(the_list)e(=)i +(history_list)e(\(\);)359 1055 y(if)h(\(the_list\))406 1105 +y(for)h(\(i)f(=)h(0;)g(the_list[i];)e(i++\))454 1155 y(printf)h(\("\045d:)g +(\045s\\n",)g(i)h(+)g(history_base,)e(the_list[i]->line\);)311 +1204 y(})263 1254 y(else)h(if)h(\(strncmp)f(\(line,)g("delete",)g(6\))g(==)h +(0\))311 1304 y({)359 1354 y(int)f(which;)359 1404 y(if)g(\(\(sscanf)g +(\(line)g(+)h(6,)f("\045d",)h(&which\)\))e(==)i(1\))406 1453 +y({)454 1503 y(HIST_ENTRY)f(*entry)g(=)g(remove_history)f(\(which\);)454 +1553 y(if)i(\(!entry\))502 1603 y(fprintf)f(\(stderr,)f("No)i(such)f(entry)g +(\045d\\n",)g(which\);)454 1653 y(else)502 1703 y({)550 1752 +y(free)g(\(entry->line\);)550 1802 y(free)g(\(entry\);)502 +1852 y(})406 1902 y(})359 1952 y(else)406 2001 y({)454 2051 +y(fprintf)g(\(stderr,)g("non-numeric)f(arg)h(given)h(to)f(`delete'\\n"\);)406 +2101 y(})311 2151 y(})215 2201 y(})120 2250 y(})p eop +%%Page: 14 16 +15 bop 0 -83 a Fo(14)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: 15 17 +16 bop 0 -83 a Fo(App)q(endix)17 b(A:)e(Concept)g(Index)1346 +b(15)0 158 y Fk(App)r(endix)13 b(A)41 b(Concept)15 b(Index)0 +405 y Fm(A)0 471 y Fe(anc)o(hored)f(searc)o(h)5 b Fd(:)i(:)f(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(8)0 +579 y Fm(E)0 646 y Fe(ev)o(en)o(t)13 b(designators)g Fd(:)6 +b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)23 +b Fe(1)1015 405 y(expansion)5 b Fd(:)k(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(1)1015 +521 y Fm(H)1015 587 y Fe(history)d(ev)o(en)o(ts)5 b Fd(:)i(:)f(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b +Fe(1)1015 646 y(History)c(Searc)o(hing)7 b Fd(:)h(:)e(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)p eop +%%Page: 16 18 +17 bop 0 -83 a Fo(16)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: 17 19 +18 bop 0 -83 a Fo(App)q(endix)17 b(B:)e(F)l(unction)h(and)g(V)l(ariable)g +(Index)1069 b(17)0 158 y Fk(App)r(endix)13 b(B)41 b(F)-7 b(unction)15 +b(and)g(V)-7 b(ariable)14 b(Index)0 405 y Fm(A)0 471 y Fc(add)p +62 471 12 2 v 13 w(history)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(7)0 529 y Fc(append)p +122 529 V 12 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)24 b Fe(10)0 654 y Fm(C)0 720 y Fc(current)p +142 720 V 11 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)24 b Fe(8)0 845 y Fm(G)0 911 y Fc(get)p 62 911 +V 13 w(history)p 215 911 V 11 w(event)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)23 b Fe(10)0 1036 y Fm(H)0 1102 y Fc(history)p +142 1102 V 11 w(arg)p 213 1102 V 13 w(extract)8 b Fd(:)t(:)e(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)21 b Fe(10)0 1160 y Fc(history)p 142 1160 +V 11 w(base)e Fd(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) +g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)20 b Fe(11)0 1218 y Fc(history)p 142 1218 V 11 w(comment)p +293 1218 V 12 w(char)g Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 +b Fe(11)0 1276 y Fc(history)p 142 1276 V 11 w(expand)10 b Fd(:)c(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fe(10)0 +1335 y Fc(history)p 142 1335 V 11 w(expansion)p 333 1335 V +11 w(char)17 b Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fe(11)0 +1393 y Fc(history)p 142 1393 V 11 w(get)8 b Fd(:)d(:)h(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(8)0 +1451 y Fc(history)p 142 1451 V 11 w(get)p 213 1451 V 13 w(history)p +366 1451 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fe(6)0 +1509 y Fc(history)p 142 1509 V 11 w(is)p 193 1509 V 14 w(stifled)7 +b Fd(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b +Fe(7)0 1567 y Fc(history)p 142 1567 V 11 w(length)16 b Fd(:)6 +b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 +b Fe(11)0 1625 y Fc(history)p 142 1625 V 11 w(list)7 b Fd(:)t(:)g(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(7)0 1683 y Fc(history)p 142 1683 V 11 w(no)p 193 1683 +V 14 w(expand)p 327 1683 V 12 w(chars)f Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 +b Fe(12)0 1741 y Fc(history)p 142 1741 V 11 w(search)t Fd(:)t(:)6 +b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(9)0 1800 y Fc(history)p 142 1800 V 11 w(search)p 273 1800 +V 12 w(pos)9 b Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 +b Fe(9)0 1858 y Fc(history)p 142 1858 V 11 w(search)p 273 1858 +V 12 w(prefix)6 b Fd(:)t(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(9)0 1916 y Fc(history)p 142 1916 V 11 w(set)p 213 1916 +V 13 w(history)p 366 1916 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(6)0 1974 y Fc(history)p 142 1974 V 11 w(set)p 213 1974 +V 13 w(pos)5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)18 b Fe(8)0 2032 y Fc(history)p 142 2032 V 11 w(subst)p +253 2032 V 13 w(char)k Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 +b Fe(11)1015 405 y Fc(history)p 1157 405 V 12 w(tokenize)9 +b Fd(:)s(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 +b Fe(11)1015 463 y Fc(history)p 1157 463 V 12 w(total)p 1269 +463 V 12 w(bytes)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 +b Fe(8)1015 521 y Fc(history)p 1157 521 V 12 w(truncate)p 1329 +521 V 11 w(file)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) +f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 +b Fe(10)1015 629 y Fm(M)1015 695 y Fc(max)p 1077 695 V 13 w(input)p +1190 695 V 13 w(history)14 b Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)17 b Fe(11)1015 803 y Fm(N)1015 870 y Fc(next)p 1097 +870 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)1015 978 y Fm(P)1015 1044 +y Fc(previous)p 1177 1044 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fe(8)1015 1152 y Fm(R)1015 +1218 y Fc(read)p 1097 1218 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(9)1015 +1276 y Fc(read)p 1097 1276 V 13 w(history)p 1250 1276 V 11 +w(range)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 +b Fe(9)1015 1335 y Fc(remove)p 1137 1335 V 12 w(history)t Fd(:)t(:)6 +b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 +b Fe(7)1015 1393 y Fc(replace)p 1157 1393 V 12 w(history)p +1309 1393 V 11 w(entry)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 +b Fe(7)1015 1501 y Fm(S)1015 1567 y Fc(stifle)p 1137 1567 V +12 w(history)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)g(:)g(:)17 b Fe(7)1015 1675 y Fm(U)1015 1741 y Fc(unstifle)p +1177 1741 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)g(:)g(:)g(:)23 b Fe(7)1015 1800 y Fc(using)p 1117 1800 V +13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)h(:)f(:)g(:)18 b Fe(6)1015 1907 y Fm(W)1015 1974 y Fc(where)p +1117 1974 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(8)1015 2032 y Fc(write)p +1117 2032 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g +(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(9)p eop +%%Page: 18 20 +19 bop 0 -83 a Fo(18)1474 b(GNU)15 b(History)g(Library)p eop +%%Page: -1 21 +20 bop 1937 -83 a Fo(i)0 158 y Fk(T)-7 b(able)15 b(of)g(Con)n(ten)n(ts)0 +333 y Fm(1)67 b(Using)22 b(History)h(In)n(teractiv)n(ely)9 +b Fb(:)k(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)31 b Fm(1)149 411 y Fo(1.1)45 +b(History)15 b(In)o(teraction)9 b Fa(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)23 +b Fo(1)299 473 y(1.1.1)44 b(Ev)o(en)o(t)14 b(Designators)6 +b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)20 b Fo(1)299 535 y(1.1.2)44 b(W)l(ord)15 b(Designators)9 +b Fa(:)d(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)23 b Fo(2)299 597 y(1.1.3)44 b(Mo)q(di\014ers)14 +b Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)28 b Fo(2)0 722 +y Fm(2)67 b(Programming)23 b(with)g(GNU)f(History)13 b Fb(:)e(:)f(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)36 b +Fm(5)149 800 y Fo(2.1)45 b(In)o(tro)q(duction)16 b(to)f(History)6 +b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(5)149 862 y(2.2)45 b(History)15 +b(Storage)d Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 +b Fo(5)149 924 y(2.3)45 b(History)15 b(F)l(unctions)c Fa(:)d(:)f(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(6)299 986 y(2.3.1)44 b(Initializing)18 +b(History)d(and)h(State)e(Managemen)o(t)f Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:) +g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 b Fo(6)299 1049 y(2.3.2)44 b(History)15 +b(List)h(Managemen)o(t)c Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h +(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)28 b Fo(7)299 1111 y(2.3.3)44 b(Information)15 b(Ab)q(out)g(the)h(History) +f(List)5 b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fo(7)299 1173 y(2.3.4)44 b(Mo)o(ving)15 +b(Around)g(the)g(History)g(List)6 b Fa(:)i(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 +b Fo(8)299 1236 y(2.3.5)44 b(Searc)o(hing)16 b(the)f(History)g(List)7 +b Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b +Fo(8)299 1298 y(2.3.6)44 b(Managing)15 b(the)g(History)g(File)5 +b Fa(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)19 b +Fo(9)299 1360 y(2.3.7)44 b(History)15 b(Expansion)d Fa(:)7 +b(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 +b Fo(10)149 1422 y(2.4)45 b(History)15 b(V)l(ariables)5 b Fa(:)k(:)e(:)g(:)g +(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g +(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(11)149 1485 y(2.5)45 b(History)15 +b(Programming)f(Example)8 b Fa(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) +g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f +(:)g(:)g(:)g(:)23 b Fo(12)0 1609 y Fm(App)r(endix)h(A)67 b(Concept)22 +b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g +(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)37 b Fm(15)0 1749 +y(App)r(endix)24 b(B)67 b(F)-6 b(unction)25 b(and)e(V)-6 b(ariable)24 +b(Index)8 b Fb(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)31 +b Fm(17)p eop +%%Page: -2 22 +21 bop 0 -83 a Fo(ii)1496 b(GNU)15 b(History)g(Library)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/lib/readline/doc/rlman.texinfo b/lib/readline/doc/rlman.texinfo 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 +#include +#include +#include +#include + +#include +#include + +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 +#include +#include +#include "getopt.h" +#include "bashansi.h" + +#if !defined (errno) +extern int errno; +#endif + +#if defined (HAVE_UNISTD_H) +# include +#else /* !HAVE_UNISTD_H */ +extern long lseek (); +#endif /* !HAVE_UNISTD_H */ + +extern char *mktemp (); + +#if !defined (HAVE_STRERROR) +extern int sys_nerr; +extern char *sys_errlist[]; +#endif + +#include + +#if defined (_AIX) || !defined (_POSIX_VERSION) +# include +#endif + +#include + +#define TI_NO_ERROR 0 +#define TI_FATAL_ERROR 1 + +#if !defined (SEEK_SET) +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif /* !SEEK_SET */ + +/* When sorting in core, this structure describes one line + and the position and length of its first keyfield. */ +struct lineinfo +{ + char *text; /* The actual text of the line. */ + union { + char *text; /* The start of the key (for textual comparison). */ + long number; /* The numeric value (for numeric comparison). */ + } key; + long keylen; /* Length of KEY field. */ +}; + +/* This structure describes a field to use as a sort key. */ +struct keyfield +{ + int startwords; /* Number of words to skip. */ + int startchars; /* Number of additional chars to skip. */ + int endwords; /* Number of words to ignore at end. */ + int endchars; /* Ditto for characters of last word. */ + char ignore_blanks; /* Non-zero means ignore spaces and tabs. */ + char fold_case; /* Non-zero means case doesn't matter. */ + char reverse; /* Non-zero means compare in reverse order. */ + char numeric; /* Non-zeros means field is ASCII numeric. */ + char positional; /* Sort according to file position. */ + char braced; /* Count balanced-braced groupings as fields. */ +}; + +/* Vector of keyfields to use. */ +struct keyfield keyfields[3]; + +/* Number of keyfields stored in that vector. */ +int num_keyfields = 3; + +/* Vector of input file names, terminated with a null pointer. */ +char **infiles; + +/* Vector of corresponding output file names, or NULL, meaning default it + (add an `s' to the end). */ +char **outfiles; + +/* Length of `infiles'. */ +int num_infiles; + +/* Pointer to the array of pointers to lines being sorted. */ +char **linearray; + +/* The allocated length of `linearray'. */ +long nlines; + +/* Directory to use for temporary files. On Unix, it ends with a slash. */ +char *tempdir; + +/* Start of filename to use for temporary files. */ +char *tempbase; + +/* Number of last temporary file. */ +int tempcount; + +/* Number of last temporary file already deleted. + Temporary files are deleted by `flush_tempfiles' in order of creation. */ +int last_deleted_tempcount; + +/* During in-core sort, this points to the base of the data block + which contains all the lines of data. */ +char *text_base; + +/* Additional command switches .*/ + +/* Nonzero means do not delete tempfiles -- for debugging. */ +int keep_tempfiles; + +/* The name this program was run with. */ +char *program_name; + +/* Forward declarations of functions in this file. */ + +void decode_command (); +void sort_in_core (); +void sort_offline (); +char **parsefile (); +char *find_field (); +char *find_pos (); +long find_value (); +char *find_braced_pos (); +char *find_braced_end (); +void writelines (); +int compare_field (); +int compare_full (); +long readline (); +int merge_files (); +int merge_direct (); +void pfatal_with_name (); +void fatal (); +void error (); +void *xmalloc (), *xrealloc (); +char *concat (); +char *maketempname (); +void flush_tempfiles (); +char *tempcopy (); + +#define MAX_IN_CORE_SORT 500000 + +void +main (argc, argv) + int argc; + char **argv; +{ + int i; + + tempcount = 0; + last_deleted_tempcount = 0; + program_name = argv[0]; + + /* Describe the kind of sorting to do. */ + /* The first keyfield uses the first braced field and folds case. */ + keyfields[0].braced = 1; + keyfields[0].fold_case = 1; + keyfields[0].endwords = -1; + keyfields[0].endchars = -1; + + /* The second keyfield uses the second braced field, numerically. */ + keyfields[1].braced = 1; + keyfields[1].numeric = 1; + keyfields[1].startwords = 1; + keyfields[1].endwords = -1; + keyfields[1].endchars = -1; + + /* The third keyfield (which is ignored while discarding duplicates) + compares the whole line. */ + keyfields[2].endwords = -1; + keyfields[2].endchars = -1; + + decode_command (argc, argv); + + tempbase = mktemp (concat ("txiXXXXXX", "", "")); + + /* Process input files completely, one by one. */ + + for (i = 0; i < num_infiles; i++) + { + int desc; + long ptr; + char *outfile; + + desc = open (infiles[i], O_RDONLY, 0); + if (desc < 0) + pfatal_with_name (infiles[i]); + lseek (desc, 0L, SEEK_END); + ptr = lseek (desc, 0L, SEEK_CUR); + + close (desc); + + outfile = outfiles[i]; + if (!outfile) + { + outfile = concat (infiles[i], "s", ""); + } + + if (ptr < MAX_IN_CORE_SORT) + /* Sort a small amount of data. */ + sort_in_core (infiles[i], ptr, outfile); + else + sort_offline (infiles[i], ptr, outfile); + } + + flush_tempfiles (tempcount); + exit (TI_NO_ERROR); +} + +void +usage () +{ + fprintf (stderr, "\ +Usage: %s [-k] infile [-o outfile] ...\n", program_name); + exit (1); +} + +/* Decode the command line arguments to set the parameter variables + and set up the vector of keyfields and the vector of input files. */ + +void +decode_command (argc, argv) + int argc; + char **argv; +{ + int optc; + char **ip; + char **op; + + /* Store default values into parameter variables. */ + + tempdir = getenv ("TMPDIR"); + if (tempdir == NULL) + tempdir = "/tmp/"; + else + tempdir = concat (tempdir, "/", ""); + + keep_tempfiles = 0; + + /* Allocate ARGC input files, which must be enough. */ + + infiles = (char **) xmalloc (argc * sizeof (char *)); + outfiles = (char **) xmalloc (argc * sizeof (char *)); + ip = infiles; + op = outfiles; + + while ((optc = getopt (argc, argv, "-ko:")) != EOF) + { + switch (optc) + { + case 1: /* Non-option filename. */ + *ip++ = optarg; + *op++ = NULL; + break; + + case 'k': + keep_tempfiles = 1; + break; + + case 'o': + if (op > outfiles) + *(op - 1) = optarg; + break; + + default: + usage (); + } + } + + /* Record number of keyfields and terminate list of filenames. */ + num_infiles = ip - infiles; + *ip = 0; + if (num_infiles == 0) + usage (); +} + +/* Return a name for a temporary file. */ + +char * +maketempname (count) + int count; +{ + char tempsuffix[10]; + sprintf (tempsuffix, "%d", count); + return concat (tempdir, tempbase, tempsuffix); +} + +/* Delete all temporary files up to TO_COUNT. */ + +void +flush_tempfiles (to_count) + int to_count; +{ + if (keep_tempfiles) + return; + while (last_deleted_tempcount < to_count) + unlink (maketempname (++last_deleted_tempcount)); +} + +/* Copy the input file open on IDESC into a temporary file + and return the temporary file name. */ + +#define BUFSIZE 1024 + +char * +tempcopy (idesc) + int idesc; +{ + char *outfile = maketempname (++tempcount); + int odesc; + char buffer[BUFSIZE]; + + odesc = open (outfile, O_WRONLY | O_CREAT, 0666); + + if (odesc < 0) + pfatal_with_name (outfile); + + while (1) + { + int nread = read (idesc, buffer, BUFSIZE); + write (odesc, buffer, nread); + if (!nread) + break; + } + + close (odesc); + + return outfile; +} + +/* Compare LINE1 and LINE2 according to the specified set of keyfields. */ + +int +compare_full (line1, line2) + char **line1, **line2; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; + and so on. */ + + for (i = 0; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], *line1, &length1); + char *start2 = find_field (&keyfields[i], *line2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base, + start2, length2, *line2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Compare LINE1 and LINE2, described by structures + in which the first keyfield is identified in advance. + For positional sorting, assumes that the order of the lines in core + reflects their nominal order. */ + +int +compare_prepared (line1, line2) + struct lineinfo *line1, *line2; +{ + int i; + int tem; + char *text1, *text2; + + /* Compare using the first keyfield, which has been found for us already. */ + if (keyfields->positional) + { + if (line1->text - text_base > line2->text - text_base) + tem = 1; + else + tem = -1; + } + else if (keyfields->numeric) + tem = line1->key.number - line2->key.number; + else + tem = compare_field (keyfields, line1->key.text, line1->keylen, 0, + line2->key.text, line2->keylen, 0); + if (tem) + { + if (keyfields->reverse) + return -tem; + return tem; + } + + text1 = line1->text; + text2 = line2->text; + + /* Compare using the second keyfield; + if that does not distinguish the lines, try the third keyfield; + and so on. */ + + for (i = 1; i < num_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], text1, &length1); + char *start2 = find_field (&keyfields[i], text2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base, + start2, length2, text2 - text_base); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Like compare_full but more general. + You can pass any strings, and you can say how many keyfields to use. + POS1 and POS2 should indicate the nominal positional ordering of + the two lines in the input. */ + +int +compare_general (str1, str2, pos1, pos2, use_keyfields) + char *str1, *str2; + long pos1, pos2; + int use_keyfields; +{ + int i; + + /* Compare using the first keyfield; + if that does not distinguish the lines, try the second keyfield; + and so on. */ + + for (i = 0; i < use_keyfields; i++) + { + long length1, length2; + char *start1 = find_field (&keyfields[i], str1, &length1); + char *start2 = find_field (&keyfields[i], str2, &length2); + int tem = compare_field (&keyfields[i], start1, length1, pos1, + start2, length2, pos2); + if (tem) + { + if (keyfields[i].reverse) + return -tem; + return tem; + } + } + + return 0; /* Lines match exactly. */ +} + +/* Find the start and length of a field in STR according to KEYFIELD. + A pointer to the starting character is returned, and the length + is stored into the int that LENGTHPTR points to. */ + +char * +find_field (keyfield, str, lengthptr) + struct keyfield *keyfield; + char *str; + long *lengthptr; +{ + char *start; + char *end; + char *(*fun) (); + + if (keyfield->braced) + fun = find_braced_pos; + else + fun = find_pos; + + start = (*fun) (str, keyfield->startwords, keyfield->startchars, + keyfield->ignore_blanks); + if (keyfield->endwords < 0) + { + if (keyfield->braced) + end = find_braced_end (start); + else + { + end = start; + while (*end && *end != '\n') + end++; + } + } + else + { + end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0); + if (end - str < start - str) + end = start; + } + *lengthptr = end - start; + return start; +} + +/* Return a pointer to a specified place within STR, + skipping (from the beginning) WORDS words and then CHARS chars. + If IGNORE_BLANKS is nonzero, we skip all blanks + after finding the specified word. */ + +char * +find_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + char *p = str; + + for (i = 0; i < words; i++) + { + char c; + /* Find next bunch of nonblanks and skip them. */ + while ((c = *p) == ' ' || c == '\t') + p++; + while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) + p++; + if (!*p || *p == '\n') + return p; + } + + while (*p == ' ' || *p == '\t') + p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') + break; + p++; + } + return p; +} + +/* Like find_pos but assumes that each field is surrounded by braces + and that braces within fields are balanced. */ + +char * +find_braced_pos (str, words, chars, ignore_blanks) + char *str; + int words, chars; + int ignore_blanks; +{ + int i; + int bracelevel; + char *p = str; + char c; + + for (i = 0; i < words; i++) + { + bracelevel = 1; + while ((c = *p++) != '{' && c != '\n' && c) + /* Do nothing. */ ; + if (c != '{') + return p - 1; + while (bracelevel) + { + c = *p++; + if (c == '{') + bracelevel++; + if (c == '}') + bracelevel--; + if (c == 0 || c == '\n') + return p - 1; + } + } + + while ((c = *p++) != '{' && c != '\n' && c) + /* Do nothing. */ ; + + if (c != '{') + return p - 1; + + if (ignore_blanks) + while ((c = *p) == ' ' || c == '\t') + p++; + + for (i = 0; i < chars; i++) + { + if (!*p || *p == '\n') + break; + p++; + } + return p; +} + +/* Find the end of the balanced-brace field which starts at STR. + The position returned is just before the closing brace. */ + +char * +find_braced_end (str) + char *str; +{ + int bracelevel; + char *p = str; + char c; + + bracelevel = 1; + while (bracelevel) + { + c = *p++; + if (c == '{') + bracelevel++; + if (c == '}') + bracelevel--; + if (c == 0 || c == '\n') + return p - 1; + } + return p - 1; +} + +long +find_value (start, length) + char *start; + long length; +{ + while (length != 0L) + { + if (isdigit (*start)) + return atol (start); + length--; + start++; + } + return 0l; +} + +/* Vector used to translate characters for comparison. + This is how we make all alphanumerics follow all else, + and ignore case in the first sorting. */ +int char_order[256]; + +void +init_char_order () +{ + int i; + for (i = 1; i < 256; i++) + char_order[i] = i; + + for (i = '0'; i <= '9'; i++) + char_order[i] += 512; + + for (i = 'a'; i <= 'z'; i++) + { + char_order[i] = 512 + i; + char_order[i + 'A' - 'a'] = 512 + i; + } +} + +/* Compare two fields (each specified as a start pointer and a character count) + according to KEYFIELD. + The sign of the value reports the relation between the fields. */ + +int +compare_field (keyfield, start1, length1, pos1, start2, length2, pos2) + struct keyfield *keyfield; + char *start1; + long length1; + long pos1; + char *start2; + long length2; + long pos2; +{ + if (keyfields->positional) + { + if (pos1 > pos2) + return 1; + else + return -1; + } + if (keyfield->numeric) + { + long value = find_value (start1, length1) - find_value (start2, length2); + if (value > 0) + return 1; + if (value < 0) + return -1; + return 0; + } + else + { + char *p1 = start1; + char *p2 = start2; + char *e1 = start1 + length1; + char *e2 = start2 + length2; + + while (1) + { + int c1, c2; + + if (p1 == e1) + c1 = 0; + else + c1 = *p1++; + if (p2 == e2) + c2 = 0; + else + c2 = *p2++; + + if (char_order[c1] != char_order[c2]) + return char_order[c1] - char_order[c2]; + if (!c1) + break; + } + + /* Strings are equal except possibly for case. */ + p1 = start1; + p2 = start2; + while (1) + { + int c1, c2; + + if (p1 == e1) + c1 = 0; + else + c1 = *p1++; + if (p2 == e2) + c2 = 0; + else + c2 = *p2++; + + if (c1 != c2) + /* Reverse sign here so upper case comes out last. */ + return c2 - c1; + if (!c1) + break; + } + + return 0; + } +} + +/* A `struct linebuffer' is a structure which holds a line of text. + `readline' reads a line from a stream into a linebuffer + and works regardless of the length of the line. */ + +struct linebuffer +{ + long size; + char *buffer; +}; + +/* Initialize LINEBUFFER for use. */ + +void +initbuffer (linebuffer) + struct linebuffer *linebuffer; +{ + linebuffer->size = 200; + linebuffer->buffer = (char *) xmalloc (200); +} + +/* Read a line of text from STREAM into LINEBUFFER. + Return the length of the line. */ + +long +readline (linebuffer, stream) + struct linebuffer *linebuffer; + FILE *stream; +{ + char *buffer = linebuffer->buffer; + char *p = linebuffer->buffer; + char *end = p + linebuffer->size; + + while (1) + { + int c = getc (stream); + if (p == end) + { + buffer = (char *) xrealloc (buffer, linebuffer->size *= 2); + p += buffer - linebuffer->buffer; + end += buffer - linebuffer->buffer; + linebuffer->buffer = buffer; + } + if (c < 0 || c == '\n') + { + *p = 0; + break; + } + *p++ = c; + } + + return p - buffer; +} + +/* Sort an input file too big to sort in core. */ + +void +sort_offline (infile, nfiles, total, outfile) + char *infile; + int nfiles; + long total; + char *outfile; +{ + /* More than enough. */ + int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT; + char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + FILE *istream = fopen (infile, "r"); + int i; + struct linebuffer lb; + long linelength; + int failure = 0; + + initbuffer (&lb); + + /* Read in one line of input data. */ + + linelength = readline (&lb, istream); + + if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') + { + error ("%s: not a texinfo index file", infile); + return; + } + + /* Split up the input into `ntemps' temporary files, or maybe fewer, + and put the new files' names into `tempfiles' */ + + for (i = 0; i < ntemps; i++) + { + char *outname = maketempname (++tempcount); + FILE *ostream = fopen (outname, "w"); + long tempsize = 0; + + if (!ostream) + pfatal_with_name (outname); + tempfiles[i] = outname; + + /* Copy lines into this temp file as long as it does not make file + "too big" or until there are no more lines. */ + + while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT) + { + tempsize += linelength + 1; + fputs (lb.buffer, ostream); + putc ('\n', ostream); + + /* Read another line of input data. */ + + linelength = readline (&lb, istream); + if (!linelength && feof (istream)) + break; + + if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') + { + error ("%s: not a texinfo index file", infile); + failure = 1; + goto fail; + } + } + fclose (ostream); + if (feof (istream)) + break; + } + + free (lb.buffer); + +fail: + /* Record number of temp files we actually needed. */ + + ntemps = i; + + /* Sort each tempfile into another tempfile. + Delete the first set of tempfiles and put the names of the second + into `tempfiles'. */ + + for (i = 0; i < ntemps; i++) + { + char *newtemp = maketempname (++tempcount); + sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp); + if (!keep_tempfiles) + unlink (tempfiles[i]); + tempfiles[i] = newtemp; + } + + if (failure) + return; + + /* Merge the tempfiles together and indexify. */ + + merge_files (tempfiles, ntemps, outfile); +} + +/* Sort INFILE, whose size is TOTAL, + assuming that is small enough to be done in-core, + then indexify it and send the output to OUTFILE (or to stdout). */ + +void +sort_in_core (infile, total, outfile) + char *infile; + long total; + char *outfile; +{ + char **nextline; + char *data = (char *) xmalloc (total + 1); + char *file_data; + long file_size; + int i; + FILE *ostream = stdout; + struct lineinfo *lineinfo; + + /* Read the contents of the file into the moby array `data'. */ + + int desc = open (infile, O_RDONLY, 0); + + if (desc < 0) + fatal ("failure reopening %s", infile); + for (file_size = 0;;) + { + i = read (desc, data + file_size, total - file_size); + if (i <= 0) + break; + file_size += i; + } + file_data = data; + data[file_size] = 0; + + close (desc); + + if (file_size > 0 && data[0] != '\\' && data[0] != '@') + { + error ("%s: not a texinfo index file", infile); + return; + } + + init_char_order (); + + /* Sort routines want to know this address. */ + + text_base = data; + + /* Create the array of pointers to lines, with a default size + frequently enough. */ + + nlines = total / 50; + if (!nlines) + nlines = 2; + linearray = (char **) xmalloc (nlines * sizeof (char *)); + + /* `nextline' points to the next free slot in this array. + `nlines' is the allocated size. */ + + nextline = linearray; + + /* Parse the input file's data, and make entries for the lines. */ + + nextline = parsefile (infile, nextline, file_data, file_size); + if (nextline == 0) + { + error ("%s: not a texinfo index file", infile); + return; + } + + /* Sort the lines. */ + + /* If we have enough space, find the first keyfield of each line in advance. + Make a `struct lineinfo' for each line, which records the keyfield + as well as the line, and sort them. */ + + lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo)); + + if (lineinfo) + { + struct lineinfo *lp; + char **p; + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + { + lp->text = *p; + lp->key.text = find_field (keyfields, *p, &lp->keylen); + if (keyfields->numeric) + lp->key.number = find_value (lp->key.text, lp->keylen); + } + + qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared); + + for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) + *p = lp->text; + + free (lineinfo); + } + else + qsort (linearray, nextline - linearray, sizeof (char *), compare_full); + + /* Open the output file. */ + + if (outfile) + { + ostream = fopen (outfile, "w"); + if (!ostream) + pfatal_with_name (outfile); + } + + writelines (linearray, nextline - linearray, ostream); + if (outfile) + fclose (ostream); + + free (linearray); + free (data); +} + +/* Parse an input string in core into lines. + DATA is the input string, and SIZE is its length. + Data goes in LINEARRAY starting at NEXTLINE. + The value returned is the first entry in LINEARRAY still unused. + Value 0 means input file contents are invalid. */ + +char ** +parsefile (filename, nextline, data, size) + char *filename; + char **nextline; + char *data; + long size; +{ + char *p, *end; + char **line = nextline; + + p = data; + end = p + size; + *end = 0; + + while (p != end) + { + if (p[0] != '\\' && p[0] != '@') + return 0; + + *line = p; + while (*p && *p != '\n') + p++; + if (p != end) + p++; + + line++; + if (line == linearray + nlines) + { + char **old = linearray; + linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4)); + line += linearray - old; + } + } + + return line; +} + +/* Indexification is a filter applied to the sorted lines + as they are being written to the output file. + Multiple entries for the same name, with different page numbers, + get combined into a single entry with multiple page numbers. + The first braced field, which is used for sorting, is discarded. + However, its first character is examined, folded to lower case, + and if it is different from that in the previous line fed to us + a \initial line is written with one argument, the new initial. + + If an entry has four braced fields, then the second and third + constitute primary and secondary names. + In this case, each change of primary name + generates a \primary line which contains only the primary name, + and in between these are \secondary lines which contain + just a secondary name and page numbers. */ + +/* The last primary name we wrote a \primary entry for. + If only one level of indexing is being done, this is the last name seen. */ +char *lastprimary; +/* Length of storage allocated for lastprimary. */ +int lastprimarylength; + +/* Similar, for the secondary name. */ +char *lastsecondary; +int lastsecondarylength; + +/* Zero if we are not in the middle of writing an entry. + One if we have written the beginning of an entry but have not + yet written any page numbers into it. + Greater than one if we have written the beginning of an entry + plus at least one page number. */ +int pending; + +/* The initial (for sorting purposes) of the last primary entry written. + When this changes, a \initial {c} line is written */ + +char *lastinitial; + +int lastinitiallength; + +/* When we need a string of length 1 for the value of lastinitial, + store it here. */ + +char lastinitial1[2]; + +/* Initialize static storage for writing an index. */ + +static void +xbzero(s, n) + char *s; + int n; +{ + register char *p; + for (p = s; n--; ) + *p++ = '\0'; +} + +void +init_index () +{ + pending = 0; + lastinitial = lastinitial1; + lastinitial1[0] = 0; + lastinitial1[1] = 0; + lastinitiallength = 0; + lastprimarylength = 100; + lastprimary = (char *) xmalloc (lastprimarylength + 1); + xbzero (lastprimary, lastprimarylength + 1); + lastsecondarylength = 100; + lastsecondary = (char *) xmalloc (lastsecondarylength + 1); + xbzero (lastsecondary, lastsecondarylength + 1); +} + +/* Indexify. Merge entries for the same name, + insert headers for each initial character, etc. */ + +void +indexify (line, ostream) + char *line; + FILE *ostream; +{ + char *primary, *secondary, *pagenumber; + int primarylength, secondarylength = 0, pagelength; + int nosecondary; + int initiallength; + char *initial; + char initial1[2]; + register char *p; + + /* First, analyze the parts of the entry fed to us this time. */ + + p = find_braced_pos (line, 0, 0, 0); + if (*p == '{') + { + initial = p; + /* Get length of inner pair of braces starting at `p', + including that inner pair of braces. */ + initiallength = find_braced_end (p + 1) + 1 - p; + } + else + { + initial = initial1; + initial1[0] = *p; + initial1[1] = 0; + initiallength = 1; + + if (initial1[0] >= 'a' && initial1[0] <= 'z') + initial1[0] -= 040; + } + + pagenumber = find_braced_pos (line, 1, 0, 0); + pagelength = find_braced_end (pagenumber) - pagenumber; + if (pagelength == 0) + abort (); + + primary = find_braced_pos (line, 2, 0, 0); + primarylength = find_braced_end (primary) - primary; + + secondary = find_braced_pos (line, 3, 0, 0); + nosecondary = !*secondary; + if (!nosecondary) + secondarylength = find_braced_end (secondary) - secondary; + + /* If the primary is different from before, make a new primary entry. */ + if (strncmp (primary, lastprimary, primarylength)) + { + /* Close off current secondary entry first, if one is open. */ + if (pending) + { + fputs ("}\n", ostream); + pending = 0; + } + + /* If this primary has a different initial, include an entry for + the initial. */ + if (initiallength != lastinitiallength || + strncmp (initial, lastinitial, initiallength)) + { + fprintf (ostream, "\\initial {"); + fwrite (initial, 1, initiallength, ostream); + fprintf (ostream, "}\n", initial); + if (initial == initial1) + { + lastinitial = lastinitial1; + *lastinitial1 = *initial1; + } + else + { + lastinitial = initial; + } + lastinitiallength = initiallength; + } + + /* Make the entry for the primary. */ + if (nosecondary) + fputs ("\\entry {", ostream); + else + fputs ("\\primary {", ostream); + fwrite (primary, primarylength, 1, ostream); + if (nosecondary) + { + fputs ("}{", ostream); + pending = 1; + } + else + fputs ("}\n", ostream); + + /* Record name of most recent primary. */ + if (lastprimarylength < primarylength) + { + lastprimarylength = primarylength + 100; + lastprimary = (char *) xrealloc (lastprimary, + 1 + lastprimarylength); + } + strncpy (lastprimary, primary, primarylength); + lastprimary[primarylength] = 0; + + /* There is no current secondary within this primary, now. */ + lastsecondary[0] = 0; + } + + /* Should not have an entry with no subtopic following one with a subtopic. */ + + if (nosecondary && *lastsecondary) + error ("entry %s follows an entry with a secondary name", line); + + /* Start a new secondary entry if necessary. */ + if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength)) + { + if (pending) + { + fputs ("}\n", ostream); + pending = 0; + } + + /* Write the entry for the secondary. */ + fputs ("\\secondary {", ostream); + fwrite (secondary, secondarylength, 1, ostream); + fputs ("}{", ostream); + pending = 1; + + /* Record name of most recent secondary. */ + if (lastsecondarylength < secondarylength) + { + lastsecondarylength = secondarylength + 100; + lastsecondary = (char *) xrealloc (lastsecondary, + 1 + lastsecondarylength); + } + strncpy (lastsecondary, secondary, secondarylength); + lastsecondary[secondarylength] = 0; + } + + /* Here to add one more page number to the current entry. */ + if (pending++ != 1) + fputs (", ", ostream); /* Punctuate first, if this is not the first. */ + fwrite (pagenumber, pagelength, 1, ostream); +} + +/* Close out any unfinished output entry. */ + +void +finish_index (ostream) + FILE *ostream; +{ + if (pending) + fputs ("}\n", ostream); + free (lastprimary); + free (lastsecondary); +} + +/* Copy the lines in the sorted order. + Each line is copied out of the input file it was found in. */ + +void +writelines (linearray, nlines, ostream) + char **linearray; + int nlines; + FILE *ostream; +{ + char **stop_line = linearray + nlines; + char **next_line; + + init_index (); + + /* Output the text of the lines, and free the buffer space. */ + + for (next_line = linearray; next_line != stop_line; next_line++) + { + /* If -u was specified, output the line only if distinct from previous one. */ + if (next_line == linearray + /* Compare previous line with this one, using only the + explicitly specd keyfields. */ + || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1)) + { + char *p = *next_line; + char c; + + while ((c = *p++) && c != '\n') + /* Do nothing. */ ; + *(p - 1) = 0; + indexify (*next_line, ostream); + } + } + + finish_index (ostream); +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This is the high-level interface that can handle an unlimited + number of files. */ + +#define MAX_DIRECT_MERGE 10 + +int +merge_files (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + char **tempfiles; + int ntemps; + int i; + int value = 0; + int start_tempcount = tempcount; + + if (nfiles <= MAX_DIRECT_MERGE) + return merge_direct (infiles, nfiles, outfile); + + /* Merge groups of MAX_DIRECT_MERGE input files at a time, + making a temporary file to hold each group's result. */ + + ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE; + tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); + for (i = 0; i < ntemps; i++) + { + int nf = MAX_DIRECT_MERGE; + if (i + 1 == ntemps) + nf = nfiles - i * MAX_DIRECT_MERGE; + tempfiles[i] = maketempname (++tempcount); + value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]); + } + + /* All temporary files that existed before are no longer needed + since their contents have been merged into our new tempfiles. + So delete them. */ + flush_tempfiles (start_tempcount); + + /* Now merge the temporary files we created. */ + + merge_files (tempfiles, ntemps, outfile); + + free (tempfiles); + + return value; +} + +/* Assume (and optionally verify) that each input file is sorted; + merge them and output the result. + Returns nonzero if any input file fails to be sorted. + + This version of merging will not work if the number of + input files gets too high. Higher level functions + use it only with a bounded number of input files. */ + +int +merge_direct (infiles, nfiles, outfile) + char **infiles; + int nfiles; + char *outfile; +{ + struct linebuffer *lb1, *lb2; + struct linebuffer **thisline, **prevline; + FILE **streams; + int i; + int nleft; + int lossage = 0; + int *file_lossage; + struct linebuffer *prev_out = 0; + FILE *ostream = stdout; + + if (outfile) + { + ostream = fopen (outfile, "w"); + } + if (!ostream) + pfatal_with_name (outfile); + + init_index (); + + if (nfiles == 0) + { + if (outfile) + fclose (ostream); + return 0; + } + + /* For each file, make two line buffers. + Also, for each file, there is an element of `thisline' + which points at any time to one of the file's two buffers, + and an element of `prevline' which points to the other buffer. + `thisline' is supposed to point to the next available line from the file, + while `prevline' holds the last file line used, + which is remembered so that we can verify that the file is properly sorted. */ + + /* lb1 and lb2 contain one buffer each per file. */ + lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); + + /* thisline[i] points to the linebuffer holding the next available line in file i, + or is zero if there are no lines left in that file. */ + thisline = (struct linebuffer **) + xmalloc (nfiles * sizeof (struct linebuffer *)); + /* prevline[i] points to the linebuffer holding the last used line + from file i. This is just for verifying that file i is properly + sorted. */ + prevline = (struct linebuffer **) + xmalloc (nfiles * sizeof (struct linebuffer *)); + /* streams[i] holds the input stream for file i. */ + streams = (FILE **) xmalloc (nfiles * sizeof (FILE *)); + /* file_lossage[i] is nonzero if we already know file i is not + properly sorted. */ + file_lossage = (int *) xmalloc (nfiles * sizeof (int)); + + /* Allocate and initialize all that storage. */ + + for (i = 0; i < nfiles; i++) + { + initbuffer (&lb1[i]); + initbuffer (&lb2[i]); + thisline[i] = &lb1[i]; + prevline[i] = &lb2[i]; + file_lossage[i] = 0; + streams[i] = fopen (infiles[i], "r"); + if (!streams[i]) + pfatal_with_name (infiles[i]); + + readline (thisline[i], streams[i]); + } + + /* Keep count of number of files not at eof. */ + nleft = nfiles; + + while (nleft) + { + struct linebuffer *best = 0; + struct linebuffer *exch; + int bestfile = -1; + int i; + + /* Look at the next avail line of each file; choose the least one. */ + + for (i = 0; i < nfiles; i++) + { + if (thisline[i] && + (!best || + 0 < compare_general (best->buffer, thisline[i]->buffer, + (long) bestfile, (long) i, num_keyfields))) + { + best = thisline[i]; + bestfile = i; + } + } + + /* Output that line, unless it matches the previous one and we + don't want duplicates. */ + + if (!(prev_out && + !compare_general (prev_out->buffer, + best->buffer, 0L, 1L, num_keyfields - 1))) + indexify (best->buffer, ostream); + prev_out = best; + + /* Now make the line the previous of its file, and fetch a new + line from that file. */ + + exch = prevline[bestfile]; + prevline[bestfile] = thisline[bestfile]; + thisline[bestfile] = exch; + + while (1) + { + /* If the file has no more, mark it empty. */ + + if (feof (streams[bestfile])) + { + thisline[bestfile] = 0; + /* Update the number of files still not empty. */ + nleft--; + break; + } + readline (thisline[bestfile], streams[bestfile]); + if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) + break; + } + } + + finish_index (ostream); + + /* Free all storage and close all input streams. */ + + for (i = 0; i < nfiles; i++) + { + fclose (streams[i]); + free (lb1[i].buffer); + free (lb2[i].buffer); + } + free (file_lossage); + free (lb1); + free (lb2); + free (thisline); + free (prevline); + free (streams); + + if (outfile) + fclose (ostream); + + return lossage; +} + +/* Print error message and exit. */ + +void +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + exit (TI_FATAL_ERROR); +} + +/* Print error message. S1 is printf control string, S2 is arg for it. */ + +void +error (s1, s2) + char *s1, *s2; +{ + printf ("%s: ", program_name); + printf (s1, s2); + printf ("\n"); +} + +#if !defined (HAVE_STRERROR) +static char * +strerror (n) + int n; +{ + static char ebuf[40]; + + if (n < sys_nerr) + return sys_errlist[n]; + else + { + sprintf (ebuf, "Unknown error %d", n); + return ebuf; + } +} +#endif + +void +perror_with_name (name) + char *name; +{ + char *s; + + s = concat ("", strerror (errno), " for %s"); + error (s, name); +} + +void +pfatal_with_name (name) + char *name; +{ + char *s; + + s = concat ("", strerror (errno), " for %s"); + fatal (s, name); +} + +/* Return a newly-allocated string whose contents concatenate those of + S1, S2, S3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +/* Just like malloc, but kills the program in case of fatal error. */ +void * +xmalloc (nbytes) + int nbytes; +{ + void *temp = (void *) malloc (nbytes); + + if (nbytes && temp == (void *)NULL) + memory_error ("xmalloc", nbytes); + + return (temp); +} + +/* Like realloc (), but barfs if there isn't enough memory. */ +void * +xrealloc (pointer, nbytes) + void *pointer; + int nbytes; +{ + void *temp; + + if (!pointer) + temp = (void *)xmalloc (nbytes); + else + temp = (void *)realloc (pointer, nbytes); + + if (nbytes && !temp) + memory_error ("xrealloc", nbytes); + + return (temp); +} + +memory_error (callers_name, bytes_wanted) + char *callers_name; + int bytes_wanted; +{ + char printable_string[80]; + + sprintf (printable_string, + "Virtual memory exhausted in %s ()! Needed %d bytes.", + callers_name, bytes_wanted); + + error (printable_string, ""); + abort (); +} diff --git a/lib/readline/emacs_keymap.c b/lib/readline/emacs_keymap.c 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 +#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 +#include +#include +#include +#include + +#include +#include + +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 +#include + + +/* **************************************************************** */ +/* */ +* 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 +#endif /* BUFSIZ */ + +#if defined (HAVE_STDLIB_H) +# include +#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 +#include +#include +#include +#include +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ +#include + +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "memalloc.h" +#include "history.h" + +#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 + +#if defined (HAVE_UNISTD_H) +# include +#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 +#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 +#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 +# else /* !IBMESA */ +# include +# endif /* !IBMESA */ +# else +extern char *alloca (); +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/lib/readline/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 +#include +#if defined (FD_SET) +# include +#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 . + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include + +#if defined (isc386) +# if !defined (S_IFDIR) +# define S_IFDIR 0040000 +# endif /* !S_IFDIR */ +# if !defined (S_IFMT) +# define S_IFMT 0170000 +# endif /* !S_IFMT */ +#endif /* isc386 */ + +/* This text is taken directly from the Cadmus I was trying to + compile on: + the following MACROs are defined for X/OPEN compatibility + however, is the param correct ?? + #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) + + Well, the answer is no. Thus... */ +#if defined (BrainDeath) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 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 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 +#include +#include +#if !defined (NO_SYS_FILE) +# include +#endif /* !NO_SYS_FILE */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) || (defined (VSTATUS) && !defined (SunOS4)) +# include +#endif /* GWINSZ_IN_SYS_IOCTL || VSTATUS */ + +/* 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 +# 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 . */ + 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 +# include +#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 +#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 +# if !defined (TCOON) +# define TCOON 1 +# endif +# endif /* USG || hpux || Xenix || sgi || DUGX || HAVE_TERMIO_H */ +#endif /* !_POSIX_VERSION */ + +/* Posix systems use termios and the Posix signal functions. */ +#if defined (_POSIX_VERSION) +# if !defined (TERMIOS_MISSING) +# undef NEW_TTY_DRIVER +# define TERMIOS_TTY_DRIVER +# include +# endif /* !TERMIOS_MISSING */ +# define HAVE_POSIX_SIGNALS +# if !defined (O_NDELAY) +# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ +# endif /* O_NDELAY */ +#endif /* _POSIX_VERSION */ + +/* System V.3 machines have the old 4.1 BSD `reliable' signal interface. */ +#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) +# if defined (USGr3) && !defined (XENIX_22) +# if !defined (HAVE_USG_SIGHOLD) +# define HAVE_USG_SIGHOLD +# endif /* !HAVE_USG_SIGHOLD */ +# endif /* USGr3 && !XENIX_22 */ +#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ + +/* Other (BSD) machines use sgtty. */ +#if defined (NEW_TTY_DRIVER) +# include +#endif + +#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) +# if !defined (HAVE_DIRENT_H) +# define HAVE_DIRENT_H +# endif /* !HAVE_DIRENT_H */ +#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ + +#if defined (HAVE_DIRENT_H) +# include +# define D_NAMLEN(d) strlen ((d)->d_name) +#else /* !HAVE_DIRENT_H */ +# define D_NAMLEN(d) ((d)->d_namlen) +# if defined (USG) +# if defined (Xenix) +# include +# else /* !Xenix (but USG...) */ +# include "ndir.h" +# endif /* !Xenix */ +# else /* !USG */ +# include +# endif /* !USG */ +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +#endif /* !HAVE_DIRENT_H */ + +#if defined (USG) && defined (TIOCGWINSZ) && !defined (Linux) +# if defined (HAVE_SYS_STREAM_H) +# include +# endif /* HAVE_SYS_STREAM_H */ +# if defined (HAVE_SYS_PTEM_H) +# include +# endif /* HAVE_SYS_PTEM_H */ +# if defined (HAVE_SYS_PTE_H) +# include +# endif /* HAVE_SYS_PTE_H */ +#endif /* USG && TIOCGWINSZ && !Linux */ + +/* Posix macro to check file in statbuf for directory-ness. + This requires that 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 +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#if defined (HAVE_VARARGS_H) +# include +#endif /* HAVE_VARARGS_H */ + +/* This is needed to include support for TIOCGWINSZ and window resizing. */ +#if defined (OSF1) || defined (BSD386) || defined (NetBSD) || \ + defined (__BSD_4_4__) || defined (FreeBSD) || defined (_386BSD) || \ + defined (AIX) +# define GWINSZ_IN_SYS_IOCTL +#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 +#include +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#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 +# 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 +#include + +#if defined (HAVE_UNISTD_H) +# include +#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 +#include +#include +#if !defined (NO_SYS_FILE) +# include +#endif /* !NO_SYS_FILE */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include +#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 +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "tilde.h" +#include +#include + +#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 + +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 +#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 + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +/* 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 + +#if defined (HAVE_STDLIB_H) +# include +#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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. + + , 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 < 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 +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 +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 +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 < +#include +#include +#include +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 ' > 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 < +#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 </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 '.\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 '.\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 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 . + % + \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 to achieve this: TeX expands \the only once, +% simply yielding the contents of the . +\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 +#include +#else +char *getenv (); +char *malloc (); +char *realloc (); +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef _POSIX_VERSION +#include +#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 +#include +#include + +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 + +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 +#include +#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 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 +# else /* !IBMESA */ +# include +# endif /* !IBMESA */ +# else +extern char *alloca (); +# endif /* !HAVE_ALLOCA_H */ +#endif /* !__GNUC__ */ + +#endif /* !BUILDING_MAKEFILE */ + +#endif /* __MEMALLOC_H__ */ diff --git a/lib/tilde/tilde.c b/lib/tilde/tilde.c 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 +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "tilde.h" +#include +#include + +#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 + +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 ). */ +# if !defined (done386) && defined (Xenix386) +# define done386 +# define M_MACHINE "i386" +# define M_OS "Xenix" +# define XENIX_CFLAGS -DUSG -DUSGr3 -DMEMMOVE_MISSING + +# if defined (XENIX_22) +# define XENIX_EXTRA -DREVERSED_SETVBUF_ARGS +# define REQUIRED_LIBRARIES -lx +# else /* !XENIX_22 */ +# define HAVE_DIRENT +# if defined (XENIX_23) +# define XENIX_EXTRA -DLD_HAS_NO_DASH_L +# define REQUIRED_LIBRARIES -ldir +# else /* !XENIX_23 */ +# define XENIX_EXTRA -xenix +# define SYSDEP_LDFLAGS -xenix +# define REQUIRED_LIBRARIES -ldir -l2.3 +# endif /* !XENIX_23 */ +# endif /* !XENIX_22 */ + +# define SYSDEP_CFLAGS XENIX_CFLAGS XENIX_EXTRA +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define ALLOCA_ASM x386-alloca.s +# define ALLOCA_OBJ x386-alloca.o +# undef HAVE_ALLOCA +# undef HAVE_GETWD +# undef HAVE_RESOURCE +# endif /* Xenix386 */ + +/* SCO UNIX 3.2 chip@count.tct.com (Chip Salzenberg) */ +# if !defined (done386) && defined (M_UNIX) +# define done386 +# define M_MACHINE "i386" +# define M_OS "SCO" +# define SCO_CFLAGS -DUSG -DUSGr3 -DPGRP_PIPE +# if defined (SCOv4) || defined (SCOv5) +# define SYSDEP_CFLAGS SCO_CFLAGS -DWAITPID_BROKEN +# else /* !SCOv4 && !SCOv5 */ +# define SYSDEP_CFLAGS SCO_CFLAGS -DOPENDIR_NOT_ROBUST -DMUST_UNBLOCK_CHILD +# endif /* !SCOv4 && !SCOv5 */ +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# undef HAVE_GETWD +# undef HAVE_RESOURCE +/* advice from wbader@cess.lehigh.edu and Eduard.Vopicka@vse.cz */ +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lc_s -lc -lPW +# else +# define REQUIRED_LIBRARIES -lc_s -lc +# endif /* !HAVE_GCC */ +# endif /* SCO Unix on 386 boxes. */ + +# if !defined (done386) && defined (__OSF1__) +# define done386 +# define M_MACHINE "i386" +# define M_OS "OSF1" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define HAVE_GETGROUPS +# define VOID_SIGHANDLER +# define HAVE_BCOPY +# define USE_TERMCAP_EMULATION +# define SYSDEP_CFLAGS -D_BSD +# define REQUIRED_LIBRARIES -lbsd +# endif /* OSF/1 */ + +/* BSDI BSD/OS running on a 386 or 486. */ +# if !defined (done386) && defined (__bsdi__) +# define done386 +# define M_MACHINE "i386" +# if defined (BSDI2) +# define M_OS "BSD_OS" +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DRLIMTYPE=quad_t +# else +# define M_OS "BSD386" +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY +# endif +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +# endif /* !done386 && bsdi */ + +/* NetBSD running on a 386 or 486. */ +# if !defined (done386) && defined (__NetBSD__) +# define done386 +# define M_MACHINE "i386" +# define M_OS "NetBSD" +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ + -DRLIMTYPE=quad_t +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +# endif /* !done386 && __NetBSD__ */ + +/* FreeBSD running on a 386 or 486. */ +# if !defined (done386) && defined (__FreeBSD__) +# define done386 +# define M_MACHINE "i386" +# define M_OS "FreeBSD" +# if __FreeBSD__ > 1 +# define SYSDEP_CFLAGS -D__BSD_4_4__ -DRLIMTYPE=quad_t +# else +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY +# endif +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +# define GCC_STANDARD +# endif /* !done386 && __FreeBSD__ */ + +/* Jolitz 386BSD running on a 386 or 486. */ +# if !defined (done386) && defined (__386BSD__) +# define done386 +# define M_MACHINE "i386" +# define M_OS "_386BSD" +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +# endif /* !done386 && __386BSD__ */ + +# if !defined (done386) && (defined (__linux__) || defined (linux)) +# define done386 +# define M_MACHINE "i386" +# define M_OS "Linux" +# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY \ + -DHAVE_GETPW_DECLS -DHAVE_GETHOSTNAME +# define REQUIRED_LIBRARIES +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define HAVE_VARARGS_H +# define SEARCH_LIB_NEEDS_SPACE +# if defined (__GNUC__) +# define HAVE_FIXED_INCLUDES +# endif /* __GNUC__ */ +# undef USE_GNU_MALLOC +# undef HAVE_SETLINEBUF +# undef HAVE_GETWD +# endif /* !done386 && __linux__ */ + +/* QNX 4.2 with GCC pt@flard.ocunix.on.ca (Paul Trunley) */ +# if !defined (done386) && defined (qnx) +# define done386 +# define M_MACHINE "i386" +# define M_OS "QNX" +# define SYSDEP_CFLAGS -D_POSIX_SOURCE -O2 -DUSG +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GCC +# define HAVE_FIXED_INCLUDES +# define HAVE_STRERROR +# define HAVE_GETGROUPS +# undef USE_GNU_MALLOC +# endif /* QNX 4.2 with GCC */ + +/* Lynx 2.1.0 (Mike Brennen ) */ +# if !defined (done386) && (defined (__Lynx__) || defined (Lynx)) +# define done386 +# define M_MACHINE "i386" +# define M_OS "Lynx" +# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY +# define REQUIRED_LIBRARIES -lc_p +# define HAVE_GETGROUPS +# define VOID_SIGHANDLER +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define HAVE_VARARGS_H +# if defined (__GNUC__) +# define HAVE_FIXED_INCLUDES +# endif /* __GNUC__ */ +/* Actually, Lynx does have unistd.h, but it defines _POSIX_VERSION, + and doesn't supply a fully compatible job control package. We just + pretend that it doesn't have it. */ +# undef HAVE_UNISTD_H +/* Lynx's wait structure reverses w_Stopval and w_Stopsig - don't use it */ +# undef HAVE_WAIT_H +# undef HAVE_DIRENT_H +# endif /* !done386 && __Lynx__ */ + +/* Assume a generic 386 running Sys V Release 3. */ +# if !defined (done386) +# define done386 +# define M_MACHINE "i386" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSGr3 +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER + /* Alloca requires either Gcc or cc with libPW.a */ +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lPW +# endif /* !HAVE_GCC */ +# undef HAVE_GETWD +# endif /* Generic i386 Box running Sys V release 3. */ +#endif /* All i386 Machines with an `i386' define in cpp. */ + +/* **************************************************************** */ +/* */ +/* Alliant FX/800 */ +/* */ +/* **************************************************************** */ +/* Original descs flushed. FX/2800 machine desc 1.13 bfox@ai.mit.edu. + Do NOT use -O with the stock compilers. If you must optimize, use + -uniproc with fxc, and avoid using scc. */ +#if defined (alliant) +# define M_MACHINE "alliant" +# define M_OS "Concentrix" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_RESOURCE +# define VOID_SIGHANDLER +# define HAVE_STRERROR +# define USE_GNU_MALLOC +# define LD_HAS_NO_DASH_L +# define SYSDEP_CFLAGS -DTERMIOS_MISSING -DMKFIFO_MISSING \ + -DBSD_GETPGRP -DRLOGIN_PGRP_BUG -w + /* Actually, Alliant does have unistd.h, but it defines _POSIX_VERSION, + and doesn't supply a fully compatible job control package. We just + pretend that it doesn't have it. */ +# undef HAVE_UNISTD_H +# undef HAVE_ALLOCA +#endif /* alliant */ + +/* ********************* */ +/* */ +/* Linux/m68k */ +/* */ +/* ********************* */ +#if defined (mc68000) && (defined (__linux__) || defined (linux)) +# define M_MACHINE "m68k" +# define M_OS "Linux" +# define SYSDEP_CFLAGS -DHAVE_BCOPY -DHAVE_GETPW_DECLS -DHAVE_GETHOSTNAME +# define REQUIRED_LIBRARIES +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define HAVE_VARARGS_H +# if defined (__GNUC__) +# define HAVE_FIXED_INCLUDES +# endif /* __GNUC__ */ +# undef USE_GNU_MALLOC +# undef HAVE_SETLINEBUF +# define HAVE_STRCASECMP +#endif /* mc68000 && __linux__ */ + +/* **************************************************************** */ +/* */ +/* Motorola Delta series running System V R3V6/7 */ +/* */ +/* **************************************************************** */ +/* Contributed by Robert L. McMillin (rlm@ms_aspen.hac.com). */ + +#if defined (m68k) && defined (sysV68) +# define M_MACHINE "Delta" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSGr3 -DMEMMOVE_MISSING +# define VOID_SIGHANDLER +# define HAVE_VFPRINTF +# define REQUIRED_LIBRARIES -lm881 +# undef HAVE_GETWD +# undef HAVE_RESOURCE +# undef HAVE_DUP2 +# undef HAVE_ALLOCA +#endif /* Delta series */ + +/* **************************************************************** */ +/* */ +/* Gould 9000 - UTX/32 R2.1A */ +/* */ +/* **************************************************************** */ +#if defined (gould) /* Maybe should be GOULD_PN ? */ +# define M_MACHINE "gould" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +#endif /* gould */ + +/* ************************ */ +/* */ +/* NeXT */ +/* */ +/* ************************ */ +#if defined (NeXT) && !defined (M_MACHINE) +# define M_MACHINE "NeXT" +# define M_OS "NeXTstep" +# define HAVE_VFPRINTF +# define HAVE_SYS_SIGLIST +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# if !defined (HAVE_RESOURCE) +# define HAVE_RESOURCE +# endif +# define HAVE_STRCASECMP +# define GCC_STANDARD +# undef HAVE_GETWD +# undef HAVE_GETCWD +# undef HAVE_DIRENT_H +# define SYSDEP_CFLAGS -DMKFIFO_MISSING -DRLOGIN_PGRP_BUG +# undef USE_GNU_MALLOC +#endif /* NeXT */ + +/* ********************** */ +/* */ +/* m68k NetBSD */ +/* */ +/* ********************** */ +#if defined (m68k) && defined (__NetBSD__) +# include +# define M_MACHINE MACHINE +# define M_OS "NetBSD" +/* os/netbsd.h */ +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ + -DRLIMTYPE=quad_t +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +#endif /* m68k && __NetBSD__ */ + +/* ************************ */ +/* */ +/* hp9000 4.4 BSD */ +/* */ +/* ************************ */ +#if defined (hp9000) && defined (__BSD_4_4__) +# define M_MACHINE "hp9000" +# define M_OS "BSD_4_4" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_STRCASECMP +# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY -DHAVE_RESOURCE +# undef HAVE_ALLOCA +#endif /* hp9000 && __BSD_4_4__ */ + +/* ************************ */ +/* */ +/* hp9000 4.3 BSD */ +/* */ +/* ************************ */ +#if defined (hp9000) && !defined (hpux) && !defined (M_MACHINE) +# define M_MACHINE "hp9000" +# define M_OS "Bsd" +# undef HAVE_ALLOCA +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define USE_VFPRINTF_EMULATION +#endif /* hp9000 && !hpux */ + +/* ************************ */ +/* */ +/* hpux */ +/* */ +/* ************************ */ +#if defined (hpux) + +/* HPUX comes in several different flavors, from pre-release 6.2 (basically + straight USG), to Posix compliant 9.0. */ + + /* HP machines come in several processor types. + They are distinguished here. */ +# if defined (hp9000s200) && !defined (hp9000s300) +# define M_MACHINE "hp9000s200" +# endif /* hp9000s200 */ +# if defined (hp9000s300) && !defined (M_MACHINE) +# define M_MACHINE "hp9000s300" +# endif /* hp9000s300 */ +# if defined (hp9000s500) && !defined (M_MACHINE) +# define M_MACHINE "hp9000s500" +# endif /* hp9000s500 */ +# if defined (hp9000s700) && !defined (M_MACHINE) +# define M_MACHINE "hp9000s700" +# endif /* hp9000s700 */ +# if defined (hp9000s800) && !defined (M_MACHINE) +# define M_MACHINE "hp9000s800" +# endif /* hp9000s800 */ +# if defined (hppa) && !defined (M_MACHINE) +# define M_MACHINE "hppa" +# endif /* hppa */ + +/* Define the OS as the particular type that we are using. */ +/* This is for HP-UX systems earlier than HP-UX 6.2 -- no job control. */ +# if defined (HPUX_USG) +# define M_OS "USG" +# define HPUX_CFLAGS -Dhpux +# define REQUIRED_LIBRARIES -lPW -lBSD +# undef HAVE_WAIT_H +# define HPUX_EXTRA +# else /* !HPUX_USG */ + +/* All of the other operating systems need HPUX to be defined. */ +# define HPUX_EXTRA -DHPUX -Dhpux -DHAVE_GETHOSTNAME -DUSG + + /* HPUX 6.2 .. 6.5 require -lBSD for getwd (), and -lPW for alloca (). */ +# if defined (HPUX_6) +# define M_OS "hpux_6" +# define REQUIRED_LIBRARIES -lPW -lBSD +# undef HAVE_ALLOCA +# undef HAVE_WAIT_H +# endif /* HPUX_6 */ + + /* On HP-UX 7.x, we do not link with -lBSD, so we don't have getwd (). */ +# if defined (HPUX_7) +# define M_OS "hpux_7" +# define REQUIRED_LIBRARIES -lPW +# define HPUX_CFLAGS -DHAVE_SOCKETS +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +# endif /* HPUX_7 */ + + /* HP-UX 8.x systems do not have a working alloca () on all platforms. + This can cause us problems, especially when globbing. HP has the + same YP bug as Sun, so we #undef USE_GNU_MALLOC. */ +# if defined (HPUX_8) +# define M_OS "hpux_8" +# if !defined (__GNUC__) +# undef HAVE_ALLOCA +# define HPUX_ANSI +O3 -Aa -D_HPUX_SOURCE +# else +# define HPUX_ANSI +# endif +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS HPUX_ANSI +# endif /* HPUX_8 */ + + /* HP-UX 9.0 reportedly fixes the alloca problems present in the 8.0 + release. If so, -lPW is required to include it. */ +# if defined (HPUX_9) +# define M_OS "hpux_9" +# if !defined (__GNUC__) +# undef HAVE_ALLOCA +# define HPUX_ANSI +O3 -Ae +# else +# define HPUX_ANSI +# endif +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +# undef HAVE_RESOURCE +# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS -DHAVE_GETHOSTNAME HPUX_ANSI +# endif /* HPUX_9 */ + +# if defined (HPUX_10) +# define M_OS "hpux_10" +# if !defined (__GNUC__) +# undef HAVE_ALLOCA +# define HPUX_ANSI +O3 -Ae +# else +# define HPUX_ANSI +# endif +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +# undef HAVE_RESOURCE +# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS -DHAVE_GETHOSTNAME -DBSD_GETPGRP HPUX_ANSI +# endif /* HPUX_9 */ + +# endif /* !HPUX_USG */ + + /* All of the HPUX systems that we have tested have the following. */ +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define USE_TERMCAP_EMULATION +# define SEARCH_LIB_NEEDS_SPACE + +# if defined (HPUX_CFLAGS) +# define SYSDEP_CFLAGS HPUX_CFLAGS HPUX_EXTRA +# else /* !HPUX_CFLAGS */ +# define SYSDEP_CFLAGS HPUX_EXTRA +# endif /* !HPUX_CFLAGS */ + +#endif /* hpux */ + +/* ************************ */ +/* */ +/* MIPS OSF/1 */ +/* */ +/* ************************ */ +# if defined (MIPSEL) && defined (__OSF1__) +# define M_MACHINE "mips" +# define M_OS "OSF1" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define HAVE_GETGROUPS +# define VOID_SIGHANDLER +# define HAVE_BCOPY +# define USE_TERMCAP_EMULATION +# define SYSDEP_CFLAGS -D_BSD +# define REQUIRED_LIBRARIES -lbsd +# endif /* MIPSEL && __OSF1__ */ + +/* ************************ */ +/* */ +/* HP OSF/1 */ +/* */ +/* ************************ */ +#if defined (__hp_osf) +# define M_MACHINE "HPOSF1" +# define M_OS "OSF1" +# define SYSDEP_CFLAGS -q no_sl_enable +# define SYSDEP_LDFLAGS -q lang_level:classic +# define REQUIRED_LIBRARIES -lPW +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# undef HAVE_ALLOCA +#endif /* __hp_osf */ + +/* ************************ */ +/* */ +/* KSR1 OSF/1 */ +/* */ +/* ************************ */ +#if defined (__ksr1__) +# define M_MACHINE "KSR1" +# define M_OS "OSF1" +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY -DHAVE_UID_T +# undef HAVE_ALLOCA +# undef USE_GNU_MALLOC +#endif /* ksr1 */ + +/* ************************ */ +/* */ +/* Intel Paragon - OSF/1 */ +/* */ +/* ************************ */ +#if defined (__i860) && defined (__PARAGON__) +# define M_MACHINE "Paragon" +# define M_OS "OSF1" +# define HAVE_GETGROUPS +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_STRERROR +# define HAVE_SYS_SIGLIST +#endif /* __i860 && __PARAGON__ */ + +/* ************************ */ +/* */ +/* IBM AIX/ESA (OSF/1) */ +/* */ +/* ************************ */ +#if defined(AIXESA) || (defined(__ibmesa) && defined(_AIX)) +# define M_MACHINE "IBMESA" +# define M_OS "OSF1" +# define HAVE_GETGROUPS +# define HAVE_SETLINEBUF +# define HAVE_VPRINTF +# define VOID_SIGHANDLER +# define HAVE_STRERROR +# define HAVE_SYS_SIGLIST +# define HAVE_ALLOCA_H /* hack for AIX/ESA, which has malloc.h */ +# undef USE_GNU_MALLOC +#endif /* AIXESA || (__ibmesa && _AIX) */ + +/* ************************ */ +/* */ +/* Intel i860 -- SVR4 */ +/* */ +/* ************************ */ +#if defined (__i860) && defined (USGr4) && !defined (M_MACHINE) +# define M_MACHINE "i860" +# define M_OS "USG" +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# if !defined (HAVE_GCC) && !defined (HAVE_ALLOCA_H) +# undef HAVE_ALLOCA +# endif /* !HAVE_GCC && !HAVE_ALLOCA_H */ +# if defined (USGr4_2) +# define SYSDEP_CFLAGS -DUSGr4 -DUSGr4_2 +# else +# define SYSDEP_CFLAGS -DUSGr4 +# endif /* ! USGr4_2 */ +# undef HAVE_GETWD +#endif /* __i860 && USGr4 */ + +/* ************************ */ +/* */ +/* Xenix286 */ +/* */ +/* ************************ */ +#if defined (Xenix286) +# define M_MACHINE "i286" +# define M_OS "Xenix" + +# define XENIX_CFLAGS -DUSG -DUSGr3 -DMEMMOVE_MISSING + +# if defined (XENIX_22) +# define XENIX_EXTRA -DREVERSED_SETVBUF_ARGS +# define REQUIRED_LIBRARIES -lx +# else /* !XENIX_22 */ +# define HAVE_DIRENT +# if defined (XENIX_23) +# define XENIX_EXTRA -DLD_HAS_NO_DASH_L +# define REQUIRED_LIBRARIES -ldir +# else /* !XENIX_23 */ +# define XENIX_EXTRA -xenix +# define SYSDEP_LDFLAGS -xenix +# define REQUIRED_LIBRARIES -ldir -l2.3 +# endif /* !XENIX_23 */ +# endif /* !XENIX_22 */ + +# define SYSDEP_CFLAGS XENIX_CFLAGS XENIX_EXTRA +# undef HAVE_ALLOCA +# undef HAVE_GETWD +# undef HAVE_RESOURCE +#endif /* Xenix286 */ + +/* ************************ */ +/* */ +/* convex */ +/* */ +/* ************************ */ +#if defined (convex) +# define M_MACHINE "convex" +# define M_OS "Bsd" +# undef HAVE_ALLOCA +# define HAVE_SETLINEBUF +# define HAVE_SYS_SIGLIST +# define HAVE_GETGROUPS +#endif /* convex */ + +/* ************************ */ +/* */ +/* AIX/RT */ +/* */ +/* ************************ */ +#if defined (aix) && !defined (aixpc) +# define M_MACHINE "AIXRT" +# define M_OS "USG" +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define HAVE_SYS_SIGLIST +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# define USE_TERMCAP_EMULATION +# if !defined (HAVE_GCC) +# undef MACHINE_CFLAGS +# define MACHINE_CFLAGS -a +# endif /* !HAVE_GCC */ +# define SYSDEP_CFLAGS MACHINE_CFLAGS -DNLS -DUSGr3 -DHAVE_BCOPY +# undef USE_GNU_MALLOC +# undef HAVE_ALLOCA +# undef HAVE_RESOURCE +#endif /* aix && !aixpc */ + +/* **************************************** */ +/* */ +/* IBM RISC 6000 */ +/* */ +/* **************************************** */ +#if defined (RISC6000) || defined (_IBMR2) +# define M_MACHINE "RISC6000" +# define M_OS "AIX" +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define USE_TERMCAP_EMULATION +# define HAVE_GETGROUPS +# define SYSDEP_CFLAGS -DNLS -DUSGr3 -DHAVE_BCOPY +# undef HAVE_ALLOCA +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +#endif /* RISC6000 */ + +/* **************************************** */ +/* */ +/* u370 IBM AIX/370 */ +/* */ +/* **************************************** */ +#if defined (u370) +# if defined (_AIX370) +# define M_MACHINE "AIX370" +# define M_OS "Bsd" +# define REQUIRED_LIBRARIES -lbsd +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define SYSDEP_CFLAGS -D_BSD +# define HAVE_GETGROUPS +# define USE_TERMCAP_EMULATION +# undef USE_GNU_MALLOC +# endif /* _AIX370 */ +# if defined (USGr4) /* System V Release 4 on 370 series architecture. */ +# define M_MACHINE "uxp" +# define M_OS "USG" +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define USE_GNU_MALLOC +# define VOID_SIGHANDLER +# if !defined (HAVE_GCC) +# undef HAVE_ALLOCA +# define EXTRA_LIB_SEARCH_PATH /usr/ucblib +# define REQUIRED_LIBRARIES -lc -lucb +# endif /* !HAVE_GCC */ +# define HAVE_GETGROUPS +# define HAVE_RESOURCE +# define SYSDEP_CFLAGS -DUSGr4 -DNO_SBRK_DECL +# endif /* USGr4 */ +#endif /* u370 */ + +/* ************************ */ +/* */ +/* ATT 3B */ +/* */ +/* ************************ */ +#if defined (att3b) || defined (u3b2) +# if defined (att3b) +# define M_MACHINE "att3b" +# define HAVE_SYS_SIGLIST +# else /* !att3b */ +# define M_MACHINE "u3b2" +# endif /* !att3b */ +# define M_OS "USG" +# undef HAVE_GETWD +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER + /* For an AT&T Unix before V.3 take out the -DUSGr3 and the HAVE_DIRENT. */ +# define SYSDEP_CFLAGS -DUSGr3 +# define HAVE_DIRENT + /* Alloca requires either Gcc or cc with libPW.a. */ +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lPW +# endif /* !HAVE_GCC */ +#endif /* att3b */ + +/* ************************ */ +/* */ +/* ATT 386 */ +/* */ +/* ************************ */ +#if defined (att386) +# define M_MACHINE "att386" +# define M_OS "USG" +# undef HAVE_GETWD + /* Alloca requires either Gcc or cc with libPW.a. */ +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lPW +# endif /* HAVE_GCC */ +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER + /* For an AT&T Unix before V.3 take out the -DUSGr3 and the HAVE_DIRENT. */ +# define SYSDEP_CFLAGS -DUSGr3 +# define HAVE_DIRENT +#endif /* att386 */ + +/* ************************ */ +/* */ +/* ATT UNIX PC */ +/* */ +/* ************************ */ +#if defined (unixpc) +# define M_MACHINE "unixpc" +# define M_OS "USG" +# define HAVE_VFPRINTF +# define HAVE_DIRENT +# if defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -ldirent -shlib +# else /* !HAVE_GCC */ +# define REQUIRED_LIBRARIES -ldirent +# endif /* !HAVE_GCC */ +# undef HAVE_GETWD +# undef HAVE_DUP2 +# undef VOID_SIGHANDLER +# undef HAVE_WAIT_H +#endif /* unixpc */ + +/* ************************ */ +/* */ +/* Encore */ +/* */ +/* ************************ */ +#if defined (MULTIMAX) +# if defined (n16) +# define M_MACHINE "Multimax32k" +# else +# define M_MACHINE "Multimax" +# endif /* n16 */ +# if defined (UMAXV) +# define M_OS "USG" +# define REQUIRED_LIBRARIES -lPW +# define SYSDEP_CFLAGS -DUSGr3 +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define USE_TERMCAP_EMULATION +# define VOID_SIGHANDLER +# else +# if defined (CMU) +# define M_OS "Mach" +# else +# define M_OS "Bsd" +# endif /* CMU */ +# define HAVE_SYS_SIGLIST +# define HAVE_STRERROR +# define HAVE_SETLINEBUF +# endif /* UMAXV */ +# define HAVE_GETGROUPS +#endif /* MULTIMAX */ + +/* ******************************************** */ +/* */ +/* Encore Series 91 (88K BCS w Job Control) */ +/* */ +/* ******************************************** */ +#if defined (__m88k) && defined (__UMAXV__) +# define M_MACHINE "Gemini" +# define M_OS "USG" +# define REQUIRED_LIBRARIES -lPW +# define USE_TERMCAP_EMULATION +# define HAVE_DIRENT +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define SYSDEP_CFLAGS -q ext=pcc -D_POSIX_JOB_CONTROL -D_POSIX_VERSION \ + -Dmalloc=_malloc -Dfree=_free -Drealloc=_realloc +#endif /* m88k && __UMAXV__ */ + +/* ******************************************** */ +/* */ +/* System V Release 4 on the ICL DRS6000 */ +/* */ +/* ******************************************** */ +#if defined (drs6000) +# define M_MACHINE "drs6000" +# define M_OS "USG" +# define SYSDEP_CFLAGS -Xa -DUSGr4 +# define SEARCH_LIB_NEEDS_SPACE +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define USE_GNU_TERMCAP +# if !defined (__GNUC__) +# undef HAVE_ALLOCA +# endif +# undef HAVE_ALLOCA_H +# undef USE_GNU_MALLOC +#endif /* drs6000 */ + +/* ******************************************** */ +/* */ +/* System V Release 4 on the Sparc (generic) */ +/* */ +/* ******************************************** */ +#if defined (sparc) && defined (__svr4__) && !defined (M_MACHINE) +# define M_MACHINE "sparc" +# define M_OS "SVR4" +# define SYSDEP_CFLAGS -DUSG -DUSGr4 -DHAVE_UID_T +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define USE_GNU_TERMCAP +# if !defined (__GNUC__) +# undef HAVE_ALLOCA +# endif +# undef HAVE_BCOPY +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +#endif /* sparc && __svr4__ */ + +/* ******************************************** */ +/* */ +/* Commodore Amiga */ +/* */ +/* ******************************************** */ +#if defined (amiga) && defined (__NetBSD__) +# define M_MACHINE "amiga" +# define M_OS "NetBSD" +# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ + -DRLIMTYPE=quad_t +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# define HAVE_DIRENT +# define HAVE_STRCASECMP +#endif /* amiga && __NetBSD__ */ + +#if defined (amiga) && !defined (M_MACHINE) +# define M_MACHINE "amiga" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSGr4 +# if !defined (HAVE_GCC) +# define EXTRA_LIB_SEARCH_PATH /usr/ucblib +# define REQUIRED_LIBRARIES -lc -lucb +# endif /* !HAVE_GCC */ +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# undef HAVE_GETWD +# undef USE_GNU_MALLOC +#endif /* System V Release 4 on amiga */ + +/* ************************ */ +/* */ +/* clipper */ +/* */ +/* ************************ */ +/* This is for the Orion 1/05 (A BSD 4.2 box based on a Clipper processor) */ +#if defined (clipper) && !defined (M_MACHINE) +# define M_MACHINE "clipper" +# define M_OS "Bsd" +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +#endif /* clipper */ + +/* ******************************** */ +/* */ +/* Integrated Solutions 68020? */ +/* */ +/* ******************************** */ +#if defined (is68k) +# define M_MACHINE "is68k" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define USE_VFPRINTF_EMULATION +# undef HAVE_ALLOCA +#endif /* is68k */ + +/* ******************************** */ +/* */ +/* Omron Luna/Mach 2.5 */ +/* */ +/* ******************************** */ +#if defined (luna88k) +# define M_MACHINE "Luna88k" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define USE_GNU_MALLOC +# define HAVE_SETLINEBUF +# define HAVE_VFPRINTF +# define HAVE_GETGROUPS +# define HAVE_VFPRINTF +#endif /* luna88k */ + +/* ************************ */ +/* */ +/* BBN Butterfly GP1000 */ +/* Mach 1000 v2.5 */ +/* */ +/* ************************ */ +#if defined (butterfly) && defined (BFLY1) +#define M_MACHINE "BBN Butterfly" +#define M_OS "Mach 1000" +#define HAVE_SETLINEBUF +#define HAVE_SYS_SIGLIST +#define HAVE_GETGROUPS +#define HAVE_VFPRINTF +# ifdef BUILDING_MAKEFILE +MAKE = make +# endif /* BUILDING_MAKEFILE */ +#endif /* butterfly */ + +/* **************************************** */ +/* */ +/* Apollo/SR10.2/BSD4.3 */ +/* */ +/* **************************************** */ +/* This is for the Apollo DN3500 running SR10.2 BSD4.3 */ +#if defined (apollo) +# define M_MACHINE "apollo" +# define M_OS "Bsd" +# define SYSDEP_CFLAGS -D_POSIX_VERSION -D_INCLUDE_BSD_SOURCE \ + -D_INCLUDE_POSIX_SOURCE -DTERMIOS_MISSING \ + -DBSD_GETPGRP -Dpid_t=int +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +#endif /* apollo */ + +/* ************************ */ +/* */ +/* DG AViiON */ +/* */ +/* ************************ */ +/* This is for the DG AViiON box (runs DG/UX with both AT&T & BSD features.) */ +/* DG/UX comes standard with Gcc. */ +#if defined (__DGUX__) || defined (DGUX) +# define M_OS "DGUX" +# if !defined (_M88KBCS_TARGET) +# define M_MACHINE "AViiON" +# define REQUIRED_LIBRARIES -ldgc +# else /* _M88KBCS_TARGET */ +# define M_MACHINE "m88kBCS_AV" +# undef MACHINE_CFLAGS +# define MACHINE_CFLAGS -D_M88K_SOURCE +# undef HAVE_RESOURCE +# endif /* _M88KBCS_TARGET */ +# define SYSDEP_CFLAGS MACHINE_CFLAGS -D_DGUX_SOURCE -DPGRP_PIPE -DUSG +# define HAVE_GCC +# define HAVE_FIXED_INCLUDES +# define HAVE_STRERROR +# define HAVE_GETGROUPS +# define VOID_SIGHANDLER +# undef HAVE_GETWD +# undef USE_GNU_MALLOC + +/* If you want to build bash for M88K BCS compliance on a DG/UX 5.4 + or above system, do the following: + - If you have built in this directory before run "make clean" to + endure the Bash directory is clean. + - Run "eval `sde-target m88kbcs`" to set the software development + environment to build BCS objects. + - Run "make". + - Do "eval `sde-target default`" to reset the SDE. */ +#endif /* __DGUX__ */ + +/* ************************ */ +/* */ +/* Harris Night Hawk */ +/* */ +/* ************************ */ +/* This is for the Harris Night Hawk family. */ +#if defined (_CX_UX) +# if defined (_M88K) +# define M_MACHINE "nh4000" +# else /* !_M88K */ +# if defined (hcx) +# define M_MACHINE "nh2000" +# else /* !hcx */ +# if defined (gcx) +# define M_MACHINE "nh3000" +# endif /* gcx */ +# endif /* !hcx */ +# endif /* !_M88K */ +# define M_OS "USG" +# define SYSDEP_CFLAGS -g -Xa -v -Dgetwd=bash_getwd -D_POSIX_SOURCE \ + -D_POSIX_JOB_CONTROL +# define USE_TERMCAP_EMULATION +# define HAVE_VFPRINTF +# define HAVE_GETGROUPS +# define VOID_SIGHANDLER +# undef USE_GNU_MALLOC +# undef HAVE_GETWD +#endif /* _CX_UX */ + +/* **************************************** */ +/* */ +/* Tektronix */ +/* */ +/* **************************************** */ +/* These are unproven as yet. */ +#if defined (Tek4132) +# define M_MACHINE "Tek4132" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +#endif /* Tek4132 */ + +#if defined (Tek4300) +# define M_MACHINE "Tek4300" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +#endif /* Tek4300 */ + +/* ************************ */ +/* */ +/* Tektronix XD88 */ +/* */ +/* ************************ */ +#if defined (m88k) && defined (XD88) +# define M_MACHINE "XD88" +# define M_OS "USG" +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define HAVE_GETCWD +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# undef HAVE_GETWD +# undef HAVE_ALLOCA +#endif /* m88k && XD88 */ + +/* ************************ */ +/* */ +/* Motorola M88100 */ +/* */ +/* ************************ */ +#if defined (m88k) && (defined (M88100) || defined (USGr4)) +# define M_MACHINE "M88100" +# define M_OS "USG" +# if defined (USGr4) +# define SYSDEP_CFLAGS -DUSGr4 -D_POSIX_JOB_CONTROL +# else +# define SYSDEP_CFLAGS -D_POSIX_JOB_CONTROL -DWAITPID_BROKEN +# endif +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_GETGROUPS +# undef HAVE_GETWD +# if !defined (USGr4) +# undef HAVE_GETCWD +# endif +# undef HAVE_ALLOCA +#endif /* m88k && M88100 */ + +/* ************************ */ +/* */ +/* Sequent Balances */ +/* (Dynix 3.x) */ +/* ************************ */ +#if defined (sequent) && !defined (M_MACHINE) +# define M_MACHINE "Sequent" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# define LD_HAS_NO_DASH_L +# undef HAVE_DUP2 +#endif /* sequent */ + +/* ****************************************** */ +/* */ +/* NCR Tower 32, System V Release 3 */ +/* */ +/* ****************************************** */ +#if defined (tower32) +# define M_MACHINE "tower32" +# define M_OS "USG" +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lPW + /* Disable stack/frame-pointer optimization, incompatible with alloca */ +# undef MACHINE_CFLAGS +# define MACHINE_CFLAGS -W2,-aat +# endif /* !HAVE_GCC */ +# define SYSDEP_CFLAGS -DUSGr3 MACHINE_CFLAGS +# define HAVE_VFPRINTF +# define USE_TERMCAP_EMULATION +# define VOID_SIGHANDLER +# undef HAVE_GETWD +#endif /* tower32 */ + +/* ************************ */ +/* */ +/* Concurrent */ +/* */ +/* ************************ */ +#if defined (concurrent) +# define M_MACHINE "Concurrent" +# if defined (USE_BSD_UNIVERSE) + /* Use the BSD universe (`universe ucb') */ +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# else /* !USE_BSD_UNIVERSE */ + /* Concurrent 7000 with RTU 6.1A using the ATT universe (`universe att') */ +# define M_OS "USG" +# define SYSDEP_CFLAGS -DHAVE_BCOPY -DHAVE_UID_T -DHAVE_GETDTABLESIZE -Dmc7000 +# define REQUIRED_LIBRARIES -ljobs +# define HAVE_VPRINTF +# define HAVE_GETGROUPS +# define HAVE_DUP2 +# define HAVE_DIRENT +# define HAVE_SYS_SIGLIST +# endif /* !USE_BSD_UNIVERSE */ +#endif /* concurrent */ + +/* **************************************************************** */ +/* */ +/* Honeywell Bull X20 (lele@idea.sublink.org) */ +/* */ +/* **************************************************************** */ +#if defined (hbullx20) +# define M_MACHINE "Honeywell" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSG + /* Bull x20 needs -lposix for struct dirent. */ +# define REQUIRED_LIBRARIES -lPW -lposix +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define USE_TERMCAP_EMULATION +# undef HAVE_GETWD +#endif /* hbullx20 */ + +/* ************************ */ +/* */ +/* CRAY */ +/* */ +/* ************************ */ +#if defined (cray) +# include +# if defined (Cray1) || defined (Cray2) +# define M_MACHINE "Cray" +# define CRAY_STACK +# endif +# if defined (CrayXMP) && !defined (M_MACHINE) +# define M_MACHINE "CrayXMP" +# define CRAY_STACK -DCRAY_STACKSEG_END=getb67 +# endif +# if defined (CrayYMP) && !defined (M_MACHINE) +# define M_MACHINE "CrayYMP" +# if RELEASE_LEVEL >= 7000 +# define CRAY_STACK -DCRAY_STACKSEG_END=_getb67 +# else +# define CRAY_STACK -DCRAY_STACKSEG_END=getb67 +# endif /* RELEASE_LEVEL < 7000 */ +# endif +# if !defined (M_MACHINE) +# define M_MACHINE "Cray" +# define CRAY_STACK +# endif +# define M_OS "Unicos" +# define SYSDEP_CFLAGS -DUSG -DPGRP_PIPE -DOPENDIR_NOT_ROBUST \ + -DHAVE_BCOPY CRAY_STACK +# define HAVE_VFPRINTF +# define HAVE_MULTIPLE_GROUPS +# define VOID_SIGHANDLER +# define USE_TERMCAP_EMULATION +# undef HAVE_ALLOCA +# undef HAVE_RESOURCE +# undef USE_GNU_MALLOC +#endif /* cray */ + +/* ************************ */ +/* */ +/* MagicStation */ +/* */ +/* ************************ */ +#if defined (MagicStation) +# define M_MACHINE "MagicStation" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSGr4 +# define HAVE_DIRENT +# define HAVE_GETGROUPS +# define HAVE_STRERROR +# define VOID_SIGHANDLER +# undef HAVE_ALLOCA +# undef HAVE_GETWD +#endif /* MagicStation */ + +/* ************************ */ +/* */ +/* Plexus */ +/* */ +/* ************************ */ +#if defined (plexus) +# define M_MACHINE "plexus" +# define M_OS "USG" +# define REQUIRED_LIBRARIES -lndir +# define USE_TERMCAP_EMULATION +# undef HAVE_DUP2 +# undef HAVE_GETWD +# define HAVE_VFPRINTF +# undef HAVE_ALLOCA /* -lPW doesn't work w/bash-cc? */ +#endif /* plexus */ + +/* ************************ */ +/* */ +/* Siemens MX500 */ +/* (SINIX 5.2x) */ +/* ************************ */ +#ifdef sinix +#define M_MACHINE "Siemens MX500" +#define M_OS "SINIX V5.2x" +#define USG +#define HAVE_GETCWD +#define VOID_SIGHANDLER +#define HAVE_STRERROR +#define HAVE_GETGROUPS +#define HAVE_VFPRINTF +#define HAVE_POSIX_SIGNALS +#define HAVE_RESOURCE +#define USE_GNU_MALLOC +#define SYSDEP_CFLAGS -DUSGr3 -DUSG +#define REQUIRED_LIBRARIES syscalls.o +#undef HAVE_ALLOCA +#undef HAVE_GETWD +#endif /* sinix */ + +/* ************************ */ +/* */ +/* Symmetric 375 (4.2 BSD) */ +/* */ +/* ************************ */ +#if defined (scs) && !defined (M_MACHINE) +# define M_MACHINE "Symmetric_375" +# define M_OS "Bsd" +# define HAVE_SYS_SIGLIST +# define HAVE_GETGROUPS +# define HAVE_SETLINEBUF +# define USE_VFPRINTF_EMULATION +# define USE_GNU_MALLOC +# undef HAVE_STRCHR +#endif /* scs */ + +/* ************************ */ +/* */ +/* Tandem */ +/* */ +/* ************************ */ +/* I don't know what this is supposed to be (Greg Lehey, LEMIS, 29 May 1995). + * Tandem had two very different machines which ran SVR3: the LXN, based on + * a Motorola 68000, and the S2, based on a MIPS R3000. Both are obsolete + * (well, S2s should now be running NonStop UX version B, which is a flavour + * of SVR4). I'm leaving this here and will test for NonStop UX B with the + * preprocessor variable __nonstopux, which is set by the native compiler and + * should also be set by any other compiler, such as gcc (caveat portor: you'$ + * need to fix gcc config to to get this). */ +#if defined (tandem) && !defined (M_MACHINE) +# define M_MACHINE "tandem" +# define M_OS "USG" +# define SYSDEP_CFLAGS -DUSGr3 +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER + /* Alloca requires either Gcc or cc with libPW.a */ +# if !defined (HAVE_GCC) +# define REQUIRED_LIBRARIES -lPW +# endif /* !HAVE_GCC */ +# undef HAVE_GETWD +#endif /* Tandem running SVR3 */ + +/* This is for NonStop UX Bxx, which is SVR4, but there's a very good + * chance it will trigger on NonStop UX Axx (SVR3). If this happens, + * fix it or upgrade your OS. */ +#if defined (mips) && defined (__nonstopux) /* Integrity, NonStop UX */ +# define M_MACHINE "Integrity" +# define M_OS "NonStop_UX" +# undef HAVE_GETWD +# define HAVE_DIRENT +# define HAVE_STRERROR +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define HAVE_SYS_SIGLIST +# define HAVE_SETLINEBUF +# define HAVE_GETGROUPS +# undef HAVE_ALLOCA +#endif + +/* ****************** */ +/* */ +/* Fujitsu UXP/M */ +/* */ +/* ****************** */ + +#if defined (__uxpm__) +# define M_MACHINE "VP" +# define M_OS "USG" +# define VOID_SIGHANDLER +# define HAVE_POSIX_SIGNALS +# define HAVE_VFPRINTF +# define HAVE_DIRENT +# define HAVE_SETVBUF +# define HAVE_STRCHR +# define HAVE_STRERROR +# define HAVE_GETGROUPS +# define HAVE_DUP2 +# undef HAVE_ALLOCA +# undef HAVE_GETWD +# define HAVE_GETCWD +# define HAVE_SYS_SIGLIST +# define NO_SBRK_DECL +# define SYSDEP_CFLAGS -DHAVE_UID_T -Dsys_siglist=_sys_siglist -DUSGr4 +# define EXTRA_LIB_SEARCH_PATH /usr/ucblib +# define REQUIRED_LIBRARIES -lc -lucb +#endif + +/* ****************** */ +/* */ +/* Amdahl UTS */ +/* */ +/* ****************** */ + +#if defined (UTS) && !defined (M_MACHINE) +# define M_MACHINE "uts" +# define M_OS "systemV" +# define SYSDEP_CFLAGS -DUSG -DMEMMOVE_MISSING +# define REQUIRED_LIBRARIES +# undef HAVE_SYS_SIGLIST +# undef HAVE_GETWD +# undef HAVE_ALLOCA +# define HAVE_VFPRINTF +# define HAVE_DIRENT +# undef HAVE_RESOURCE +#endif /* UTS */ + +/* ************************ */ +/* */ +/* Stratus i860 running FTX (jonathan@sybase.com (Jonathan Stockley)) */ +/* */ +/* ************************ */ +/* Use 'make CPP_DEFINES=-D_FTX' to build as /usr/ccs/lib/cpp doesn't set + anything other than i860 which may be set on other i860 machines. + The C compiler, cc, sets _FTX & i860 but, unfortunately it barfs at stuff + in cpp-Makefile that has a # in it (it has it's own builtin cpp). +*/ +#if defined(_FTX) && defined (i860) && !defined (M_MACHINE) +#define M_MACHINE "Stratus_i860" +#define M_OS "FTX" +#define VOID_SIGHANDLER +#define HAVE_POSIX_SIGNALS +#define HAVE_VFPRINTF +#define HAVE_SETVBUF +#define REVERSED_SETVBUF_ARGS +#define HAVE_STRCHR +#define HAVE_STRERROR +#define HAVE_GETGROUPS +#define HAVE_DUP2 +#undef HAVE_ALLOCA +#undef HAVE_GETWD +#define HAVE_GETCWD +#define HAVE_SYS_SIGLIST +#define SYSDEP_CFLAGS -DHAVE_UID_T -Dsys_siglist=_sys_siglist -DUSGr4 +#define EXTRA_LIB_SEARCH_PATH /usr/ucblib +#define REQUIRED_LIBRARIES -lc -lucb +#endif /* _FTX */ + +/* ************************ */ +/* */ +/* PCS Cadmus System */ +/* */ +/* ************************ */ +#if defined (cadmus) && !defined (M_MACHINE) +# define M_MACHINE "cadmus" +# define M_OS "BrainDeath" +# define SYSDEP_CFLAGS -DUSG +# define HAVE_DIRENT +# define HAVE_VFPRINTF +# define VOID_SIGHANDLER +# define USE_TERMCAP_EMULATION +# undef HAVE_GETWD +# undef HAVE_ALLOCA +# undef HAVE_WAIT_H +#endif /* cadmus */ + +/* **************************************************************** */ +/* */ +/* Generic Entry */ +/* */ +/* **************************************************************** */ + +/* Use this entry for your machine if it isn't represented here. It + is loosely based on a Vax running 4.3 BSD. */ + +#if !defined (M_MACHINE) +# define UNKNOWN_MACHINE +#endif + +#if defined (UNKNOWN_MACHINE) +# define M_MACHINE "UNKNOWN_MACHINE" +# define M_OS "UNKNOWN_OS" + +/* Required libraries for building on this system. */ +# define REQUIRED_LIBRARIES + +/* Define HAVE_SYS_SIGLIST if your system has sys_siglist[]. */ +# define HAVE_SYS_SIGLIST + +/* Undef HAVE_GETWD if your C library does not provide a working version + of getwd(). */ +/* # undef HAVE_GETWD */ + +/* Undef HAVE_GETCWD if your C library does not provide a working version + of getcwd(). */ +/* # undef HAVE_GETCWD */ + +/* Undef HAVE_ALLOCA if you are not using Gcc, and neither your library + nor compiler has a version of alloca (). In that case, we will use + our version of alloca () in alloca.c */ +/* # undef HAVE_ALLOCA */ + +/* Undef USE_GNU_MALLOC if there appear to be library conflicts, or if you + especially desire to use your OS's version of malloc () and friends. We + reccommend against this because GNU Malloc has debugging code built in. */ +/* # undef USE_GNU_MALLOC */ + +/* Define USE_GNU_TERMCAP if you want to use the GNU termcap library + instead of your system termcap library. */ +/* # define USE_GNU_TERMCAP */ + +/* Define HAVE_SETLINEBUF if your machine has the setlinebuf () + stream library call. Otherwise, setvbuf () will be used. If + neither of them work, you can edit in your own buffer control + based upon your machines capabilities. */ +# define HAVE_SETLINEBUF + +/* Define HAVE_VFPRINTF if your machines has the vfprintf () library + call. Otherwise, printf will be used. */ +# define HAVE_VFPRINTF + +/* Define USE_VFPRINTF_EMULATION if you want to use the BSD-compatible + vfprintf() emulation in vprint.c. */ +/* # define USE_VFPRINTF_EMULATION */ + +/* Define HAVE_GETGROUPS if your OS allows you to be in multiple + groups simultaneously by supporting the `getgroups' system call. */ +# define HAVE_GETGROUPS + +/* Define SYSDEP_CFLAGS to be the flags to cc that make your compiler + work. For example, `-ma' on the RT makes alloca () work. */ +/* This is a summary of the semi-machine-independent definitions that + can go into SYSDEP_CFLAGS: + + AFS - The Andrew File System is being used + AFS_CREATE_BUG - AFS has a bug with file creation if O_CREAT is + specified + BSD_GETPGRP - getpgrp(2) takes a pid argument, a la 4.3 BSD + HAVE_BCOPY - bcopy(3) exists and works as in BSD + HAVE_GETDTABLESIZE - getdtablesize(2) exists and works correctly + HAVE_GETHOSTNAME - gethostname(2) or gethostname(3) is present and + works as in BSD + HAVE_GETPW_DECLS - USG machines with the getpw* functions defined in + that cannot handle redefinitions in the + bash source + HAVE_RESOURCE - and [gs]rlimit exist and work + HAVE_SETDTABLESIZE - setdtablesize(2) exists and works correctly + HAVE_SOCKETS - this system has BSD sockets added to a System V base + HAVE_UID_T - Definitions for uid_t and gid_t are in + INT_GROUPS_ARRAY - the second argument to getgroups(3) is an array + of integers + MEMMOVE_MISSING - the system does not have memmove(3) + MKFIFO_MISSING - named pipes do not work or mkfifo(3) is missing + NO_SBRK_DECL - don't declare sbrk as extern char *sbrk() in + lib/malloc/malloc.c + OPENDIR_NOT_ROBUST - opendir(3) allows you to open non-directory files + PGRP_PIPE - Requires parent-child synchronization via pipes to + make job control work right + REVERSED_SETVBUF_ARGS - brain-damaged implementation of setvbuf that + has args 2 and 3 reversed from the SVID and + ANSI standard + RLOGIN_PGRP_BUG - processes started by rlogind have a process group + of 0 + TERMIOS_LDISC - system has a c_line line discipline member in struct + termios + TERMIOS_MISSING - the termios(3) functions are not present or don't + work, even though _POSIX_VERSION is defined + USG - The machine is running some sort of System V Unix + USGr3 - The machine is running SVR3.x + USGr4 - The machine is running SVR4 + USGr4_2 - The machine is running SVR4.2 +*/ +# define SYSDEP_CFLAGS + +/* Define HAVE_STRERROR if your system supplies a definition for strerror () + in the C library, or a macro in a header file. */ +/* # define HAVE_STRERROR */ + +/* Define HAVE_STRCASECMP if your system supplies definitions for the + casel-insensitive string comparison functions strcasecmp and strncasemp + in the C library or one of the system header files. */ +/* # define HAVE_STRCASECMP */ + +/* Define HAVE_DIRENT if you have the dirent library and a definition of + struct dirent. If not, the BSD directory reading library and struct + direct are assumed. */ +/* # define HAVE_DIRENT */ + +/* If your system does not supply /usr/lib/libtermcap.a, but includes + the termcap routines as a part of the curses library, then define + this. This is the case on some System V machines. */ +/* # define USE_TERMCAP_EMULATION */ + +/* Define VOID_SIGHANDLER if your system's signal () returns a pointer to + a function returning void. */ +/* # define VOID_SIGHANDLER */ + +/* Define EXTRA_LIB_SEARCH_PATH if your required libraries (or standard) + ones for that matter) are not normally in the ld search path. For + example, some machines require /usr/ucblib in the ld search path so + that they can use -lucb. */ +/* # define EXTRA_LIB_SEARCH_PATH /usr/ucblib */ + +/* Define SEARCH_LIB_NEEDS_SPACE if your native ld requires a space after + the -L argument, which gives the name of an alternate directory to search + for libraries specified with -llib. For example, the HPUX ld requires + this: + -L lib/readline -lreadline + instead of: + -Llib/readline -lreadline + */ +/* # define SEARCH_LIB_NEEDS_SPACE */ + +/* Define LD_HAS_NO_DASH_L if your ld can't grok the -L flag in any way, or + if it cannot grok the -l flag, or both. */ +/* # define LD_HAS_NO_DASH_L */ + +/* Define GCC_STANDARD if the standard `cc' is gcc and you don't want + to use the compiler named `gcc' for some reason. */ +/* # define GCC_STANDARD */ + +# if defined (LD_HAS_NO_DASH_L) +# undef SEARCH_LIB_NEEDS_SPACE +# endif /* LD_HAS_NO_DASH_L */ + +#endif /* UNKNOWN_MACHINE */ diff --git a/mailcheck.c b/mailcheck.c 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 +#include "bashtypes.h" +#include "posixstat.h" +#include +#include "bashansi.h" +#include "shell.h" +#include "maxpath.h" +#include "execute_cmd.h" +#include + +#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 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 +#include "bashtypes.h" +#include +#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: /* <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: /* 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 +# endif /* BUILDING_MAKEFILE */ +#endif /* !MAXPATHLEN && HAVE_LIMITS_H */ + +#if !defined (MAXPATHLEN) && defined (HAVE_SYS_PARAM) +# include +#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 +# else /* !IBMESA */ +# include +# 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 +#include "posixstat.h" +#include + +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 +#include "bashtypes.h" +#include +#include +#include + +#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 +#else +# if defined (_POSIX_VERSION) +# include +# else +# include +# if !defined (AIXRT) +# include +# 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); +} diff --git a/parse.y b/parse.y new file mode 100644 index 0000000..9c4c75a --- /dev/null +++ b/parse.y @@ -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 +#include "bashtypes.h" +#include +#include "bashansi.h" +#include "shell.h" +#include "flags.h" +#include "input.h" + +#if defined (READLINE) +# include +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bashhist.h" +# include +#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 +#include +#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 ASSIGNMENT_WORD +%token 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 inputunit command pipeline +%type list list0 list1 simple_list simple_list1 +%type simple_command shell_command_1 shell_command select_command +%type group_command function_def if_command elif_clause subshell +%type redirection redirections +%type simple_command_element +%type words pattern +%type 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 \ 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 \ 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 \ 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 + \ 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 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 < /dev/null 2>&1; then + : +else + echo '#undef HAVE_ALLOCA' +fi +rm -f x.c x.o a.out + +cat > x.c << EOF +#include +#include +extern char *getwd(); +main() +{ + getwd(); +} +EOF + +if ${CC} x.c > /dev/null 2>&1; then + echo '#define HAVE_GETWD' +else + echo '#undef HAVE_GETWD' + rm -f x.c x.o a.out + + cat > x.c << EOF +extern char *getcwd(); + +main() +{ + getcwd(); +} +EOF + + if ${CC} x.c >/dev/null 2>&1; then + echo '#define HAVE_GETCWD' + fi +fi +rm -f a.out x.c x.o + +cat > x.c << EOF +/* + * exit 0 if we have bcopy in libc and it works as in BSD + */ + +extern int bcopy(); + +char x[] = "12345"; +char y[] = "67890"; + +main() +{ + bcopy(x, y, 5); + exit(strcmp(x, y)); +} +EOF + +if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then + BC='-DHAVE_BCOPY' +fi + +rm -f x.c x.o a.out + +cat > x.c << EOF +/* + * If this compiles, the system has uid_t and gid_t + */ + +#include + +uid_t u; +gid_t g; + +main() +{ + exit(0); +} +EOF + +if ${CC} x.c > /dev/null 2>&1; then + UIDT='-DHAVE_UID_T' +fi + +rm -f x.c x.o a.out + +cat > x.c < + +extern char *sys_siglist[]; + +main() +{ + char *x; + + x = sys_siglist[3]; + write(2, x, strlen(x)); + exit(0); +} +EOF + +if ${CC} ./x.c >/dev/null 2>&1; then + echo '#define HAVE_SYS_SIGLIST' +else + + cat > x.c < + +extern char *_sys_siglist[]; + +main() +{ + exit(0); +} +EOF + + if ${CC} ./x.c >/dev/null 2>&1; then + echo '#define HAVE_SYS_SIGLIST' + SL='-Dsys_siglist=_sys_siglist' + fi +fi + +PG= +if ${CC} pgrp.c >/dev/null 2>&1; then + PG=`./a.out` +fi + +if [ -f /unix ] && [ -f /usr/ccs/lib/libc.so ]; then + R4="-DUSGr4" +fi + +touch not_a_directory +if [ -f /usr/include/dirent.h ]; then + d='' +else + d='' +fi + +cat > x.c << EOF +/* + * exit 0 if opendir does not check whether its argument is a directory + */ + +#include $d +DIR *dir; + +main() +{ + dir = opendir("not_a_directory"); + exit (dir == 0); +} +EOF + +if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then + OD='-DOPENDIR_NOT_ROBUST' +fi + +rm -f x.c x.o a.out pgrp.o not_a_directory +echo "#define SYSDEP_CFLAGS $BC $UIDT $SL $PG $R4 $OD" +exit 0 diff --git a/portbash/mkdesc.sh b/portbash/mkdesc.sh 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 +#include + +int pid; +int pg1, pg2, pg3, pg4; +int ng, np, s, child; + +main() +{ + pid = getpid(); + pg1 = getpgrp(0); + pg2 = getpgrp(); + pg3 = getpgrp(pid); + pg4 = getpgrp(1); + + /* + * If all of these values are the same, it's pretty sure that + * we're on a system that ignores getpgrp's first argument. + */ + if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3) + exit(0); + + child = fork(); + if (child < 0) + exit(1); + else if (child == 0) { + np = getpid(); + /* + * If this is Sys V, this will not work; pgrp will be + * set to np because setpgrp just changes a pgrp to be + * the same as the pid. + */ + setpgrp(np, pg1); + ng = getpgrp(0); /* Same result for Sys V and BSD */ + if (ng == pg1) { + printf("-DBSD_GETPGRP\n"); + exit(0); + } else + exit(1); + } else { + wait(&s); + exit(s>>8); + } +} diff --git a/portbash/signals.sh b/portbash/signals.sh 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 < + +main() +{ +} +EOF + +${CC} -E x.c > x.i || { rm -f x.c x.i ; exit 1; } + +if egrep 'void.*signal' x.i >/dev/null 2>&1 +then + echo '#define VOID_SIGHANDLER' +fi +rm -f x.c x.i + +cat > x.c << EOF +#include +sigset_t set, oset; +main() +{ + sigemptyset(&set); + sigemptyset(&oset); + sigaddset(&set, 2); + sigprocmask(SIG_BLOCK, &set, &oset); +} +EOF +if ${CC} x.c >/dev/null 2>&1; then + echo '#define HAVE_POSIX_SIGNALS' +else + cat > x.c << EOF +#include +main() +{ + long omask = sigblock(sigmask(2)); + sigsetmask(omask); +} +EOF + if ${CC} x.c >/dev/null 2>&1; then + echo '#define HAVE_BSD_SIGNALS' + else + cat > x.c << EOF +#include +main() +{ + int n; + n = sighold(2); + sigrelse(2); +} +EOF + if ${CC} x.c >/dev/null 2>&1; then + echo '#define HAVE_USG_SIGHOLD' + fi + fi +fi + +rm -f x.c x.o a.out + +exit 0 diff --git a/portbash/stdio.sh b/portbash/stdio.sh 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 +#include + +xp(va_alist) +va_dcl +{ + va_list args; + va_start (args); + vfprintf(stdout, "abcde", args); +} + +main() +{ + xp(); + exit(0); +} +EOF + +if ${CC} x.c >/dev/null 2>&1 +then + echo '#define HAVE_VFPRINTF' + rm -f x.c x.o a.out +else + + cat > x.c << EOF +#include + +main() +{ + _doprnt(); +} +EOF + + if ${CC} x.c >/dev/null 2>&1 + then + echo '#define USE_VFPRINTF_EMULATION' + rm -f x.c x.o a.out + fi +fi + +cat > x.c << EOF +#include +main() +{ + setlinebuf(stdout); +} +EOF + +if ${CC} x.c > /dev/null 2>&1 +then + rm -f x.c x.o a.out + echo '#define HAVE_SETLINEBUF' +else + # check for setvbuf + # If this compiles, the system has setvbuf. If this segfaults while + # running, non-reversed systems get a seg violation + + cat > x.c << EOF +#include + +main() +{ + setvbuf(stdout, _IOLBF, (char *)0, BUFSIZ); /* reversed */ + exit(0); /* non-reversed systems segv */ +} +EOF + + if ${CC} x.c >/dev/null 2>&1 ; then + echo '#define HAVE_SETVBUF' + if a.out; then + : + else + rm -f core + echo '#define REVERSED_SETVBUF_ARGS' + fi + fi +fi + +rm -f x.c x.o a.out +exit 0 diff --git a/portbash/strings.sh b/portbash/strings.sh 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='' +elif [ -f /usr/include/strings.h ]; then + STRINGH='' +else + exit 1 +fi + +cat > x.c << EOF +#include $STRINGH + +#ifndef strchr +extern char *strchr(); +#endif + +char *x = "12345"; + +main() +{ + char *s; + + s = strchr(x, '2'); + if (s) + exit(0); + exit(1); +} +EOF + +if ${CC} x.c >/dev/null 2>&1 +then + if ./a.out + then + echo '#define HAVE_STRCHR' + fi +fi + +rm -f x.c x.o a.out + +cat > x.c << EOF +extern char *strerror(); + +main() +{ + char *s; + + s = strerror(2); + if (s) + exit(0); + exit(1); +} +EOF + +if ${CC} x.c >/dev/null 2>&1 +then + if ./a.out + then + echo '#define HAVE_STRERROR' + fi +fi + +rm -f x.c x.o a.out + + +cat > x.c << EOF + +main() +{ + if (strcasecmp("abc", "AbC") == 0) + exit(0); + exit(1); +} +EOF + +if ${CC} x.c >/dev/null 2>&1 +then + if ./a.out + then + echo '#define HAVE_STRCASECMP' + fi +fi + +rm -f x.c x.o a.out +exit 0 diff --git a/portbash/syscalls.sh b/portbash/syscalls.sh 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 . + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H) +#define _POSIXSTAT_H + +#include + +#if defined (isc386) +# if !defined (S_IFDIR) +# define S_IFDIR 0040000 +# endif /* !S_IFDIR */ +# if !defined (S_IFMT) +# define S_IFMT 0170000 +# endif /* !S_IFMT */ +#endif /* isc386 */ + +/* This text is taken directly from the Cadmus I was trying to + compile on: + the following MACROs are defined for X/OPEN compatibility + however, is the param correct ?? + #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) + + Well, the answer is no. Thus... */ +#if defined (BrainDeath) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +#endif /* BrainDeath */ + +/* Posix 1003.1 5.6.1.1 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 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 + +#if defined (HAVE_VARARGS_H) +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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); + } +} diff --git a/quit.h b/quit.h new file mode 100644 index 0000000..57de7a0 --- /dev/null +++ b/quit.h @@ -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__ */ diff --git a/sh b/sh new file mode 120000 index 0000000..5d4150d --- /dev/null +++ b/sh @@ -0,0 +1 @@ +/bin/bash \ No newline at end of file diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..26b20c0 --- /dev/null +++ b/shell.c @@ -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 +#include +#include +#include +#include "filecntl.h" +#include +#include "posixstat.h" +#include "bashansi.h" + +#if defined (HAVE_VARARGS_H) +#include +#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 +#endif + +#include + +#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 +#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 */ +} diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..b7d3132 --- /dev/null +++ b/shell.h @@ -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 +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 +#include +#include + +#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 +#include +#include +#if defined (HAVE_STDLIB_H) +# include +#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); +} diff --git a/stdc.h b/stdc.h new file mode 100644 index 0000000..5dcc32b --- /dev/null +++ b/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/subst.c b/subst.c new file mode 100644 index 0000000..9dd00a8 --- /dev/null +++ b/subst.c @@ -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 +#include +#include +#include +/* 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 +#else +# include +#endif + +#if defined (HISTORY) +# include "bashhist.h" +# include +#endif + +#include +#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: + $ ` " \ ''. + + 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 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 , 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 , , or , 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 */ +} diff --git a/subst.h b/subst.h new file mode 100644 index 0000000..6584ef9 --- /dev/null +++ b/subst.h @@ -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 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 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 +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 /bash.xbm. If + using a twm window manager, insert the lines: + +IconDirectory "" +Icons { + "" "bash.xbm" +} + in your ~/.twmrc file. The 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 <> $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 +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 + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + C1*:ConvexOS:*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:*) + echo c2-convex-bsd + exit 0 ;; + CRAY*X-MP:UNICOS:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:UNICOS:*:*) + echo ymp-cray-unicos + exit 0 ;; + CRAY-2:UNICOS:*:*) + echo cray2-cray-unicos + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + i[34]86:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd${UNAME_RELEASE} + exit 0 ;; + i[34]86:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux + exit 0 ;; + i[34]86:UNIX_SV:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i[34]86:*:3.2:*) + if /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-unknown-sysv3.2 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M680[234]0:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:*) + uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m680[234]0:LynxOS:2.2*:*) + echo m68k-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + i[34]86:LynxOS:2.2*:*) + echo i386-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.2*:*) + echo sparc-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c <&2 + +exit 1 diff --git a/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 + +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 +# diff --git a/test.c b/test.c new file mode 100644 index 0000000..d8356f1 --- /dev/null +++ b/test.c @@ -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 +#include "bashtypes.h" + +#if !defined (STANDALONE) +# if !defined (_POSIX_VERSION) +# include +# 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 +# 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 +#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 + * '-'(eq|ne|le|lt|ge|gt) + * file '-'(nt|ot|ef) file + * '(' ')' + * 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] = +argv[1] = +argv[2] = 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 "" +recho abcd""efgh +expect "" +recho abcd''efgh +expect "" +recho ""abcdefgh +expect "" +recho ''abcdefgh +expect "" +recho abcd"" +expect "" +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 '' +recho $xxx"" +expect '' +recho ""$xxx +expect '' +recho $xxx'' +expect '' +recho ''$xxx +expect '' +recho $xxx""$yyy +expect '' +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 '' +# 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 ' ' +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> ' +set abc def ghi jkl +recho " $@ " + +expect '<--abc> ' +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 '' +recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" + +# Test the various Posix parameter expansions + +expect '' +recho "${x:-$(echo "foo bar")}" +expect ' ' +recho ${x:-$(echo "foo bar")} + +unset X +expect '' +recho ${X:=abc} +expect '' +recho $X + +set a b c +expect '' +recho ${3:+posix} + +POSIX=/usr/posix +expect '<10>' +recho ${#POSIX} + +# remove shortest trailing match +x=file.c +expect '' +recho ${x%.c}.o + +# remove longest trailing match +x=posix/src/std +expect '' +recho ${x%%/*} + +# remove shortest leading pattern +x=$HOME/src/cmd +expect '' +recho ${x#$HOME} + +# remove longest leading pattern +x=/one/two/three +expect '' +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 ' ' +recho $* + +expect '' +recho "$*" + +OIFS="$IFS" +IFS=":$IFS" + +# The special behavior of "$*", using the first character of $IFS as separator +expect '' +recho "$*" + +IFS="$OIFS" + +expect ' ' +recho "$@" + +expect ' ' +recho "xx$@yy" + +expect ' ' +recho "$@$@" + +foo=abc +bar=def + +expect '' +recho "$foo""$bar" + +unset foo +set $foo bar '' xyz "$foo" abc + +expect ' <> <> ' +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 '' +case "$x" in +*$NL*) recho "newline expected" ;; +esac + +expect '' +case \? in +*"?"*) recho "got it" ;; +esac + +expect '' +case \? in +*\?*) recho "got it" ;; +esac + +set one two three four five +expect ' ' +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] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = < > +argv[1] = <--> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +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] = +argv[1] = <`> +argv[1] = <"> +argv[1] = <\^A> +argv[1] = <\$> +argv[1] = <\\> +argv[1] = +argv[2] = +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] = +argv[3] = +argv[4] = +argv[1] = <--abc> +argv[2] = +argv[3] = +argv[4] = +argv[1] = < > +argv[1] = < - > +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <10> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <\$x> +argv[1] = <$x> +argv[1] = <\$x> +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[1] = +argv[2] = +argv[3] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[1] = +argv[2] = <> +argv[3] = +argv[4] = <> +argv[5] = +argv[1] = <$foo> +argv[1] = <10> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +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 ' ' +recho a* X* + +expect ' ' +recho \a* + +# see if null glob expansion works +allow_null_glob_expansion= + +expect ' ' +recho a* X* + +unset allow_null_glob_expansion + +# see if the code that expands directories only works +expect '' +recho b*/ + +# Test quoted and unquoted globbing characters +expect '<*>' +recho \* + +expect '' +recho 'a*' + +expect '' +recho a\* + +expect ' <*q*>' +recho c* a\* *q* + +expect '<**>' +recho "*"* + +expect '<**>' +recho \** + +expect '<\.\./*/>' +recho "\.\./*/" + +expect '' +recho 's/\..*//' + +# Pattern from Larry Wall's Configure that caused bash to blow up +expect '' +recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" + +# Make sure character classes work properly + +expect ' ' +recho [a-c]b* + +expect '

' +recho [a-y]*[^c] + +expect ' ' +recho a*[^c] + +touch a-b aXb +expect ' ' +recho a[X-]b + +touch .x .y +expect '
' +recho [^a-c]* + +# Make sure that filenames with embedded globbing characters are handled +# properly +mkdir a\*b +> a\*b/ooo + +expect '' +recho a\*b/* + +expect '' +recho a\*?/* + +expect '' +cmd='echo !7' +case "$cmd" in +*\\!*) echo match ;; +*) echo no match ;; +esac + +expect '' +file='r.*' +case $file in +*.\*) echo not there ;; +*) echo there ;; +esac + +# examples from the Posix.2 spec (d11.2, p. 243) +expect '' +recho a[b]c + +expect '' +recho a["b"]c + +expect '' +recho a[\b]c + +expect '' +recho a?c + +expect '' +case abc in +a"b"c) echo match + ;; +*) echo BAD + ;; +esac + +expect '' +case abc in +a*c) echo match + ;; +*) echo BAD + ;; +esac + +expect '' +case abc in +"a?c") echo bad + ;; +*) echo ok + ;; +esac + +expect '' +case abc in +a\*c) echo bad + ;; +*) echo ok + ;; +esac + +expect '' +case abc in +a\[b]c) echo bad + ;; +*) echo ok + ;; +esac + +expect '' +case "$nosuchvar" in +"") echo ok ;; +*) echo bad ;; +esac + +# This is very odd, but sh and ksh seem to agree +expect '' +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] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[1] = <*> +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = <*q*> +argv[1] = <**> +argv[1] = <**> +argv[1] = <\.\./*/> +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[7] = +argv[8] =
+argv[9] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] =
+argv[3] = +argv[1] = +argv[1] = +no match +not there +argv[1] = +argv[1] = +argv[1] = +argv[1] = +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 4a +exec 5>b +echo "Point 2" +echo to a 1>&4 +echo to b 1>&5 +exec 11&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] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +./new-exp.tests: ${HOME:`echo }`}: bad substitution +./new-exp.tests: ${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}: bad substitution +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <*@> +argv[1] = <@*> +argv[1] = <)> +argv[1] = <")"> +argv[1] = <-abcd> +argv[2] = <-> +argv[1] = <-abcd> +argv[2] = <-> +argv[1] = <-abcd-> +argv[1] = +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 '' +recho "${undef-"foo bar"}" # should be foo bar +expect '' +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 '' +IFS="" +recho "$@" +IFS=' +' + +foo=bar +expect '' +echo -n $foo' ' ; echo foo + +expect '' +echo -n $foo" " ; echo foo + +expect '' +echo -n "$foo " ; echo foo + +expect '' +echo -e "$foo\c " ; echo foo + +expect '' +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 diff --git a/trap.c b/trap.c new file mode 100644 index 0000000..c2b951b --- /dev/null +++ b/trap.c @@ -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 + +#include "bashtypes.h" +#include "trap.h" + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#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; +} diff --git a/trap.h b/trap.h new file mode 100644 index 0000000..1670231 --- /dev/null +++ b/trap.h @@ -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 +#include +#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 +#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 +#include "bashtypes.h" +#include "posixstat.h" +#include +#include + +#include "bashansi.h" +#include "shell.h" +#include "hash.h" +#include "flags.h" +#include "execute_cmd.h" + +#include "builtins/common.h" +#include + +/* 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 + +#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 + +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); +} diff --git a/y.tab.c b/y.tab.c new file mode 100644 index 0000000..0b1fd09 --- /dev/null +++ b/y.tab.c @@ -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 +#include "bashtypes.h" +#include +#include "bashansi.h" +#include "shell.h" +#include "flags.h" +#include "input.h" + +#if defined (READLINE) +# include +#endif /* READLINE */ + +#if defined (HISTORY) +# include "bashhist.h" +# include +#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 +#include +#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 + +#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 +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#include +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include + #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 \ 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 \ 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 \ 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 + \ 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/y.tab.h b/y.tab.h new file mode 100644 index 0000000..7ba3b28 --- /dev/null +++ b/y.tab.h @@ -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; -- 2.7.4