From 0e5ad4671a0f319a6b1046e452a15078fcfc56b5 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Sat, 3 Dec 2011 13:04:22 -0500 Subject: [PATCH] bash-3.0 cleanup of extra files --- AUTHORS~ | 454 -- CHANGES~ | 4688 ------------- COMPAT~ | 216 - CWRU/CWRU.chlog~ | 9638 --------------------------- CWRU/old/set.def.save | 544 -- CWRU/save/unwind_prot.h.save | 50 - MANIFEST~ | 955 --- Makefile.in~ | 1435 ---- NEWS~ | 1097 --- README~ | 90 - Y2K~ | 5 - aclocal.m4.orig | 3952 ----------- bashhist.c~ | 813 --- bashline.c~ | 3049 --------- builtins/alias.def~ | 229 - builtins/cd.def.orig | 484 -- builtins/cd.def~ | 494 -- builtins/common.c.orig | 815 --- builtins/common.c~ | 815 --- builtins/common.h~ | 161 - builtins/getopts.def~ | 322 - builtins/jobs.def.save1 | 281 - builtins/jobs.def~ | 283 - builtins/kill.def.save1 | 250 - builtins/kill.def~ | 250 - builtins/read.def~ | 736 -- builtins/trap.def~ | 261 - builtins/umask.def~ | 309 - builtins/wait.def.save1 | 183 - builtins/wait.def~ | 177 - config-bot.h~ | 181 - config.h.in~ | 974 --- configure.in~ | 1019 --- doc/FAQ-3.0~ | 1771 ----- doc/FAQ.orig | 1745 ----- doc/FAQ.save | 1745 ----- doc/bash.1.orig | 8583 ------------------------ doc/bash.1~ | 8740 ------------------------ doc/bashref.texi.orig | 7105 -------------------- doc/bashref.texi~ | 7267 -------------------- doc/version.texi~ | 10 - examples/scripts/adventure.sh.save1 | 549 -- execute_cmd.c~ | 4027 ----------- expr.c.save1 | 1243 ---- expr.c.save2 | 1268 ---- externs.h~ | 375 -- flags.c~ | 355 - general.c~ | 958 --- general.h~ | 311 - include/memalloc.h.save | 58 - include/shmbutil.h.save1 | 470 -- include/shmbutil.h~ | 470 -- jobs.c~ | 3537 ---------- jobs.h~ | 182 - lib/glob/glob.c~ | 839 --- lib/glob/sm_loop.c~ | 750 --- lib/glob/smatch.c~ | 410 -- lib/glob/strmatch.c~ | 79 - lib/glob/strmatch.h~ | 64 - lib/glob/xmbsrtowcs.c~ | 247 - lib/malloc/malloc.c.save | 1213 ---- lib/readline/bind.c~ | 2223 ------ lib/readline/complete.c~ | 2189 ------ lib/readline/display.c~ | 2280 ------- lib/readline/doc/rluser.texi~ | 1824 ----- lib/readline/histexpand.c~ | 1591 ----- lib/readline/histfile.c~ | 542 -- lib/readline/input.c~ | 551 -- lib/readline/misc.c~ | 500 -- lib/readline/parens.c~ | 179 - lib/readline/readline.h~ | 828 --- lib/readline/rlprivate.h~ | 288 - lib/readline/text.c~ | 1547 ----- lib/readline/vi_mode.c.save | 1485 ----- lib/readline/vi_mode.c~ | 1499 ----- lib/sh/strftime.c~ | 859 --- parse.y~ | 4851 -------------- po/bash.po.orig | 5623 ---------------- po/bash.pot~ | 4174 ------------ print_cmd.c~ | 1282 ---- shell.c~ | 1786 ----- stringlib.c~ | 284 - subst.c.new | 7293 -------------------- subst.c.orig | 7376 -------------------- subst.c.save1 | 7346 -------------------- subst.c.save2 | 7005 ------------------- subst.c~ | 7383 -------------------- support/bashbug.sh.orig | 294 - support/bashbug.sh~ | 271 - syntax.h~ | 100 - tests/RUN-ONE-TEST~ | 9 - tests/arith.tests~ | 281 - tests/cprint.right.save1 | 72 - tests/dollar-at-star~ | 218 - tests/dollar-at1.sub~ | 29 - tests/errors.right~ | 100 - tests/exec.right~ | 53 - tests/execscript~ | 105 - tests/histexp.right~ | 129 - tests/history.tests.save | 97 - tests/jobs.right~ | 97 - tests/jobs.tests~ | 179 - tests/misc/regress/log.orig | 50 - tests/misc/regress/shx.orig | 10 - tests/read.tests~ | 92 - tests/trap.tests~ | 86 - variables.c~ | 4090 ------------ xx | Bin 16288 -> 0 bytes xx.c | 26 - xx.o | Bin 1856 -> 0 bytes xx2 | Bin 16288 -> 0 bytes xx2.c | 22 - xx2.o | Bin 1856 -> 0 bytes 113 files changed, 168779 deletions(-) delete mode 100644 AUTHORS~ delete mode 100644 CHANGES~ delete mode 100644 COMPAT~ delete mode 100644 CWRU/CWRU.chlog~ delete mode 100644 CWRU/old/set.def.save delete mode 100644 CWRU/save/unwind_prot.h.save delete mode 100644 MANIFEST~ delete mode 100644 Makefile.in~ delete mode 100644 NEWS~ delete mode 100644 README~ delete mode 100644 Y2K~ delete mode 100644 aclocal.m4.orig delete mode 100644 bashhist.c~ delete mode 100644 bashline.c~ delete mode 100644 builtins/alias.def~ delete mode 100644 builtins/cd.def.orig delete mode 100644 builtins/cd.def~ delete mode 100644 builtins/common.c.orig delete mode 100644 builtins/common.c~ delete mode 100644 builtins/common.h~ delete mode 100644 builtins/getopts.def~ delete mode 100644 builtins/jobs.def.save1 delete mode 100644 builtins/jobs.def~ delete mode 100644 builtins/kill.def.save1 delete mode 100644 builtins/kill.def~ delete mode 100644 builtins/read.def~ delete mode 100644 builtins/trap.def~ delete mode 100644 builtins/umask.def~ delete mode 100644 builtins/wait.def.save1 delete mode 100644 builtins/wait.def~ delete mode 100644 config-bot.h~ delete mode 100644 config.h.in~ delete mode 100644 configure.in~ delete mode 100644 doc/FAQ-3.0~ delete mode 100644 doc/FAQ.orig delete mode 100644 doc/FAQ.save delete mode 100644 doc/bash.1.orig delete mode 100644 doc/bash.1~ delete mode 100644 doc/bashref.texi.orig delete mode 100644 doc/bashref.texi~ delete mode 100644 doc/version.texi~ delete mode 100755 examples/scripts/adventure.sh.save1 delete mode 100644 execute_cmd.c~ delete mode 100644 expr.c.save1 delete mode 100644 expr.c.save2 delete mode 100644 externs.h~ delete mode 100644 flags.c~ delete mode 100644 general.c~ delete mode 100644 general.h~ delete mode 100644 include/memalloc.h.save delete mode 100644 include/shmbutil.h.save1 delete mode 100644 include/shmbutil.h~ delete mode 100644 jobs.c~ delete mode 100644 jobs.h~ delete mode 100644 lib/glob/glob.c~ delete mode 100644 lib/glob/sm_loop.c~ delete mode 100644 lib/glob/smatch.c~ delete mode 100644 lib/glob/strmatch.c~ delete mode 100644 lib/glob/strmatch.h~ delete mode 100644 lib/glob/xmbsrtowcs.c~ delete mode 100644 lib/malloc/malloc.c.save delete mode 100644 lib/readline/bind.c~ delete mode 100644 lib/readline/complete.c~ delete mode 100644 lib/readline/display.c~ delete mode 100644 lib/readline/doc/rluser.texi~ delete mode 100644 lib/readline/histexpand.c~ delete mode 100644 lib/readline/histfile.c~ delete mode 100644 lib/readline/input.c~ delete mode 100644 lib/readline/misc.c~ delete mode 100644 lib/readline/parens.c~ delete mode 100644 lib/readline/readline.h~ delete mode 100644 lib/readline/rlprivate.h~ delete mode 100644 lib/readline/text.c~ delete mode 100644 lib/readline/vi_mode.c.save delete mode 100644 lib/readline/vi_mode.c~ delete mode 100644 lib/sh/strftime.c~ delete mode 100644 parse.y~ delete mode 100644 po/bash.po.orig delete mode 100644 po/bash.pot~ delete mode 100644 print_cmd.c~ delete mode 100644 shell.c~ delete mode 100644 stringlib.c~ delete mode 100644 subst.c.new delete mode 100644 subst.c.orig delete mode 100644 subst.c.save1 delete mode 100644 subst.c.save2 delete mode 100644 subst.c~ delete mode 100644 support/bashbug.sh.orig delete mode 100644 support/bashbug.sh~ delete mode 100644 syntax.h~ delete mode 100755 tests/RUN-ONE-TEST~ delete mode 100644 tests/arith.tests~ delete mode 100644 tests/cprint.right.save1 delete mode 100755 tests/dollar-at-star~ delete mode 100644 tests/dollar-at1.sub~ delete mode 100644 tests/errors.right~ delete mode 100644 tests/exec.right~ delete mode 100644 tests/execscript~ delete mode 100644 tests/histexp.right~ delete mode 100644 tests/history.tests.save delete mode 100644 tests/jobs.right~ delete mode 100644 tests/jobs.tests~ delete mode 100644 tests/misc/regress/log.orig delete mode 100644 tests/misc/regress/shx.orig delete mode 100644 tests/read.tests~ delete mode 100644 tests/trap.tests~ delete mode 100644 variables.c~ delete mode 100755 xx delete mode 100644 xx.c delete mode 100644 xx.o delete mode 100755 xx2 delete mode 100644 xx2.c delete mode 100644 xx2.o diff --git a/AUTHORS~ b/AUTHORS~ deleted file mode 100644 index fde36d953..000000000 --- a/AUTHORS~ +++ /dev/null @@ -1,454 +0,0 @@ -# -# Master author manifest for bash -# -# Any files appearing in the bash distribution not listed in this file -# were created by Chet Ramey. -# -# Filename authors (first is original author) -# -README Brian Fox, Chet Ramey -INSTALL Brian Fox, Chet Ramey -COPYING Brian Fox, Chet Ramey -MANIFEST Brian Fox, Chet Ramey -configure Chet Ramey -Makefile.in Brian Fox, Chet Ramey -configure.in Chet Ramey -aclocal.m4 Chet Ramey -config.h.top Chet Ramey -config.h.bot Chet Ramey -config.h.in Chet Ramey -array.c Chet Ramey -print_cmd.c Brian Fox, Chet Ramey -general.c Brian Fox, Chet Ramey -variables.c Brian Fox, Chet Ramey -make_cmd.c Brian Fox, Chet Ramey -copy_cmd.c Brian Fox, Chet Ramey -unwind_prot.c Brian Fox, Chet Ramey -dispose_cmd.c Brian Fox, Chet Ramey -getcwd.c Roland McGrath, Brian Fox, Chet Ramey -bashhist.c Chet Ramey -hash.c Brian Fox, Chet Ramey -parse.y Brian Fox, Chet Ramey -subst.c Brian Fox, Chet Ramey -shell.c Brian Fox, Chet Ramey -sig.c Chet Ramey -trap.c Brian Fox, Chet Ramey -siglist.c Brian Fox, Chet Ramey -version.c Brian Fox, Chet Ramey -flags.c Brian Fox, Chet Ramey -jobs.c Brian Fox, Chet Ramey -input.c Chet Ramey -mailcheck.c Brian Fox, Chet Ramey -pathexp.c Chet Ramey -test.c Brian Fox, Chet Ramey -expr.c Chet Ramey, Brian Fox -alias.c Brian Fox, Chet Ramey -execute_cmd.c Brian Fox, Chet Ramey -bashline.c Brian Fox, Chet Ramey -braces.c Brian Fox, Chet Ramey -bracecomp.c Brian Fox, Chet Ramey, Tom Tromey -nojobs.c Brian Fox, Chet Ramey -vprint.c Chet Ramey -oslib.c Chet Ramey -error.c Brian Fox, Chet Ramey -xmalloc.c Brian Fox, Chet Ramey -alias.h Brian Fox, Chet Ramey -array.h Chet Ramey -builtins.h Brian Fox, Chet Ramey -parser.h Brian Fox, Chet Ramey -variables.h Brian Fox, Chet Ramey -machines.h Brian Fox, Chet Ramey -jobs.h Brian Fox, Chet Ramey -maxpath.h Brian Fox, Chet Ramey -pathexp.h Chet Ramey -mailcheck.h Chet Ramey -filecntl.h Brian Fox, Chet Ramey -hash.h Brian Fox, Chet Ramey -quit.h Brian Fox, Chet Ramey -flags.h Brian Fox, Chet Ramey -shell.h Brian Fox, Chet Ramey -bashjmp.h Chet Ramey -sig.h Chet Ramey -trap.h Brian Fox, Chet Ramey -general.h Brian Fox, Chet Ramey -unwind_prot.h Brian Fox, Chet Ramey -input.h Brian Fox, Chet Ramey -error.h Brian Fox, Chet Ramey -command.h Brian Fox, Chet Ramey -externs.h Chet Ramey -siglist.h Chet Ramey -subst.h Brian Fox, Chet Ramey -dispose_cmd.h Brian Fox, Chet Ramey -bashansi.h Brian Fox, Chet Ramey -make_cmd.h Brian Fox, Chet Ramey -bashhist.h Chet Ramey -bashline.h Chet Ramey -execute_cmd.h Chet Ramey -bashtypes.h Chet Ramey -bashtty.h Chet Ramey -pathnames.h Chet Ramey -y.tab.c Brian Fox, Chet Ramey -y.tab.h Brian Fox, Chet Ramey -parser-built Brian Fox, Chet Ramey -posixstat.h Brian Fox, Chet Ramey -stdc.h Chet Ramey -ansi_stdlib.h Brian Fox, Chet Ramey -memalloc.h Chet Ramey -builtins/ChangeLog Brian Fox, Chet Ramey -builtins/Makefile.in Brian Fox, Chet Ramey -builtins/alias.def Brian Fox, Chet Ramey -builtins/bind.def Brian Fox, Chet Ramey -builtins/break.def Brian Fox, Chet Ramey -builtins/builtin.def Brian Fox, Chet Ramey -builtins/caller.def Rocky Bernstein, Chet Ramey -builtins/cd.def Brian Fox, Chet Ramey -builtins/colon.def Brian Fox, Chet Ramey -builtins/command.def Brian Fox, Chet Ramey -builtins/common.c Brian Fox, Chet Ramey -builtins/declare.def Brian Fox, Chet Ramey -builtins/echo.def Brian Fox, Chet Ramey -builtins/enable.def Brian Fox, Chet Ramey -builtins/eval.def Brian Fox, Chet Ramey -builtins/exec.def Brian Fox, Chet Ramey -builtins/exit.def Brian Fox, Chet Ramey -builtins/fc.def Brian Fox, Chet Ramey -builtins/fg_bg.def Brian Fox, Chet Ramey -builtins/getopt.c Roland McGrath, Brian Fox, Chet Ramey -builtins/getopt.h Roland McGrath, Brian Fox, Chet Ramey -builtins/getopts.def Brian Fox, Chet Ramey -builtins/hash.def Brian Fox, Chet Ramey -builtins/hashcom.h Brian Fox, Chet Ramey -builtins/help.def Brian Fox, Chet Ramey -builtins/let.def Chet Ramey, Brian Fox -builtins/history.def Brian Fox, Chet Ramey -builtins/jobs.def Brian Fox, Chet Ramey -builtins/kill.def Brian Fox, Chet Ramey -builtins/mkbuiltins.c Brian Fox, Chet Ramey -builtins/pushd.def Brian Fox, Chet Ramey -builtins/read.def Brian Fox, Chet Ramey -builtins/reserved.def Brian Fox, Chet Ramey -builtins/return.def Brian Fox, Chet Ramey -builtins/set.def Brian Fox, Chet Ramey -builtins/setattr.def Brian Fox, Chet Ramey -builtins/shift.def Brian Fox, Chet Ramey -builtins/shopt.def Chet Ramey -builtins/source.def Brian Fox, Chet Ramey -builtins/suspend.def Brian Fox, Chet Ramey -builtins/test.def Brian Fox, Chet Ramey -builtins/times.def Brian Fox, Chet Ramey -builtins/trap.def Brian Fox, Chet Ramey -builtins/type.def Brian Fox, Chet Ramey -builtins/ulimit.def Chet Ramey, Brian Fox -builtins/umask.def Brian Fox, Chet Ramey -builtins/wait.def Brian Fox, Chet Ramey -builtins/psize.c Chet Ramey, Brian Fox -builtins/psize.sh Chet Ramey, Brian Fox -builtins/inlib.def Chet Ramey -builtins/bashgetopt.c Chet Ramey -builtins/common.h Chet Ramey -builtins/bashgetopt.h Chet Ramey -lib/doc-support/texindex.c bug-texinfo@prep.ai.mit.edu, Chet Ramey -lib/doc-support/Makefile.in Chet Ramey -lib/doc-support/getopt.h Roland McGrath -lib/doc-support/getopt.c Roland McGrath -lib/doc-support/getopt1.c Roland McGrath -lib/glob/ChangeLog Brian Fox, Chet Ramey -lib/glob/Makefile.in Brian Fox, Chet Ramey -lib/glob/strmatch.c Roland McGrath, Brian Fox, Chet Ramey -lib/glob/strmatch.h Roland McGrath, Brian Fox, Chet Ramey -lib/glob/glob.c Richard Stallman, Roland McGrath, Brian Fox, Chet Ramey -lib/glob/glob.h Chet Ramey -lib/glob/ndir.h Doug Gwyn, Richard Stallman -lib/glob/doc/Makefile.in Brian Fox, Chet Ramey -lib/glob/doc/glob.texi Brian Fox, Chet Ramey -lib/malloc/Makefile.in Chet Ramey -lib/malloc/alloca.c Doug Gwyn, Richard Stallman, Brian Fox, Chet Ramey -lib/malloc/getpagesize.h Brian Fox, Chet Ramey -lib/malloc/malloc.c Chris Kingsley, Mike Muuss, Richard Stallman, Brian Fox, Chet Ramey -lib/malloc/gmalloc.c Mike Haertel, Roland McGrath -lib/malloc/stub.c Chet Ramey -lib/malloc/i386-alloca.s Richard Stallman -lib/malloc/x386-alloca.s Chip Salzenberg, Richard Stallman -lib/malloc/xmalloc.c Brian Fox, Chet Ramey -lib/posixheaders/posixstat.h Brian Fox, Chet Ramey -lib/posixheaders/ansi_stdlib.h Brian Fox, Chet Ramey -lib/posixheaders/stdc.h Chet Ramey -lib/posixheaders/memalloc.h Chet Ramey -lib/posixheaders/filecntl.h Brian Fox, Chet Ramey -lib/readline/Makefile.in Brian Fox, Chet Ramey -lib/readline/COPYING Brian Fox, Chet Ramey -lib/readline/ChangeLog Brian Fox, Chet Ramey -lib/readline/readline.c Brian Fox, Chet Ramey -lib/readline/vi_mode.c Brian Fox, Chet Ramey -lib/readline/emacs_keymap.c Brian Fox, Chet Ramey -lib/readline/vi_keymap.c Brian Fox, Chet Ramey -lib/readline/funmap.c Brian Fox, Chet Ramey -lib/readline/keymaps.c Brian Fox, Chet Ramey -lib/readline/xmalloc.c Brian Fox, Chet Ramey -lib/readline/search.c Brian Fox, Chet Ramey -lib/readline/isearch.c Brian Fox, Chet Ramey -lib/readline/parens.c Brian Fox, Chet Ramey -lib/readline/rltty.c Brian Fox, Chet Ramey -lib/readline/complete.c Brian Fox, Chet Ramey -lib/readline/bind.c Brian Fox, Chet Ramey -lib/readline/display.c Brian Fox, Chet Ramey -lib/readline/signals.c Brian Fox, Chet Ramey -lib/readline/kill.c Brian Fox, Chet Ramey -lib/readline/undo.c Brian Fox, Chet Ramey -lib/readline/input.c Brian Fox, Chet Ramey -lib/readline/macro.c Brian Fox, Chet Ramey -lib/readline/util.c Brian Fox, Chet Ramey -lib/readline/callback.c Chet Ramey -lib/readline/readline.h Brian Fox, Chet Ramey -lib/readline/chardefs.h Brian Fox, Chet Ramey -lib/readline/keymaps.h Brian Fox, Chet Ramey -lib/readline/rldefs.h Brian Fox, Chet Ramey -lib/readline/posixstat.h Brian Fox, Chet Ramey -lib/readline/ansi_stdlib.h Brian Fox, Chet Ramey -lib/readline/memalloc.h Chet Ramey -lib/readline/rlconf.h Chet Ramey -lib/readline/rltty.h Chet Ramey -lib/readline/history.c Brian Fox, Chet Ramey -lib/readline/histexpand.c Brian Fox, Chet Ramey -lib/readline/histfile.c Brian Fox, Chet Ramey -lib/readline/histsearch.c Brian Fox, Chet Ramey -lib/readline/history.h Brian Fox, Chet Ramey -lib/readline/histlib.h Brian Fox, Chet Ramey -lib/readline/tilde.c Brian Fox, Chet Ramey -lib/readline/tilde.h Brian Fox, Chet Ramey -lib/readline/doc/texindex.c bug-texinfo@prep.ai.mit.edu, Chet Ramey -lib/readline/doc/Makefile Brian Fox, Chet Ramey -lib/readline/doc/rlman.texinfo Brian Fox, Chet Ramey -lib/readline/doc/rltech.texinfo Brian Fox, Chet Ramey -lib/readline/doc/rluser.texinfo Brian Fox, Chet Ramey -lib/readline/doc/hist.texinfo Brian Fox, Chet Ramey -lib/readline/doc/hstech.texinfo Brian Fox, Chet Ramey -lib/readline/doc/hsuser.texinfo Brian Fox, Chet Ramey -lib/readline/examples/Makefile Brian Fox -lib/readline/examples/fileman.c Brian Fox -lib/readline/examples/manexamp.c Brian Fox -lib/readline/examples/histexamp.c Brian Fox, Chet Ramey -lib/readline/examples/rltest.c Brian Fox, Chet Ramey -lib/readline/examples/Inputrc Brian Fox, Chet Ramey -lib/termcap/Makefile.in David MacKenzie, Chet Ramey -lib/termcap/termcap.c David MacKenzie -lib/termcap/termcap.h David MacKenzie -lib/termcap/tparam.c David MacKenzie -lib/termcap/version.c David MacKenzie -lib/termcap/grot/termcap.info David MacKenzie -lib/termcap/grot/termcap.info-1 David MacKenzie -lib/termcap/grot/termcap.info-2 David MacKenzie -lib/termcap/grot/termcap.info-3 David MacKenzie -lib/termcap/grot/termcap.info-4 David MacKenzie -lib/termcap/grot/NEWS David MacKenzie -lib/termcap/grot/INSTALL David MacKenzie -lib/termcap/grot/ChangeLog David MacKenzie -lib/termcap/grot/texinfo.tex David MacKenzie -lib/termcap/grot/termcap.texi David MacKenzie -lib/termcap/grot/Makefile.in David MacKenzie -lib/termcap/grot/configure David MacKenzie -lib/termcap/grot/configure.in David MacKenzie -lib/termcap/grot/COPYING David MacKenzie -lib/termcap/grot/README David MacKenzie -lib/tilde/ChangeLog Brian Fox, Chet Ramey -lib/tilde/Makefile.in Brian Fox, Chet Ramey -lib/tilde/doc/tilde.texi Brian Fox, Chet Ramey -lib/tilde/doc/Makefile Brian Fox, Chet Ramey -lib/tilde/tilde.c Brian Fox, Chet Ramey -lib/tilde/tilde.h Brian Fox, Chet Ramey -lib/tilde/memalloc.h Brian Fox, Chet Ramey -CWRU/misc/open-files.c Chet Ramey -CWRU/misc/sigs.c Chet Ramey -CWRU/misc/pid.c Chet Ramey -CWRU/misc/sigstat.c Chet Ramey -CWRU/misc/bison Chet Ramey -CWRU/misc/aux-machine-desc Chet Ramey -CWRU/PLATFORMS Chet Ramey -CWRU/README Chet Ramey -CWRU/CWRU.CHANGES.051093 Chet Ramey -CWRU/POSIX.NOTES Chet Ramey -CWRU/CWRU.CHANGES.071193 Chet Ramey -CWRU/CWRU.CHANGES.090393 Chet Ramey -doc/Makefile.in Brian Fox, Chet Ramey -doc/bash.1 Chet Ramey -doc/builtins.1 Chet Ramey -doc/bash.ps Chet Ramey -doc/bash.txt Chet Ramey -doc/readline.3 Chet Ramey -doc/readline.ps Chet Ramey -doc/readline.txt Chet Ramey -doc/texinfo.tex Richard Stallman -doc/features.texi Brian Fox, Chet Ramey -doc/features.ps Brian Fox, Chet Ramey -doc/features.info Brian Fox, Chet Ramey -doc/features.dvi Brian Fox, Chet Ramey -doc/bash_builtins.1 Chet Ramey -doc/bash_builtins.ps Chet Ramey -doc/bash_builtins.txt Chet Ramey -doc/bash_builtins.readme Chet Ramey -doc/article.ms Chet Ramey -doc/FAQ Chet Ramey -support/cat-s Brian Fox, Chet Ramey -support/mksysdefs Brian Fox, Chet Ramey -support/mkversion.c Brian Fox, Chet Ramey -support/mksignames.c Brian Fox, Chet Ramey -support/getcppsyms.c Brian Fox, Chet Ramey -support/cppmagic Brian Fox, Chet Ramey -support/pagesize.sh Chet Ramey, Brian Fox -support/pagesize.c Chet Ramey, Brian Fox -support/bash.xbm Brian Fox -support/FAQ Brian Fox -support/PORTING Brian Fox -support/mklinks Brian Fox -support/fixlinks Chet Ramey -support/mkdirs Chet Ramey -support/clone-bash Chet Ramey -support/bashbug.sh Chet Ramey -support/mkmachtype Chet Ramey -support/recho.c Chet Ramey -support/config.guess Per Bothner, Chet Ramey -support/config.sub Richard Stallman, Chet Ramey -support/install.sh MIT X Consortium (X11R5) -support/endian.c Chet Ramey -support/printenv Chet Ramey -examples/precedence-tester Brian Fox, Chet Ramey -examples/functions/substr Brian Fox, Chet Ramey -examples/functions/kshenv Chet Ramey -examples/functions/autoload Chet Ramey -examples/functions/csh-compat Brian Fox, Chet Ramey -examples/functions/shcat Chet Ramey -examples/functions/substr2 Chet Ramey -examples/functions/term Chet Ramey -examples/functions/whatis Chet Ramey -examples/functions/whence Chet Ramey -examples/functions/func Chet Ramey -examples/functions/dirname Brian Fox, Noah Friedman -examples/functions/basename Brian Fox, Noah Friedman -examples/functions/exitstat Noah Friedman, Roland McGrath -examples/functions/external Noah Friedman -examples/functions/fact Brian Fox -examples/functions/manpage Tom Tromey -examples/functions/fstty Chet Ramey -examples/functions/jj.bash Chet Ramey -examples/functions/notify.bash Chet Ramey -examples/scripts/shprompt Chet Ramey -examples/scripts/adventure.sh Chet Ramey, Doug Gwyn -examples/scripts/bcsh.sh Chris Robertson, Chet Ramey -examples/startup-files/Bashrc Brian Fox -examples/startup-files/Bash_aliases Brian Fox -examples/startup-files/Bash_profile Brian Fox -examples/startup-files/bash-profile Brian Fox -examples/startup-files/bashrc Chet Ramey -examples/suncmd.termcap Brian Fox, Chet Ramey -examples/alias-conv.sh Brian Fox, Chet Ramey -tests/README Chet Ramey -tests/arith.tests Chet Ramey -tests/arith.right Chet Ramey -tests/array.tests Chet Ramey -tests/array.right Chet Ramey -tests/dollar-at.sh Chet Ramey -tests/dollar-star.sh Chet Ramey -tests/dollar.right Chet Ramey -tests/exp-tests Chet Ramey -tests/exp.right Chet Ramey -tests/glob-test Chet Ramey -tests/glob.right Chet Ramey -tests/ifs-test-1.sh Chet Ramey -tests/ifs-test-2.sh Chet Ramey -tests/ifs-test-3.sh Chet Ramey -tests/ifs.1.right Chet Ramey -tests/ifs.2.right Chet Ramey -tests/ifs.3.right Chet Ramey -tests/input-line.sh Chet Ramey -tests/input-line.sub Chet Ramey -tests/input.right Chet Ramey -tests/minus-e Chet Ramey -tests/minus-e.right Chet Ramey -tests/new-exp.tests Chet Ramey -tests/new-exp.right Chet Ramey -tests/prec.right Chet Ramey -tests/precedence Chet Ramey -tests/run-all Chet Ramey -tests/run-dollars Chet Ramey -tests/run-exp-tests Chet Ramey -tests/run-glob-test Chet Ramey -tests/run-ifs-tests Chet Ramey -tests/run-input-test Chet Ramey -tests/run-minus-e Chet Ramey -tests/run-new-exp Chet Ramey -tests/run-precedence Chet Ramey -tests/run-set-e-test Chet Ramey -tests/run-strip Chet Ramey -tests/run-varenv Chet Ramey -tests/set-e-test Chet Ramey -tests/set-e.right Chet Ramey -tests/strip.tests Chet Ramey -tests/strip.right Chet Ramey -tests/tilde-tests Chet Ramey -tests/tilde.right Chet Ramey -tests/varenv.right Chet Ramey -tests/varenv.sh Chet Ramey -tests/misc/chld-trap.sh Chet Ramey -tests/misc/dot-test-1.sh Chet Ramey -tests/misc/dot-test-1.sub Chet Ramey -tests/misc/gotest Chet Ramey -tests/misc/perf-script Chet Ramey -tests/misc/redir.t1.sh Chet Ramey -tests/misc/redir.t2.sh Chet Ramey -tests/misc/redir.t3.sh Chet Ramey -tests/misc/redir.t3.sub Chet Ramey -tests/misc/redir.t4.sh Chet Ramey -tests/misc/run.r1.sh Chet Ramey -tests/misc/run.r2.sh Chet Ramey -tests/misc/run.r3.sh Chet Ramey -tests/misc/sigint.t1.sh Chet Ramey -tests/misc/sigint.t2.sh Chet Ramey -tests/misc/sigint.t3.sh Chet Ramey -tests/misc/sigint.t4.sh Chet Ramey -tests/misc/test-minus-e.1 Chet Ramey -tests/misc/test-minus-e.2 Chet Ramey -lib/sh/Makefile.in Chet Ramey -lib/sh/clktck.c Chet Ramey -lib/sh/clock.c Chet Ramey -lib/sh/fmtullong.c Chet Ramey -lib/sh/fmtulong.c Chet Ramey -lib/sh/getcwd.c Chet Ramey, Roland McGrath -lib/sh/getenv.c Chet Ramey, Brian Fox -lib/sh/inet_aton.c Chet Ramey, Ulrich Drepper, Paul Vixie -lib/sh/itos.c Chet Ramey -lib/sh/mailstat.c Chet Ramey -lib/sh/makepath.c Chet Ramey -lib/sh/mktime.c Chet Ramey, Paul Eggert -lib/sh/netconn.c Chet Ramey -lib/sh/netopen.c Chet Ramey -lib/sh/oslib.c Chet Ramey, Brian Fox -lib/sh/pathcanon.c Chet Ramey -lib/sh/pathphys.c Chet Ramey -lib/sh/rename.c Chet Ramey -lib/sh/setlinebuf.c Chet Ramey, Brian Fox -lib/sh/shquote.c Chet Ramey -lib/sh/shtty.c Chet Ramey -lib/sh/snprintf.c Chet Ramey, Unknown -lib/sh/spell.c Chet Ramey -lib/sh/strcasecmp.c Chet Ramey, Brian Fox -lib/sh/strerror.c Chet Ramey, Brian Fox -lib/sh/strftime.c Arnold Robbins -lib/sh/strindex.c Chet Ramey -lib/sh/stringlist.c Chet Ramey -lib/sh/stringvec.c Chet Ramey -lib/sh/strpbrk.c Roland McGrath -lib/sh/strtod.c Chet Ramey, Roland McGrath -lib/sh/strtoimax.c Chet Ramey, Paul Eggert -lib/sh/strtol.c Chet Ramey, Paul Eggert -lib/sh/strtoll.c Chet Ramey, Paul Eggert -lib/sh/strtoul.c Chet Ramey, Paul Eggert -lib/sh/strtoull.c Chet Ramey, Paul Eggert -lib/sh/strtoumax.c Chet Ramey, Paul Eggert -lib/sh/strtrans.c Chet Ramey -lib/sh/times.c Chet Ramey, Brian Fox -lib/sh/timeval.c Chet Ramey -lib/sh/tmpfile.c Chet Ramey -lib/sh/vprint.c Chet Ramey, Brian Fox -lib/sh/xstrchr.c Chet Ramey, Mitsuru Chinen -lib/sh/zread.c Chet Ramey -lib/sh/zwrite.c Chet Ramey diff --git a/CHANGES~ b/CHANGES~ deleted file mode 100644 index dd48f75a4..000000000 --- a/CHANGES~ +++ /dev/null @@ -1,4688 +0,0 @@ -This document details the changes between this version, bash-3.0-release, -and the previous version, bash-3.0-rc1. - -1. Changes to Bash - -a. Fixed a boundary overrun that could cause segmentation faults when the - completion code hands an incomplete construct to the word expansion - functions. - -b. Changed posix mode behavior so that an error in a variable assignment - preceding a special builtin causes a non-interactive shell to exit. - -c. Change the directory expansion portion of the completion code to not - expand embedded command substitutions if the directory name appears in - the file system. - -d. Fixed a problem with the default operation of the `umask' builtin. - -2. Changes to Readline - -a. Fixed a problem with readline saving the contents of the current line - before beginning a non-interactive search. - -b. Fixed a problem with EOF detection when using rl_event_hook. - -c. Fixed a problem with the vi mode `p' and `P' commands ignoring numeric - arguments. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.0-rc1, -and the previous version, bash-3.0-beta1. - -1. Changes to Bash - -a. Fixed a bug that caused incorrect behavior when referecing element 0 of - an array using $array, element 0 was unset, and `set -u' was enabled. - -b. System-specific changes for: SCO Unix 3.2, Tandem. - -c. Fixed a bug that caused inappropriate word splitting when a variable was - expanded within a double-quoted string that also included $@. - -d. Fixed a bug that caused `pwd' to not display anything in physical mode - when the file system had changed underneath the shell. - -e. Fixed a bug in the pre- and post- increment and decrement parsing in the - expression evaluator that caused errors when the operands and corresponding - operators were separated by whitespace. - -f. Fixed a bug that caused `history -p' to add an entry to the history list, - counter to the documentation. (Keeps the history expansions invoked by - emacs-mode command line editing from doing that as well.) - -g. Fixed a bug that could cause a core dump if `cd' is asked to print out a - pathname longer than PATH_MAX characters. - -h. Fixed a bug that caused jobs to be put into the wrong process group under - some circumstances after enabling job control with `set -m'. - -i. `unalias' now returns failure if no alias name arguments are supplied. - -j. Documented the characters not allowed to appear in an alias name. - -k. $* is no longer expanded as if in double quotes when it appears in the - body of a here document, as the SUS seems to require. - -l. The `bashbug' script now uses a directory in $TMPDIR for exclusive - access rather than trying to guess how the underlying OS provides for - secure temporary file creation. - -m. Fixed a few problems with `cd' and `pwd' when asked to operate on pathnames - longer than PATH_MAX characters. - -n. Fixed a memory leak caused when creating multiple local array variables - with identical names. - -o. Fixed a problem with calls to getcwd() so that bash now operates better - when the full pathname to the current directory is longer than PATH_MAX - bytes. - -p. The `trap' builtin now reports an error if a single non-signal argument - is specified. - -q. Fixed a bug that caused `umask' to not work correctly when presented - with a mask of all 0s. - -r. When `getopts' reaches the end of options, OPTARG is unset, as POSIX - appears to specify. - -s. Interactive mode now depends on whether or not stdin and stderr are - connected to a tty; formerly it was stdin and stdout. POSIX requires - this. - -t. Fixed vi-mode completion to work more as POSIX specifies (e.g., doing the - right kind of filename generation). - -2. Changes to Readline - -a. Fixed a problem that could cause readline to refer to freed memory when - moving between history lines while doing searches. - -b. Improvements to the code that expands and displays prompt strings - containing multibyte characters. - -c. Fixed a problem with vi-mode not correctly remembering the numeric argument - to the last `c'hange command for later use with `.'. - -d. Fixed a bug in vi-mode that caused multi-digit count arguments to work - incorrectly. - -e. Fixed a problem in vi-mode that caused the last text modification command - to not be remembered across different command lines. - -f. Fixed problems with changing characters and changing case at the end of - the line. - -3. New Features in Bash - -a. The `jobs', `kill', and `wait' builtins now accept job control notation - even if job control is not enabled. - -b. The historical behavior of `trap' that allows a missing `action' argument - to cause each specified signal's handling to be reset to its default is - now only supported when `trap' is given a single non-option argument. - -4. New Features in Readline - -a. When listing completions, directories have a `/' appended if the - `mark-directories' option has been enabled. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.0-beta1, -and the previous version, bash-3.0-alpha. - -1. Changes to Bash - -a. Fixes to build correctly when arrays are not compiled into the shell. - -b. Fixed command substitution to run any exit trap defined in the command - substitution before returning; the exit trap is not inherited from the - calling shell. - -c. Fixes to process group synchronization code so that every child process - attempts to set the terminal's process group; fixes some synchronization - problems on Linux kernels that schedule the child to always run before - the parent. - -d. Fixed processing of octal and hex constants in printf builtin for POSIX.2 - compliance. - -e. Fixed a couple of core dumps in the pattern removal code. - -f. Fixes to the array subrange extraction code to deal better with sparse - arrays. - -g. Parser errors and other errors that result in the shell exiting now cause - the exit trap to be run. - -h. Change the command substitution completion functions to not append any - closing quote, because it would be inserted a closing "`" or ")". - -i. Fix history initialization so assignments to $histchars made in startup - files are honored. - -j. If an exit trap does not contain a call to `exit', the shell now uses - the exit status of the last command executed before the trap as the exit - status of the shell. - -k. The parser now prompts with $PS2 if it reads a newline while parsing a - compound array assignment statement. - -l. When performing a compound array assignment, the parser doesn't treat - words of the form [index]=value as assignments if they're the result of - expansions. - -m. Fixed a bug that caused `return' executed in a trap command to make the - shell think it was still running the trap. - -n. Fixed the value of errno set by the pathname canonicalization functions. - -o. Changed the grammar so that `time' alone on a line times a null command - rather than being a syntax error. - -p. The pattern substitution coded no longer performs quote removal on the - pattern before trying to match it, as the pattern removal functions do. - -q. Fixed a bug that could cause core dumps when checking whether a quoted - command name was being completed. - -r. Fixes to the pattern removal and pattern replacement expansions to deal - with multibyte characters better (and faster). - -s. Fix to the substring expansion (${param:off[:len]}) to deal with (possibly - multibyte) characters instead of raw bytes. - -t. Fixed a bug that caused some key bindings set in an inputrc to be ignored - at shell startup. - -u. Fixed a bug that caused unsetting a local variable within a function to - not work correctly. - -v. Fixed a bug that caused invalid variables to be created when using - `read -a'. - -w. Fixed a bug that caused "$@" to expand incorrectly when used as the right - hand side of a parameter expansion such as ${word:="$@"} if the first - character of $IFS was not a space. - -x. Fixed a slight cosmetic problem when printing commands containing a - `>&word' redirection. - -y. Fixed a problem that could cause here documents to not be created correctly - if the system temporary directory did not allow writing. - -2. Changes to Readline - -a. Change to history expansion functions to treat `^' as equivalent to word - one, as the documention states. - -b. Some changes to the display code to improve display and redisplay of - multibyte characters. - -c. Changes to speed up the multibyte character redisplay code. - -d. Fixed a bug in the vi-mode `E' command that caused it to skip over the - last character of a word if invoked while point was on the word's - next-to-last character. - -e. Fixed a bug that could cause incorrect filename quoting when - case-insensitive completion was enabled and the word being completed - contained backslashes quoting word break characters. - -f. Fixed a bug in redisplay triggered when the prompt string contains - invisible characters. - -g. Fixed some display (and other) bugs encountered in multibyte locales - when a non-ascii character was the last character on a line. - -h. Fixed some display bugs caused by multibyte characters in prompt strings. - -i. Fixed a problem with history expansion caused by non-whitespace characters - used as history word delimiters. - -3. New Features in Bash - -a. printf builtin understands two new escape sequences: \" and \?. - -b. `echo -e' understands two new escape sequences: \" and \?. - -c. The GNU `gettext' package and libintl have been integrated; the shell's - messages can be translated into different languages. - -d. The `\W' prompt expansion now abbreviates $HOME as `~', like `\w'. - -e. The error message printed when bash cannot open a shell script supplied - as argument 1 now includes the name of the shell, to better identify - the error as coming from bash. - -4. New Features in Readline - -a. New application variable, rl_completion_quote_character, set to any - quote character readline finds before it calls the application completion - function. - -b. New application variable, rl_completion_suppress_quote, settable by an - application completion function. If set to non-zero, readline does not - attempt to append a closing quote to a completed word. - -c. New application variable, rl_completion_found_quote, set to a non-zero - value if readline determines that the word to be completed is quoted. - Set before readline calls any application completion function. - -d. New function hook, rl_completion_word_break_hook, called when readline - needs to break a line into words when completion is attempted. Allows - the word break characters to vary based on position in the line. - -e. New bindable command: unix-filename-rubout. Does the same thing as - unix-word-rubout, but adds `/' to the set of word delimiters. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.0-alpha, -and the previous version, bash-2.05b-release. - -1. Changes to Bash - -a. Fixes so that the shell will compile without some of the default options - defined. - -b. Fixed an error message that did not pass enough arguments to printf. - -c. Fixed a bug that caused input redirection to a builtin inside a script - being read from standard input to result in the rest of the already- - read and buffered script to be discarded. - -d. Fixed a bug that caused subshell initialization to close the file - descriptor from which the shell was reading a script under certain - circumstances. - -e. Fixed a bug that caused the shell to not advance a string pointer over - a null wide character when doing string operations. - -f. Fixed the internal logout code so that shells that time out waiting for - input (using $TMOUT) run ~/.bash_logout. - -g. Portability and configuration changes for: cygwin, HP/UX, GNU/FreeBSD. - -h. The parser no longer adds implicit double quotes to ((...)) arithmetic - commands. - -i. The ((...)) arithmetic command evaluation code was fixed to not dump core - when the expanded string is null. - -j. The ((...)) arithmetic command evaluation code was fixed to not perform - variable assignments while expanding the expression. - -k. Fixed a bug that caused word splitting to be performed incorrectly when - IFS is set, but null. - -l. Fixed a bug in brace expansion that caused a quoted `$' preceding an - open brace to inhibit brace expansion. - -m. Fixed a bug that caused a leading `-' in the shell's name to cause it to - not be recognized as a restricted shell. - -n. Fixed a bug in the arithmetic evaluation code that could cause longjmps - to an invalid location and result in a core dump. - -o. Fixed a bug in the calculation of how many history lines are new in a - single shell session when reading new history lines from a file with - `history -n'. - -p. Fixed a bug in pathname canonicalization that caused the shell to dump - core when presented with a pathname longer than PATH_MAX. - -q. Fixed the parser so that it doesn't try to compare a char variable to - EOF, which fails when chars are unsigned. - -r. Fixed a bug in the simple command execution code that caused occasional - core dumps. - -s. The shell does a better job of saving any partial parsing state during - operations which cause a command to be executed while a line is being - entered and parsed. - -t. The completion code now splits words more like the expansion code when - $IFS is used to split. - -u. The locale code does a better job of recomputing the various locale - variable values when LC_ALL is unset. - -v. The programmable completion code does a better job of dequoting expanded - word lists before comparing them against the word to be matched. - -w. The shell no longer seg faults if the expanded value of $PS4 is null - and `set -x' is enabled. - -x. Fixed a bug that caused core dumps when a here string expanded to NULL. - -y. The mail checking code now makes sure the mailbox is bigger before - reporting the existence of new mail. - -z. The parser does not try to expand $'...' and $"..." when the appear - within double quotes unless the `extquote' option has been enabled with - `shopt'. For backwards compatibility, it is enabled by default. - -aa. Fixed a bug that caused `for x; do ...' and `select x; do ... to use - $@ instead of "$@" for the implicit list of arguments. - -bb. Fixed a bug that caused a subshell of a restricted shell (e.g., one - spawned to execute a pipeline) to not exit immediately if attempting - to use a command containing a slash. - -cc. Fixed a problem with empty replacements for a pattern that doesn't match - when performing ${param/word/} expansion. - -dd. Word expansions performed while expanding redirections no longer search - a command's temporary environment to expand variable values. - -ee. Improvements to the alias expansion code when expanding subsequent words - because an aliase's value ends with a space. - -ff. `cd -' now prints the current working directory after a successful chdir - even when the shell is not interactive, as the standard requires. - -gg. The shell does a better job of ensuring a child process dies of SIGINT - before resending SIGINT to itself. - -hh. The arithmetic expansion variable assignment code now does the right - thing when assigning to `special' variables like OPTIND. - -ii. When history expansion verification is enabled, the bash readline helper - functions that do history expansion on the current line don't print - the results. - -jj. Fixed bugs with multiple consecutive alias expansion when one of the - expansions ends with a space. - -kk. Fixed a problem in the programmable completion code that could cause core - dumps when trying to initialize a set of possible completions from a - list of variables. - -ll. The \[ and \] escape characters are now ignored when decoding the prompt - string if the shell is started with editing disabled. - -mm. Fixed a bug that could leave extra characters in a string when doing - quoted null character removal. - -nn. Command substitution and other subshell operations no longer reset the - line number (aids the bash debugger). - -oo. Better line number management when executing simple commands, conditional - commands, for commands, and select commands. - -pp. The globbing code now uses malloc, with its better failure properties, - rather than alloca(). - -qq. Fixed a bug that caused expansions like #{a[2]:=value} to create the - appropriate array element instead of a variable named `a[2]'. - -rr. Fixed a bug in the handling of a `?(...)' pattern immediately following - a `*' when extglob is enabled. - -ss. Fixed a bug that caused a `return' invoked in an exit trap when exit is - invoked in a function to misbehave. - -tt. Fixed a bug that caused CTLESC and CTLNUL characters to not be escaped - by the internal shell string quoting functions. - -uu. Fixed a bug that caused quoted null characters in an expanded word list - to be inappropriately assigned to an array variable when using `read -a'. - -vv. Fixed a bug that caused redirections accompanying a null command to persist - in the current shell. - -ww. Fixed a bug that caused the prompt to be printed when the shell was - expanding a multiline alias. - -xx. Fixed a bug that resulted in core dumps when the completion for a command - changed the compspec. - -yy. Fixed a bug that caused evaluation of programmable completions to print - notifications of completed jobs. - -zz. Bash now disables line editing when $EMACS == `t' and $TERM == `dumb' - (which is what emacs shell windows do). - -aaa. In posix mode, `kill -l' causes signal names to be displayed without - a leading `SIG'. - -bbb. Clear error flag on standard output so it doesn't persist across multiple - builtin commands. - -ccc. In posix mode, `alias' displays alias values without the leading `alias', - so the output cannot be used as subsequent input. - -ddd. In posix mode, the `trap' builtin doesn't check whether or not its - first argument is a signal specification and revert the signal handling - to its original disposition if it is. - -eee. Fixed several bugs in the handling of "$*" and "${array[*]}" by the - pattern substitution and removal expansions. - -fff. Fixed several problems with the handling of ${array[@]}, ${array[*]}, - $@, and $* by the indirect variable expansion code. - -ggg. Fixed a bug that did not allow `time' to be aliased. - -hhh. Improved the mail checking code so it won't check (and possibly cause an - NFS file system mount) until MAILPATH or MAIL is given a value -- there - is no default if DEFAULT_MAIL_DIRECTORY is not defined at compile time. - (It is computed by configure, but can be #undef'd in config-bot.h.) - -iii. If the `chkwinsize' option is enabled, the shell checks for window size - changes if a child process exits due to a signal. - -jjj. Removed the attempts to avoid adding a slash at the end of a completed - executable name if there was a directory with the same name in the - current directory. - -kkk. Fixed PATH lookup code so it treats the permission bits separately for - owner, group, and other, rather than checking them all. - -lll. Fixed the locale code to reset the parser's idea of the character class - , which controls how it splits tokens, when the locale changes. - -mmm. The shell now binds its special readline functions and key bindings only - if the user's inputrc file has not already bound them. - -nnn. The shell now reports on processes that dump core due to signals when - invoked as `-c command'. - -2. Changes to Readline - -a. Fixes to avoid core dumps because of null pointer references in the - multibyte character code. - -b. Fix to avoid infinite recursion caused by certain key combinations. - -c. Fixed a bug that caused the vi-mode `last command' to be set incorrectly. - -d. Readline no longer tries to read ahead more than one line of input, even - when more is available. - -e. Fixed the code that adjusts the point to not mishandle null wide - characters. - -f. Fixed a bug in the history expansion `g' modifier that caused it to skip - every other match. - -g. Fixed a bug that caused the prompt to overwrite previous output when the - output doesn't contain a newline and the locale supports multibyte - characters. This same change fixes the problem of readline redisplay - slowing down dramatically as the line gets longer in multibyte locales. - -h. History traversal with arrow keys in vi insertion mode causes the cursor - to be placed at the end of the new line, like in emacs mode. - -i. The locale initialization code does a better job of using the right - precedence and defaulting when checking the appropriate environment - variables. - -j. Fixed the history word tokenizer to handle <( and >( better when used as - part of bash. - -k. The overwrite mode code received several bug fixes to improve undo. - -l. Many speedups to the multibyte character redisplay code. - -m. The callback character reading interface should not hang waiting to read - keyboard input. - -n. Fixed a bug with redoing vi-mode `s' command. - -o. The code that initializes the terminal tracks changes made to the terminal - special characters with stty(1) (or equivalent), so that these changes - are reflected in the readline bindings. New application-callable function - to make it work: rl_tty_unset_default_bindings(). - -p. Fixed a bug that could cause garbage to be inserted in the buffer when - changing character case in vi mode when using a multibyte locale. - -q. Fixed a bug in the redisplay code that caused problems on systems - supporting multibyte characters when moving between history lines when the - new line has more glyphs but fewer bytes. - -r. Undo and redo now work better after exiting vi insertion mode. - -s. Make sure system calls are restarted after a SIGWINCH is received using - SA_RESTART. - -t. Improvements to the code that displays possible completions when using - multibyte characters. - -u. Fixed a problem when parsing nested if statements in inputrc files. - -v. The completer now takes multibyte characters into account when looking for - quoted substrings on which to perform completion. - -w. The history search functions now perform better bounds checking on the - history list. - -3. New Features in Bash - -a. ANSI string expansion now implements the \x{hexdigits} escape. - -b. There is a new loadable `strftime' builtin. - -c. New variable, COMP_WORDBREAKS, which controls the readline completer's - idea of word break characters. - -d. The `type' builtin no longer reports on aliases unless alias expansion - will actually be performed. - -e. HISTCONTROL is now a colon-separated list of values, which permits - more extensibility and backwards compatibility. - -f. HISTCONTROL may now include the `erasedups' option, which causes all lines - matching a line being added to be removed from the history list. - -g. `configure' has a new `--enable-multibyte' argument that permits multibyte - character support to be disabled even on systems that support it. - -h. New variables to support the bash debugger: BASH_ARGC, BASH_ARGV, - BASH_SOURCE, BASH_LINENO, BASH_SUBSHELL, BASH_EXECUTION_STRING, - BASH_COMMAND - -i. FUNCNAME has been changed to support the debugger: it's now an array - variable. - -j. for, case, select, arithmetic commands now keep line number information - for the debugger. - -k. There is a new `RETURN' trap executed when a function or sourced script - returns (not inherited child processes; inherited by command substitution - if function tracing is enabled and the debugger is active). - -l. New invocation option: --debugger. Enables debugging and turns on new - `extdebug' shell option. - -m. New `functrace' and `errtrace' options to `set -o' cause DEBUG and ERR - traps, respectively, to be inherited by shell functions. Equivalent to - `set -T' and `set -E' respectively. The `functrace' option also controls - whether or not the DEBUG trap is inherited by sourced scripts. - -n. The DEBUG trap is run before binding the variable and running the action - list in a `for' command, binding the selection variable and running the - query in a `select' command, and before attempting a match in a `case' - command. - -o. New `--enable-debugger' option to `configure' to compile in the debugger - support code. - -p. `declare -F' now prints out extra line number and source file information - if the `extdebug' option is set. - -q. If `extdebug' is enabled, a non-zero return value from a DEBUG trap causes - the next command to be skipped, and a return value of 2 while in a - function or sourced script forces a `return'. - -r. New `caller' builtin to provide a call stack for the bash debugger. - -s. The DEBUG trap is run just before the first command in a function body is - executed, for the debugger. - -t. `for', `select', and `case' command heads are printed when `set -x' is - enabled. - -u. There is a new {x..y} brace expansion, which is shorthand for {x.x+1, - x+2,...,y}. x and y can be integers or single characters; the sequence - may ascend or descend; the increment is always 1. - -v. New ksh93-like ${!array[@]} expansion, expands to all the keys (indices) - of array. - -w. New `force_fignore' shopt option; if enabled, suffixes specified by - FIGNORE cause words to be ignored when performing word completion even - if they're the only possibilities. - -x. New `gnu_errfmt' shopt option; if enabled, error messages follow the `gnu - style' (filename:lineno:message) format. - -y. New `-o bashdefault' option to complete and compgen; if set, causes the - whole set of bash completions to be performed if the compspec doesn't - result in a match. - -z. New `-o plusdirs' option to complete and compgen; if set, causes directory - name completion to be performed and the results added to the rest of the - possible completions. - -aa. `kill' is available as a builtin even when the shell is built without - job control. - -bb. New HISTTIMEFORMAT variable; value is a format string to pass to - strftime(3). If set and not null, the `history' builtin prints out - timestamp information according to the specified format when displaying - history entries. If set, bash tells the history library to write out - timestamp information when the history file is written. - -cc. The [[ ... ]] command has a new binary `=~' operator that performs - extended regular expression (egrep-like) matching. - -dd. `configure' has a new `--enable-cond-regexp' option (enabled by default) - to enable the =~ operator and regexp matching in [[ ... ]]. - -ee. Subexpressions matched by the =~ operator are placed in the new - BASH_REMATCH array variable. - -ff. New `failglob' option that causes an expansion error when pathname - expansion fails to produce a match. - -gg. New `set -o pipefail' option that causes a pipeline to return a failure - status if any of the processes in the pipeline fail, not just the last - one. - -4. New Features in Readline - -a. History expansion has a new `a' modifier equivalent to the `g' modifier - for compatibility with the BSD csh. - -b. History expansion has a new `G' modifier equivalent to the BSD csh `g' - modifier, which performs a substitution once per word. - -c. All non-incremental search operations may now undo the operation of - replacing the current line with the history line. - -d. The text inserted by an `a' command in vi mode can be reinserted with - `.'. - -e. New bindable variable, `show-all-if-unmodified'. If set, the readline - completer will list possible completions immediately if there is more - than one completion and partial completion cannot be performed. - -f. There is a new application-callable `free_history_entry()' function. - -g. History list entries now contain timestamp information; the history file - functions know how to read and write timestamp information associated - with each entry. - -h. Four new key binding functions have been added: - - rl_bind_key_if_unbound() - rl_bind_key_if_unbound_in_map() - rl_bind_keyseq_if_unbound() - rl_bind_keyseq_if_unbound_in_map() - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05b-release, -and the previous version, bash-2.05b-beta2. - -1. Changes to Bash - -a. Fixed an off-by-one error in the function that translates job - specifications. - -b. Note that we're running under Emacs and disable line editing if - $EMACS == `t'. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05b-beta2, -and the previous version, bash-2.05b-beta1. - -1. Changes to Bash - -a. Fixed the /= and %= arithmetic operators to catch division by zero. - -b. Added putenv, setenv, unsetenv to getenv replacement for completeness. - -c. Fixed a bug that could cause the -O expand_aliases invocation option - to not take effect. - -d. Fixed a problem with process substitution that resulted in incorrect - behavior when the number of process substitutions in an individual - command approached 64. - -2. Changes to Readline - -a. Fixed a problem with backward-char-search when on a system with support - for multibyte characters when running in a locale without any multibyte - characters. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05b-beta1, -and the previous version, bash-2.05b-alpha1. - -1. Changes to Bash - -a. Fixed a problem when parsing a POSIX.2 character class name while - evaluating a bracket expression containing multibyte characters. - -b. Changed the help text for `bind' to make it clear that any command - that may be placed in ~/.inputrc is a valid argument to `bind'. - -c. Added `help' builtin entries for `((', `[[', and arithmetic for. - -d. malloc updated again: - o slightly better overflow and underflow detection by putting the - chunk size at the beginning and end of the chunk and making - sure they match in free/realloc - o partial page allocated to make things page-aligned no longer - completely wasted - o block coalescing now enabled by default - o splitting and coalescing enabled for 32-byte chunks, the most - common size requested - o fixed a problem that resulted in spurious underflow messages and - aborts - o bin sizes are precomputed and stored in an array rather than - being computed at run time - o malloc will return memory blocks back to the system if the block - being freed is at the top of the heap and of sufficient size to - make it worthwhile - o malloc/free/realloc now inline memset instead of calling the - libc function; uses Duff's device for good performance - -e. Check for getservent(); make the service name completion code dependent - on its presence. - -f. Changed the readline callback that executes a command bound to a key - sequence to not save the executed command on the history list and to - save and restore the parsing state. - -g. Changes to lib/sh/snprintf.c: fixed some bugs in the `g' and `G' - floating point format display; implemented the "'" flag character - that turns on thousands' grouping; fixed behavior on systems where - MB_CUR_MAX does not evaluate to a constant. - -h. The `unset' builtin no longer returns a failure status when asked to - unset a previously-unset variable or function. - -i. Changes to the build system to make it easier to cross-compile bash - for different systems. - -j. Added `,' to the characters that are backslash-escaped during filename - completion, to avoid problems with complete-into-braces and RCS filenames - containing commas. - -k. Some changes to the multibyte character support code to avoid many calls - to strlen(). - -l. Bash now correctly honors setting LANG to some value when LC_ALL does not - already have a value. - -m. Fixed a bug that could cause SIGSEGV when processing nested traps with - trap handlers. - -n. The `source/.' builtin now restores the positional parameters when it - returns unless they were changed using the `set' builtin during the file's - execution. - -o. Fixed a bug that caused a syntax error when a command was terminated by - EOF. - -2. New Features in Bash - -a. There is now support for placing the long help text into separate files - installed into ${datadir}/bash. Not enabled by default; can be turned - on with `--enable-separate-helpfiles' option to configure. - -b. All builtins that take operands accept a `--' pseudo-option, except - `echo'. - -c. The `echo' builtin now accepts \0xxx (zero to three octal digits following - the `0') in addition to \xxx (one to three octal digits) for SUSv3/XPG6/ - POSIX.1-2001 compliance. - -3. Changes to Readline - -a. Fixed a small problem in _rl_insert_char with multibyte characters. - -b. Fixes from IBM for line wrapping problems when using multibyte characters. - -c. Fixed a problem which caused the display to be messed up when the last - line of a multi-line prompt (possibly containing invisible characters) - was longer than the screen width. - -d. Fixed a problem with the vi-mode `r' command that ocurred on systems with - support for multibyte characters when running in a locale without any - multibyte characters. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05b-alpha1, -and the previous version, bash-2.05a-release. - -1. Changes to Bash - -a. Some changes to work around inlining differences between compilers. - -b. Added more prototypes for internal shell typedefs, to catch argument - passing errors when using pointers to functions. - -c. The `cd' builtin now fails in posix mode when a valid directory cannot be - constructed from a relative pathname argument and the $PWD using pathname - canonicalization, and the -P option has not been supplied. Previously, - the shell would attempt to use what the user typed, leading to weird - values for $PWD and discrepancies between the value of $PWD and the - actual working directory. - -d. The `cd' builtin now resets $PWD when canonicalization fails but a chdir - to the pathname passed as an argument succeeds (when not in posix mode). - -e. The `fc' builtin has been fixed, as POSIX requires, to use the closest - history position in range when given an out-of-range argument. - -f. The history file loading code was changed to allow lines to be saved in - the history list from the shell startup files. - -g. `history -s args' now works better in compound commands. - -h. The tilde expansion code was fixed to better recognize when it's being - invoked in an assignment context, which enables expansion after `=' - and `:'. - -i. Fixed the command name completion code so a slash is no longer appended - to a single match if there happens to be a directory with that name in - $PWD. - -j. Fixed compound array assignment to no longer perform alias expansion, to - allow reserved words as array members, and to not produce extra output - when the `-v' option had been enabled. - -k. Fixed the programmable completion code to better handle newlines in lists - of possible completions (e.g., `complete -W'). - -l. Removed the reserved words from the `bash-builtins' manual page. - -m. Parser error reporting now attempts to do a better job of identifying the - token in error rather than doing straight textual analysis. - -n. Fixes for Inf/NaN, locales, wide/multibyte characters and zero-length - arguments in the library snprintf(3) replacement. - -o. `read -e' no longer does command name completion on the first word on - the line being read. - -p. `select' now returns failure if the read of the user's selection fails. - -q. Fixed a bug that could cause a core dump when setting $PIPESTATUS. - -r. Fixes to not allocate so many job slots when the shell is running a loop - with job control enabled in a subshell of an interactive shell. - -s. Fixed a bug in the trap code that caused traps to be inherited by - command substitutions in some cases. - -t. Fixed a bug that could cause alias expansion to inappropriately expand - the word following the alias. - -u. Fixed a bug in the `kill' builtin that mishandled negative pid arguments. - -v. The parser is less lenient when parsing assignment statements where the - characters before the `=' don't comprise a valid identifier. - -w. The arithmetic expression evaluation code now honors the setting of the - `-u' option when expanding variable names. - -x. Fixed the arithmetic evaluation code to allow array subscripts to be - assigned (`let b[7]=42') and auto-incremented and auto-decremented - (e.g., b[7]++). - -y. Reimplemented the existing prompt string date and time expansions using - strftime(3), which changed the output of \@ in some locales. - -z. Fixed a bug that could cause a core dump when a special shell variable - (like RANDOM) was converted to an array with a variable assignment. - -aa. Fixed a bug that would reset the handler for a signal the user had - trapped to a function that would exit the shell when setting the exit - trap in a non-interactive shell. - -bb. Changed the execve(2) wrapper code to check whether or not a failing - command is a directory before looking at whether a `#!' interpreter - failed for some reason. - -cc. Fixed a bug in the command printing code so it no longer inserts a `;' - after a newline, which produces a syntax error when reused as input. - -dd. The code that expands $PS4 no longer inherits the `-x' flag. - -ee. The bash-specific completion functions may now take advantage of the - double-TAB and M-? features of the standard readline completion - functions. - -ff. The mail checking code no longer prints a message if the checked file's - size has not increased, even if the access time is less than the modification time. - -gg. Rewrote the variable symbol table code: there is now a stack of - contexts, each possibly including a separate symbol table; there can - be more than one temporary environment supplied to nested invocations - of `./source'; the temporary environments no longer require so much - special-case code; shell functions now handle the temporary environment - and local variables more consistently; function scope exit is faster now - that the entire symbol table does not have to be traversed to dispose of - local variables; it is now easier to push vars from the temporary - environment to the shell's variable table in posix mode; some duplicated - code has been removed. - -hh. Regularized the error message printing code; builtin_error is now called - more consistently, and common error message strings are handled by small - functions. This should make eventual message translation easier. - -ii. Error messages now include the line number in a script when the shell - is not interactive. - -jj. Array subscript expansion now takes place even when the array variable is - unset, so side effects will take place. - -kk. Fixed a bug in the SICGHLD child-reaping code so that it won't find - jobs already marked as terminated if the OS reuses pids quickly enough. - -ll. Fixed a bug that could cause a signal to not interrupt the `wait' - builtin while it was waiting for a background process to terminate. - -mm. A couple of changes to make it easier for multiple shells to share history - files using `history -n', `history -r', and `history -w'. - -nn. The `getopts' builtin always increments OPTIND to point to the next - option to be handled when an option is returned, whether it's valid - or not, as POSIX 1003.x-2001 requires. - -oo. Changed some parts of the expansion code to avoid allocating and - immediately freeing memory without using the results for anything. - -pp. The shell now keeps track of $IFS internally, updating its internal map - each time the variable is assigned a new value (or at local scope exit). - This saves thousands of hash lookups for IFS, which, while individually - cheap, add up. - -qq. Rewrote the hash table code: searching and insertion are much faster now, - and it uses a better string hashing function; augmented the function - interface to simplify other parts of the code and remove duplicated code - -rr. The shell now uses a simple, generic `object cache' for allocating and - caching words and word lists, which were the major users of - malloc/free. - -ss. Fixed the assignment statement parsing code to allow whitespace and - newlines in subscripts when performing array element assignment. - -tt. The shell now issues many fewer calls to sigprocmask and other signal - masking system calls. - -uu. Fixed the `test' and conditional command file comparison operators to - work right when one file has a non-positive timestamp and the other - does not exist. - -vv. Fixed some cases where the special characters '\001' and '\177' in the - values of variables or positional parameters caused incorrect expansion - results. - -2. Changes to Readline - -a. Fixed output of comment-begin character when listing variable values. - -b. Added some default key bindings for common escape sequences produced by - HOME and END keys. - -c. Fixed the mark handling code to be more emacs-compatible. - -d. A bug was fixed in the code that prints possible completions to keep it - from printing empty strings in certain circumstances. - -e. Change the key sequence printing code to print ESC as M\- if ESC is a - meta-prefix character -- it's easier for users to understand than \e. - -f. Fixed unstifle_history() to return values that match the documentation. - -g. Fixed the event loop (rl_event_hook) to handle the case where the input - file descriptor is invalidated. - -h. Fixed the prompt display code to work better when the application has a - custom redisplay function. - -i. Changes to make reading and writing the history file a little faster, and - to cope with huge history files without calling abort(3) from xmalloc. - -j. The vi-mode `S' and `s' commands are now undone correctly. - -3. New Features in Bash - -a. If set, TMOUT is the default timeout for the `read' builtin. - -b. `type' has two new options: `-f' suppresses shell function lookup, and - `-P' forces a $PATH search. - -c. New code to handle multibyte characters. - -d. `select' was changed to be more ksh-compatible, in that the menu is - reprinted each time through the loop only if REPLY is set to NULL. - The previous behavior is available as a compile-time option. - -e. `complete -d' and `complete -o dirnames' now force a slash to be - appended to names which are symlinks to directories. - -f. There is now a bindable edit-and-execute-command readline command, - like the vi-mode `v' command, bound to C-xC-e in emacs mode. - -g. Added support for ksh93-like [:word:] character class in pattern matching. - -h. The $'...' quoting construct now expands \cX to Control-X. - -i. A new \D{...} prompt expansion; passes the `...' to strftime and inserts - the result into the expanded prompt. - -j. The shell now performs arithmetic in the largest integer size the - machine supports (intmax_t), instead of long. - -k. If a numeric argument is supplied to one of the bash globbing completion - functions, a `*' is appended to the word before expansion is attempted. - -l. The bash globbing completion functions now allow completions to be listed - with double tabs or if `show-all-if-ambiguous' is set. - -m. New `-o nospace' option for `complete' and `compgen' builtins; suppresses - readline's appending a space to the completed word. - -n. New `here-string' redirection operator: <<< word. - -o. When displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -p. There is a new configuration option `--enable-mem-scramble', controls - bash malloc behavior of writing garbage characters into memory at - allocation and free time. - -q. The `complete' and `compgen' builtins now have a new `-s/-A service' - option to complete on names from /etc/services. - -r. `read' has a new `-u fd' option to read from a specified file descriptor. - -s. Fix the completion code so that expansion errors in a directory name - don't cause a longjmp back to the command loop. - -t. Fixed word completion inside command substitution to work a little more - intuitively. - -u. The `printf' %q format specifier now uses $'...' quoting to print the - argument if it contains non-printing characters. - -v. The `declare' and `typeset' builtins have a new `-t' option. When applied - to functions, it causes the DEBUG trap to be inherited by the named - function. Currently has no effect on variables. - -w. The DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops. - -x. The expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires. - -y. The bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better. Code - from Gary Vaughan. - -z. New [n]<&word- and [n]>&word- redirections from ksh93 -- move fds (dup - and close). - -aa. There is a new `-l' invocation option, equivalent to `--login'. - -bb. The `hash' builtin has a new `-l' option to list contents in a reusable - format, and a `-d' option to remove a name from the hash table. - -4. New Features in Readline - -a. Support for key `subsequences': allows, e.g., ESC and ESC-a to both - be bound to readline functions. Now the arrow keys may be used in vi - insert mode. - -b. When listing completions, and the number of lines displayed is more than - the screen length, readline uses an internal pager to display the results. - This is controlled by the `page-completions' variable (default on). - -c. New code to handle editing and displaying multibyte characters. - -d. The behavior introduced in bash-2.05a of deciding whether or not to - append a slash to a completed name that is a symlink to a directory has - been made optional, controlled by the `mark-symlinked-directories' - variable (default is the 2.05a behavior). - -e. The `insert-comment' command now acts as a toggle if given a numeric - argument: if the first characters on the line don't specify a - comment, insert one; if they do, delete the comment text - -f. New application-settable completion variable: - rl_completion_mark_symlink_dirs, allows an application's completion - function to temporarily override the user's preference for appending - slashes to names which are symlinks to directories. - -g. New function available to application completion functions: - rl_completion_mode, to tell how the completion function was invoked - and decide which argument to supply to rl_complete_internal (to list - completions, etc.). - -h. Readline now has an overwrite mode, toggled by the `overwrite-mode' - bindable command, which could be bound to `Insert'. - -i. New application-settable completion variable: - rl_completion_suppress_append, inhibits appending of - rl_completion_append_character to completed words. - -j. New key bindings when reading an incremental search string: ^W yanks - the currently-matched word out of the current line into the search - string; ^Y yanks the rest of the current line into the search string, - DEL or ^H deletes characters from the search string. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05a-release, -and the previous version, bash-2.05a-rc1. - -1. Changes to Bash - -a. Fixed the `printf' builtin so that the variable name supplied as an - argument to a %n conversion must be a valid shell identifier. - -b. Improved the random number generator slightly. - -c. Changes to configuration to not put -I/usr/include into $CFLAGS, since - it messes up some includes. - -d. Corrected description of POSIXLY_CORRECT in man page and info manual. - -e. Fixed a couple of cases of incorrect function prototypes that sneaked - through and caused compilation problems. - -f. A few changes to avoid potential core dumps in the programmable completion - code. - -g. Fixed a configure problem that could cause a non-existent file to show - up in LIBOBJS. - -h. Fixed a configure problem that could cause siglist.o to not be built when - required. - -i. Changes to the strtoimax and strtoumax replacement functions to work - around buggy compilers. - -j. Fixed a problem with the snprintf replacement function that could - potentially cause a core dump. - -2. Changes to Readline - -a. Fixed a locale-specific problem in the vi-mode `goto mark' command. - -b. Fixed Makefile to not put -I/usr/include into CFLAGS, since it can cause - include file problems. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05a-rc1, -and the previous version, bash-2.05a-beta1. - -1. Changes to Bash - -a. Fixed the snprintf replacement to correctly implement the `alternate form' - of the %g and %G conversions. - -b. Fixed snprintf to correctly handle the optional precision with the %g and - %G conversions. - -c. Fixed the arithmetic evaluation code to correct the values of `@' and `_' - when translating base-64 constants (they were backwards). - -d. New library functions for formatting long and long long ints. - -e. Fixed a few places where negative array subscripts could have occurred, - mostly as the result of systems using signed characters. - -f. Fixed a few places that assumed a pid_t was no wider than an int. - -g. Fixed the `maildir' mail checking code to work on systems where a - `struct stat' doesn't include an `st_blocks' member. - -h. Fixed snprintf to make `unsigned long long' conversion formats (%llu) - work better. - -i. Fixed snprintf to not print a sign when asked to do an unsigned conversion. - -j. Made configure changes to avoid compiling empty source files in lib/sh. - -k. New replacement functions (if necessary) for strtoull, strtoll, strtoimax, - strtoumax. - -l. The `printf' builtin now handles the `ll' and `j' length modifiers - directly, since they can affect the type and width of the argument - passed to printf(3). - -m. Renamed a number of the bash-specific autoconf macros in aclocal.m4 to - have more sytematic naming, with accompanying changes to configure.in. - -n. Fixed snprintf to handle long doubles and the %a/%A conversions by - falling back to sprintf, as long as sprintf supports them. - -o. Fixed return value from vsnprintf/snprintf to be the number of characters - that would have been printed, even if that number exceeds the buffer - size passed as an argument. - -p. Bash no longer attempts to define its own versions of some ctype macros - if they are implemented as functions in libc but not as macros in - . - -q. Changed the variable printing code (used by `set', `export', etc.) to - not use the $'...' syntax when in posix mode, since that caused - interoperability problems with other shells (most notably with autoconf). - When not in posix mode, it uses $'...' if the string to be printed - contains non-printing characters and regular single quotes otherwise. - -r. snprintf now recognizes the %F conversion. - -s. Fixed a bug that could cause the wrong status to be returned by a shell - function when the shell is compiled without job control and a null - command containing a command substutition was executed in the function. - -t. When in posix mode, the default value for MAILCHECK is 600. - -u. Bash only initializes FUNCNAME, GROUPS, and DIRSTACK as special variables - if they're not in the initial environment. - -v. If SECONDS appears in the initial environment with a valid integer value, - bash uses that as the starting value, as if an assignment had been - performed. - -w. Bash no longer auto-exports HOME, PATH, SHELL, or TERM, even though it - gives them default values if they don't appear in the initial environment. - -x. Bash no longer auto-exports HOSTNAME, HOSTTYPE, MACHTYPE, or OSTYPE, - even if it assigns them default values. - -y. Bash no longer removes the export attribute from SSH_CLIENT or SSH2_CLIENT - if they appear in the initial environment. - -z. Bash no longer attempts to discover if it's being run by sshd in order to - run the startup files. If the SSH_SOURCE_BASHRC is uncommented in - config-top.h it will attempt to do so as previously, but that's commented - out in the distributed version. - -aa. Fixed a typo in the code that tests for LC_NUMERIC. - -bb. The POSIXLY_CORRECT shell variable and its effects are now documented. - -cc. Some changes to several of the support shell scripts included in the - definitions to try to avoid race conditions and attacks. - -dd. Several changes to avoid warnings from `gcc -Wall'. - -ee. Fixed a problem with the `unset' builtin that could cause incorrect - results if asked to unset a variable and an array subscript in the - same command. - -ff. A few changes to the shell's temporary file creation code to avoid - potential file descriptor leaks and to prefer the system's idea of - the temporary directory to use. - -gg. Fixes to build with the C alloca in lib/malloc/alloca.c if the system - requires it but the shell has been configured --without-bash-malloc. - -hh. Updated the documentation to note that only interactive shells resend - SIGHUP to all jobs before exiting. - -ii. Fixes to only pass unquoted tilde words to tilde_expand, rather than - rely on tilde_expand or getpwnam(3) to handle the quotes (MacOS 10.x - will remove backslashes in any login name passed to getpwnam(3)). - -jj. Small change from Paul Eggert to make LINENO right in commands run with - `bash -c'. - -2. New Features in Bash - -a. The `printf' builtin now handles the %a and %A conversions if they're - implemented by printf(3). - -b. The `printf' builtin now handles the %F conversion (just about like %f). - -c. The `printf' builtin now handles the %n conversion like printf(3). The - corresponding argument is the name of a shell variable to which the - value is assigned. - -3. Changes to Readline - -a. Fixed a few places where negative array subscripts could have occurred. - -b. Fixed the vi-mode code to use a better method to determine the bounds of - the array used to hold the marks. - -c. Fixed the defines in chardefs.h to work better when chars are signed. - -d. Fixed configure.in to use the new names for bash autoconf macros. - -e. Readline no longer attempts to define its own versions of some ctype - macros if they are implemented as functions in libc but not as macros in - . - -f. Fixed a problem where rl_backward could possibly set point to before - the beginning of the line. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05a-beta1, -and the previous version, bash-2.05a-alpha1. - -1. Changes to Bash - -a. Fixed a bug in the evalution of arithmetic `for' statements when the - expanded expression is NULL. - -b. Fixed an unassigned variable problem in the redirection printing code. - -c. Added more prototypes to extern function declarations in the header - files and to static function declarations in C source files. - -d. Make sure called functions have a prototype in scope, to get the arguments - and return values right instead of casting. Removed extern function - declarations from C source files that were already included in header - files. - -e. Changed some function arguments to use function typedefs in general.h so - the prototypes can be checked. The only use of Function and VFunction - now is for unwind-protects. - -f. More const changes to function arguments and appropriate variables. - -g. Changed the mail checking support to handle `maildir'-style mail - directories. - -h. Augmented the bash malloc to pass in the file and line number information - for each malloc, realloc, and free. This should result in better error - messages. - -i. The `old' gnu malloc is no longer a configuration option. - -j. Augmented the bash malloc with optional tracing and registering allocated - and freed memory. - -k. Prompt string decoding now saves and restores the value of $? when it - expands the prompt string, so command substitutions don't change $?. - -i. Array indices are now `long', since shell arithmetic is performed as long, - and the internal arrayind_t type is used consistently. - -j. Some more `unsigned char *' fixes from Paul Eggert. - -k. Fixed a bad call to builtin_error that could cause core dumps when making - local variables. - -l. `return' may no longer be used to terminate a `select' command, for - compatibility with ksh. - -m. Changed code that reads octal numbers to do a better job of detecting - overflows. - -n. The time formatting code no longer uses absolute indices into a buffer, - because the buffer size changes depending on the size of a `time_t'. - -o. `umask' now prints four digits when printing in octal mode, for - compatibility with other shells. - -p. Lots of changes to the `printf' builtin from Paul Eggert: it handles `L' - formats and long doubles better, and internal functions have been - simpified where appropriate. - -q. Some `time_t' fixes for machines were a time_t is bigger than a long. - -r. Replaced some bash-specific autoconf macros with standard equivalents. - -s. Improvmed the code that constructs temporary filenames to make the - generated names a bit more random. - -t. Added code that checks for ascii before calling any of the is* ctype - functions. - -u. Changed some places where a `char' was used as an array subscript to use - `unsigned char', since a `char' can be negative if it's signed by default. - -v. Lots of changes to the `ulimit' builtin from Paul Eggert to add support - for the new POSIX-200x RLIM_SAVED_CUR and RLIM_SAVED_MAX values and - simplify the code. - -w. `ulimit' now prints the description of a resource in any error message - relating to fetching or setting that resource's limits. - -x. The `snprintf' replacement now computes maximum values at compile - time rather than using huge constants for things like long long. - -y. Interactive shells now ignore `set -n'. - -z. Changed the malloc bookkeeping information so that it's now 8 bytes - instead of 12 on most 32-bit machines (saving 4 bytes per allocation), - restoring 8-byte alignment. - -aa. The malloc error reporting code now attempts to print the file and line - number of the call that caused the error. - -bb. Changed the redirection error reporting code to catch EBADF errors and - report the file descriptor number rather than the file being redirected - to or from (e.g., things like `exec 4242&word' redirection now works in POSIX mode as it does by default, - since POSIX.2 leaves it unspecified. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05-beta2, -and the previous version, bash-2.05-beta1. - -1. Changes to Bash - -a. Fixed a bug in the arithmetic evaluation code so that a^=b is supported. - -b. Fixed startup so posixly_correct is retained across subshells begun to - execute scripts without a leading `#!'. - -c. Fixed a bug that caused $(< file) to not work in a (...) subshell. - -d. Added config support for Linux running on the IBM S390. - -e. Fixed a bug that caused bash to get its input pointer out of sync when - reading commands through a pipe and running a command with standard - input redirected from a file. - -f. Made a change so that command completion now makes about half as many - stat(2) calls when searching the $PATH. - -g. Fixed a bug that caused variable assignments preceding `return' to not - be propagated to the shell environment in POSIX mode. - -h. Fixed a bug with ${parameter[:]?word} -- tilde expansion was not performed - on `word'. - -i. In POSIX mode, `break' and `continue' do not complain and return success - if called when the shell is not executing a loop. - -j. Fixed `bash -o posix' to work the same as `bash --posix'. - -k. Fixed a bug where variable assignments preceding `eval' or `source/.' - would not show up in the environment exported to subshells run by the - commands. - -l. In POSIX mode, shells started to execute command substitutions inherit - the value of the `-e' option from their parent shell. - -m. In POSIX mode, aliases are expanded even in non-interactive shells. - -n. Changed some of the job control messages to display the text required by - POSIX.2 when the shell is in POSIX mode. - -o. Fixed a bug in `test' that caused it to occasionally return incorrect - results when non-numeric arguments were supplied to `-t'. - -2. Changes to Readline - -a. Some changes were made to avoid gcc warnings with -Wall. - -b. rl_get_keymap_by_name now finds keymaps case-insensitively, so - `set keymap EMACS' works. - -c. The history file writing and truncation functions now return a useful - status on error. - -d. Fixed a bug that could cause applications to dereference a NULL pointer - if a NULL second argument was passed to history_expand(). - -3. New Features in Bash - -a. doc/readline.3 has been moved to the readline distribution. - -4. New Features in Readline - -a. New function, rl_get_screen_size (int *rows, int *columns), returns - readline's idea of the screen dimensions. - -b. The timeout in rl_gather_tyi (readline keyboard input polling function) - is now settable via a function (rl_set_keyboard_input_timeout()). - -c. Renamed the max_input_history variable to history_max_entries; the old - variable is maintained for backwards compatibility. - -d. The list of characters that separate words for the history tokenizer is - now settable with a variable: history_word_delimiters. The default - value is as before. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05-beta1, -and the previous version, bash-2.05-alpha1. - -1. Changes to Bash - -a. Changes to allow shared library and object building on the GNU Hurd. - -b. Fixes to the way exported functions are placed into the environment and - cached. - -c. The globbing library once again respects locales when processing ranges - in bracket expressions while doing pattern matching. - -d. System-specific configuration changes for: Tru 64, Interix - -e. Bashbug now uses /usr/bin/editor as one of the editing alternatives, and - will use mktemp(1) or tempfile(1), if present, for temporary file creation. - -f. Bash no longer performs a binary file check on a script argument that's - really a tty (like /dev/fd/0 or /dev/stdin). - -g. Fixed a bug in the execution of shell scripts that caused the effects of - $BASH_ENV to be undone in some cases. - -h. Fixed several bugs that made `bash [-i] /dev/stdin' not work correctly. - -i. Several changes to the job control code to avoid some signal state - manipulation. - -j. The Bash malloc no longer blocks signals as often, which should make it - faster. - -k. Fixed a parsing bug that did not allow backslash to escape a single quote - inside a $'...' construct. - -l. Fixed a bug that caused things like ${var:=$'value'} to be parsed - incorrectly. This showed up in newer versions of autoconf. - -m. Fixed a bug in the bash-specific readline initialization that caused - key bindings to bash-specific function names appearing in .inputrc to - not be honored. - -n. Bash now sets the file descriptor it uses to save the file descriptor - opened on a shell script to close on exec. - -o. Fixed a bug in the prompt string decoding that caused it to misbehave - when presented an octal sequence of fewer than three characters. - -p. Fixed the `test' builtin to return an error if `[' is supplied a single - argument that is not `]'. - -q. Fixed a bug that caused subshells started to run executable shell scripts - without a leading `#!' to incorrectly inherit an argument list preceding - a shell builtin (like such a script called from a script sourced with `.', - where there were variable assignments preceding the `.' command) - -r. Fixed a bug that caused changes to variables supplied in an assignment - statement preceding a shell builtin to not be honored (like a script - run with `.'). - -s. HOSTTYPE, OSTYPE, and MACHTYPE are set only if they do not have values - when the shell is started. - -t. Fixed a bug that caused SIGINT to kill shell scripts after the script - called `wait'. - -u. The `fc' builtin now tries to create its temporary files in the directory - named by $TMPDIR. - -v. Bash no longer calls any Readline functions or uses any Readline variables - not declared in readline.h. - -w. Fixed a bug that caused some substitutions involving $@ to not be split - correctly, especially expansions of the form ${paramterOPword}. - -x. SSH2_CLIENT is now treated like SSH_CLIENT and not auto-exported if it - appears in the initial environment. - -y. Fixed a couple of problems with shell scripts without a leading `#!' - being executed out of shell functions that could cause core dumps if - such a script attempted to execute `return'. - -z. Fixed a problem with the `-nt' and `-ot' binary operators for the - `test/[' builtin and the `[[' conditional command that caused wrong - return values if one of the file arguments did not exist. - -aa. Fixed a bug that caused non-interactive shells which had previously - executed `shopt -s expand_aliases' to fail to expand aliases in a - command like `(command) &'. - -2. Changes to Readline - -a. Changes to make most (but not yet all -- there is still crlf()) of the - exported readline functions declared in readline.h have an rl_ prefix. - -b. More `const' changes in function arguments, mostly for completion - functions. - -c. Fixed a bug in rl_forward that could cause the point to be set to before - the beginning of the line in vi mode. - -d. Fixed a bug in the callback read-char interface to make it work when a - readline function pushes some input onto the input stream with - rl_execute_next (like the incremental search functions). - -e. Fixed a file descriptor leak in the history file manipulation code that - was tripped when attempting to truncate a non-regular file (like - /dev/null). - -f. Some existing variables are now documented and part of the public - interface (declared in readline.h): rl_explict_arg, rl_numeric_arg, - rl_editing_mode, rl_last_func. - -g. Renamed rltty_set_default_bindings to rl_tty_set_default_bindings and - crlf to rl_crlf, so there are no public functions declared in readline.h - without an `rl_' prefix. The old functions still exist for backwards - compatibility. - -3. New Features in Bash - -a. A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. - -b. When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. - -4. New Features in Readline - -a. New application-callable function rl_set_prompt(const char *prompt): - expands its prompt string argument and sets rl_prompt to the result. - -b. New application-callable function rl_set_screen_size(int rows, int cols): - public method for applications to set readline's idea of the screen - dimensions. - -c. The history example program (examples/histexamp.c) is now built as one - of the examples. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.05-alpha1, -and the previous version, bash-2.04-release. - -1. Changes to Bash - -a. A fix was made to allow newlines in compond array assignments. - -b. configure now checks for real-time signals with unusable values. - -c. Interactive shells no longer exit if a substitution fails because of an - unset variable within a sourced file. - -d. Fixed a problem with incorrect matching of extended glob patterns when - doing pattern substitution. - -e. `{' is now quoted by the completion code when it appears in a filename. - -f. Fixed an error in pattern matching that caused the matcher to not - correctly skip the rest of a bracket expression after a character - matched. - -g. Fixed a bug in the IFS word splitting code to make a non-whitespace IFS - character preceded by IFS whitespace part of the current delimiter rather - than generating a separate field. - -h. The {!prefix@} expansion now generates separate words, analogous to $@, - when double-quoted. - -i. Command substitution now ignores NUL bytes in the command output, and the - parser ignores them on input. - -j. A fix was made to the job control code to prevent hanging processes when - the shell thinks background processes are running but the kernel returns - -1/ECHILD from waitpid(). - -k. `pwd' now prints an error message if the write fails when displaying the - current directory. - -l. When in POSIX mode, the shell prints trap dispostions without a leading - `SIG' in the signal specification. - -m. Fixed a parser bug that caused the current command's line count to be - messed up by a compound array assignment. - -n. Fixed a bug in the unwind-protect code that caused bad behavior on machines - where ints and pointers are not the same size. - -o. System-specific configure changes for: MacOS X. - -p. Changes for Cygwin to translate \r\n and \r to \n and to set file - descriptors used for reading input to text mode in various places. - -q. Fixed a bug that caused `!' to occasionally not be honored when in - a (...) subshell. - -r. Bash no longer assumes that getcwd() will return any useful error message - in the buffer passed as an argument if the call fails. - -s. The `source', `.', and `fc' builtins no longer check whether a file is - binary before reading commands from it. - -t. Subshells no longer turn off job control when they exit, since that - sometimes resulted in the terminal being reset to the wrong process - group. - -u. The history code no longer tries to save the second and subsequent lines - of a multi-line command if the first line was not saved. - -v. The history saving code now does a better job of saving blank lines in a - multi-line command. - -w. Removed a `feature' that made `ulimit' silently translate `unlimited' to - the current hard limit, which obscured some kernel error returns. - -x. Fixed the grammar so that `}' is recognized as a reserved word after - another reserved word, rather than requiring a `;' or newline. This - means that constructs like - - { { echo a b c ; } } - - work as expected. - -y. Conditional commands ([[...]]) now perform tilde expansion on their - arguments. - -z. Noted in the documentation that `set -a' will cause functions to be - exported if they are defined after `set -a' is executed. - -aa. When an interactive login shell starts, if $PWD and $HOME refer to the - same directory but are not the same string, $PWD is set to $HOME. - -bb. Fixed `printf' to handle invalid floating point numbers better. - -cc. Temporary files are now created with random filenames, to improve security. - -dd. The readline initialization code now binds the custom bash functions and - key bindings after the readline defaults are set up. - -ee. Fixed the `source' builtin to no longer overwrite a shell function's - argument list, even if the sourced file changes the positional parameters. - -ff. A bug fix was made in the expansion of `$*' in contexts where it should - not be split, like assignment statements. - -gg. Fixed a bug in the parameter substring expansion to handle conditional - arithmetic expressions ( exp ? val1 : val2 ) without cutting the expression - off at the wrong `:'. - -hh. The `<>' redirection is no longer subject to the current setting of - `noclobber', as POSIX.2 specifies. - -ii. Fixed a bug in the conditional command parsing code that caused expressions - in parentheses to occasionally be parsed incorrectly. - -jj. Fixed a bug in the ((...)) arithmetic command to allow do...done or - {...} to follow the )) without an intervening list terminator. - -kk. `printf' now treats `\E' the same as `\e' when performing backslash escape - expansion for the `%b' format specifier. - -ll. When in POSIX mode, the shell no longer searches the current directory for - a file to be sourced with `.' or `source' if `.' is not in $PATH. - -mm. Interactive comments are no longer turned off when POSIX mode is disabled. - -nn. The UID, EUID, HOSTNAME variables are not set if they are in the shell's - environment when it starts up. - -oo. Fixed a bug in the `command' builtin so the effect of a command like - `command exec 4(...) - expansions to defer removal until after any current shell function has - finished executing. - -f. Fixed a bug in `select' which caused it to not handle the `continue' - builtin correctly. - -g. Autoconf tests added for cygwin32 and mingw32. - -2. New Features in Bash - -a. The `--with-bash-malloc' configure option replaces `--with-gnu-malloc' - (which is still there for backwards compatibility). - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.04-beta1, -and the previous version, bash-2.04-alpha1. - -1. Changes to Bash - -a. Fixed a bug in the programmable completion code that occurred when - trying to complete command lines containing a `;' or `@'. - -b. The file descriptor from which the shell is reading a script is now - moved to a file descriptor above the user-addressible range. - -c. Changes to `printf' so that it can handle integers beginning with 0 - or 0x as octal and hex, respectively. - -d. Fixes to the programmable completion code so it handles nonsense like - `compgen -C xyz' gracefully. - -e. The shell no longer modifies the signal handler for SIGPROF, allowing - profiling again on certain systems. - -f. The shell checks for a new window size, if the user has requested it, - after a process exits due to a signal. - -g. Fixed a bug with variables with null values in a program's temporary - environment and the bash getenv() replacement. - -h. `declare' and the other builtins that take variable assignments as - arguments now honor `set -a' and mark modified variables for export. - -i. Some changes were made for --dump-po-strings mode when writing strings - with embedded newlines. - -j. The code that caches export strings from the initial environment now - duplicates the string rather than just pointing into the environment. - -k. The filename completion quoting code now uses single quotes by default - if the filename being completed contains newlines, since \ - has a special meaning to the parser. - -l. Bash now uses typedefs bits32_t and u_bits32_t instead of int32_t and - u_int32_t, respectively to avoid conflicts on certain Unix versions. - -m. Configuration changes were made for: Rhapsody, Mac OS, FreeBSD-3.x. - -n. Fixed a problem with hostname-to-ip-address translation in the - /dev/(tcp|udp)/hostname/port redirection code. - -o. The texinfo manual has been reorganized slightly. - -p. Filename generation (globbing) range comparisons in bracket expressions - no longer use strcoll(3) even if it is available, since it has unwanted - effects in certain locales. - -q. Fixed a cosmetic problem in the source that caused the shell to not - compile if DPAREN_ARITHMETIC was not defined but ARITH_FOR_COMMAND was. - -r. Fixed a bug in the here-document code tripped when the file descriptor - opened to the file containing the text of the here document was the - same as a redirector specified by the user. - -s. Fixed a bug where the INVERT_RETURN flag was not being set for `pipeline' - in `time ! pipeline'. - -t. Fixed a bug with the `wait' builtin which manifested itself when an - interrupt was received while the shell was waiting for asynchronous - processes in a shell script. - -u. Fixed the DEBUG trap code so that it has the correct value of $?. - -v. Fixed a bug in the parameter pattern substitution code that could cause - the shell to attempt to free unallocated memory if the pattern started - with `/' and an expansion error occurs. - -w. Fixed a bug in the positional parameter substring code that could - cause the shell to loop freeing freed memory. - -x. Fixed a bug in the positional parameter pattern substitution code so - that it correctly handles null replacement strings with a pattern - string prefixed with `%' or `#'. - -y. The shell no longer attempts to import functions from the environment if - started with `-n'. - -z. Fixed a bug that caused `return' in a command substitution executed in - a shell function to return from the function in a subshell and continue - execution. - -aa. `hash -p /pathname/with/slashes name' is no longer allowed when the shell - is restricted. - -bb. The wait* job control functions now behave better if called when there - are no unwaited-for children. - -cc. Command substitution no longer unconditionally disables job control in - the subshell started to run the command. - -dd. A bug was fixed that occasionally caused traps to mess up the parser - state. - -ee. `bashbug' now honors user headers in the mail message it sends. - -ff. A bug was fixed that caused the `:p' history modifier to not print the - history expansion if the `histverify' option was set. - -2. Changes to Readline - -a. Fixed a bug in the redisplay code for lines with more than 256 line - breaks. - -b. A bug was fixed which caused invisible character markers to not be - stripped from the prompt string if the terminal was in no-echo mode. - -c. Readline no longer tries to get the variables it needs for redisplay - from the termcap entry if the calling application has specified its - own redisplay function. Readline treats the terminal as `dumb' in - this case. - -d. Fixes to the SIGWINCH code so that a multiple-line prompt with escape - sequences is redrawn correctly. - -3. New Features in Bash - -a. `bashbug' now accepts `--help' and `--version' options. - -b. There is a new `xpg_echo' option to `shopt' that controls the behavior - of echo with respect to backslash-escaped characters at runtime. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.04-alpha1, -and the previous version, bash-2.04-devel. - -1. Changes to Bash - -a. Fixed a bug that could cause core dumps when performing substring - expansion. - -b. Shared object configuration changes for: Solaris, OSF/1 - -c. The POSIX_GLOB_LIBRARY code that uses the POSIX.2 globbing facilities - for pathname expansion now understands GLOBIGNORE. - -d. The code that implements `eval' was changed to save the value of the - current prompt, so an eval in a shell function called by the programmable - completion code will not change the prompt to $PS2. - -e. Restored the undocumented NON_INTERACTIVE_LOGIN_SHELLS #define to - config-top.h. If this is defined, all login shells will read the - startup files, not just interactive and non-interactive started with - the `--login' option. - -f. Fixed a bug that caused the expansion code to occasionally dump core if - IFS contained characters > 128. - -g. Fixed a problem with the grammar so that a newline is not required - after the `))' in the new-style arithmetic for statement; a semicolon - may be used as expected. - -h. Variable indirection may now reference the shell's special variables. - -i. The $'...' and $"..." constructs are now added to the history correctly - if they contain newlines and command-oriented history is enabled. - -j. It is now an error to try to assign a value to a function-local copy - of a readonly shell variable (declared with the `local' builtin). - -2. Changes to Readline - -a. The history file code now uses O_BINARY mode when reading and writing - the history file on cygwin32. - -3. New Features in Bash - -a. A new programmable completion facility, with two new builtin commands: - complete and compgen. - -b. configure has a new option, `--enable-progcomp', to compile in the - programmable completion features (enabled by default). - -c. `shopt' has a new option, `progcomp', to enable and disable programmable - completion at runtime. - -d. Unsetting HOSTFILE now clears the list of hostnames used for completion. - -4. New Features in Readline - -a. A new variable, rl_gnu_readline_p, always 1. The intent is that an - application can verify whether or not it is linked with the `real' - readline library or some substitute. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.04-devel, -and the previous version, bash-2.03-release. - -1. Changes to Bash - -a. System-specific configuration and source changes for: Interix, Rhapsody - -b. Fixed a bug in execute_cmd.c that resulted in a compile-time error if - JOB_CONTROL was not defined. - -c. An obscure race condition in the trap code was fixed. - -d. The string resulting from $'...' is now requoted to avoid any further - expansion. - -e. The $'...' quoting syntax now allows backslash to escape a single quote, - for ksh-93 compatibility. - -f. The $"..." quoting syntax now escapes backslashes and double quotes in - the translated string when displaying them with the --dump-po-strings - option. - -g. `echo -e' no longer converts \' to '. - -h. Fixes were made to the extended globbing code to handle embedded (...) - patterns better. - -i. Some improvements were made to the code that unsets `nodelay' mode on - the file descriptor from which bash is reading input. - -j. Some changes were made to the replacement termcap library for better - operation on MS-DOS. - -k. Some changes were made to the tilde expansion code to handle backslash - as a pathname separator on MS-DOS. - -l. The source has been reorganized a little bit -- there is now an `include' - subdirectory, and lib/posixheaders has been removed. - -m. Improvements were made to the `read' builtin so that it makes many - fewer read(2) system calls. - -n. The expansion of $- will include `c' and `s' when those options are - supplied at shell invocation. - -o. Several improvments were made to the completion code: variable completion - now works better when there are unterminated expansions, command - completion understands quotes better, and completion now works in certain - unclosed $(... constructs. - -p. The arithmetic expansion code was fixed to not need the value of a - variable being assigned a value (fixes the "ss=09; let ss=10" bug). - -q. Some changes were made to make exported environment creation faster. - -r. The html documentation will be installed into $(htmldir) if that variable - has a value when `make install' is run. - -s. Fixed a bug that would cause the bashrc file to be sourced inappropriately - when bash is started by sshd. - -t. The SSH_CLIENT environment variable is no longer auto-exported. - -u. A bug that caused redirections with (...) subshells to be performed in - the wrong order was fixed. - -v. A bug that occasionally caused inappropriate expansion of assignment - statements in compound array assignments was fixed. - -w. The code that parses the words in a compound array assignment was - simplified considerably and should work better now. - -x. Fixes to the non-job-control code in nojobs.c to make it POSIX.2-compliant - when a user attempts to retrieve the status of a terminated background - process. - -y. Fixes to the `printf' builtin so that it doesn't try to expand all - backslash escape sequences in the format string before parsing it for - % format specifiers. - -2. Changes to Readline - -a. The history library tries to truncate the history file only if it is a - regular file. - -b. A bug that caused _rl_dispatch to address negative array indices on - systems with signed chars was fixed. - -c. rl-yank-nth-arg now leaves the history position the same as when it was - called. - -d. Changes to the completion code to handle MS-DOS drive-letter:pathname - filenames. - -e. Completion is now case-insensitive by default on MS-DOS. - -f. Fixes to the history file manipulation code for MS-DOS. - -g. Readline attempts to bind the arrow keys to appropriate defaults on MS-DOS. - -h. Some fixes were made to the redisplay code for better operation on MS-DOS. - -i. The quoted-insert code will now insert tty special chars like ^C. - -j. A bug was fixed that caused the display code to reference memory before - the start of the prompt string. - -k. More support for __EMX__ (OS/2). - -l. A bug was fixed in readline's signal handling that could cause infinite - recursion in signal handlers. - -m. A bug was fixed that caused the point to be less than zero when rl_forward - was given a very large numeric argument. - -n. The vi-mode code now gets characters via the application-settable value - of rl_getc_function rather than calling rl_getc directly. - -3. New Features in Bash - -a. The history builtin has a `-d offset' option to delete the history entry - at position `offset'. - -b. The prompt expansion code has two new escape sequences: \j, the number of - active jobs; and \l, the basename of the shell's tty device name. - -c. The `bind' builtin has a new `-x' option to bind key sequences to shell - commands. - -d. There is a new shell option, no_empty_command_completion, which, when - enabled, disables command completion when TAB is typed on an empty line. - -e. The `help' builtin has a `-s' option to just print a builtin's usage - synopsys. - -f. There are several new arithmetic operators: id++, id-- (variable - post-increment/decrement), ++id, --id (variabl pre-increment/decrement), - expr1 , expr2 (comma operator). - -g. There is a new ksh-93 style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done - -h. The `read' builtin has a number of new options: - -t timeout only wait timeout seconds for input - -n nchars only read nchars from input instead of a full line - -d delim read until delim rather than newline - -s don't echo input chars as they are read - -i. The redirection code now handles several filenames specially: - /dev/fd/N, /dev/stdin, /dev/stdout, and /dev/stderr, whether or - not they are present in the file system. - -j. The redirection code now recognizes pathnames of the form - /dev/tcp/host/port and /dev/udp/host/port, and tries to open a socket - of the appropriate type to the specified port on the specified host. - -k. The ksh-93 ${!prefix*} expansion, which expands to the names of all - shell variables whose names start with prefix, has been implemented. - -l. There is a new dynamic variable, FUNCNAME, which expands to the name of - a currently-executing function. Assignments to FUNCNAME have no effect. - -m. The GROUPS variable is no longer readonly; assignments to it are silently - discarded. This means it can be unset. - -4. New Features in Readline - -a. Parentheses matching is now always compiled into readline, and enabled - or disabled when the value of the `blink-matching-paren' variable is - changed. - -b. MS-DOS systems now use ~/_inputrc as the last-ditch inputrc filename. - -c. MS-DOS systems now use ~/_history as the default history file. - -d. history-search-{forward,backward} now leave the point at the end of the - line when the string to search for is empty, like - {reverse,forward}-search-history. - -e. history-search-{forward,backward} now leave the last history line found - in the readline buffer if the second or subsequent search fails. - -f. New function for use by applications: rl_on_new_line_with_prompt, used - when an application displays the prompt itself before calling readline(). - -g. New variable for use by applications: rl_already_prompted. An application - that displays the prompt itself before calling readline() must set this to - a non-zero value. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.03-release, -and the previous version, bash-2.03-beta2. - -1. Changes to Bash - -a. A file descriptor leak in the `fc' builtin was fixed. - -b. A bug was fixed in the `read' builtin that caused occasional spurious - failures when using `read -e'. - -c. The version code needed to use the value of the cpp variable - CONF_MACHTYPE rather than MACHTYPE. - -d. A new test was added to exercise the command printing and copying code. - -e. A bug was fixed that caused `time' to be recognized as a reserved word - if it was the first pattern in a `case' statement pattern list. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.03-beta2, -and the previous version, bash-2.03-beta1. - -1. Changes to Bash - -a. Slight additions to support/shobj-conf, mostly for the benefit of AIX 4.2. - -b. config.{guess,sub} support added for the NEC SX4. - -c. Changed some of the cross-compiling sections of the configure macros in - aclocal.m4 so that configure won't abort. - -d. Slight changes to how the HTML versions of the bash and readline manuals - are generated. - -e. Fixed conditional command printing to avoid interpreting printf `%'-escapes - in arguments to [[. - -f. Don't include the bash malloc on all variants of the alpha processor. - -g. Changes to configure to make --enable-profiling work on Solaris 2.x. - -h. Fixed a bug that manifested itself when shell functions were called - between calls to `getopts'. - -i. Fixed pattern substitution so that a bare `#'as a pattern causes the - replacement string to be prefixed to the search string, and a bare - `%' causes the replacement string to be appended to the search string. - -j. Fixed a bug in the command execution code that caused child processes - to occasionally have the wrong value for $!. - -2. Changes to Readline - -a. Added code to the history library to catch history substitutions using - `&' without a previous history substitution or search having been - performed. - -3. New Features in Bash - -4. New Features in Readline - -a. New bindable variable: `isearch-terminators'. - -b. New bindable function: `forward-backward-delete-char' (unbound by default). - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.03-beta1, -and the previous version, bash-2.03-alpha. - -1. Changes to Bash - -a. A change was made to the help text for `{...}' to make it clear that a - semicolon is required before the closing brace. - -b. A fix was made to the `test' builtin so that syntax errors cause test - to return an exit status > 1. - -c. Globbing is no longer performed on assignment statements that appear as - arguments to `assignment builtins' such as `export'. - -d. System-specific configuration changes were made for: Rhapsody, - AIX 4.2/gcc, BSD/OS 4.0. - -e. New loadable builtins: ln, unlink. - -f. Some fixes were made to the globbing code to handle extended glob patterns - which immediately follow a `*'. - -g. A fix was made to the command printing code to ensure that redirections - following compound commands have a space separating them from the rest - of the command. - -h. The pathname canonicalization code was changed to produce fewer leading - `//' sequences, since those are interpreted as network file system - pathnames on some systems. - -i. A fix was made so that loops containing `eval' commands in commands passed - to `bash -c' would not exit prematurely. - -j. Some changes were made to the job reaping code when the shell is not - interactive, so the shell will retain exit statuses longer for examination - by `wait'. - -k. A fix was made so that `jobs | command' works again. - -l. The erroneous compound array assignment var=((...)) is now a syntax error. - -m. A change was made to the dynamic loading code in `enable' to support - Tenon's MachTen. - -n. A fix was made to the globbing code so that extended globbing patterns - will correctly match `.' in a bracket expression. - -2. Changes to Readline - -a. A fix was made to the completion code in which a typo caused the wrong - value to be passed to the function that computed the longest common - prefix of the list of matches. - -b. The completion code now checks the value of rl_filename_completion_desired, - which is set by application-supplied completion functions to indicate - that filename completion is being performed, to decide whether or not to - call an application-supplied `ignore completions' function. - -3. New Features in Bash - -a. A change was made to the startup file code so that any shell begun with - the `--login' option, even non-interactive shells, will source the login - shell startup files. - -4. New Features in Readline - -a. A new variable, rl_erase_empty_line, which, if set by an application using - readline, will cause readline to erase, prompt and all, lines on which the - only thing typed was a newline. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.03-alpha, -and the previous version, bash-2.02.1-release. - -1. Changes to Bash - -a. System-specific configuration changes were made for: Irix 6.x, Unixware 7. - -b. The texi2dvi and texi2html scripts were updated to the latest versions - from the net. - -c. The configure tests that determine which native type is 32 bits were - changed to not require a compiled program. - -d. Fixed a bug in shell_execve that could cause memory to be freed twice - after a failed exec. - -e. The `printf' test uses `diff -a' if it's available to prevent confusion - due to the non-ascii output. - -f. Shared object configuration is now performed by a shell script, - support/shobj-conf, which generates values to be substituted into - makefiles by configure. - -g. Some changes were made to `ulimit' to avoid the use of RLIM_INVALID as a - return value. - -h. Changes were made to `ulimit' to work around HPUX 9.x's peculiar - handling of RLIMIT_FILESIZE. - -i. Some new loadable builtins were added: id, printenv, sync, whoami, push, - mkdir. `pushd', `popd', and `dirs' can now be built as regular or - loadable builtins from the same source file. - -j. Changes were made to `printf' to handle NUL bytes in the expanded format - string. - -k. The various `make clean' Makefile targets now descend into lib/sh. - -l. The `type' builtin was changed to use the internal `getopt' so that things - like `type -ap' work as expected. - -m. There is a new configuration option, --with-installed-readline, to link - bash with a locally-installed version of readline. Only readline version - 4.0 and later releases can support this. Shared and static libraries - are supported. The installed include files are used. - -n. There is a new autoconf macro used to find which basic type is 64 bits. - -o. Dynamic linking and loadable builtins should now work on SCO 3.2v5*, - AIX 4.2 with gcc, Unixware 7, and many other systems using gcc, where - the `-shared' options works correctly. - -p. A bug was fixed in the bash filename completion code that caused memory to - be freed twice if a directory name containing an unset variable was - completed and the -u option was set. - -q. The prompt expansion code now quotes the `$' in the `\$' expansion so it - is not processed by subsequent parameter expansion. - -r. Fixed a parsing bug that caused a single or double quote after a `$$' to - trigger ANSI C expansion or locale translation. - -s. Fixed a bug in the globbing code that caused quoted filenames containing - no globbing characters to sometimes be incorrectly expanded. - -t. Changes to the default prompt strings if prompt string decoding is not - compiled into the shell. - -u. Added `do', `then', `else', `{', and `(' to the list of keywords that may - precede the `time' reserved word. - -v. The shell may now be cross-built for BeOS as well as cygwin32. - -w. The conditional command execution code now treats `=' the same as `==' - for deciding when to perform pattern matching. - -x. The `-e' option no longer causes the shell to exit if a command exits - with a non-zero status while running the startup files. - -y. The `printf' builtin no longer dumps core if a modifier is supplied in - the format string without a conversion character (e.g. `%h'). - -z. Array assignments of the form a=(...) no longer show up in the history - list. - -aa. The parser was fixed to obey the POSIX.2 rules for finding the closing - `}' in a ${...} expression. - -bb. The history file is now opened with mode 0600 rather than 0666, so bash - no longer relies on the user's umask being set appropriately. - -cc. Setting LANG no longer causes LC_ALL to be assigned a value; bash now - relies on proper behavior from the C library. - -dd. Minor changes were made to allow quoted variable expansions using - ${...} to be completed correctly if there is no closing `"'. - -ee. Changes were made to builtins/Makefile.in so that configuring the shell - with `--enable-profiling' works right and builtins/mkbuiltins is - generated. - -2. Changes to Readline - -a. The version number is now 4.0. - -b. There is no longer any #ifdef SHELL code in the source files. - -c. Some changes were made to the key binding code to fix memory leaks and - better support Win32 systems. - -d. Fixed a silly typo in the paren matching code -- it's microseconds, not - milliseconds. - -e. The readline library should be compilable by C++ compilers. - -f. The readline.h public header file now includes function prototypes for - all readline functions, and some changes were made to fix errors in the - source files uncovered by the use of prototypes. - -g. The maximum numeric argument is now clamped at 1000000. - -h. Fixes to rl_yank_last_arg to make it behave better. - -i. Fixed a bug in the display code that caused core dumps if the prompt - string length exceeded 1024 characters. - -j. The menu completion code was fixed to properly insert a single completion - if there is only one match. - -k. A bug was fixed that caused the display code to improperly display tabs - after newlines. - -3. New Features in Bash - -a. New `shopt' option, `restricted_shell', indicating whether or not the - shell was started in restricted mode, for use in startup files. - -b. Filename generation is now performed on the words between ( and ) in - array assignments (which it probably should have done all along). - -c. OLDPWD is now auto-exported, as POSIX.2 seems to require. - -d. ENV and BASH_ENV are read-only variables in a restricted shell. - -4. New Features in Readline - -a. Many changes to the signal handling: - o Readline now catches SIGQUIT and cleans up the tty before returning; - o A new variable, rl_catch_signals, is available to application writers - to indicate to readline whether or not it should install its own - signal handlers for SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, - SIGTTIN, and SIGTTOU; - o A new variable, rl_catch_sigwinch, is available to application - writers to indicate to readline whether or not it should install its - own signal handler for SIGWINCH, which will chain to the calling - applications's SIGWINCH handler, if one is installed; - o There is a new function, rl_free_line_state, for application signal - handlers to call to free up the state associated with the current - line after receiving a signal; - o There is a new function, rl_cleanup_after_signal, to clean up the - display and terminal state after receiving a signal; - o There is a new function, rl_reset_after_signal, to reinitialize the - terminal and display state after an application signal handler - returns and readline continues - -b. There is a new function, rl_resize_terminal, to reset readline's idea of - the screen size after a SIGWINCH. - -c. New public functions: rl_save_prompt and rl_restore_prompt. These were - previously private functions with a `_' prefix. - -d. New function hook: rl_pre_input_hook, called just before readline starts - reading input, after initialization. - -e. New function hook: rl_display_matches_hook, called when readline would - display the list of completion matches. The new function - rl_display_match_list is what readline uses internally, and is available - for use by application functions called via this hook. - -f. New bindable function, delete-char-or-list, like tcsh. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.02.1-release, -and the previous version, bash-2.02-release. - -1. Changes to Bash - -a. A bug that caused the bash readline support to not compile unless aliases - and csh-style history were configured into the shell was fixed. - -b. Fixed a bug that could cause a core dump when here documents contained - more than 1000 characters. - -c. Fixed a bug that caused a CDPATH entry of "" to not be treated the same - as the current directory when in POSIX mode. - -d. Fixed an alignment problem with the memory returned by the bash malloc, - so returned memory is now 64-bit aligned. - -e. Fixed a bug that caused command substitutions executed within pipelines - to put the terminal in the wrong process group. - -f. Fixes to support/config.sub for: alphas, SCO Open Server and Open Desktop, - Unixware 2, and Unixware 7. - -g. Fixes to the pattern matching code to make it work correctly for eight-bit - characters. - -h. Fixed a problem that occasionally caused the shell to display the wrong - value for the new working directory when changing to a directory found - in $CDPATH when in physical mode. - -i. Fixed a bug that caused core dumps when using conditional commands in - shell functions. - -j. Fixed a bug that caused the printf builtin to loop forever if the format - string did not consume any of the arguments. - -k. Fixed a bug in the parameter expansion code that caused "$@" to be - incorrectly split if $IFS did not contain a space character. - -l. Fixed a bug that could cause a core dump when completing hostnames if - the number of matching hostnames was an exact multiple of 16. - -m. Fixed a bug that caused the shell to fork too early when a command - such as `%2 &' was given. - -2. Changes to Readline - -a. Fixed a problem with redisplay that showed up when the prompt string was - longer than the screen width and the prompt contained invisible characters. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.02-release, -and the previous version, bash-2.02-beta2. - -1. Changes to Bash - -a. A bug was fixed that caused the terminal process group to be set - incorrectly when performing command substitution of builtins in a - pipeline. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.02-beta2, -and the previous version, bash-2.02-beta1. - -1. Changes to Bash - -a. Attempting to `wait' for stopped jobs now generates a warning message. - -b. Pipelines which exit due to SIGPIPE in non-interactive shells are now - not reported if the shell is compiled -DDONT_REPORT_SIGPIPE. - -c. Some changes were made to builtins/psize.sh and support/bashbug.sh to - attempt to avoid some /tmp file races and surreptitious file - substitutions. - -d. Fixed a bug that caused the shell not to compile if configured with - dparen arithmetic but without aliases. - -e. Fixed a bug that caused the input stream to be switched when assigning - empty arrays with `bash -c'. - -f. A bug was fixed in the readline expansion glue code that caused bash to - dump core when expanding lines with an unclosed single quote. - -g. A fix was made to the `cd' builtin so that using a non-empty directory - from $CDPATH results in an absolute pathname of the new current working - directory to be displayed after the current directory is changed. - -h. Fixed a bug in the variable assignment code that caused the shell to - dump core when referencing an unset variable with `set -u' enabled in - an assignment statement preceding a command. - -i. Fixed a bug in the exit trap code that caused reserved words to not be - recognized under certain circumstances. - -j. Fixed a bug in the parameter pattern substitution code so that quote - removal is performed. - -k. The shell should now configure correctly on Apple Rhapsody systems. - -l. The `kill' builtin now prints a usage message if it is not passed any - arguments. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.02-beta1, -and the previous version, bash-2.02-alpha1. - -1. Changes to Bash - -a. A few compilation bugs were fixed in the new extended globbing code. - -b. Executing arithmetic commands now sets the command name to `((' so - error messages look right. - -c. Fixed some build problems with various configuration options. - -d. The `printf' builtin now aborts immediately if an illegal format - character is encountered. - -e. The code that creates here-documents now behaves better if the file it's - trying to create already exists for some reason. - -f. Fixed a problem with the extended globbing code that made patterns like - `x+*' expand incorrectly. - -g. The prompt string expansion code no longer quotes tildes with backslashes. - -h. The bash getcwd() implementation in lib/sh/getcwd.c now behaves better in - the presence of lstat(2) failures. - -i. Fixed a bug with strsub() that caused core dumps when executing `fc -s'. - -j. The mail checking code now ensures that it has a valid default mailpath. - -k. A bug was fixed that caused local variables to be unset inappropriately - when sourcing a script from within another sourced script. - -l. A bug was fixed in the history saving code so that functions are saved - in the history list correctly if `cmdhist' is enabled, but `lithist' - is not. - -m. A bug was fixed that caused printf overflows when displaying error - messages. - -n. It should be easier to build the loadble builtins in examples/loadables, - though some manual editing of the generated Makefile is still required. - -o. The user's primary group is now always ${GROUPS[0]}. - -p. Some updates were made to support/config.guess from the GNU master copy. - -q. Some changes were made to the autoconf support for Solaris 2.6 large - files. - -r. The `command' builtins now does the right thing when confstr(3) cannot - find a value for _CS_PATH. - -s. Extended globbing expressions like `*.!(c)' are not history expanded if - `extglob' is enabled. - -t. Using the `-P' option to `cd' will force the value that is assigned to - PWD to not contain any symbolic links. - -2. Changes to Readline - -a. The code that prints completion listings now behaves better if one or - more of the filenames contains non-printable characters. - -b. The time delay when showing matching parentheses is now 0.5 seconds. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.02-alpha1, -and the previous version, bash-2.01.1-release. - -1. Changes to Bash - -a. OS-specific configuration changes for: BSD/OS 3.x, Minix 2.x, - Solaris 2.6, SINIX SVR4. - -b. Changes were made to the generated `info' files so that `install-info' - works correctly. - -c. PWD is now auto-exported. - -d. A fix was made to the pipeline code to make sure that the shell forks - to execute simple commands consisting solely of assignment statements. - -e. Changes to the test suite for systems with 14-character filenames. - -f. The default sizes of some internal hash tables have been made smaller - to reduce the shell's memory footprint. - -g. The `((...))' arithmetic command is now executed directly instead of - being translated into `let "..."'. - -h. Fixes were made to the expansion code so that "$*", "$@", "${array[@]}", - and "${array[@]}" expand correctly when IFS does not contain a space - character, is unset, or is set to NULL. - -i. The indirect expansion code (${!var}) was changed so that the only - valid values of `var' are variable names, positional parameters, `#', - `@', and `*'. - -j. An arithmetic expression error in a $((...)) expansion now causes a - non-interactive shell running in posix mode to exit. - -k. Compound array assignment now splits the words within the parentheses - on shell metacharacters like the parser would before expansing them - and performing the assignment. This is for compatibility with ksh-93. - -l. The internal shell backslash-quoting code (used in the output of `set' - and completion) now quotes tildes if they appear at the start of the - string or after a `=' or `:'. - -m. A couple of bugs with `shopt -o' were fixed. - -n. `bash +o' now displays the same output as `set +o' before starting an - interactive shell. - -o. A bug that caused command substitution and the `eval' builtin to - occasionally free memory twice when an error was encountered was fixed. - -p. The filename globbing code no longer requires read permission for a - directory when the filename to be matched does not contain any globbing - characters, as POSIX.2 specifies. - -q. A bug was fixed so that the job containing the last asynchronous - process is not removed from the job table until a `wait' is executed - for that process or another asynchronous process is started. This - satisfies a POSIX.2 requirement. - -r. A `select' bug was fixed so that a non-numeric user response is treated - the same as a numeric response that is out of range. - -s. The shell no longer parses the value of SHELLOPTS from the environment - if it is restricted, running setuid, or running in `privileged mode'. - -t. Fixes were made to enable large file support on systems such as - Solaris 2.6, where the size of a file may be larger than can be held - in an `int'. - -u. The filename hashing code was fixed to not add `./' to the beginning of - filenames which already begin with `./'. - -v. The configure script was changed so that the GNU termcap library is not - compiled in if `prefer-curses' has been specified. - -w. HISTCONTROL and HISTIGNORE are no longer applied to the second and - subsequent lines of a multi-line command. - -x. A fix was made to `disown' so that it does a better job of catching - out-of-range jobs. - -y. Non-interactive shells no longer report the status of processes terminated - due to SIGINT, even if the standard output is a terminal. - -z. A bug that caused the output of `jobs' to have extra carriage returns - was fixed. - -aa. A bug that caused PIPESTATUS to not be set when builtins or shell - functions were executed in the foreground was fixed. - -bb. Bash now attempts to detect when it is being run by sshd, and treats - that case identically to being run by rshd. - -cc. A bug that caused `set -a' to export SHELLOPTS when one of the shell - options was changed was fixed. - -dd. The `kill' builtin now disallows empty or missing process id arguments - instead of treating them as identical to `0', which means the current - process. - -ee. `var=value declare -x var' now behaves identically to - `var=value export var'. Similarly for `var=value declare -r var' and - `var=value readonly var'. - -ff. A few memory leaks were fixed. - -gg. `alias' and `unalias' now print error messages when passed an argument - that is not an alias for printing or deletion, even when the shell is - not interactive, as POSIX.2 specifies. - -hh. `alias' and `alias -p' now return a status of 0 when no aliases are - defined, as POSIX.2 specifes. - -ii. `cd -' now prints the pathname of the new working directory if the shell - is interactive. - -jj. A fix was made so that the code that binds $PWD now copes with getcwd() - returning NULL. - -kk. `unset' now checks whether or not a function name it's trying to unset - is a valid shell identifier only when the shell is running in posix mode. - -ll. A change was made to the code that generates filenames for here documents - to make them less prone to name collisions. - -mm. The parser was changed so that `time' is recognized as a reserved word - only at the beginning of a pipeline. - -nn. The pathname canonicalization code was changed so that `//' is converted - into `/', but all other pathnames beginning with `//' are left alone, as - POSIX.2 specifies. - -oo. The `logout' builtin will no longer exit a non-interactive non-login - shell. - -2. Changes to Readline - -a. Fixed a problem in the readline test program rltest.c that caused a core - dump. - -b. The code that handles parser directives in inputrc files now displays - more error messages. - -c. The history expansion code was fixed so that the appearance of the - history comment character at the beginning of a word inhibits history - expansion for that word and the rest of the input line. - -3. New Features in Bash - -a. A new version of malloc, based on the older GNU malloc, that has many - changes, is more page-based, is more conservative with memory usage, - and does not `orphan' large blocks when they are freed. - -b. A new version of gmalloc, based on the old GLIBC malloc, with many - changes and range checking included by default. - -c. A new implementation of fnmatch(3) that includes full POSIX.2 Basic - Regular Expression matching, including character classes, collating - symbols, equivalence classes, and support for case-insensitive pattern - matching. - -d. ksh-88 egrep-style extended pattern matching ([@+*?!](patlist)) has been - implemented, controlled by a new `shopt' option, `extglob'. - -e. There is a new ksh-like `[[' compound command, which implements - extended `test' functionality. - -f. There is a new `printf' builtin, implemented according to the POSIX.2 - specification. - -g. There is a new feature for command substitution: $(< filename) now expands - to the contents of `filename', with any trailing newlines removed - (equivalent to $(cat filename)). - -h. There are new tilde prefixes which expand to directories from the - directory stack. - -i. There is a new `**' arithmetic operator to do exponentiation. - -j. There are new configuration options to control how bash is linked: - `--enable-profiling', to allow bash to be profiled with gprof, and - `--enable-static-link', to allow bash to be linked statically. - -k. There is a new configuration option, `--enable-cond-command', which - controls whether or not the `[[' command is included. It is on by - default. - -l. There is a new configuration option, `--enable-extended-glob', which - controls whether or not the ksh extended globbing feature is included. - It is enabled by default. - -m. There is a new configuration #define in config.h.top that, when enabled, - will cause all login shells to source /etc/profile and one of the user- - specific login shell startup files, whether or not the shell is - interactive. - -n. There is a new invocation option, `--dump-po-strings', to dump - a shell script's translatable strings ($"...") in GNU `po' format. - -o. There is a new `shopt' option, `nocaseglob', to enable case-insensitive - pattern matching when globbing filenames and using the `case' construct. - -p. There is a new `shopt' option, `huponexit', which, when enabled, causes - the shell to send SIGHUP to all jobs when an interactive login shell - exits. - -q. `bind' has a new `-u' option, which takes a readline function name as an - argument and unbinds all key sequences bound to that function in a - specified keymap. - -r. `disown' now has `-a' and `-r' options, to limit operation to all jobs - and running jobs, respectively. - -s. The `shopt' `-p' option now causes output to be displayed in a reusable - format. - -t. `test' has a new `-N' option, which returns true if the filename argument - has been modified since it was last accessed. - -u. `umask' now has a `-p' option to print output in a reusable format. - -v. A new escape sequence, `\xNNN', has been added to the `echo -e' and $'...' - translation code. It expands to the character whose ascii code is NNN - in hexadecimal. - -w. The prompt string expansion code has a new `\r' escape sequence. - -x. The shell may now be cross-compiled for the CYGWIN32 environment on - a Unix machine. - -4. New Features in Readline - -a. There is now an option for `iterative' yank-last-arg handline, so a user - can keep entering `M-.', yanking the last argument of successive history - lines. - -b. New variable, `print-completions-horizontally', which causes completion - matches to be displayed across the screen (like `ls -x') rather than up - and down the screen (like `ls'). - -c. New variable, `completion-ignore-case', which causes filename completion - and matching to be performed case-insensitively. - -d. There is a new bindable command, `magic-space', which causes history - expansion to be performed on the current readline buffer and a space to - be inserted into the result. - -e. There is a new bindable command, `menu-complete', which enables tcsh-like - menu completion (successive executions of menu-complete insert a single - completion match, cycling through the list of possible completions). - -f. There is a new bindable command, `paste-from-clipboard', for use on Win32 - systems, to insert the text from the Win32 clipboard into the editing - buffer. - -g. The key sequence translation code now understands printf-style backslash - escape sequences, including \NNN octal escapes. These escape sequences - may be used in key sequence definitions or macro values. - -h. An `$include' inputrc file parser directive has been added. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.01.1-release, -and the previous version, bash-2.01-release. - -1. Changes to Bash - -a. The select command was fixed to check the validity of the user's - input more strenuously. - -b. A bug was fixed that prevented `time' from timing commands correctly - when supplied as an argument to `bash -c'. - -c. A fix was made to the mail checking code to keep from adding the same - mail file to the list of files to check multiple times when parsing - $MAILPATH. - -d. Fixed an off-by-one error in the tilde expansion library. - -e. When using the compound array assignment syntax, the old value of - the array is cleared before assigning the new value. - -f. Fixed a bug that could cause a core dump when a trap handler was reset - to the default in the trap command associated with that signal. - -g. Fixed a bug in the locale code that occurred when assigning a value - to LC_ALL. - -h. A change was made to the parser so that words of the form xxx=(...) - are not considered compound assignment statements unless there are - characters before the `='. - -i. A fix was made to the command tracing code to correctly quote each - word of output. - -j. Some changes were made to the bash-specific autoconf tests to make them - more portable. - -k. Completion of words with globbing characters now correctly quotes the - result. - -l. The directory /var/spool/mail is now preferred to /usr/spool/mail when - configure is deciding on the default mail directory. - -m. The brace completion code was fixed to not quote the `{' and `}'. - -n. Some fixes were made to make $RANDOM more random in subshells. - -o. System-specific changes were made to configure for: SVR4.2 - -p. Changes were made so that completion of words containing globbing chars - substitutes the result only if a single filename was matched. - -q. The window size is now recomputed after a job is stopped with SIGTSTP if - the user has set `checkwinsize' with `shopt'. - -r. When doing substring expansion, out-of-range substring specifiers now - cause nothing to be substituted rather than an expansion error. - -s. A fix was made so that you can no longer trap `SIGEXIT' or `SIGDEBUG' -- - only `EXIT' and `DEBUG' are accepted. - -t. The display of trapped signals now uses the signal number if signals - for which bash does not know the name are trapped. - -u. A fix was made so that `bash -r' does not turn on restricted mode until - after the startup files are executed. - -v. A bug was fixed that occasionally caused a core dump when a variable - found in the temporary environment of export/declare/readonly had a - null value. - -w. A bug that occasionally caused unallocated memory to be passed to free() - when doing arithmetic substitution was fixed. - -x. A bug that caused a buffer overrun when expanding a prompt string - containing `\w' and ${#PWD} exceeded PATH_MAX was fixed. - -y. A problem with the completion code that occasionally caused it to - refer to a character before the beginning of the readline line buffer - was fixed. - -z. A bug was fixed so that the `read' builtin restarts reads when - interrupted by signals other than SIGINT. - -aa. Fixed a bug that caused a command to be freed twice when there was - an evaluation error in the `eval' command. - -2. Changes to Readline - -a. Added a missing `extern' to a declaration in readline.h that kept - readline from compiling cleanly on some systems. - -b. The history file is now opened with mode 0600 when it is written for - better security. - -c. Changes were made to the SIGWINCH handling code so that prompt redisplay - is done better. - -d. ^G now interrupts incremental searches correctly. - -e. A bug that caused a core dump when the set of characters to be quoted - when completing words was empty was fixed. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.01-release, -and the previous version, bash-2.01-beta2. - -1. Changes to Bash - -a. The `distclean' target should remove the `printenv' executable if it - has been created. - -b. The test suite was changed slightly to ensure that the error messages - are printed in English. - -c. A bug that caused the shell to dump core when a filename containing a - `/' was passed to `hash' was fixed. - -d. Pathname canonicalization now leaves a leading `//' intact, as POSIX.1 - requires. - -e. A memory leak when completing commands was fixed. - -f. A memory leak that occurred when checking the hash table for commands - with relative paths was fixed. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.01-beta2, -and the previous version, bash-2.01-beta1. - -1. Changes to Bash - -a. The `ulimit' builtin translates RLIM_INFINITY to the hard limit only if - the current (soft) limit is less than or equal to the hard limit. - -b. Fixed a bug that caused the bash emulation of strcasecmp to produce - incorrect results. - -c. A bug that caused memory to be freed twice when a trap handler resets - the trap more than once was fixed. - -d. A bug that caused machines where sizeof (pointer) > sizeof (int) to - fail (and possibly dump core) when trying to unwind-protect a null - pointer was fixed. - -e. The startup files should not be run with job control enabled. This fix - allows SIGINT to once again interrupt startup file execution. - -f. Bash should not change the SIGPROF handler if it is set to something - other than SIG_DFL. - -g. The completion code that provides bash-specific completions for readline - now quotes characters that the readline code would treat as word break - characters if they appear in a file name. - -h. The completion code now correctly quotes filenames containing a `!', - even if the user attempted to use double quotes when attempting - completion. - -i. A bug that caused the shell to dump core when `disown' was called without - arguments and there was no current job was fixed. - -j. A construct like $((foo);bar) is now processed as a command substitution - rather than as a bad arithmetic substitution. - -k. A couple of bugs that caused `fc' to not obey the `cmdhist' and `lithist' - shell options when editing and re-executing a series of commands were - fixed. - -l. A fix was made to the grammar -- the list of commands between `do' and - `done' in the body of a `for' command should be treated the same as a - while loop. - -2. Changes to Readline - -a. A couple of bugs that caused the history search functions to attempt to - free a NULL pointer were fixed. - -b. If the C library provides setlocale(3), readline does not need to look - at various environment variables to decide whether or not to go into - eight-bit mode automatically -- just check whether the current locale - is not `C' or `POSIX'. - -c. If the filename completion function finds that a directory was not closed - by a previous (interrupted) completion, it closes the directory with - closedir(). - -3. New Features in Bash - -a. New bindable readline commands: history-and-alias-expand-line and - alias-expand-line. The code was always in there, there was just no - way to execute it. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.01-beta1, -and the previous version, bash-2.01-alpha1. - -1. Changes to Bash - -a. Fixed a problem that could cause file descriptors used for process - substitution to conflict with those used explicitly in redirections. - -b. Made it easier to regenerate configure if the user changes configure.in. - -c. ${GROUPS[0]} should always be the primary group, even on systems without - multiple groups. - -d. Spelling correction is no longer enabled by default. - -e. Fixes to quoting problems in `bashbug'. - -f. OS-specific configuration changes were made for: Irix 6. - -g. OS-specific code changes were made for: QNX. - -h. A more meaningful message is now printed when the file in /tmp for a - here document cannot be created. - -i. Many changes to the shell's variable initialization code to speed - non-interactive startup. - -j. Changes to the non-job-control code so that it does not try to open - /dev/tty. - -k. The output of `set' and `export' is once again sorted, as POSIX wants. - -l. Fixed a problem caused by a recursive call reparsing the value of - $SHELLOPTS. - -m. The tilde code no longer calls getenv() when it's compiled as part of - the shell, which should eliminate problems on systems that cannot - redefine getenv(), like the NeXT OS. - -n. Fixed a problem that caused `bash -o' or `bash +o' to not list all - the shell options. - -o. Fixed `ulimit' to convert RLIM_INFINITY to the appropriate hard limit - only if the hard limit is greater than the current (soft) limit. - -p. Fixed a problem that arose when building bash in a different directory - than the source and y.tab.[ch] were remade with something other than - bison. This came up most often on NetBSD. - -q. Fixed a problem with completion -- it thought that `pwd`/[TAB] indicated - an unfinished command completion (`/), which generated errors. - -r. The bash special tilde expansions (~-, ~+) are now attempted before - calling the standard tilde expansion code, which should eliminate the - problems people have been seeing with this on Solaris 2.5.1. - -s. Added support for to places where it was missing. - -t. Changed the code that reads the output of a command substitution to not - go through stdio. This reduces the memory requirements and is faster. - -u. A number of changes to speed up export environment creation were made. - -v. A number of memory leaks were fixed as the result of running the test - scripts through Purify. - -w. Fixed a bug that caused subshells forked to interpret executable - scripts without a leading `#!' to not reinitialize the values of - the shell options. - -2. Changes to Readline - -a. History library has less `#ifdef SHELL' code -- abstracted stuff out - into application-specific function hooks. - -b. Readline no longer calls getenv() if it's compiled as part of the shell, - which should eliminate problems on systems that cannot redefine getenv(), - like the NeXT OS. - -c. Fixed translation of ESC when `untranslating' macro values. - -d. The region kill operation now fixes the mark if it ends up beyond the - boundaries of the line after the region is deleted. - -3. New Features in Bash - -a. New argument for `configure': `--with-curses'. This can be used to - override the selection of the termcap library on systems where it is - deficient. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.01-alpha1, -and the previous version, bash-2.0-release. - -1. Changes to Bash - -a. System-specific configuration changes for: FreeBSD, SunOS4, Irix, - MachTen, QNX 4.2, Harris Night Hawk, SunOS5. - -b. System-specific code changes were made for: Linux, 4.4 BSD, QNX 4.2, - HP-UX, AIX 4.2. - -c. A bug that caused the exec builtin to fail because the full pathname of - the command could not be found was fixed. - -d. The code that performs output redirections is now more resistant to - race conditions and possible security exploits. - -e. A bug that caused the shell to dump core when performing pattern - substitutions on variable values was fixed. - -f. More hosts are now recognized by the auto-configuration mechanism - (OpenBSD, QNX, others). - -g. Assignments to read-only variables that attempt to convert them to - arrays are now errors. - -h. A bug that caused shell scripts using array assignments in POSIX mode - to exit after the assignment was performed was fixed. - -i. The substring expansion code is now more careful about running off the - ends of the expanded variable value. - -j. A bug that caused completion to fail if a backquoted command substitution - appeared anywhere on the line was fixed. - -k. The `source' builtin no longer turns off history if it has been enabled - in a non-interactive shell. - -l. A bug that caused the shell to crash when `disown' was given a pid - instead of a job number was fixed. - -m. The `cd' spelling correction code will not try to change to `.' if no - directory entries match a single-character argument. - -n. A bad variable name supplied to `declare', `export', or `readonly' no - longer causes a non-interactive shell in POSIX mode to exit. - -o. Some fixes were made to the test suite to handle peculiarities of - various Unix versions. - -p. The bash completion code now quotes characters that readline would - treat as word breaks for completion but are not shell metacharacters. - -q. Bad options supplied at invocation now cause a usage message to be - displayed. - -r. Fixes were made to the code that handles DEBUG traps so that the trap - string is not freed inappropriately. - -s. Some changes were made to the bash debugger in examples/bashdb -- it - should be closer to working now. - -t. A problem that caused the default filename used for mail checking to be - wrong was fixed. - -u. A fix was made to the `echo' builtin so that NUL characters printed with - `echo -e' do not cause the output to be truncated. - -v. A fix was made to the job control code so that the shell behaves better - when monitor mode is enabled in a non-interactive shell. - -w. Bash no longer catches all of the terminating signals in a non- - interactive shell until a trap is set on EXIT, which should result in - quicker startup. - -x. A fix was made to the command timing code so that `time' can be used in - a loop. - -y. A fix was made to the parser so that `((cmd); cmd2)' is now parsed as - a nested subshell rather than strictly as an (erroneous) arithmetic - command. - -z. A fix was made to the globbing code so that it correctly matches quoted - filenames beginning with a `.'. - -aa. A bug in `fc' that caused some multi-line commands to not be stored as - one command in the history when they were re-executed after editing - (with `fc -e') was fixed. - -bb. The `ulimit' builtin now attempts to catch some classes of integer - overflows. - -cc. The command-oriented-history code no longer attempts to add `;' - inappropriately when a newline appears while reading a $(...) command - substitution. - -dd. A bug that caused the shell to dump core when `help --' was executed - was fixed. - -ee. A bug that caused the shell to crash when an unset variable appeared - in the body of a here document after `set -u' had been executed was - fixed. - -ff. Implicit input redirections from /dev/null for asynchronous commands - are now handled better. - -gg. A bug that caused the shell to fail to compile when configured with - `--disable-readline' was fixed. - -hh. The globbing code should now be interruptible. - -ii. Bash now notices when the `kill' builtin is used to send SIGCONT to a - stopped job and adjusts the data structures accordingly, as if `bg' had - been executed instead. - -jj. A bug that caused the shell to crash when mixing calls to `getopts' - and `shift' on the same set of positional parameters was fixed. - -kk. The command printing code now preserves the `-p' flag to `time'. - -ll. The command printing code now handles here documents better when there - are other redirections associated with the command. - -mm. The special glibc environment variable (NNN_GNU_nonoption_argv_flags_) - is no longer placed into the environment of executed commands -- users - of glibc had too many problems with it. - -nn. Reorganized the code that generates signames.h. The signal_names list - is now more complete but may be slightly different (SIGABRT is favored - over SIGIOT, for example). The preferred signal names are those - listed in the POSIX.2 standard. - -oo. `bashbug' now uses a filename shorter than 14 characters for its - temporary file, and asks for confirmation before sending the bug - report. - -pp. A bug that caused TAB completion in vi editing mode to not be turned - off when `set -o posix' was executed or back on when `set +o posix' - was executed was fixed. - -qq. A bug in the brace expansion code that caused brace expansions appearing - in new-style $(...) command substitutions to be inappropriately expanded - was fixed. - -rr. A bug in the readline hook shell-expand-line that could cause memory to - be inappropriately freed was fixed. - -ss. A bug that caused some arithmetic expressions containing `&&' and `||' - to be parsed with the wrong precedence has been fixed. - -tt. References to unbound variables after `set -u' has been executed now - cause the shell to exit immediately, as they should. - -uu. A bug that caused the shell to exit inappropriately when `set -e' had - been executed and a command's return status was being inverted with the - `!' reserved word was fixed. - -vv. A bug that could occasionally cause the shell to crash with a - divide-by-zero error when timing a command was fixed. - -ww. A bug that caused parameter pattern substitution to leave stray - backslashes in the replacement string when the expression is in - double quotes was fixed. - -xx. The `break' and `continue' builtins now break out of all loops when an - invalid count argument is supplied. - -yy. Fixed a bug that caused PATH to be set to the empty string if - `command -p' is executed with PATH unset. - -zz. Fixed `kill -l signum' to print the signal name without the `SIG' prefix, - as POSIX specifies. - -aaa. Fixed a bug that caused the shell to crash while setting $SHELLOPTS - if there were no shell options set. - -bbb. Fixed `export -p' and `readonly -p' so that when the shell is in POSIX - mode, their output is as POSIX.2 specifies. - -ccc. Fixed a bug in `readonly' so that `readonly -a avar=(...)' actually - creates an array variable. - -ddd. Fixed a bug that prevented `time' from correctly timing background - pipelines. - -2. Changes to Readline - -a. A bug that caused an extra newline to be printed when the cursor was on - an otherwise empty line was fixed. - -b. An instance of memory being used after it was freed was corrected. - -c. The redisplay code now works when the prompt is longer than the screen - width. - -d. `dump-macros' is now a bindable name, as it should have been all along. - -e. Non-printable characters are now expanded when displaying macros and - their values. - -f. The `dump-variables' and `dump-macros' commands now output a leading - newline if they're called as the result of a key sequence, rather - than directly by an application. - -3. New Features in Bash - -a. There is a new builtin array variable: GROUPS, the set of groups to which - the user belongs. This is used by the test suite. - -4. New Features in Readline - -a. If a key sequence bound to `universal-argument' is read while reading a - numeric argument started with `universal-argument', it terminates the - argument but is otherwise ignored. This provides a way to insert multiple - instances of a digit string, and is how GNU emacs does it. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-release, -and the previous version, bash-2.0-beta3. - -1. Changes to Bash - -a. Fix to the `getopts' builtin so that it does the right thing when a - required option argument is not present. - -b. The completion code now updates the common prefix of matched names - after FIGNORE processing is done, since any names that were removed - may have changed the common prefix. - -c. Fixed a bug that made messages in MAILPATH entries not work correctly. - -d. Fixed a serious documentation error in the description of the new - ${parameter:offset[:length]} expansion. - -e. Fixes to make parameter substring expansion ({$param:offset[:length]}) - work when within double quotes. - -f. Fixes to make ^A (CTLESC) survive an unquoted expansion of positional - parameters. - -g. Corrected a misspelling of `unlimited' in the output of `ulimit'. - -h. Fixed a bug that caused executable scripts without a leading `#!' to - occasionally pick up the wrong set of positional parameters. - -i. Linux systems now have a working `ulimit -v', using RLIMIT_AS. - -j. Updated config.guess so that many more machine types are recognized. - -k. Fixed a bug with backslash-quoted slashes in the ${param/pat[/sub]} - expansion. - -l. If the shell is named `-su', and `-c command' is supplied, read and - execute the login shell startup files even though the shell is not - interactive. This is to support the `-' option to `su'. - -m. Fixed a bug that caused core dumps when the DEBUG trap was ignored - with `trap "" DEBUG' and a shell function was subsequently executed. - -n. Fixed a bug that caused core dumps in the read builtin when IFS was - set to the null string and the input had leading whitespace. - -2. Changes to Readline - -a. Fixed a bug that caused a numeric argument of 1024 to be ignored when - inserting text. - -b. Fixed the display code so that the numeric argument is displayed as it's - being entered. - -c. Fixed the numeric argument reading code so that `M-- command' is - equivalent to `M--1 command', as the prompt implies. - -3. New Features in Bash - -a. `ulimit' now sets both hard and soft limits and reports the soft limit - by default (when neither -H nor -S is specified). This is compatible - with versions of sh and ksh that implement `ulimit'. - -b. Integer constants have been extended to base 64. - -4. New Features in Readline - -a. The `home' and `end' keys are now bound to beginning-of-line and - end-of-line, respectively, if the corresponding termcap capabilities - are present. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-beta3, -and the previous version, bash-2.0-beta2. - -1. Changes to Bash - -a. System-specific changes for: AIX 4.2, SCO 3.2v[45], HP-UX. - -b. When in POSIX mode, variable assignments preceding a special builtin - persist in the shell environment after the builtin completes. - -c. Changed all calls to getwd() to getcwd(). Improved check for systems - where the libc getcwd() calls popen(), since that breaks on some - systems when job control is being used. - -d. Fixed a bug that caused seg faults when executing scripts with the - execute bit set but without a leading `#!'. - -e. The environment passed to executed commands is never sorted. - -f. A bug was fixed in the code that expands ${name[@]} to the number of - elements in an array variable. - -g. A bug was fixed in the array compound assignment code ( A=( ... ) ). - -h. Window size changes now correctly propagate down to readline if - the shopt `checkwinsize' option is enabled. - -i. A fix was made in the code that expands to the length of a variable - value (${#var}). - -j. A fix was made to the command builtin so that it did not turn on the - `no fork' flag inappropriately. - -k. A fix was made to make `set -n' work more reliably. - -l. A fix was made to the job control initialization code so that the - terminal process group is set to the shell's process group if the - shell changes its own process group. - -2. Changes to Readline - -a. System-specific changes for: SCO 3.2v[45]. - -b. The behavior of the vi-mode `.' when redoing an `i' command was changed - to insert the text previously inserted by the `i' command rather than - simply entering insert mode. - -3. New features in Bash - -a. There is a new version of the autoload function package, in - examples/functions/autoload.v2, that uses arrays and provides more - functionality. - -b. Support for LC_COLLATE and locale-specific sorting of the results of - pathname expansion if strcoll() is available. - -4. New Features in Readline - -a. Support for locale-specific sorting of completion possibilities if - strcoll() is available. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-beta2, -and the previous version, bash-2.0-beta1. - -1. Changes to Bash - -a. `pushd -' is once again equivalent to `pushd $OLDPWD'. - -b. OS-specific changes for: SCO 3.2v[45]. - -c. A change was made to the fix for the recently-reported security hole - when reading characters with octal value 255 to make it work better on - systems with restartable system calls when not using readline. - -d. Some changes were made to the test suite so that it works if you - configure bash with --enable-usg-echo-default. - -e. A fix was made to the parsing of conditional arithmetic expressions. - -f. Illegal arithmetic bases now cause an arithmetic evaluation error rather - than being silently reset. - -g. Multiple arithmetic bases now cause an arithmetic evaluation error - instead of being ignored. - -h. A fix was made to the evaluation of ${param?word} to conform to POSIX.2. - -i. A bug that sometimes caused array indices to be evaluated twice (which - would cause errors when they contained assignment statements) was fixed. - -j. `ulimit' was rewritten to avoid problems with getrlimit(2) returning - unsigned values and to simplify the code. - -k. A bug in the command-oriented-history code that caused it to sometimes - put semicolons after right parens inappropriately was fixed. - -l. The values inserted into the prompt by the \w and \W escape sequences - are now quoted to prevent further expansion. - -m. An interactive shell invoked as `sh' now reads and executes commands - from the file named by $ENV when it starts up. If it's a login shell, - it does this after reading /etc/profile and ~/.profile. - -n. The file named by $ENV is never read by non-interactive shells. - -2. Changes to Readline - -a. A few changes were made to hide some macros and functions that should not - be public. - -b. An off-by-one error that caused seg faults in the history expansion code - was fixed. - -3. New Features in Bash - -a. The ksh-style ((...)) arithmetic command was implemented. It is exactly - identical to let "...". This is controlled by a new option to configure, - `--enable-dparen-arithmetic', which is on by default. - -b. There is a new #define available in config.h.top: SYS_BASH_LOGOUT. If - defined to a filename, bash reads and executes commands from that file - when a login shell exits. It's commented out by default. - -c. `ulimit' has a `-l' option that reports the maximum amount of data that - may be locked into memory on 4.4BSD-based systems. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-beta1, -and the previous version, bash-2.0-alpha4. - -1. Changes to Bash - -a. A bug that sometimes caused traps to be ignored on signals the - shell treats specially was fixed. - -b. The internationalization code was changed to track the values of - LC_* variables and call setlocale() as appropriate. The TEXTDOMAIN - and TEXTDOMAINDIR variables are also tracked; changes cause calls - to textdomain() and bindtextdomain(), if available. - -c. A bug was fixed that sometimes caused double-quoted strings to be - parsed incorrectly. - -d. Changes were made so that the siglist code compiles correctly on - Solaris 2.5. - -e. Added `:' to the set of characters that cause word breaks for the - completion code so that pathnames in assignments to $PATH can be - completed. - -f. The `select' command was fixed to print $PS3 to stderr. - -g. Fixed an error in the manual page section describing the effect that - setting and unsetting GLOBIGNORE has on the setting of the `dotglob' - option. - -h. The time conversion code now uses CLK_TCK rather than CLOCKS_PER_SEC - on systems without gettimeofday() and resources. - -i. The getopt static variables are now initialized each time a subshell - is started, so subshells using `getopts' work right. - -j. A sign-extension bug that caused a possible security hole was fixed. - -k. The parser now reads characters between backquotes within a double- - quoted string as a single word, so double quotes in the backquoted - string don't terminate the enclosing double-quoted string. - -l. A bug that caused `^O' to work incorrectly when typed as the first - thing to an interactive shell was fixed. - -m. A rarely-exercised off-by-one error in the code that quotes variable - values was fixed. - -n. Some memory and file descriptor leaks encountered when running a - shell script that is executable but does not have a leading `#!' - were plugged. - -2. Changes to Readline - -a. A bug that sometimes caused incorrect results when trying to read - typeahead on systems without FIONREAD was fixed. - -3. New Features in Bash - -a. The command timing code now uses the value of the TIMEFORMAT variable - to format and display timing statistics. - -b. The `time' reserved word now accepts a `-p' option to force the - POSIX.2 output format. - -c. There are a couple of new and updated scripts to convert csh startup - files to bash format. - -d. There is a new builtin array variable: BASH_VERSINFO. The various - members hold the parts of the version information in BASH_VERSION, - plus the value of MACHTYPE. - -4. New Features in Readline - -a. Setting LANG to `en_US.ISO8859-1' now causes readline to enter - eight-bit mode. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-alpha4, -and the previous version, bash-2.0-alpha3. - -1. Changes to Bash - -a. There is better detection of rsh connections on Solaris 2. - -b. Assignments to read-only variables preceding a command name are now - variable assignment errors. Variable assignment errors cause - non-interactive shells running in posix mode to exit. - -c. The word tokenizer was rewritten to handle nested quotes and pairs - ('', "", ``, ${...}, $(...), $[...], $'...', $"...", <(...), >(...)) - correctly. Some of the parameter expansion code was updated as a - consequence. - -d. A fix was made to `test' when given three arguments so that a binary - operator is checked for first, before checking that the first argument - is `!'. - -e. 2''>/dev/null is no longer equivalent to 2>/dev/null. - -f. Parser error messages were regularized, and in most cases the name of - the shell script being read by a non-interactive shell is not printed - twice. - -g. A fix was made to the completion code so that it no longer removes the - text the user typed in some cases. - -h. The special glibc `getopt' environment variable is no longer put into - the environment on machines with small values of ARG_MAX. - -i. The expansion of ${...} now follows the POSIX.2 rules for finding the - closing `}'. - -j. The shell no longer displays spurious status messages for background - jobs in shell scripts that complete successfully when the script is - run from a terminal. - -k. `shopt -o' now correctly updates $SHELLOPTS. - -l. A bug that caused the $PATH searching code to return a non-executable - file even when an executable file with the same name appeared later in - $PATH was fixed. - -m. The shell now does tilde expansions on unquoted `:~' in assignment - statements when not in posix mode. - -n. Variable assignment errors when a command consists only of assignments - now cause non-interactive shells to exit when in posix mode. - -o. If the variable in a `for' or `select' command is read-only, or not a - legal shell identifier, a variable assignment error occurs. - -p. `test' now handles `-a' and `-o' as binary operators when three arguments - are supplied, and correctly parses `( word )' as equivalent to `word'. - -q. `test' was fixed so that file names of the form /dev/fd/NN mean the same - thing on all systems, even Linux. - -r. Fixed a bug in the globbing code that caused patterns with multiple - consecutive `*'s to not be matched correctly. - -s. Fixed a bug that caused $PS2 to not be printed when an interactive shell - not using readline is reading a here document. - -t. Fixed a bug that caused history expansion to be performed inappropriately - when a single-quoted string spanned more than one line. - -u. `getopts' now checks that the variable name passed by the user as the - second argument is a legal shell identifier and that the variable is - not read-only. - -v. Fixed `getopts' to obey POSIX.2 rules for setting $OPTIND when it - encounters an error. - -w. Fixed `set' to display variable values in a form that can be re-read. - -x. Fixed a bug in the code that keeps track of whether or not local variables - have been declared at the current level of function nesting. - -y. Non-interactive shells in posix mode now exit if the name in a function - declaration is not a legal identifier. - -z. The job control code now ignores stopped children when the shell is not - interactive. - -aa. The `cd' builtin no longer attempts spelling correction on the directory - name if the shell is not interactive, regardless of the setting of the - `cdspell' option. - -bb. Some OS-specific changes were made for SCO 3.2v[45] and AIX 4.2. - -cc. `time' now prints its output to stderr, as POSIX.2 specifies. - -2. Fixes to Readline - -a. After printing possible completions, all lines of a multi-line prompt - are redisplayed. - -b. Some changes were made to the terminal handling code in rltty.c to - work around AIX 4.2 bugs. - -3. New Features in Bash - -a. There is a new loadable builtin: sprintf, with calling syntax - sprintf var format [args] - This provides an easy way to simulate ksh left- and right-justified - variable values. - -b. The expansions of \h and \H in prompt strings were swapped. \h now - expands to the hostname up to the first `.', as in bash-1.14. - -4. New Features in Readline - -a. The bash-1.14 behavior when ^M is typed while doing an incremental - search was restored. ^J may now be used to terminate the search without - accepting the line. - -b. There is a new bindable variable: disable-completion. This inhibits - word completion and causes the completion character to be inserted as - if it had been bound to self-insert. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-2.0-alpha3, -and the previous version, bash-2.0-alpha2. - -There is now a file `COMPAT' included in the distribution that lists the -user-visible incompatibilities between 1.14 and 2.0. - -1. Changes to Bash - -a. Some work was done so that word splitting of the rhs of assignment - statements conforms more closely to historical practice. - -b. A couple of errant memory frees were fixed. - -c. A fix was made to the test builtin so it recognizes `<' and `>' as - binary operators. - -d. The GNU malloc in lib/malloc/malloc.c now scrambles memory as it's - allocated and freed. This is to catch callers that refer to freed - memory or assume something about newly-allocated memory. - -e. Fixed a problem with conversion to 12-hour time in the prompt - expansion code. - -f. Fixed a problem with configure's argument parsing order. Now you can - correctly turn on specific options after using --enable-minimal-config. - -g. The configure script now automatically disables the use of GNU malloc - on systems where it's appropriate (better than having people read the - NOTES file and do it manually). - -h. There are new prompt expansions (\v and \V) to insert version information - into the prompt strings. - -i. The default prompt string now includes the version number. - -j. Most of the builtins that take no options were changed to use the - internal getopt so they can produce proper error messages for -? - and incorrect options. - -k. Some system-specific changes were made for SVR4.2 and Solaris 2.5. - -l. Bash now uses PATH_MAX instead of MAXPATHLEN and NAME_MAX instead of - MAXNAMLEN. - -m. A couple of problems caused by uninitialized variables were fixed. - -n. There are a number of new loadable builtin examples: logname, basename, - dirname, tty, pathchk, tee, head, and rmdir. All of these conform to - POSIX.2. - -o. Bash now notices changes in TZ and calls tzset() if present, so - changing TZ will alter the time printed by prompt expansions. - -p. The source was reorganized a bit so I don't have to wait so long for - some files to compile, and to facilitate the creation of a `shell - library' at some future point. - -q. Bash no longer turns off job control if called as `sh', since the - POSIX.2 spec includes job control as a standard feature. - -r. `bash -o posix' now works as intended. - -s. Fixed a problem with the completion code: when completing a filename - that contained globbing characters, if show-all-if-ambiguous was set, - the completion code would remove the user's text. - -t. Fixed ulimit so that (hopefully) the full range of limits is available - on HPUX systems. - -u. A new `shopt' option (`hostcomplete') enables and disables hostname - completion. - -v. The shell no longer attempts to save the history on an abort(), - which is usually called by programming_error(). - -w. The `-s' option to `fc' was changed to echo the command to be executed - to stderr instead of stdout. - -x. If the editor invoked by `fc -e' exits with a non-zero status, no - commands are executed. - -y. Fixed a bug that made the shopt `histverify' option work incorrectly. - -z. There is a new variable `MACHTYPE' whose value is the GNU-style - `cpu-company-system' system description as set by configure. (The - values of MACHTYPE and HOSTTYPE should really be swapped.) - -aa. The `ulimit' builtin now allows the maximum virtual memory size to be - set via setrlimit(2) if RLIMIT_VMEM is defined. - -bb. `bash -nc 'command'' no longer runs `command'. - -2. Changes to Readline - -a. Fixed a typo in the code that checked for FIONREAD in input.c. - -b. Fixed a bug in the code that outputs keybindings, so things like C-\ - are quoted properly. - -c. Fixed a bug in the inputrc file parsing code to handle the problems - caused by inputrc files created from the output of `bind -p' in - previous versions of bash. The problem was due to the bug fixed - in item b above. - -d. Readline no longer turns off the terminal's meta key, and turns it on - once the first time it's called. - ------------------------------------------------------------------------------- -This file documents the changes between this version, bash-2.0-alpha2, -and the previous version, bash-2.0-alpha. - -1. Changes to Bash - -a. The shell no longer thinks directories are executable. - -b. `disown' has a new option, `h', which inhibits the resending of SIGHUP - but does not remove the job from the jobs table. - -c. The varargs functions in error.c now use ANSI-C `stdarg' if available. - -d. The build process now treats the `build version' in .build as local to - the build directory, so different versions built from the same source - tree have different `build versions'. - -e. Some problems with the grammar have been fixed. (It used `list' in a few - productions where `compound_list' was needed. A `list' must be terminated - with a newline or semicolon; a `compound_list' need not be.) - -f. A fix was made to keep `wait' from hanging when waiting for all background - jobs. - -g. `bash --help' now writes its output to stdout, like the GNU Coding Standards - specify, and includes the machine type (the value of MACHTYPE). - -h. `bash --version' now prints more information and exits successfully, like - the GNU Coding Standards specify. - -i. The output of `time' and `times' now prints fractional seconds with three - places after the decimal point. - -j. A bug that caused process substitutions to screw up the pipeline printed - by `jobs' was fixed. - -k. Fixes were made to the code that implements $'...' and $"..." so they - work as documented. - -l. The process substitution code now opens named pipes for reading with - O_NONBLOCK to avoid hanging. - -m. Fixes were made to the trap code so the shell cleans up correctly if the - trap command contains a `return' and we're executing a function or - sourcing a script with `.'. - -n. Fixes to doc/Makefile.in so that it doesn't try to remake all of the - documentation (ps, dvi, etc.) on a `make install'. - -o. Fixed an auto-increment error that caused bash -c args to sometimes dump - core. - -p. Fixed a bug that caused $HISTIGNORE to fail when the history line - contained globbing characters. - -2. Changes to Readline - -a. There is a new string variable, rl_library_version, available for use by - applications. The current value is "2.1". - -b. A bug encountered when expand-tilde was enabled and file completion was - attempted on a word beginning with `~/' was fixed. - -c. A slight change was made to the incremental search termination behavior. - ESC still terminates the search, but if input is pending or arrives - within 0.1 seconds (on systems with select(2)), it is used as a prefix - character. This is intented to allow users to terminate searches with - the arrow keys and get the behavior they expect. diff --git a/COMPAT~ b/COMPAT~ deleted file mode 100644 index 06131f1b3..000000000 --- a/COMPAT~ +++ /dev/null @@ -1,216 +0,0 @@ -This document details the incompatibilites between this version of bash, -bash-3.0, and a previous widely-available version, bash-1.14 (which -is still the `standard' version for a few Linux distributions). These -were discovered by users of bash-2.x and 3.x, so this list is not -comprehensive. Some of these incompatibilities occur between the current -version and versions 2.0 and above. (The differences between bash-1.14 -and bash-2.0 were significant.) - -1. Bash uses a new quoting syntax, $"...", to do locale-specific - string translation. Users who have relied on the (undocumented) - behavior of bash-1.14 will have to change their scripts. For - instance, if you are doing something like this to get the value of - a variable whose name is the value of a second variable: - - eval var2=$"$var1" - - you will have to change to a different syntax. - - This capability is directly supported by bash-2.0: - - var2=${!var1} - - This alternate syntax will work portably between bash-1.14 and bash-2.0: - - eval var2=\$${var1} - -2. One of the bugs fixed in the YACC grammar tightens up the rules - concerning group commands ( {...} ). The `list' that composes the - body of the group command must be terminated by a newline or - semicolon. That's because the braces are reserved words, and are - recognized as such only when a reserved word is legal. This means - that while bash-1.14 accepted shell function definitions like this: - - foo() { : } - - bash-2.0 requires this: - - foo() { :; } - - This is also an issue for commands like this: - - mkdir dir || { echo 'could not mkdir' ; exit 1; } - - The syntax required by bash-2.0 is also accepted by bash-1.14. - -3. The options to `bind' have changed to make them more consistent with - the rest of the bash builtins. If you are using `bind -d' to list - the readline key bindings in a form that can be re-read, use `bind -p' - instead. If you were using `bind -v' to list the key bindings, use - `bind -P' instead. - -4. The `long' invocation options must now be prefixed by `--' instead - of `-'. (The old form is still accepted, for the time being.) - -5. There was a bug in the version of readline distributed with bash-1.14 - that caused it to write badly-formatted key bindings when using - `bind -d'. The only key sequences that were affected are C-\ (which - should appear as \C-\\ in a key binding) and C-" (which should appear - as \C-\"). If these key sequences appear in your inputrc, as, for - example, - - "\C-\": self-insert - - they will need to be changed to something like the following: - - "\C-\\": self-insert - -6. A number of people complained about having to use ESC to terminate an - incremental search, and asked for an alternate mechanism. Bash-2.03 - uses the value of the settable readline variable `isearch-terminators' - to decide which characters should terminate an incremental search. If - that variable has not been set, ESC and Control-J will terminate a - search. - -7. Some variables have been removed: MAIL_WARNING, notify, history_control, - command_oriented_history, glob_dot_filenames, allow_null_glob_expansion, - nolinks, hostname_completion_file, noclobber, no_exit_on_failed_exec, and - cdable_vars. Most of them are now implemented with the new `shopt' - builtin; others were already implemented by `set'. Here is a list of - correspondences: - - MAIL_WARNING shopt mailwarn - notify set -o notify - history_control HISTCONTROL - command_oriented_history shopt cmdhist - glob_dot_filenames shopt dotglob - allow_null_glob_expansion shopt nullglob - nolinks set -o physical - hostname_completion_file HOSTFILE - noclobber set -o noclobber - no_exit_on_failed_exec shopt execfail - cdable_vars shopt cdable_vars - -8. `ulimit' now sets both hard and soft limits and reports the soft limit - by default (when neither -H nor -S is specified). This is compatible - with versions of sh and ksh that implement `ulimit'. The bash-1.14 - behavior of, for example, - - ulimit -c 0 - - can be obtained with - - ulimit -S -c 0 - - It may be useful to define an alias: - - alias ulimit="ulimit -S" - -9. Bash-2.01 uses a new quoting syntax, $'...' to do ANSI-C string - translation. Backslash-escaped characters in ... are expanded and - replaced as specified by the ANSI C standard. - -10. The sourcing of startup files has changed somewhat. This is explained - more completely in the INVOCATION section of the manual page. - - A non-interactive shell not named `sh' and not in posix mode reads - and executes commands from the file named by $BASH_ENV. A - non-interactive shell started by `su' and not in posix mode will read - startup files. No other non-interactive shells read any startup files. - - An interactive shell started in posix mode reads and executes commands - from the file named by $ENV. - -11. The <> redirection operator was changed to conform to the POSIX.2 spec. - In the absence of any file descriptor specification preceding the `<>', - file descriptor 0 is used. In bash-1.14, this was the behavior only - when in POSIX mode. The bash-1.14 behavior may be obtained with - - <>filename 1>&0 - -12. The `alias' builtin now checks for invalid options and takes a `-p' - option to display output in POSIX mode. If you have old aliases beginning - with `-' or `+', you will have to add the `--' to the alias command - that declares them: - - alias -x='chmod a-x' --> alias -- -x='chmod a-x' - -13. The behavior of range specificiers within bracket matching expressions - in the pattern matcher (e.g., [A-Z]) depends on the current locale, - specifically the value of the LC_COLLATE environment variable. Setting - this variable to C or POSIX will result in the traditional ASCII behavior - for range comparisons. If the locale is set to something else, e.g., - en_US (specified by the LANG or LC_ALL variables), collation order is - locale-dependent. For example, the en_US locale sorts the upper and - lower case letters like this: - - AaBb...Zz - - so a range specification like [A-Z] will match every letter except `z'. - Other locales collate like - - aAbBcC...zZ - - which means that [A-Z] matches every letter except `a'. - - The portable way to specify upper case letters is [:upper:] instead of - A-Z; lower case may be specified as [:lower:] instead of a-z. - - Look at the manual pages for setlocale(3), strcoll(3), and, if it is - present, locale(1). - - You can find your current locale information by running locale(1): - - caleb.ins.cwru.edu(2)$ locale - LANG=en_US - LC_CTYPE="en_US" - LC_NUMERIC="en_US" - LC_TIME="en_US" - LC_COLLATE="en_US" - LC_MONETARY="en_US" - LC_MESSAGES="en_US" - LC_ALL=en_US - - My advice is to put - - export LC_COLLATE=C - - into /etc/profile and inspect any shell scripts run from cron for - constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - - from removing every file in the current directory except those beginning - with `z' and still allow individual users to change the collation order. - Users may put the above command into their own profiles as well, of course. - -14. Bash versions up to 1.14.7 included an undocumented `-l' operator to - the `test/[' builtin. It was a unary operator that expanded to the - length of its string argument. This let you do things like - - test -l $variable -lt 20 - - for example. - - This was included for backwards compatibility with old versions of the - Bourne shell, which did not provide an easy way to obtain the length of - the value of a shell variable. - - This operator is not part of the POSIX standard, because one can (and - should) use ${#variable} to get the length of a variable's value. - Bash-2.x does not support it. - -15. Bash no longer auto-exports the HOME, PATH, SHELL, TERM, HOSTNAME, - HOSTTYPE, MACHTYPE, or OSTYPE variables. - -16. Bash no longer initializes the FUNCNAME, GROUPS, or DIRSTACK variables - to have special behavior if they appear in the initial environment. - -17. Bash no longer removes the export attribute from the SSH_CLIENT or - SSH2_CLIENT variables, and no longer attempts to discover whether or - not it has been invoked by sshd in order to run the startup files. - -18. Bash no longer requires that the body of a function be a group command. - Thus, the following is accepted: - - foo() echo bar; diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ deleted file mode 100644 index 5687e0239..000000000 --- a/CWRU/CWRU.chlog~ +++ /dev/null @@ -1,9638 +0,0 @@ - 4/9/2001 - -------- -[bash-2.05 released] - - 4/10 - ---- -redir.c - - check return value of fclose() in write_here_document() for error - returns; don't just rely on fwrite() failing - -support/bashbug.sh - - set TMPDIR to /tmp if it's null or unset - - use $TMPDIR in the TEMP tempfile name template - - fixed the call to `mktemp', if it exists, to make it more portable - -jobs.c - - if WCONTINUED is not defined, define it to 0 and add a define for - WIFCONTINUED(wstatus) which expands to 0 - - add WCONTINUED to the flags passed to waitpid(2) in waitchld() - - don't increment children_exited if waitpid's status is WIFCONTINUED, - since we don't want to call a SIGCHLD trap handler in this case - - in waitchld(), we set child->running to 1 if WIFCONTINUED(status) - is non-zero - - make sure pretty_print_job doesn't check for the core dump bit if - the process has been continued; it's only valid if the job is dead - - in set_job_status_and_cleanup, set the job to JRUNNING if job_state - is non-zero and the job was previously marked as JSTOPPED - -configure.in - - add -DBROKEN_DIRENT_D_INO to interix LOCAL_CFLAGS - -lib/glob/glob.c - - if BROKEN_DIRENT_D_INO is defined, define REAL_DIR_ENTRY to 1 - -jobs.c - - in kill_pid, we only need to block and unblock SIGCHLD if the - `group' argument is non-zero, since otherwise we just call `kill' - on the pid argument - -version.c - - update copyright date to 2001 - -bashline.c - - prog_complete_return needs to take a `const char *' as its first - argument - - history_completion_generator needs to take a `const char *' as - its first argument, and `text' needs to be a `const char *' - - 4/11 - ---- -redir.c - - fixed a weird typo in redir_special_open, case RF_DEVFD, added - call to all_digits before call to legal_number - - fixed do_redirection_internal to call legal_number instead of atol(3) - when translating r_duplicating_{in,out}put_word, so it handles - overflow better - - produce an error message in redirection_error for out-of-range - file descriptors - - change allocation strategy in redirection_error so we don't have to - malloc scratch memory if redirection_expand() fails - -jobs.h - - added defines for `running' member of a struct process - -general.c - - fix legal_number to return 0 when strtol(3) reports overflow or - underflow - -parse.y - - changed read_token_word to call legal_number instead of atoi(3) - -input.c - - return -1/EBADF from close_buffered_fd if fd is < 0 - -command.h - - fixed bogus comment about IS_DESCRIPTOR in description of the - REDIRECTEE struct - -print_cmd.c - - change cprintf's 'd' modifier code to display negative numbers as - an out-of-range value. We can do this only because the only use - of %d is to output file descriptor numbers in redirections - -support/mksignames.c - - need to include config.h to get a possible value for - UNUSABLE_RT_SIGNALS - - 4/16 - ---- -lib/readline/doc/rluser.texinfo - - corrected a small error in one description of M-DEL - - 4/17 - ---- -stringlib.c - - need to initialize `ind' before calls to RESIZE_MALLOCED_BUFFER - in strcreplace() - -support/bashversion.c - - new file, prints bash version information - -Makefile.in - - rules for building bashversion and linking it to version.o - - 4/24 - ---- -conftypes.h - - new file with HOSTTYPE, OSTYPE, MACHTYPE, etc. defines from - variables.h - -variables.h, version.c - - include conftypes.h - -patchlevel.h - - new file, contains define for PATCHLEVEL. Doing away with the old - scheme of having the information in configure.in - -version.c - - include patchlevel.h - -Makefile.in - - run bashversion -p to find patch level rather than have configure - substitute in a value - - pass -S ${top_srcdir} to support/mkversion.sh - -support/mkversion.sh - - don't put PATCHLEVEL define into version.h, but accept and ignore - a -p option - - take a new -S srcdir option - - find the patch level by parsing it out of patchlevel.h - -configure.in - - hard-code BASHVERS assignment instead of reading it from a file - - remove BASHPATCH; don't substitute it - -_distribution,_patchlevel - - removed - - 4/26 - ---- -shell.c - - call init_noninteractive() in open_shell_script if forced_interactive - is non-zero (the shell was started with -i) and fd_is_tty is 0 - (the script file is a real file, not something like /dev/stdin), - since it wasn't done earlier - -builtins/printf.def - - change for POSIX.2 compliance when conversion errors are encountered - when processing %d, %u, and floating point conversion operators - (print a warning message, return the value accumulated at the time - of the error -- which is always 0 -- and exit with a non-zero status) - -command.h - - added CMD_COMMAND_BUILTIN for use by the `command' builtin and the - code in execute_cmd.c - -builtins/command.def - - add CMD_COMMAND_BUILTIN to the created command's flags - - 5/1 - --- -configure.in - - add call to AC_C_CONST to test `const' compiler behavior - - add call to AC_C_INLINE to test `inline' compiler behavior - - add call to AC_C_STRINGIZE to test cpp #x stringizing operator - -config.h.in - - add `#undef const' for configure to substitute - - add `#undef inline' for configure to substitute - - add `#undef HAVE_STRINGIZE' for configure to substitute - -include/stdc.h - - remove code that defines or undefines `const' and `inline' - - change the __STRING macro to be defined depending on the value - of HAVE_STRINGIZE - -lib/malloc/malloc.c - - change the __STRING macro to be defined depending on the value - of HAVE_STRINGIZE - -lib/readline/{readline,rlprivate}.h - - moved rl_get_termcap to readline.h, making it a public function - -lib/readline/readline.h - - new #define, RL_READLINE_VERSION, hex-encoded library version - number, currently set to 0x0402 - - new public int variable, rl_readline_version - -lib/readline/readline.c - - #define RL_READLINE_VERSION if it is not already defined (which it - should be in readline.h) - - initialize rl_readline_version to RL_READLINE_VERSION - -lib/readline/doc/rltech.texinfo - - documented rl_get_termcap - - documented rl_readline_version - -jobs.c - - job_exit_status should return an int, not a WAIT (undetected - before because on most POSIX-like systems a WAIT is really an int) - -builtins/evalfile.c - - added FEVAL_REGFILE (file must be a regular file) to accepted - _evalfile flags - - fc_execute_file() adds FEVAL_REGFILE to _evalfile flags. This - means that startup files and files read with `.' no longer need - to be regular files - - 5/2 - --- - -lib/termcap/Makefile.in - - fix target for installed termcap library (normally unused) - -lib/tilde/Makefile.in - - fix install target to install in $(libdir) (normally unused) - -Makefile.in - - don't make $(man3dir) since there's nothing installed there - -Makefile.in,doc/Makefile.in - - change `man1ext' to `.1', `man3ext' to `.3' - - change appropriate install targets to use new values of man[13]ext - - use `test ...' instead of `[...]' - - add support for DESTDIR root installation prefix, for package - building (installdirs, install, install-strip, uninstall targets) - -builtins/common.c - - new function int get_exitstat(WORD_LIST *list) returns an eight-bit - exit status value for use in return, exit, logout builtins - -builtins/common.h - - extern declaration for get_exitstat() - -builtins/{exit,return}.def - - call get_exitstat where appropriate - -builtins/printf.def - - add support for "'" flag character as posix 1003.2-200x d6 says - - fix core dump when user-supplied field width or precision is 0 - - fix to printstr() to handle zero-length precision with `%b' format - specifier (printf '%.0b-%.0s\n' foo bar) - - fix to printstr() to treat a negative field width as a positive - field width with left-justification - - fix to mklong to avoid static buffers, which can always be overrun - by someone sufficiently motivated - -bashline.c - - change var in add_host_name to type `size_t' for passing to xrealloc - - 5/3 - --- -execute_cmd.c - - change restore_signal_mask to accept a sigset_t *, since a sigset_t - may not fit into a pointer, change call - -unwind_prot.c - - use a union UWP in restore_variable when restoring a variable whose - size is the same as sizeof(int), the reverse of the method used to - store it in unwind_protect_int - -builtins/printf.def - - use a #define LENMODS containing the length modifiers instead of - testing against each possible modifier character, save any mod - character found - - add support for ISO C99 length specifiers `j', `t', and `z' - - if `L' modifier is supplied with a floating point conversion char, - pass a `long double' to printf if HAVE_LONG_DOUBLE is defined - -configure.in,config.h.in - - call AC_C_LONG_DOUBLE to check for `long double'; define - HAVE_LONG_DOUBLE if supported - -bashline.c - - fix an inadvertantly-unclosed comment in attempt_shell_completion - - make set_saved_history return a value - - make dynamic_complete_history return a useful value - -{make_cmd,execute_cmd,shell,subst,trap,variables,input,unwind_prot,test, -pcomplete}.c - - removed some declared-but-unused variables - -builtins/{cd,enable,fc,set,setattr,type,umask,printf,complete}.def - - removed some declared-but-unused variables - -lib/sh/{zread,netopen}.c - - removed some declared-but-unused variables - -execute_cmd.c - - in execute_arith_command, use a long variable to hold the result - of evalexp(), since that's what it returns - -builtins/evalstring.c - - make cat_file return -1 on a read or write error - -lib/sh/stringlib.c - - make merge_stringlists() return the right value - - 5/7 - --- -pcomplete.c - - remove typo that caused empty declaration (;;) - -parse.y - - fix yyerror() to accept a single string argument; fix callers - -trap.c - - cast pointer to long instead of int when printing message with - internal_warning() in run_pending_traps() - -subst.c - - fix process_substitute to handle stdin being closed - -test.c - - change `while' to `if' in and() and or(), since the loop isn't - actually performed -- there's an unconditional `return' in the - loop body - - check for integer overflow of arguments to `-t' - -lib/sh/netopen.c - - change _getserv() to reject negative port/service numbers - -expr.c - - fix strlong() to not convert the base specification from long to - int before checking for overflow, since truncation on machines - where sizeof(int) != sizeof(long) may mask errors - -builtins/{jobs,kill,wait}.def - - use legal_number instead of atoi when converting strings to pid_t; - check for numeric overflow - -input.c - - fix for cygwin in b_fill_buffer -- off-by-one error when checking - buffer for \r\n termination - -general.h - - new #define INT_STRLEN_BOUND(t), computes max length of string - representing integer value of type T, possibly including a sign - character - - include if it's present - -{execute_cmd,findcmd,test}.c - - don't include , since general.h does it now - -{execute_cmd,lib/sh/itos,pcomplete,print_cmd,subst,variables}.c - - use INT_STRLEN_BOUND instead of static array sizes when converting - various strings to integer values - -shell.h - - struct fd_bitmap now uses an `int' size, since it's bounded by - the number of file descriptors, which must fit into an `int' - -execute_cmd.c - - FD_BITMAP_DEFAULT_SIZE is now 32, not 32L - - new_fd_bitmap takes an `int' size parameter, not a `long' - -execute_cmd.h - - change prototype for new_fd_bitmap() - -test.c - - fix test_stat to check for overflow when parsing the integer file - descriptor number; return ENOENT instead of EBADF for files that - are not open - -hashlib.c - - don't discard the upper 32 bits of the random value, if present - -lib/readline/shell.c - - use the same INT_STRLEN_BOUND mechanism to decide how much space to - allocated in sh_set_lines_and_columns - - 5/8 - --- -aclocal.m4 - - add check for libtinfo (termcap-specific portion of ncurses-5.2) to - BASH_CHECK_LIB_TERMCAP - - new macro, RL_LIB_READLINE_VERSION, checks version of installed - readline library and (optionally) writes version #defines to - config.h. Bash doesn't use the version defines - -configure.in - - call RL_LIB_READLINE_VERSION instead of support/rlvers.sh - -execute_cmd.c - - fix execute_shell_script and the WHITECHAR and STRINGCHAR macros - to check array bounds before indexing into the sample string - -unwind_prot.[ch] - - import new versions submitted by Paul Eggert - with a couple of changes for backwards compatibility, so the rest - of the source doesn't need to be changed yet - -jobs.c - - use unwind_protect_var on last_made_pid in run_sigchld_trap - -builtins/bind.def - - use unwind_protect_var on rl_outstream - -general.c - - rework print_rlimtype to use INT_STRLEN_BOUND and handle the - most negative number correctly - -expr.c - - `tokval' should have been a `long', since all arithmetic is done - as longs - -builtins/history.def - - consolidate tests for valid history position in one block to - avoid duplicate code and strings - -builtins/ulimit.def - - fix check for overflow when setting limit to work when int is 32 - bits and RLIMTYPE is 64 - -lib/sh/tmpfile.c - - don't truncate the result of time(3) to int; just use time_t, - since it's being assigned to an `unsigned long' - -mailcheck.c - - use legal_number instead of atoi in time_to_check_mail() to catch - more numeric errors; consolidate error checking in one block - - last_time_mail_checked should be a time_t - - 5/9 - --- -builtins/set.def - - recognize `set [-+]o nolog' if HISTORY is defined - -bashline.c - - new variable `dont_save_function_defs', set by `set -o nolog'; - currently ignored - -command.h - - the `dest' member of a REDIRECTEE is now an `int' - -parse.y,redir.c - - changed uses of `redir.test' (where redir is a REDIRECTEE) since - it's now an int - -lib/readline/rlstdc.h - - don't mess around with `const', rely on configure to supply a - proper definition if the compiler doesn't support it - -lib/tilde/tilde.h - - include if HAVE_CONFIG_H is defined - - don't mess around with `const', rely on configure - -builtins/shopt.def - - new read-only `shopt' option, login_shell, non-zero if shell is a - login shell (as decided by shell.c) - - new function set_login_shell(), sets shopt private value of - login_shell - -builtins/common.h - - new extern declaration for set_login_shell - -shell.c - - call set_login_shell after setting value of login_shell (in - main() and set_shell_name()) - -parse.y - - added new `\A' prompt string escape sequence: time in 24-hour - HH:MM format - -configure.in, config.h.in - - check for , define HAVE_GRP_H if found - -builtins/complete.def - - add new `-A group/-g' option to complete group names - -pcomplete.h - - new define for CA_GROUP, used with group name completion - -pcomplete.c - - add code to support CA_GROUP group name completion - -bashline.c - - new function, bash_groupname_completion_function(), supports - programmable completion of group names - -bashline.h - - extern declaration for bash_groupname_completion_function - -lib/readline/bind.c - - new inputrc variable, `match-hidden-files', controls completion - matching files beginning with a `.' (on Unix) - -lib/readline/complete.c - - new variable, _rl_match_hidden_files, mirrors `match-hidden-files' - inputrc variable - -lib/readline/rlprivate.h - - extern declaration for _rl_match_hidden_files - -builtins/hash.def - - new `-t' option to list hash values for each filename argument - -builtins/read.def - - alarm(3) takes an `unsigned int' argument, not int - - check for arithmetic overflow with -t and -n options - -input.c - - check for read error before doing \r\n translation on cygwin in - b_fill_buffer - - reset bp->b_used to 0 instead of leaving it at -1 on read error - in b_fill_buffer - -builtins/shopt.def - - new functions, shopt_setopt(name, mode) and - shopt_listopt(name, mode) to give the rest of the shell an easy - interface - -builtins/common.h - - extern declarations for shopt_setopt and shopt_listopt - -shell.c - - new invocation options -O and +O, to list or set/unset shopt - options like +o/-o sets and unsets `set -o' options - -doc/{bash.1,bashref.texi} - - document `set -o nolog' - - document `login_shell' shopt option - - document new `\A' prompt string escape sequence - - document new `-t' option to `hash' - - document new `[+-]O' invocation option - -doc/bashref.texi - - add text to `Invoking Bash' section defining a login shell; text - taken from man page - -doc/bash.1, lib/readline/doc/rluser.texinfo - - documented new complete/compgen `-A group/-g' option - -lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 - - documented new `match-hidden-files' inputrc variable - - 5/10 - ---- -configure.in - - fix AC_CHECK_PROG(ar, ...) - - add AC_CHECK_TYPE for ssize_t - -config.h.in - - new #undef for ssize_t - -lib/sh/zread.c - - int -> ssize_t fixes to mirror modern declarations of read and write - - the `off' variable in zsyncfd should be an off_t since it computes - a file offset - - the local buffer `lbuf' is now char, since it's not nice to pass - unsigned char * to read(2), and the values from it are assigned to - a char anyway - - lind and lused are now size_t, since they index into a buffer - - set lused to 0 on read error - -lib/sh/zwrite.c - - change second argument to type `char *', since ISO C says you have - to pass a `char *' to `write' - -externs.h - - fix extern declarations of zread, zread1, zreadc, and zwrite - - prototype extern declaration of qsort_string_compare - - add extern declaration for history_delimiting_chars() from parse.y - -input.h - - b_used and b_inputp members ofr struct BSTREAM are now size_t - -builtins/evalstring.c - - the number of chars read with zread in cat_file should be assigned - to a variable of type ssize_t - -input.c - - the number of chars read with zread in b_fill_buffer should be - assigned to a variable of type ssize_t - - `localbuf' is now type char[], since POSIX says you shouldn't pass - unsigned char * to read(2) - - in getc_with_restart(), use a variable of type unsigned char to - get a value from the local buffer and return it - - in ungetc_with_restart, explicitly return the character arg passed - to avoid relying on localbuf being unsigned char - -subst.c - - the number of chars read with zread in read_comsub should be - assigned to a variable of type ssize_t - -mksyntax.c - - instead of casting to unsigned char * in addcstr, use a variable - of type unsigned char and let the compiler do the work - -parse.y - - instead of casting to unsigned char * in yy_readline_get, use a - variable of type unsigned char and let the compiler do the work - - ditto for yy_string_get and shell_getc (cast to unsigned char) - -subst.c - - instead of casting to unsigned char when assigning to ifscmap in - expand_word_internal, use a variable of type unsigned char and - let the compiler do the work - -lib/sh/strtrans.c - - instead of casting to unsigned char in ansic_quote, use a variable - of type unsigned char and let the compiler do the work - -builtins/evalstring.c - - remove extern declarations for zwrite and run_trap_cleanup; they're - in externs.h - - prototype cat_file forward declaration - -Makefile.in - - remove -I$(includedir) from INCLUDES and SUBDIR_INCLUDES - -aclocal.m4 - - change RL_LIB_READLINE_VERSION to set RL_PREFIX, RL_LIBDIR, - and RL_INCLUDEDIR to what it used to test the installed readline - library version for use by the caller - - change RL_LIB_READLINE_VERSION to not compute ac_cv_rl_prefix if - the caller has already assigned it a value - - rename _rl_prefix -> ac_cv_rl_prefix, _rl_libdir -> ac_cv_rl_libdir, - _rl_includedir -> ac_cv_rl_includedir - -configure.in - - change testing of whether to use the value of - $opt_with_installed_readline to be != no, to allow the user to - specify a prefix where the installed readline library may be found - - if --with-installed-readline=PREFIX is supplied, set ac_cv_rl_prefix - to PREFIX before calling RL_LIB_READLINE_VERSION - - if --with-installed-readline[=PREFIX] is supplied, don't set - RL_LIBDIR and RL_INCLUDEDIR; let RL_LIB_READLINE_VERSION take care - of it, set RL_INCLUDE=-I${RL_INCLUDEDIR} - - if --with-installed-readline[=PREFIX] is supplied, and we're - linking with the history library, assign $RL_LIBDIR to HIST_LIBDIR - so we use the same version of the installed readline and history - libraries - -Makefile.in, builtins/Makefile.in - - have configure substitute RL_INCLUDEDIR, set RL_INCLUDEDIR variable - -doc/bashref.texi - - updated description of --with-installed-readline configure option - -general.c - - moved QSFUNC typedef here from builtins/common.c - -{alias,bashline,variables,lib/sh/stringvec}.c - - cast fourth argument to qsort to (QSFUNC *) - -alias.c - - prototype forward declaration of qsort_alias_compare - -bashhist.c - - include for extern declaration of glob_pattern_p - - remove extern declaration of history_delimiting_chars; it's now - in externs.h - - prototype forward declarations of histignore_item_func, - maybe_add_history, and bash_add_history - -bracecomp.c - - remove extern declaration for sh_backslash_quote; it's in externs.h - -braces.c - - remove extern declaration for extract_command_subst; it's in subst.h - - prototype forward declarations for expand_amble, array_concat, and - brace_gobbler - -error.c - - prototype extern declaration of give_terminal_to, fix bad call - -{execute_cmd,expr,findcmd,jobs,mailcheck,nojobs,pcomplete,print_cmd,redir, -shell}.c - - prototype all static forward function declarations - -pcomplete.c - - changed some function parameters to `const char *' to avoid discarding - const qualifier - -make_cmd.c - - make_bare_word, make_word_flags, and make_word now take a - `const char *' string argument - -make_cmd.h - - changed extern declarations for make_bare_word and make_word - -print_cmd.c - - cprintf now takes a `const char *' as its first argument, like - xprintf and printf - - the conditional define for xprintf should have been HAVE_VPRINTF, - not HAVE_VFPRINTF - -shell.c - - in isnetconn(), the return value of sizeof() is size_t - -aclocal.m4 - - add inclusion of stddef.h if STDC_HEADERS is defined to 1 in - BASH_CHECK_TYPE - -configure.in - - add a call to BASH_CHECK_TYPE for socklen_t (type of third argument - to getpeername(2)) - - 5/11 - ---- -lib/readline/bind.c - - make `useq' a char array to pass to rl_macro_bind in - rl_parse_and_bind - -lib/readline/{{bind,isearch}.c,rlprivate.h} - - _rl_isearch_terminators is now a char *, not unsigned char * - -{subst,variables,lib/sh/tmpfile}.c - - dollar_dollar_pid is now a `pid_t' instead of `int' - -variables.c - - sbrand() now takes an `unsigned long' to set the seed value - - changed last_random_value to type int, since it's always between - 0 and 32767 - - use strtoul to convert the value in assign_random instead of atoi - - take out casts in any arguments to sbrand() - - take out cast to int in call to inttostr in set_ppid() - -subst.c - - don't cast last_asynchronous_pid when passing to itos() - -{sig,subst}.c - - prototype all static forward function declarations - - 5/14 - ---- -{test,trap,variables}.c - - prototype all static forward function declarations - -variables.c - - free_variable_hash_data() now takes a PTR_T, a `generic pointer' - -builtins/{alias,bind,break,cd,complete,declare,enable,exit,fc,fg_bg,help, -history,jobs,pushd,read,set,trap,umask, - - prototype all static forward function declarations - -builtins/read.def - - reset_eol_delim now takes a `char *' arg, since that's what the - unwind_protect functions pass it, and it ignores its arguments - anyway - -lib/readline/{histsearch,input,kill,rltty,search,vi_mode}.c - - prototype all static forward function declarations - -lib/tilde/tilde.c - - prototype all static forward function declarations - - tilde_find_prefix, tilde_find_suffix, isolate_tilde_prefix, and - glue_prefix_and_suffix now take `const char *' arguments where - appropriate - -configure.in,config.h.in - - check for vsnprintf, define HAVE_VSNPRINTF if found - -lib/readline/display.c - - use vsnprintf() in rl_message if it's available; if we don't, at - least set the last character in msg_buf to 0 to avoid overrun -- - we really can't do anything about overflow at this point. if it's - available, this fixes buffer overflow problems in rl_message - - 5/15 - ---- -lib/readline/histexpand.c - - in get_history_word_specifier, allow any character to terminate - a `:first-' modifier, not just `:' and null. This is what csh - appears to do. This allows things like `!:0- xyzzy' to replace the - last argument with xyzzy - - 5/18 - ---- -configure.in, config.h.in - - check for , define HAVE_STDINT_H if found - - check for intmax_t in , define intmax_t as long if not - found - - 5/21 - ---- -builtins/kill.def - - change to use strerror() for error message when kill(2) fails - -aclocal.m4 - - new macro, BASH_C_LONG_LONG, check for `long long' - -configure.in, config.h.in - - call BASH_C_LONG_LONG, define HAVE_LONG_LONG if found - -lib/sh/snprintf.c - - new file, with implementations of snprintf, vsnprintf, asprintf, - and vasprintf, derived from inetutils version - -Makefile.in, lib/sh/Makefile.in - - add snprintf.c/snprintf.o - -configure.in, config.h.in - - add checks for snprintf, asprintf, vasprintf, with appropriate - cpp defines - -lib/readline/{rldefs,xmalloc}.h, lib/readline/xmalloc.c - - xmalloc and xrealloc now take `size_t' arguments, like their bash - counterparts - -externs.h,lib/sh/itos.c - - inttostr and itos now take `long' arguments - - inttostr takes a `size_t' argument for the buffer size - -{expr,lib/malloc/malloc,variables,general}.c - - fixed calls to itos() by removing casts, etc. - -subst.[ch] - - get_dollar_var_value now takes a long, not an int - - sub_append_number now takes a long, not an int - -subst.c - - in parameter_brace_expand_word, use a long and legal_number to - translate ${N}, to avoid overflow - - in parameter_brace_expand_length, use a long and legal_number to - translate ${#N}, to avoid overflow - - in do_array_element_assignment, array_expand_index, - array_value_internal, use arrayind_t instead of int - - let verify_substring_values take long * arguments for the return - value of evalexp() - - pass long * arguments to verify_substring_values in - parameter_brace_substring - - parameter_brace_expand_length now returns `long' - - parameter_brace_expand now uses a long variable for the return - value of parameter_brace_expand_length - - param_expand now uses a long variable for the return value from - evalexp - - array_length reference now returns an `arrayind_t', since it can - return the num_elements member of an array, which is of type - arrayind_t - -subst.h - - array_expand_index now returns an `arrayind_t' - -array.[ch] - - array_subrange now takes arrayind_t arguments, not `int' - - dup_array_subrange now uses arrayind_t local variable to do - array indexing - - use long to print array indices in print_element - -variables.c - - null_array_assign, assign_dirstack, bind_array_variable - now take arrayind_t arguments as array indices - - assign_array_var_from_word_list, assign_array_var_from_string, - unbind_array_element now use arrayind_t local variables for - array indexing - -variables.h - - change extern declaration of bind_array_variable - -builtins/common.[ch] - - get_numeric_arg now returns a `long', since it usually returns - the value of legal_number() - -builtins/{shift,break}.def - - use long variables for the return value of get_numeric_arg - -builtins/history.def - - convert string argument to int only if it's in range - -builtins/pushd.def - - set_dirstack_element and get_dirstack_element now take `long' - index arguments - - get_dirstack_index now takes a `long' index argument, since it's - passed the converted value from legal_number - -lib/sh/timeval.c - - in print_timeval, don't assume that the number of minutes fits into - an int, since it's just seconds/60. - -lib/sh/clock.c - - ditto for print_clock_t - - 5/22 - ---- -shell.c - - since the -O option settings may possibly be overridden by the - normal shell initialization or posix initialization, save the - invocation options on an alist (with add_shopt_to_alist) and - process them after basic initialization (with run_shopt_alist) - - 5/23 - ---- -trap.h - - new define, BASH_NSIG, all system signals plus special bash traps - -trap.c, builtins/trap.def - - use BASH_NSIG for array bounds and loops where appropriate - -trap.c - - change decode_signal to disallow numeric signal numbers above - NSIG -- this means you can only reference special traps like - DEBUG by name - - new SPECIAL_TRAP(s) macro to test whether s is one of the special - bash traps (currently DEBUG and EXIT) - - change reset_or_restore_signal_handlers so command substitution - doesn't inherit the debug trap (like ksh93), and child processes - don't have to rely on initialize_traps being run to get rid of - any debug trap - -support/mksignames.c - - add extra "ERR" signal name, value NSIG+1, allocate space for it - and write it out in signal_names[] - -trap.h - - new define: ERROR_TRAP == NSIG+1, change BASH_NSIG to NSIG+2 - - extern declarations for set_error_trap, run_error_trap - - new define: TRAP_STRING(s), expands to trap_list[s] if signal S - is trapped and not ignored, NULL otherwise - -trap.c - - add ERROR_TRAP to SPECIAL_TRAPS define - - initialize ERROR_TRAP stuff in initialize_traps - - new function: set_error_trap(command), sets the ERR trap string - - new function: run_error_trap(command), runs the ERR trap string - - set trap string for ERROR_TRAP to NULL in free_trap_strings - - change reset_or_restore_signal_handlers so child processes don't - inherit the ERR trap - - add case to call run_error_trap in maybe_call_trap_handler - -execute_cmd.c - - in execute_command_internal, keep track of ERR trap and call it if - necessary - - use TRAP_STRING to get the value of debug and error traps - - in execute_function, arrange things so the ERR trap is not inherited - by shell functions, and is saved and restored like the DEBUG trap - -doc/{bash.1,bashref.texi} - - documented new ERR trap - -tests/{trap.{tests,right},trap2.sub,trap2a.sub} - - added ERR trap tests - -subst.c - - on machines without /dev/fd, change the named pipe fifo list to a - list of structs containing pathname and proc information - - change unlink_fifo_list to kill the proc in the fifo list with - signal 0 and not remove the fifo if the proc is still alive. This - should fix the problem on those backward systems without /dev/fd - where fifos were removed when a job using process substitution was - suspended - - 5/24 - ---- -examples/loadables/getconf.h - - new file, with basic defines needed to make getconf work minimally - on POSIX systems without the necessary definitions - -examples/loadables/getconf.c - - replacement functions for confstr, sysconf, pathconf for systems - that lack them, providing a minimal posix interface - - heavily augmented getconf, now supports all POSIX.1-200x, - POSIX.2-200x, Solaris 7, AIX 4.2 getconf variables - - 5/29 - ---- -builtins/setattr.def - - make `readonly', `export', and `declare' print `invisible' variables - as just a command and variable name, without a value, when listing - all variables (as POSIX.2-200x d6 requires) - - 5/30 - ---- - -configure.in - - upgraded to autoconf-2.50 on main development machine, so require - autoconf-2.50 in preparation for using some if its new features - - call AC_C_PROTOTYPES - - remove call to AC_EXEEXT, which now does the wrong thing - - changed AC_INIT to new flavor - - added call to AC_CONFIG_SRCDIR - - AC_CONFIG_HEADER -> AC_CONFIG_HEADERS - - AC_RETSIGTYPE -> AC_TYPE_SIGNAL - -configure.in, aclocal.m4, config.h.in - - removed call to BASH_LARGE_FILE_SUPPORT, use AC_SYS_LARGEFILE - standard support, with new macros _FILE_OFFSET_BITS and - _LARGE_FILES - - removed definition of BASH_LARGE_FILE_SUPPORT - -doc/bashref.texi - - document new `--enable-largefile' configure option - -lib/readline/readline.c - - change rl_set_prompt to call rl_expand_prompt unconditionally, so - local_prompt and local_prompt_prefix get set correctly - - 6/6 - --- -lib/readline/complete.c - - don't append `/' or ` ' to a match when completing a symlink that - resolves to a directory, unless the match doesn't add anything - to the word. This means that a tab will complete the word up to - the full name, but not add anything, and a subsequent tab will add - a slash. Change to append_to_match; callers changed - -hashlib.c - - new function, hash_table_nentries (table), returns the number of - items in TABLE - -hashlib.h - - extern declaration for hash_table_nentries - -configure.in - - configure without bash malloc on openbsd; they claim it needs - eight-bit alignment (which the bash malloc provides, but...) - - 7/2 - --- -stringlib.c - - only call RESIZE_MALLOCED_BUFFER from strsub() if the replacement - string length is > 0, avoid possible hangs if replacement is null - -subst.c - - don't include input.h; no longer needed - -configure.in - - remove calls to AC_SYS_RESTARTABLE_SYSCALLS and - BASH_SYS_RESTARTABLE_SYSCALLS; the results are no longer used - -config.h.in - - remove define for HAVE_RESTARTABLE_SYSCALLS - -aclocal.m4 - - removed definition of BASH_SYS_RESTARTABLE_SYSCALLS; no longer used - -execute_cmd.c - - changed select command so `return' no longer terminates the select - command, so it can be used to return from an enclosing function. - This is as ksh (88 and 93) does it - -lib/readline/vi_mode.c - - fix trivial typo in declaration of vi_motion; `t' appears twice; - the second instance should be `T' - - 7/3 - --- -configure.in - - don't add -static to LDFLAGS on Solaris 2.x. This means that the - auxiliary programs will be built as dynamic executables, but that - should do no harm - - 7/5 - --- -lib/glob/fnmatch.c - - fix the code that processes **(pattern) to short-circuit if the - pattern is ill-formed or lacks a trailing `)' -- this fixes the - segfault on **(/*) - -Makefile.in, builtins/Makefile.in - - split CCFLAGS into CCFLAGS_FOR_BUILD and CFLAGS, to aid in - cross-compilation - - build programs that use $(CC_FOR_BUILD) using $(CCFLAGS_FOR_BUILD) - -configure.in, config.h.in - - check for getaddrinfo(3), define HAVE_GETADDRINFO if found - -lib/sh/netopen.c - - implemented a version of _netopen (_netopen6) that uses - getaddrinfo(3) if available, use if HAVE_GETADDRINFO is defined. - old _netopen is _netopen4; _netopen now calls either _netopen6 - or _netopen4 as appropriate - - 7/9 - --- -builtins/exit.def - - don't source ~/.bash_logout if subshell_environment is non-zero - -execute_command.c - - in execute_until_or_while, handle the case where `breaking' is - set in the loop test (e.g., by the job control code when a job - is stopped with SIGTSTP), but the return value from the test is - something that would cause the loop to break. Need to decrement - `breaking' in this case - - 7/10 - ---- -execute_cmd.c - - in execute_in_subshell, make sure a command of type cm_subshell - inherits its `enclosing' command's CMD_IGNORE_RETURN flag - -variables.c - - in maybe_make_export_env, don't allow restricted shells to put - exported functions in the export environment - - 7/11 - ---- -lib/glob/strmatch.h - - renamed old fnmatch.h - - changed guard #ifdef to _STRMATCH_H - - include system if HAVE_LIBC_FNM_EXTMATCH is defined - -lib/glob/strmatch.c - - renamed old fnmatch.c - - include "strmatch.h" - - if HAVE_LIBC_FNM_EXTMATCH is defined, define a dummy version of - strmatch() that just calls fnmatch(3) - -lib/glob/glob.c - - include "strmatch.h" - - fnmatch -> strmatch - -Makefile.in, lib/glob/Makefile.in - - fnmatch -> strmatch - -{bashhist,execute_cmd,pathexp,pcomplete,shell,stringlib,subst,test}.c, -pathexp.h,builtins/help.def - - include - - fnmatch -> strmatch - -execute_cmd.c - - broke the code that parses the interpreter name from a #! line - out from execute_shell_script to a new function, getinterp() - - call getinterp from execute_shell_script - - use return value from getinterp in error message about bad - #! interpreter in shell_execve - - 7/12 - ---- -lib/readline/isearch.c - - the last isearch string is now remembered in a new static variable, - last_isearch_string - - if ^R^R is typed, readline now searches for the remembered isearch - string, if one exists - - 7/24 - ---- -pcomplete.h - - extern declaration for completions_to_stringlist() - - 7/25 - ---- -builtins/complete.def - - make compgen handle -o default option - - make compgen return success only if sl->list_len is non-zero, - indicating that there are items on the list - - 7/31 - ---- -execute_cmd.c - - in execute_connection, force stdin to /dev/null for asynchronous - commands if job control is not active, not just if the shell is - running a shell script (since you can run `set -m' in a script) - -lib/readline/rltty.c - - make sure _rl_tty_restore_signals resets `tty_sigs_disabled' on - successful restoration of the terminal modes - - make sure _rl_tty_disable_signals turns off IXON so that ^S and - ^Q can be read by rl_quoted_insert - - 8/1 - --- -aclocal.m4 - - new check for FNM_EXTMATCH being defined in , as Ullrich - Drepper intends to do for new versions of GNU libc - -config.h.in - - new definition for HAVE_LIBC_FNM_EXTMATCH - -configure.in - - check for fnmatch, but don't define anything in config.h - - call BASH_FUNC_FNMATCH_EXTMATCH to check for FNM_EXTMATCH - - 8/2 - --- -alias.h - - remove bogus extern declaration for xmalloc() - - include "stdc.h" - - add prototype declarations for all extern function declarations - -xmalloc.c,lib/readline/xmalloc.c - - fix xmalloc to return a PTR_T - - fix xrealloc to return a PTR_T and take a PTR_T as first argument - -include/ansi_stdlib.h - - extern declarations for malloc and realloc have them return PTR_T - -xmalloc.h - - new file, with extern declarations for functions in xmalloc.c - -general.h - - removed extern declarations for functions in xmalloc.c - - include xmalloc.h - -Makefile.in,builtins/Makefile.in - - update dependencies to include xmalloc.h - -parse.y,{alias,array,bashline,bracecomp,execute_cmd,findcmd,flags,general, -hashcmd,locale,mailcheck,make_cmd,pathexp,pcomplete,print_cmd,stringlib, -subst,unwind_prot,variables}.c -builtins/{common,evalfile}.c -builtins/{cd,command,enable,exec,printf,read,set}.def -lib/sh/{makepath,netopen,pathphys,setlinebuf,shquote,snprintf,stringlist, -strtrans,tmpfile}.c -lib/readline/{util,terminal,shell,readline,macro,kill,isearch,input, -histfile,histexpand,display,complete,bind}.c - - make sure all calls to xmalloc are cast to the right return value - -siglist.c - - include xmalloc.h - -parse.y,{alias,bashline,bracecomp,expr,make_cmd,nojobs,print_cmd,subst}.c -builtins/{fc,printf,read}.def -lib/sh/snprintf.c, lib/tilde/tilde.c -lib/readline/{bind,display,histexpand,isearch,macro,util,vi_mode}.c - - make sure all calls to xrealloc are cast to the right return value - -lib/sh/{netopen,setlinebuf,shquote,snprintf}.c, lib/tilde/tilde.c - - include xmalloc.h, remove extern declaration of xmalloc - -lib/readline/xmalloc.h - - xmalloc and xrealloc should return PTR_T - -lib/readline/rldefs.h - - don't include an extern declaration for xmalloc - - 8/7 - --- -support/shobj-conf - - fixed up commented-out stanzas for HP's unbundled C compiler on - HP/UX - -support/bashbug.sh - - force the subject to be changed from the default - -lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 - - document that transpose-words swaps the last two words on the line - if point is at the end of the line - - 8/9 - --- -stringlib.c - - fix possible infinite recursion problem with null pattern in - strsub() - -hashlib.c - - new function copy_hash_table to copy a hash table using a caller- - supplied function to copy item data (defaults to savestring()) - -hashlib.h - - new extern declaration for copy_hash_table - -builtins/declare.def - - changes so that declare [-a] var=value assigns `value' to element 0 - of array variable `var' like ksh93 - - change so that declare [-a] var[N]=value assigns `value' to element - N of array variable `var' like ksh93 - - 8/13 - ---- -arrayfunc.c - - new file, for miscellaneous array functions - -arrayfunc.h - - new file, extern declarations for functions in arrayfunc.c - -variables.c - - move convert_var_to_array, bind_array_variable, - assign_array_from_string, assign_array_var_from_word_list, - assign_array_var_from_string, quote_array_assignment_chars, - skipsubscript, unbind_array_element, print_array_assignment - to arrayfunc.c - -shell.h - - include arrayfunc.h after variables.h - -variables.h - - remove above extern function declarations moved to arrayfunc.h - - add extern declaration for var_lookup - -Makefile.in - - add arrayfunc.c, arrayfunc.h in appropriate places - - add arrayfunc.h to dependencies - -subst.c - - move valid_array_reference, array_expand_index, array_variable_part, - array_value_internal, array_value (now global), get_array_value, - do_array_element_assignment to arrayfunc.c - -subst.h - - extern declarations for functions above moved to arrayfunc.h - -arrayfunc.h - - extern declarations for above functions from subst.c - -subst.[ch] - - string_list_dollar_star and string_list_dollar_at are now global - functions - - quote_escapes is now a global function - -subst.c - - maybe_expand_string -> expand_string_if_necessary - - expand_string_to_string -> expand_string_to_string_internal - - new functions: expand_string_to_string and - expand_string_unsplit_to_string, which call - expand_string_to_string_internal with expand_string and - expand_string_unsplit as the FUNC arguments, respectively - -arrayfunc.c - - change array_expand_index to call expand_string_to_string instead - of maybe_expand_string - - 8/14 - ---- -shell.c - - in execute_env_file, call expand_string_unsplit_to_string - -mailcheck.c - - in check_mail, call expand_string_to_string - -variables.c - - in assign_in_env, call expand_string_unsplit_to_string - -arrayfunc.c - - new function, array_variable_name, splits an array reference into - a name (which is returned as a new string) and subscript - - change array_variable_part to just call array_variable_name and - look up the string returned with find_variable - - new function, find_or_make_array_variable (name, flags) which will - look up an array variable and convert a string variable to an - array if necessary. The FLAGS argument, if non-zero, says to - check the readonly and noassign attributes and fail if either is set - -builtins/read.def - - make `read -a aname' honor any readonly status of `aname' - - read -a now calls find_or_make_array_variable with FLAGS value 1 - -arrayfunc.[ch], subst.c, builtins/{declare,read}.def - - do_array_element_assignment -> assign_array_element - - 8/20 - ---- -parse.y - - changed `for' command grammar to allow missing word list after `IN' - token, like latest POSIX drafts require - -lib/sh/tmpfile.c - - in sh_mktmpname(), check for filenum == 0 and init to non-zero number - in this case. it can happen on arithmetic overflow - -support/mkversion.sh - - added `[0-9].[0-9][0-9][a-z]' as an acceptable value for a - distribution to allow for intermediate versions, like 2.05a - -support/config.guess - - removed the addition of the output of `/usr/bin/objformat' when - creating the canonical name on FreeBSD machines, so the canonical - name is once again `freebsd4.2' instead of `freebsdelf4.2' - - 8/22 - ---- -lib/readline/{rlstdc,history,keymaps,readline,rldefs,rlprivate,rlshell, -rltypedefs,xmalloc}.h -lib/readline/{bind,compat,complete,display,funmap,histexpand,histsearch, -input,isearch,kill,nls,parens,readline,rltty,search,shell,signals,vi_mode - - changed __P to PARAMS - -lib/tilde/tilde.[ch] - - changed __P to PARAMS - -{Makefile,configure}.in - - changed the version number to 2.05a - - changed the release status to `alpha1' - - 8/23 - ---- -support/shobj-conf - - support for building shared libraries on Darwin/MacOS X - -siglist.h - - extern declaration for strsignal() to compensate for lack of - a definition in some system include files - -jobs.c - - remove casts from strsignal() calls - -[bash-2.05a-alpha1 frozen] - - 8/27 - ---- -[bash-2.05a-alpha1 released] - - 8/27 - ---- -execute_cmd.c - - fix eval_arith_for_expr to handle the case where the expanded - word list is NULL, returning 0 in this case - -print_cmd.c - - in print_function_def, make sure that func_redirects is assigned - a value before being used - - 8/28 - ---- -alias.c - - include for definition of isalpha() - -bashhist.h - - add prototypes for extern function declarations - -flags.c - - include bashhist.h for extern function declarations - -mksyntax.c - - include if HAVE_UNISTD_H is defined in config.h - -parse.y - - include test.h for extern function declarations - -externs.h - - change extern declaration for setlinebuf to sh_setlinebuf - -stringlib.c - - include for extern function declarations - -variables.h - - add function prototypes for all of the sv_* functions - -builtins/common.h - - add extern declarations for set_shellopts() and parse_shellopts() - from builtins/set.def - -variables.c - - include "hashcmd.h" for extern declaration for flush_hashed_filenames - - include "pathexp.h" for extern declaration for setup_glob_ignore - -lib/malloc/malloc.c - - cast to `long' instead of `int' in memalign for 64-bit machines - -{pcomplete,trap}.c - - changed printf escape sequences used to print pointers to %p - -lib/readline/undo.c - - include "xmalloc.h" for extern function declaration - -input.h - - add function prototypes to extern declarations for getc_with_restart - and ungetc_with_restart - -variables.[ch] - - changed type of `function' member of `struct name_and_function' to - `sv_func_t', which is defined and prototyped in variables.h - - map_over now takes an `sh_var_map_func_t *' - -shell.h - - start of a set of function pointer typedefs like those in - lib/readline/rltypedefs.h - -hashlib.[ch] - - second paramter to flush_hash_table is now an `sh_free_func_t *' - -trap.c - - parameter to reset_or_restore_signal_handlers is now an - `sh_resetsig_func_t *' - -pcomplete.h, pcomplib.c - - function pointer argument to print_all_compspecs is now an - `sh_csprint_func_t *' - - function pointer `list_getter' element of an `ITEMLIST' is now - prototyped with __P((...)) instead of using `Function *' - -jobs.[ch] - - `j_cleanup' member of a JOB is now an `sh_vptrfunc_t *' - -alias.c - - map_over_aliases now takes an `sh_alias_map_func_t *' - - free_alias_data now takes a `PTR_T' - -pathexp.c - - function pointer argument to ignore_globbed_names is now an - `sh_ignore_func_t *' - -bashline.c - - function pointer argument to _ignore_completion_names is now an - `sh_ignore_func_t *' - -pathexp.h,{bashhist,bashline.c - - `item_func' member of a `struct ignorevar' is now an - `sh_iv_item_func_t *' - -builtins/evalfile.c - - `errfunc' is now an `sh_vmsg_func_t *' - -jobs.c - - map_over_job now takes an `sh_job_map_func_t *' as its first argument - -array.[ch] - - function pointer argument to array_walk is now an - `sh_ae_map_func_t *' - -general.c - - tilde_expansion_preexpansion_hook has type `tilde_hook_func_t *', - and so the assignment in tilde_initialize doesn't need a cast - -list.c - - map_over_words now takes an `sh_icpfunc_t *' as its second argument - -input.h - - the `getter' and `ungetter' function pointer members of a - BASH_INPUT are now of types `sh_cget_func_t *' and - `sh_cunget_func_t *' respectively - - init_yy_io now takes an `sh_cget_func_t *' as its first argument and - an `sh_cunget_func_t *' as its second - -parse.y - - init_yy_io now takes an `sh_cget_func_t *' as its first argument and - an `sh_cunget_func_t *' as its second - - initialize_bash_input casts bash_input.getter and bash_input.ungetter - appropriately - -builtins/mkbuiltins.c - - make the extern function definitions written to builtext.h have - prototypes with __P((...)) - - include "stdc.h" - - change Function to mk_handler_func_t - - fixed comment_handler to take the right number of args - - prototyped all the handler functions with __P((...)) - -builtins.h - - the `function' member of a struct builtin is now of type - `sh_builtin_func_t *' - -builtins/common.[ch] - - last_shell_builtin, this_shell_builtin are now of type - `sh_builtin_func_t *' - - find_shell_builtin, builtin_address, find_special_builtin now return - `sh_builtin_func_t *' - -builtins/exit.def, {execute_cmd,jobs,nojobs,variables}.c, parse.y - - changed all declarations of last_shell_builtin and this_shell_builtin - -execute_cmd.c - - execute_builtin, execute_builtin_or_function, - execute_subshell_builtin_or_function now take an - `sh_builtin_func_t *' instead of a `Function *' for argument - - changed appropriate variables from `Function *' to - `sh_builtin_func_t *' - -builtins/{bind,builtin,enable,read,setattr}.def - - replaced uses of `Function *' in variable declarations with - appropriate types (sh_builtin_func_t * or rl_command_func_t *) - -builtins/set.def - - set_func and get_func members of binary_o_options are now of types - `setopt_set_func_t *' and `setopt_get_func_t *', which are - prototyped - -builtins/shopt.def - - set_func member of shopt_vars is now of type `shopt_set_func_t *' - -bashline.c - - enable_hostname_completion now returns `int' (the old value of - perform_hostname_completion) - -[The only use of Function and VFunction now is for unwind-protects] - - 9/4 - --- -lib/sh/getcwd.c - - use const define from config.h rather than `CONST' - - use PTR_T define from xmalloc.h rather than `PTR' - - include xmalloc.h for PTR_T - - remove PATH_MAX define, rely on value from maxpath.h - -{general,mailcheck}.c, lib/sh/{pathcanon,pathphys}.c - - don't include maxpath.h directly; it's already included by shell.h - -lib/sh/mailstat.c - - new `mailstat()' implementation, to stat a mailbox file for - mail checking. handles maildir-style mail directories with one - file per message and creates a dummy stat struct from them - -lib/sh/Makefile.in - - add mailstat.c and mailstat.o in the appropriate places - -lib/malloc/malloc.c - - augmented implementation with wrapper functions that pass in file - and line number information from cpp. currently unused, but a - placeholder for future debugging and use tracking - -lib/malloc/shmalloc.h - - new file, extern declarations for allocation wrapper functions for - use by the shell (and others, I guess) - -xmalloc.[ch] - - wrapper functions for xmalloc, xfree, xrealloc (sh_ prefixed) that - pass cpp line number information through to the malloc functions, - if USING_BASH_MALLOC is defined - - 9/5 - --- -lib/malloc/gmalloc.c - - removed; no longer part of distribution - -lib/malloc/Makefile.in - - removed references to gmalloc.[co] - -configure.in, doc/bashref.texi - - removed references to `--with-glibc-malloc' configure option - -{configure,Makefile}.in - - changed the way bash malloc is configured into the Makefile, making - it more like how readline is configured. If the bash malloc is - not configured in, nothing in lib/malloc will be built - - 9/6 - --- -lib/malloc/imalloc.h - - new file, some internal malloc definitions - -lib/malloc/mstats.h - - new file, definitions for malloc statistics structs and functions - -lib/malloc/trace.c - - new file, malloc tracing functions (currently just print messages - to stderr), code is #ifdef MALLOC_TRACE - -lib/malloc/stats.c - - new file, moved malloc stats code from malloc.c to here - -lib/malloc/malloc.c - - moved some definitions to imalloc.h - - moved stats code to stats.c - - malloc tracing calls added to internal_{malloc,realloc,free}, all - #ifdef MALLOC_TRACE - -lib/malloc/Makefile.in, Makefile.in - - added {imalloc,mstats}.h, {trace,stats}.c - -parse.y - - changed decode_prompt_string to save and restore $? - (last_command_exit_value) around calls to expand_prompt_string(), - so command substitutions in PS1, etc. don't change $? - -{array,subst}.c - - a couple more arrayind_t fixes from Paul Eggert - -configure.in - - remove redundant check for wait3(2) - -redir.h - - fixed a typo (stdin_redirs -> stdin_redirects) - - 9/10 - ---- -execute_cmd.c - - remove check for \n and \r from WHITESPACE macro, since those - chars are not whitespace as returned by the whitespace(c) macro - - getinterp now takes a `char *' as first arg, not unsigned char * - - execute_shell_script now takes a `char *' as first arg, not - unsigned char * - - fix typo in forward declaration for `initialize_subshell' - -general.[ch] - - check_binary_file now takes a (char *) argument, not unsigned char * - - pass unsigned char to isspace and isprint because of ISO C fuckup - - bash_tilde_expand now takes a `const char *' as its argument - -builtins/evalfile.c, shell.c - - buffer passed to check_binary_file is char, not unsigned char - -parse.y - - fix extern declaration for yyerror() - - yyerror now takes a `const char *' as first arg - -{error,jobs}.c - - fixes to printf-style functions to handle pids wider than an int - -lib/readline/{isearch,vi_mode}.c - - fix call to rl_message in rl_display_search (remove extra arg) - -variables.c - - fix missing argument to builtin_error in make_local_variable - -builtins/getopts.def - - since getopts takes no options, change while loop calling - internal_getopts to a simple `if' check - -builtins/printf.def - - since printf takes no options, change while loop calling - internal_getopts to a simple `if' check - -lib/readline/bind.c - - remove _SET_BELL macro, expand code inline - -lib/readline/input.c - - change _rl_input_available to use either select or FIONREAD, - but not both - -lib/readline/readline.c - - fix rl_digit_loop to remove unreachable code at end of loop - -{bashhist,bashline,expr,jobs,redir,shell}.c, builtins/fc.def, lib/sh/snprintf.c - - bracket unused functions with #ifdef INCLUDE_UNUSED/#endif - - remove some unused variables - -execute_cmd.c - - remove #ifdef'd code that allowed `return' to terminate a select - statement - -expr.c - - remove some extraneous tests from strlong() - -array.h - - arrayind_t is now a long, since shell arithmetic is performed as - longs - - remove second declaration of new_array_element - -builtins/printf.def - - in mklong, xrealloc cannot return NULL, so don't check for it - - remove some #if 0 code - - fix core dump triggered by a format specification with more than - one `*' - - remove `foundmod', since its value mirrors `modchar != 0' - - include "common.h" for builtin_{error,usage} declarations - -Makefile.in,builtins/Makefile.in - - updated some dependencies due to new include files - -pcomplete.c - - include "execute_cmd.h" for declaration of execute_shell_function - -arrayfunc.c - - include for printf - - include "builtins/common.h" for builtin_error declaration - -builtins/evalstring.c - - include "../trap.h" for run_trap_cleanup declaration - -builtins/help.def - - include "common.h" instead of locally declaring builtin_error - and builtin_usage - -error.h - - add extern declaration for itrace() - - add prototype to extern declaration of get_name_for_error - - file_error now takes a `const char *' as first argument - -externs.h - - added prototype for sh_setlinebuf declaration, bracketed with - NEED_SH_SETLINEBUF_DECL so we don't need stdio.h everywhere - - add extern declaration for parse.y:return_EOF() - -shell.c - - add NEED_SH_SETLINEBUF_DECL before including shell.h - -lib/readline/callback.c - - include or "ansi_stdlib.h" for abort declaration - -quit.h - - remove declaration of throw_to_top_level - -subst.c - - remove unused extern declaration for getopts_reset - -lib/sh/netopen.c - - include for legal_number, etc. - - add prototype for inet_aton extern declaration - -lib/sh/clock.c - - include for __P declaration - - add extern declaration for get_clk_tck - -support/mkversion.sh - - changed so that extern function declarations for functions in - version.c (moved from externs.h) are in the generated version.h - -shell.h - - include version.h - -version.c - - various `char *' version variables are now `const char *' - -general.h - - add prototype for same_file, bracketed with _POSIXSTAT_H - #ifdef, since that's what include/posixstat.h defines - -builtins/common.[ch] - - _evalfile, maybe_execute_file, source_file, and fc_execute_file - now take a `const char *' as their first argument - -eval.c - - removed extern declaration of yyparse; it's in externs.h - -parse.y - - added prototypes to static forward function declarations - - changed local `all_digits' variable in read_token_word () to - all_digit_token to avoid clash with all_digits() function in - general.c - -{bashhist,copy_cmd,make_cmd,hashlib,mailcheck}.c - - added prototypes for static function declarations - -shell.h - - add extern declarations for interactive, interactive_shell, - changed c files with extern declarations - -pcomplete.c - - changed it_init_aliases to avoid shadowing global variable - `aliases' - -bashline.c,pathexp.c,general.h - - sh_ignore_func_t is now a pointer to a function taking a - `const char *'; users changed - -configure.in - - test for - -config.h.in - - add #undef HAVE_STRINGS_H - -bashansi.h - - change like recommended in autoconf manual - - 9/11 - ---- -[a date which will live in infamy. prayers for the victims.] - -execute_cmd.c - - don't use an absolute index into abuf in mkfmt, use - sizeof(abuf) to compute last index - -builtins/common.c - - fix read_octal to do a better job of detecting overflow while - iterating through the string - -builtins/umask.def - - change octal-print mode to print 4 digits, like other shells - - cast umask to unsigned long to avoid problems on systems where - it's wider than an int (POSIX doesn't guarantee that mode_t is - no wider than an int, but real-world systems use int) - -builtins/printf.def - - mklong can never return NULL (it uses xrealloc), so the mainline - doesn't need to check for NULL returns - - new function, getldouble (long double *), to get long doubles - - mklong now takes a `char *' as its second argument, the modifier(s) - to use - - changed use of `modchar' to handle more than a single modifier - character - - changed to handle `long double' and `L' formats better, rather - than discarding long double information - - since printf now follows the POSIX.2 rules for conversion errors, - we can dispense with the status returns from the get* functions - - make the get* functions as similar in structure as possible, - removing type casts, etc. - -lib/sh/timeval.c,execute_cmd.c - - change some instances of `long' to `time_t', for systems where - a time_t is bigger than a long - -jobs.c - - include "posixtime.h" instead of - -config.h.in - - add defines for HAVE_DECL_CONFSTR, HAVE_DECL_STRTOLD, - HAVE_DECL_SBRK, HAVE_DECL_PRINTF - - remove defines for SBRK_DECLARED and PRINTF_DECLARED - - add _GNU_SOURCE define - -configure.in - - add AC_CHECK_DECLS for strtold, confstr, sbrk, printf - - remove call to BASH_FUNC_SBRK_DECLARED - - remove call to BASH_FUNC_PRINTF - -xmalloc.c, lib/malloc/malloc.c - - change check of SBRK_DECLARED to HAVE_SBRK_DECL - -print_cmd.c - - change PRINTF_DECLARED to HAVE_DECL_PRINTF - -builtins/evalstring.c, builtins/common.h - - parse_and_execute now takes a `const char *' as its second argument - -input.h,parse.y - - with_input_from_* functions now take a `const char *' as their - second argument - - init_yy_io now takes a `const char *' as its fourth argument - -parse.y,externs.h - - parse_string_to_word_list now takes a `const char *' as its second - argument - -tests/builtins.right - - change output to account for extra digit in umask output - -pcomplib.c - - free_progcomp now takes a PTR_T argument - -builtins/bashgetopt.h - - include - - add prototypes to extern declarations - -builtins/shopt.def - - add prototypes to static function declarations - -builtins/{fc,umask,wait}.def, builtins/{bashgetopt,common}.c - - include for isdigit macro (referenced by `digit(x)') - -lib/readline/complete.c - - added more static function declarations with prototypes - - 9/12 - ---- -lib/sh/tmpfile.c - - use `^' instead of `*' in sh_mktmpname to make filenames a bit - more random - -include/stdc.h,lib/readline/rldstdc.h - - add __attribute__ definition - -builtins/common.h - - add printf __attribute__ to declaration of builtin_error - -error.h - - add printf __attribute__ to declaration of programming_error, - report_error, parser_error, fatal_error, sys_error, internal_error, - internal_warning - -lib/readline/readline.h - - add printf __attribute__ to declaration of rl_message - -pcomplete.c - - add printf __attribute__ to declaration of debug_printf - -print_cmd.c - - add printf __attribute__ to declarations of cprintf, xprintf - -include/chartypes.h - - new file, includes and defines macros that check for - safe (ascii) arguments before calling the regular ctype macros - -{alias,bashline,execute_cmd,expr,findcmd,general,locale,mksyntax,stringlib,subst,variables}.c -parse.y -builtins/{bashgetopt,common}.c -builtins/{fc,printf,umask,wait}.def -lib/glob/strmatch.c -lib/sh/{oslib,pathcanon,pathphys,snprintf,strcasecmp,strindex,stringvec,strtod,strtol,strtrans}.c -examples/loadables/{head,sleep}.c - - include "chartypes.h" or instead of - -Makefile.in,{builtins,lib/{glob,sh}}/Makefile.in - - update dependencies to include chartypes.h - -lib/sh/inet_aton.c - - use `unsigned char' instead of `char' to pass to ctype.h functions - -lib/sh/netopen.c - - check for '0' <= host[0] <= '9' in _getaddr instead of using - isdigit - -subst.c,lib/sh/shquote.c - - change array subscripts into sh_syntaxtab from `char' to - `unsigned char' - -{alias,bashline,execute_cmd,expr,general,subst}.c, parse.y -builtins/{fc,printf,umask,wait}.def builtins/{bashgetopt,common}.c -lib/sh/{pathcanon,pathphys,snprintf,strcasecmp,strindex,strtod,strtol,strtrans}.c -examples/loadables/{head,sleep}.c - - change to use some of the new macros in chartypes.h - - remove old local macro definitions now provided by chartypes.h - -general.h - - remove definition of isletter, ISOCTAL, digit, digit_value - - change legal_variable_starter and legal_variable_char to use - chartypes.h macros - - change ABSPATH to use chartypes.h macros - -lib/readline/util.c - - change to use Paul Eggert's FUNCTION_FOR_MACRO define to define - function replacements for macros in chardefs.h - -lib/readline/chardefs.h - - added some of the same macros as in chartypes.h - - change _rl_lowercase_p, _rl_uppercase_p, _rl_digit_p, - _rl_to_upper, _rl_to_lower to use new IS* macros - - added _rl_isident macro from vi_mode.c:isident - -lib/readline/{bind,complete,nls}.c - - change to use some of the new macros from chardefs.h - -lib/readline/vi_mode.c - - isident -> _rl_isident - - remove local defines of macros in chardefs.h - -lib/sh/strtol.c - - updated to new version, modified from glibc 2.2.4 and sh-utils-2.0. - This one can do strtoll and strtoull, if necessary - - 9/13 - ---- -builtins/ulimit.def - - changed get_limit so it retrieves both hard and soft limits - instead of one or the other - - changed callers of get_limit - - changed getmaxvm to take soft limit, hard limit as arguments - - changed getmaxuprc to just take a single argument, the value - - changed calls to printone() to pass soft limit or hard limit - depending on `mode' instead of using old current_limit variable - - moved check for out-of-range limits in ulimit_internal into the - block that converts a string argument to a value of type rlim_t - - changed RESOURCE_LIMITS struct to break the description into a - description string and separate scale factor string - - changed print_all_limits to print a single error message if - get_limit fails, including limits[i].description now that the - scale factor has been removed from the description string - - removed DESCFMT define, since it's now used only in printone() - - changed printone to print the option character associated with a - particular limit if we're printing multiple limits - - changed calls to builtin_error to print the description associated - with a limit if setting or getting the limit fails - - added support for new POSIX 1003.1-200x rlim_t values: - RLIM_SAVED_CUR and RLIM_SAVED_MAX, which expand to the current - soft and hard limits, whatever they are - - changed printone to print `hard' or `soft' if the current limit is - RLIM_SAVED_MAX or RLIM_SAVED_CUR, respectively - - changed ulimit_internal to handle new `hard' and `soft' arguments - - changed help text do describe the special limit arguments `hard', - `soft', and `unlimited' - -doc/{bash.1,bashref.texi} - - documented new `hard' and `soft' limit arguments to `ulimit' - -hashlib.[ch] - - find_hash_item now takes a `const char *' is its first argument - - hash_string now takes a `const char *' is its first argument - - remove_hash_item now takes a `const char *' as its first argument - -pcomplib.c - - removed cast from first argument to find_hash_item in find_compspec - -general.[ch] - - absolute_program now takes a `const char *' as its argument - - absolute_pathname now takes a `const char *' as its argument - -lib/glob/glob.[ch] - - glob_pattern_p now takes a `const char *' as its argument - -bashline.c - - removed cast from first argument to absolute_program in - command_word_completion_function - - removed cast from first argument to glob_pattern_p in - attempt_shell_completion - -findcmd.[ch] - - find_absolute_program, find_user_command, find_path_file, - search_for_command, user_command_matches now take a - `const char *' as their first argument - - file_status, executable_file, is_directory, executable_or_directory - now take a `const char *' as their argument - - _find_user_command_internal, find_user_command_internal, - find_user_command_in_path - -lib/sh/makepath.c, externs.h - - changed sh_makepath so it takes `const char *' for its first - two arguments - -hashcmd.[ch] - - find_hashed_filename now takes a `const char *' as its first arg - - remove_hashed_filename now takes a `const char *' as its first arg - -variables.[ch] - - new_shell_variable, var_lookup, shell_var_from_env_string, - find_name_in_env_array, bind_function, makunbound, - bind_name_in_env_array, bind_tempenv_variable, bind_variable - now take a `const char *' as their first arg - - find_function, make_new_variable, find_tempenv_variable, - find_variable_internal, find_variable, set_func_read_only, - set_func_auto_export, all_variables_matching_prefix, assign_in_env, - assignment, kill_local_variable, make_local_variable, unbind_variable - now take a `const char *' as their arg - - mk_env_string now takes `const char *' arguments - -arrayfunc.[ch] - - skipsubscript now takes a `const char *' as its argument - - 9/17 - ---- -lib/readline/complete.c - - attempt to preserve case of what the user typed in - compute_lcd_of_matches if we're ignoring case in completion - -builtins/{let,pushd}.def,{execute_cmd,expr}.c - - change some 0L constants to 0 and let the compiler sort it out - - 9/18 - ---- -lib/malloc/alloca.c - - alloca now takes a `size_t' argument - -include/memalloc.h - - if we're providing an extern function declaration for alloca, - use `void *' and prototype if __STDC__ is defined - - if HAVE_ALLOCA_H is defined, but C_ALLOCA is defined, don't - define HAVE_ALLOCA - - 9/19 - ---- -subst.c - - do_assignment_internal, do_assignment, and do_assignment_no_expand - now take a `const char *' as their first argument - -general.h - - a `sh_assign_func_t' is now a function taking a `const char *' and - returning int - -hashcmd.c - - free_filename_data now takes a `PTR_T' argument to agree with the - typedef for `sh_free_func_t' - -lib/sh/snprintf.c - - use TYPE_MAXIMUM define like strtol.c instead of huge constants - - 9/20 - ---- -lib/sh/snprintf.c - - don't bother to compile the bulk of the body unless HAVE_SNPRINTF - or HAVE_ASPRINTF is not defined - - 9/24 - ---- -flags.c - - ignore `set -n' if the shell was started interactively - -lib/readline/readline.c - - initialize readline_echoing_p to 0; let the terminal-specific code - in rltty.c set it appropriately - -lib/malloc/malloc.c - - changed internal_memalign() slightly to avoid compiler warnings about - negating an unsigned variable (-alignment -> (~alignment + 1)) - - 9/27 - ---- -lib/readline/readline.c - - changed rl_newline to set _rl_history_saved_point appropriately - for the {previous,next}_history code - -lib/readline/rlprivate.h - - extern declaration for _rl_history_preserve_point - -lib/readline/bind.c - - new bindable variable, `history-preserve-point', sets value of - _rl_history_preserve_point - - 10/1 - ---- -lib/malloc/table.c - - new file, with a map of allocated (and freed) memory for debugging - multiple frees, etc. Indexed by hash on values returned by - malloc(); holds size, file and line number info for last alloc or - free and a couple of statistics pointers - -lib/malloc/malloc.c - - a few cleanups; added calls for registering allocations and frees - if MALLOC_REGISTER is defined - - replaced MALLOC_RETURN with explicit MALLOC_NOTRACE define - - reordered fields in `struct...minfo' in `union mhead' to restore - eight-byte alignment - - added explicit checks for underflow in free and realloc since - checking mh_magic2 is not sufficient to detect everything (it's - no longer the last field in the struct, and thus not the bytes - immediately preceding what's returned to the user) - - new function, xbotch, for printing file and line number info for - the failed assertion before calling botch() (programming_error()) - -configure.in - - replaced call to BASH_C_LONG_LONG with call to - AC_CHECK_TYPES([long long]) - - moved the C compiler tests before the tests for various - system types, so we can know whether we have `long long' - before testing for 64-bit types - - if we have `long long', check for sizeof(long long) and save value - -aclocal.m4 - - changed BASH_TYPE_BITS64_T to check `long long' before `long', but - after `double' - - 10/2 - ---- -lib/malloc/malloc.c - - made malloc and realloc both agree on the rounding for a request of - size N (round up to nearest multiple of 8 after adjusting for - malloc overhead); uses new ALLOCATED_BYTES macro - - realloc and free now use new IN_BUCKET macro for underflow checks - -execute_cmd.c - - fixed time_command() to use `time_t' instead of `long' to hold - time stamps - -lib/sh/clock.c - - clock_t_to_secs now takes a `time_t *' second argument - - fixed print_clock_t to call clock_t_to_secs with right arguments - -lib/sh/timeval.c - - fixed print_timeval to make `minutes' a `long' and make its - structure identical to print_clock_t - -redir.c - - changed redirection_error to check for EBADF and use the file - descriptor being redirected from in the error message if it - is >= 0 - -Makefile.in - - changed release status to `beta1' - -lib/glob/collsyms.h - - added a few ASCII symbols to the posix_collsyms array - - 10/3 - ---- -aclocal.m4 - - fixed typo in BASH_TYPE_BITS64_T - -configure.in - - added check for unsigned chars with AC_C_CHAR_UNSIGNED - -config.h.in - - added PROTOTYPES and __CHAR_UNSIGNED__ #defines - -general.h - - if CHAR_MAX is not define by , provide a definition - -builtins/printf.def - - change tescape() to mask \0 and \x escape sequences with 0xFF - - change tescape() to process at most two hex digits after a `\x' - -lib/sh/strtrans.c - - change strtrans() to mask \0 and \x escape sequences with 0xFF - - change strtrans() to process at most two hex digits after a `\x'. - This affects `echo -e' and $'...' processing - -lib/readline/bind.c - - changed rl_translate_keyseq() to process at most two hex digits - after a `\x' - -lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 - - changed documentation for key binding escape sequences to specify - that at most two hex digits after \x are translated - - changed documentation for key binding to specify that the result - of \nnn or \xhh escapes is an eight-bit value, not just ASCII - -doc/{bash.1,bashref.texi} - - changed documentation of $'...' to specify that at most two hex - digits after \x are translated - - changed `echo' documentation to specify that at most two hex - digits after \x are translated - - changed documentation for `echo' and $'...' to specify that the - result of \nnn or \xhh escapes is an eight-bit value, not just ASCII - - 10/4 - ---- -lib/malloc/malloc.c - - changed interface for xbotch to pass memory address and error code - as two additional arguments - - call mregister_describe_mem from xbotch to get the last allocation - or free before the botch - -configure.in - - call AC_CHECK_DECLS([strsignal]) - -config.h.in - - add HAVE_DECL_STRSIGNAL - -siglist.h - - make declaration of strsignal() dependent on !HAVE_DECL_STRSIGNAL - - 10/5 - ---- -support/texi2html - - upgraded to version 1.64 - - 10/9 - ---- -aclocal.m4 - - added check for `long long' to BASH_TYPE_PTRDIFF_T - -configure.in - - replaced call to BASH_HAVE_TIOCGWINSZ with AC_HEADER_TIOCGWINSZ - -aclocal.m4 - - replaced body of BASH_STRUCT_TERMIOS_LDISC with call to - AC_CHECK_MEMBER(struct termios.c_line, ...) - - replaced body of BASH_STRUCT_TERMIO_LDISC with call to - AC_CHECK_MEMBER(struct termios.c_line, ...) - -[bash-2.05a-beta1 frozen] - - 10/10 - ----- -lib/sh/snprintf.c - - fixed exponent() to not smash the trailing zeros in the fraction - when using %g or %G with an `alternate form' - - fixed exponent() to handle the optional precision with %g and %G - correctly (number of significant digits before the exponent) - - 10/11 - ----- -expr.c - - fixed strlong() to correct the values of `@' and `_' when - translating base-64 constants (64#@ == 62 and 64#_ == 64), for - compatibility with ksh - -lib/sh/itos.c - - added a slightly more flexible fmtlong() function that takes a - base argument and flags (for future use) - - rewrote itos and inttostr in terms of fmtlong - -lib/sh/fmtulong.c - - new file, converts unsigned long to string. hooks for `unsigned - long long' in the future. unused as yet - - 10/15 - ----- -lib/readline/rltty.c - - change the SET_SPECIAL macro to avoid possible (but highly - unlikely) negative array subscripts - -error.h - - add __attribute__ to extern declaration of itrace (even though the - function isn't defined in released versions of bash) - -bashansi.h - - include if HAVE_STRINGS_H is defined, to get any extra - function declarations provided therein - -copy_cmd.c - - fix typo in forward declaration for copy_arith_for_command - -lib/malloc/stats.c - - make the accumulators in _print_malloc_stats be `unsigned long' - instead of `int' - -externs.h, sig.h - - add `__noreturn__' gcc attribute to exit_shell and jump_to_top_level - declarations - -lib/sh/mailstat.c, support/bashversion.c - - include for some string function declarations - -lib/malloc/shmalloc.h - - added extern declarations of functions that do malloc debugging - -lib/readline/{isearch,readline,vi_mode}.c - - make sure we index into _rl_keymap with a non-negative index - -parse.y - - make sure we index into sh_syntaxtab with a non-negative index - -lib/readline/vi_mode.c - - bound the vi_mark_chars array with the number of characters between - 'a' and 'z' rather than using a fixed amount - - don't use _rl_lowercase_p when deciding whether the char read by - rl_vi_set_mark is a valid mark; just use 'a' <= char <= 'z' - -lib/readline/chardefs.h - - conditionally include memory.h and strings.h as in general.h - - replace ISASCII with IN_CTYPE_DOMAIN like other GNU software - - add defines for ISPRINT(c), ISLOWER(c) and ISUPPER(c) - - fix defines for _rl_lowercase_p, _rl_uppercase_p, _rl_digit_p, - _rl_pure_alphabetic, ALPHABETIC, _rl_to_upper, _rl_to_lower, - and _rl_isident to work on systems with signed chars - -include/chartypes.h - - replace ISASCII with IN_CTYPE_DOMAIN like other GNU software - -lib/sh/{strcasecmp,strtod,strtol}.c - - don't pass possibly-negative characters to tolower() or toupper() - -lib/glob/strmatch.c - - don't bother testing for isupper in FOLD; rely on TOLOWER macro - from to do it - - don't use local definitions of isblank, et al.; rely on macros - from - -lib/readline/{display,readline}.c, mksyntax.c - - use new ISPRINT macro instead of isprint() - -builtins/{kill.def,mkbuiltins.c},{error,execute_cmd,jobs,nojobs,subst}.c - - don't assume that a pid_t fits into an int for printing and other - uses - -variables.[ch] - - the unused put_gnu_argv_flags_into_env now takes a `long' pid - argument - -configure.in, config.h.in - - call AC_STRUCT_ST_BLOCKS, define HAVE_STRUCT_STAT_ST_BLOCKS if found - - check for strtoull(), define HAVE_STRTOULL if found - - check for uintmax_t, define to `unsigned long' if not found - -lib/sh/mailstat.c - - don't use st_blocks member of struct stat unless - HAVE_STRUCT_STAT_ST_BLOCKS is defined; otherwise use the st_nlink - field to return the total number of messages in a maildir-style - mail directory - -general.h,{alias,expr,general,subst,variables}.c -builtins/{printf,read}.def -lib/readline/{bind,complete,nls}.c -lib/sh/{pathcanon,pathphys,shquote,snprintf,strindex,strtod,strtol,strtrans}.c - - cast args to ctype macros to unsigned char for systems with signed - chars; other fixes for signed chars - -lib/sh/{fmtullong,strtoull.c} - - new files, more support for `long long' - -Makefile.in, lib/sh/Makefile.in - - make fmtullong.o and strtoull.o part of libsh - -lib/sh/itos.c - - remove local copy of fmtlong; use fmtulong instead - - new functions: uitos, uinttostr work on `unsigned long' - -lib/sh/snprintf.c - - fixes to make `unsigned long long' work (%llu) - - fixes to make unsigned formats not print the sign when given - an unsigned long that is greater than LONG_MAX - -externs.h - - extern declarations for fmtulong, fmtulloing, strtoull - - extern declarations for uitos, uinttostr - - 10/16 - ----- -configure.in - - move header checks before function checks - - move c compiler tests before header checks - - check for with BASH_HEADER_INTTYPES - - change type checks for intmax_t, uintmax_t to not attempt to - include - - check for strtoimax, strtoumax, strtoll, strtol, strtoull, strtoul - with BASH_CHECK_DECL (for declarations in header files) and - AC_REPLACE_FUNCS (for availability and LIBOBJS substitution) - - remove check for have_long_long around sizeof check for long long - (since autoconf will give it a size of 0 if the type isn't found) - -config.h.in - - add a define for HAVE_INTTYPES_H - - add a define for HAVE_UNSIGNED_LONG_LONG - - add defines for HAVE_STRTOIMAX, HAVE_STRTOUMAX, HAVE_STRTOLL - -aclocal.m4 - - new func, BASH_HEADER_INTTYPES, which just calls AC_CHECK_HEADERS - on ; separate so it can be AC_REQUIREd - - AC_REQUIRE([BASH_HEADER_INTTYPES]) in BASH_CHECK_TYPE - - include in BASH_CHECK_TYPE if HAVE_INTTYPES_H is - defined - - change AC_DEFINE to AC_DEFINE_UNQUOTED in BASH_CHECK_TYPE - - new `long long' checking macros: BASH_TYPE_LONG_LONG and - BASH_TYPE_UNSIGNED_LONG_LONG - - new BASH_CHECK_DECL - -lib/sh/{strto[iu]max,strtoll}.c, lib/sh/Makefile.in, Makefile.in - - new files - -externs.h - - extern declarations for strtoll, strtoimax, strtoumax - -lib/malloc/alloca.c - - include for size_t - -builtins/printf.def - - new functions: getllong, getullong, getintmax, getuintmax; return - long long, unsigned long long, intmax_t, uintmax_t respectively - - builtin printf now handles `ll' and `j' length modifiers directly - -lib/sh/Makefile.in - - use LIBOBJS to decide whether or not the strto* functions are - needed - - 10/17 - ----- -configure.in - - call AC_REPLACE_FUNCS(rename) - - move getcwd, strpbrk, strcasecmp, strerror, strtod - from AC_CHECK_FUNCS to AC_REPLACE_FUNCS - - only call BASH_FUNC_GETCWD if $ac_func_getcwd == "yes" - - call BASH_CHECK_SYS_SIGLIST - - if we don't have vprintf but have _doprnt, call AC_LIBOBJ(vprint) - -lib/sh/Makefile.in - - remove rename, getcwd, inet_aton, strpbrk, strcasecmp, strerror, - strtod, vprint from OBJECTS; picked up from LIBOBJS - -aclocal.m4 - - change BASH_FUNC_GETCWD to call AC_LIBOBJ(getcwd) if the libc - getcwd(3) calls popen(3) - - change BASH_FUNC_INET_ATON to call AC_LIBOBJ(inet_aton) if it's - not found in libc or as a #define even with the special includes - - BASH_KERNEL_RLIMIT_CHECK -> BASH_CHECK_KERNEL_RLIMIT - - BASH_DEFAULT_MAILDIR -> BASH_SYS_DEFAULT_MAILDIR - - BASH_JOB_CONTROL_MISSING -> BASH_SYS_JOB_CONTROL_MISSING - - BASH_REINSTALL_SIGHANDLERS -> BASH_SYS_REINSTALL_SIGHANDLERS - - BASH_SIGNAL_CHECK -> BASH_SYS_SIGNAL_VINTAGE - - BASH_DUP2_CLOEXEC_CHECK -> BASH_FUNC_DUP2_CLOEXEC_CHECK - - BASH_PGRP_SYNC -> BASH_SYS_PGRP_SYNC - - BASH_RLIMIT_TYPE -> BASH_TYPE_RLIMIT - - BASH_FUNC_PRINTF -> BASH_DECL_PRINTF - - BASH_FUNC_SBRK_DECLARED -> BASH_DECL_SBRK - - BASH_MISC_SPEED_T -> BASH_CHECK_SPEED_T - - BASH_CHECK_SOCKLIB -> BASH_CHECK_LIB_SOCKET - - new macro, BASH_CHECK_SYS_SIGLIST, encapsulates all the checks for - sys_siglist, _sys_siglist, and strsignal(), sets SIGLIST_O to - siglist.o if appropriate - -Makefile.in - - use SIGLIST_O variable to decide whether or not we need siglist.o - -{execute_cmd,subst}.c - - change a couple of instances of ISDIGIT to DIGIT, where we really, - really only want ascii digits - -ansi_stdlib.h - - don't need a declaration for atol() - - 10/18 - ----- - -aclocal.m4 - - new macro, BASH_FUNC_PRINTF_A_FORMAT, checks for printf support - for %a, %A conversion specifiers, defines HAVE_PRINTF_A_FORMAT - if successful - -configure.in - - call AC_CHECK_FUNCS for isascii - - call BASH_FUNC_PRINTF_A_FORMAT - -config.h.in - - add a define for HAVE_ISASCII - - add a define for HAVE_PRINTF_A_FORMAT - -lib/sh/snprintf.c - - for long double output, fall back to sprintf using ldfallback() - function for floating point formats - - support %a, %A using dfallback() or ldfallback() if - HAVE_PRINTF_A_FORMAT is defined - - fix bug in vasprintf that returned wrong value in its first - argument if the buffer holding the result string got reallocated - - fixed PUT_CHAR macro to increment the counter even if we've - exceeded the buffer size, for the return value from - vsnprintf/snprintf - - fix vsnprintf_internal to not use counter < length as a loop - condition, but always process the entire format string (for - the return value from vsnprintf/snprintf) - -builtins/printf.def - - support %a, %A if HAVE_PRINTF_A_FORMAT is defined - -include/typemax.h - - new file, with the TYPE_MAXIMUM stuff that's duplicated in several - files in lib/sh - -lib/sh/{fmtulong,strtol,snprintf}.c - - include instead of having the definitions in each file - -lib/sh/Makefile.in - - updated dependencies for typemax.h - - 10/22 - ----- -configure.in - - call AC_CHECK_FUNCS on ctype.h functions/macros that bash redefines - in chartypes.h - -config.h.in - - defines for HAVE_IS{ASCII,BLANK,GRAPH,PRINT,SPACE,XDIGIT} - -include/chartypes.h, lib/glob/strmatch.c, lib/readline/chardefs.h - - don't redefine some is* ctype macros/functions if HAVE_ISXXX is - defined (meaning that an appropriate function, but not a macro, - exists) - -lib/sh/strtrans.c - - new function, ansic_shouldquote, returns 1 if argument string - contains non-printing chars that should be quoted with $'...' - -externs.h - - new declaration for ansic_shouldquote() - -variables.c - - change print_var_value to ansi C quote the string if we're not in - posix mode and the variable's value contains non-printing chars, - to use the regular shell single quoting if the value contains - shell meta-characters, and to just output the string otherwise - -lib/sh/shquote.c - - add `break' to `case '~':' to avoid fallthrough and extra test - -doc/bashref.texi - - note that in POSIX mode, `set' displays variable values that - include nonprinting characters without quoting, unless they - contain shell metacharacters - -builtins/printf.def, lib/sh/snprintf.c - - handle `F' conversion specifier as equivalent to 'f' - -parse.y, {nojobs,variables}.c - - a couple of cleanups for when building a minimal configuration - -nojobs.c - - new function: stop_making_children(), just sets - already_making_children to 0 (like stop_pipeline) - -subst.c - - call stop_making_children from subst.c:command_substitute if - JOB_CONTROL is not defined. This fixes the bug where the wrong - process is waited for (and its status returned) when using - command substitution in a null command in a shell function - -builtins/printf.def - - new variable `tw' used to keep track of the total number of - characters written by a single call to `printf' -- to be - used for the `%n' conversion, which will be added later. It - gets reset each time we reuse the format string, which is what - ksh93 seems to do - - 10/23 - ----- -variables.c - - new function, bind_var_to_int (char *var, long val) - -variables.h - - extern declaration for bind_var_to_int - -lib/sh/netopen.c - - use gai_strerror() for error messages when getaddrinfo() fails - - use PF_INET if DEBUG is defined, since IPv6 doesn't work for me - -Makefile.in - - pass DEBUG=${DEBUG} down to makes in some subdirectories - -{builtins,lib/{glob,sh}}/Makefile.in - - append ${DEBUG} to LOCAL_CFLAGS value, passed by top-level Makefile - -builtins/printf.def - - added support for %n format conversion char (number of chars printed - so far from current format string) - - 10/24 - ----- -variables.c - - if posixly_correct is set, the default value of $MAILCHECK is 600 - - use legal_number instead of atoi in adjust_shell_level - - treat non-numeric assignments to SECONDS as 0 in assign_seconds - - new function, init_funcname_var; sets FUNCNAME as a dynamic variable - if it's not set in the initial environment - - new function, init_groups_var; sets GROUPS as a dynamic array - variable if it's not set in the initial environment - - new function, init_dirstack_var; sets DIRSTACK as a dynamic array - variable if it's not set in the initial environment - - new function, init_seconds_var; sets SECONDS as a dynamic - variable using any valid integer value in the initial environment - as the initial value, as if an assignment had been performed - - call init_funcname_var, init_groups_var, init_dirstack_var, - init_seconds_var from initialize_dynamic_variables - - non-numeric values assigned to LINENO are treated as 0 - - change initialize_shell_variables to not auto-export PATH or TERM - - change set_home_var to not auto-export HOME - - change set_shell_var to not auto-export SHELL - - broke the code that sets HOSTNAME, HOSTTYPE, MACHTYPE, OSTYPE - out into a separate function, set_machine_vars; none of those - variables are auto-exported - - bash no longer un-exports SSH_CLIENT or SSH2_CLIENT - -shell.c - - changed isnetconn() to check SSH_CLIENT and SSH2_CLIENT only if - SSH_SOURCE_BASHRC is defined in config-top.h - -config-top.h - - added a commented-out definition for SSH_SOURCE_BASHRC - - 10/25 - ----- - -Makefile.in - - changed RELSTATUS to `rc1' (release candidate 1) - - 10/29 - ----- -locale.c - - fixed an `=' vs. `==' typo in set_locale_var when parsing - LC_NUMERIC - -doc/{bash.1,bashref.texi} - - document what bash does with $POSIXLY_CORRECT - -doc/builtins.1 - - some updates - -builtins/psize.sh - - some mktemp(1) changes - -lib/readline/readline.c - - change rl_backward to check for rl_point < 0 and reset to 0 if so - -lib/readline/util.c - - don't compile in _rl_strpbrk if HAVE_STRPBRK is defined - -lib/readline/rlprivate.h - - remove extern declaration of _rl_strpbrk - -lib/readline/rldefs.h - - #define _rl_strpbrk as strpbrk if HAVE_STRPBRK is define, otherwise - add extern declaration of _rl_strpbrk from rlprivate.h - -{mailcheck,shell,variables}.c - - make sure to include posixtime.h to get any prototype for time(3) - in scope - -{array,eval,execute_cmd,mksyntax,subst}.c, parse.y -builtins/common.c -lib/sh/pathcanon.c - - a few changes as the result of `gcc -Wall' patches from solar - designer - -builtins/read.def, parse.y - - change some calls to free() to xfree() - -builtins/set.def - - make sure unset_builtin() resets unset_array to 0 each time through - the loop, because it's set (and used) depending on the current - argument - -shell.h - - new define, USE_VAR, to force the compiler to not put a particular - variable in a register -- helpful if registers are not restored - by setjmp/longjmp - -builtins/{evalfile.c,{read,wait}.def}, {eval,execute_cmd,shell,test}.c - - use USE_VAR for some variables - -subst.c - - fixed a case in expand_word_internal where a NULL pointer could - have been passed to free() (though free() should ignore it) - - fixed a case at the end of expand_word_internal where LIST could - have been used uninitialized (it makes gcc happy, though it - doesn't happen in practice) - -test.c - - give test_syntax_error(), beyond(), and integer_expected_error() - the `__noreturn__' attribute for gcc - -unwind_prot.c - - in clear_unwind_protect_list(), convert `flags' to `long' (via - assignment to a `long' variable) before casting to `char *', in - case pointers and longs are 64 bits and ints are 32 (makes no - difference on 32-bit machines) - - 10/30 - ----- -print_cmd.c - - fixed cprintf to avoid gcc warning about assigning const pointer - to non-const (discarding type qualifier) - -{make_cmd,pcomplete,test}.c,parse.y - - some minor changes to shut up gcc warnings - -lib/sh/tmpfile.c - - fixed sh_mktmpfp to avoid file descriptor leaks in the case that - sh_mktmpfd succeeds but fdopen fails for some reason - - change sh_mktmpfd to use the same scheme for computing `filenum' - as sh_mktmpname - - change get_sys_tmpdir to prefer P_tmpdir if P_tmpdir is defined - - changed sh_mktmpname and sh_mktmpfd to avoid trying to assign to - `nameroot' if `nameroot == 0' (duh) - - add code to sh_mktmpfd to use mkstemp(3) if USE_MKSTEMP is defined - - add code to sh_mktmpname to use mktemp(3) if USE_MKTEMP is defined - -support/{fixlinks,mkclone} - - use mktemp if it's available for the symlink test - - use $TMPDIR instead of hardcoding /tmp; default to /tmp - - use a better filename for the symlink test instead of `z' - -support/bashbug.sh - - more changes inspired by a patch from solar designer - -lib/malloc/Makefile.in - - new target `alloca', which builds libmalloc.a with alloca.o only - (for systems without alloca that are configured --without-bash-malloc) - -configure.in - - if we don't have a working alloca and are not configured to build - the bash malloc library, make a malloc library containing only - alloca.o - -aclocal.m4 - - slight change to RL_LIB_READLINE_VERSION to deal with minor version - numbers with a letter appended (like 4.2a) - - 10/31 - ----- -doc/{bash.1,bashref.texi} - - slight change to note that only interactive shells resend a SIGHUP - to all jobs before exiting - -externs.h - - declare strto[ui]max only if NEED_STRTOIMAX_DECL is defined. This - keeps picky compilers from choking because intmax_t is not defined - (MacOS X 10.1) - -builtins/printf.def - - #define NEED_STRTOIMAX_DECL before including shell.h - - 11/1 - ---- -general.c - - check in bash_tilde_expand() for an unquoted tilde-prefix; don't - bother passing the string to tilde_expand unless the prefix is - unquoted - -shell.c - - fix a problem with $LINENO when executing commands supplied with - the -c invocation option when ONESHOT is defined - -[bash-2.05a-rc1 frozen] - -builtins/printf.def - - fix the %n conversion to require that the variable name supplied - be a valid shell identifier - -variables.c - - improve random number generator slightly by using the upper 16 - bits of the running random number instead of the lower 16, which - are incrementally more random - - 11/2 - ---- -configure.in - - if RL_INCLUDEDIR ends up being /usr/include, don't put - -I$(RL_INCLUDEDIR) into CFLAGS - - 11/5 - ---- -doc/{bash.1,bashref.texi} - - correct description of POSIXLY_CORRECT to note that the shell enters - posix mode *before* the startup files are read if POSIXLY_CORRECT - is in the initial environment - -variables.c - - fix function prologues for init_dirstack_var and init_groups_var - to agree with caller (no arguments) - -jobs.c - - fix forward function declarations for pipe_read and pipe_close - -subst.c - - removed `inline' attribute from skip_double_quoted because it can - potentially be called recursively - -bashline.c - - quick fix to bashline.c:attempt_shell_completion programmable - completion code to just punt if the end of the command word found - by find_cmd_end is <= the start found by find_cmd_start (the bug - is probably in find_cmd_start -- fix later) - -pcomplete.c - - fix gen_matches_from_itemlist to return if the stringlist is null - after any cleaning or initialization, before trying to use it - - fix GEN_COMPS to only bother to try to append the STRINGLIST - returned by gen_matches_from_itemlist to `glist' if it's non-NULL - -lib/sh/stringlist.c - - make copy_stringlist return NULL if the STRINGLIST * passed as an - argument is NULL - - make append_stringlist call copy_stringlist only if M2 is non-NULL; - otherwise just return NULL if m1 is NULL - - make word_list_to_stringlist return 0 immediately if the passed - LIST argument is NULL - - make realloc_stringlist call alloc_stringlist if the passed - STRINGLIST argument (`sl') is 0, just like realloc calls malloc - -subst.c - - in skip_to_delim(), if we have an unclosed ${, and it's at the end - of the string (string[i] == '{', string[i+1] == '{' and - string[i+2] == 0, return si (i +2) immediately without bothering - to call extract_dollar_brace_string or extract_delimited_string - - in skip_to_delim(), if string[i] is 0 after a call to - extract_dollar_brace_string or extract_delimited_string (meaning we - have an unclosed ${ or other expansion, return i immediately without - doing a `continue' (which will increment i past the end of string) - - in split_at_delims, don't increment te by 1 if it's pointing to a - delimiter. this has the effect of skipping the first delimiter - char in a possibly multi-character delimiter, and ignoring - single-char delimiters like `>' - -configure.in - - use AC_CHECK_MEMBERS([struct stat.st_blocks]) instead of a call to - AC_STRUCT_ST_BLOCKS to avoid configure changing LIBOBJS if the test - fails - -general.c - - introduce two new variables: bash_tilde_{prefixes,suffixes}, set - to the additional prefixes and suffixes bash wants to pass to the - tilde expansion code (reserved for post-bash-2.05a fix) - -aclocal.m4 - - add missing `test' in BASH_CHECK_SYS_SIGLIST - - 11/7 - ---- -lib/readline/vi_mode.c - - fix rl_vi_goto_mark to explicitly check that the desired mark is - between 'a' and 'z', since some locales have lowercase letters - outside that range, which could cause a negative subscript - -include/chartypes.h - - remove superfluous `#undef ISASCII' - -lib/sh/strto[iu]max.c - - changes from Paul Eggert to work around buggy compilers and catch - configuration errors at compile time - -aclocal.m4 - - new macro, BASH_C_LONG_DOUBLE, identical to AC_C_LONG_DOUBLE but - with a fix for Irix 5.3 (not called, since I'm not sure it's the - right thing to do -- the C standard allows double and long double - to be the same size) - -lib/sh/snprintf.c - - only try to write the trailing NUL in vsnprintf_internal if - data->length is >= 0, since if it's not, we probably don't have - a buffer - -Makefile.in - - changed RELSTATUS to `release' - - 11/8 - ---- -lib/sh/strtol.c - - make sure chars passed to toupper are cast to unsigned - -unwind_prot.c - - change clear_unwind_protect_list to not require a cast from `int' - to `char *' - -lib/readline/chardefs.h - - make _rl_digit_p succeed only for ascii digits, since that's what - most callers assume - - 11/13 - ----- -doc/bashref.texi - - added `ERR' trap and [-+]O invocation option to section listing - differences from the Bourne shell - - 11/15 - ----- -[bash-2.05a released] - - 11/19 - ----- -include/stdc.h - - new define, INLINE, defined as `inline' for gcc and empty otherwise - -subst.c - - make skip_double_quoted, sub_append_string have INLINE attribute - -trap.c - - use BASH_NSIG as upper limit for signal names in signal_name() - -lib/readline/bind.c - - use RL_COMMENT_BEGIN_DEFAULT in output for rl-comment-begin value - -error.c - - fix sys_error to save value of errno around calls to fprintf - -doc/Makefile.in - - added rules to create PDF files from postscript and dvi input - -MANIFEST.doc - - added {article,bash,bashref,rose94}.pdf - -doc/bash.1 - - rearranged some `.PD 0' and `.TP' directives so man2html will - handle them better (shouldn't affect groff output) - -support/man2html.c - - small fix to handle quoted string arguments to directives like - `.BR' without mangling the output - - 11/20 - ----- -{arrayfunc,variables}.c - - changed calling sequence for dynamic array variable `assign' - functions to (SHELL_VAR *self, char *value, arrayind_t ind) - - changed calling sequence for dynamic variable assign functions - to the same as array variable assign_func. Now this can be - prototyped - -variables.h - - the assign_func member of a `struct variable' is now of type - `sh_var_assign_func_t', which is prototyped - - the dynamic_value member of a `struct variable' is now of type - `sh_var_value_func_t', which is prototyped - -variables.c - - changed to use `sh_var_assign_func_t' and `sh_var_value_func_t' - -builtins/cd.def - - when in posix mode, if the new directory name formed by PWD and - the argument passed by the user cannot be canonicalized, and the - -P option has not been supplied, return failure immediately - - if canonicalization failed, but the fallback to the directory - name specified by the user succeeds, reset the current working - directory - -lib/readline/{input.c,rlprivate.h} - - renamed rl_unget_char to _rl_unget_char; made library global - -lib/readline/{{bind,readline}.c,{keymaps,rlprivate}.h} - - support for `key subsequences'; allows a key sequence and a function - mapped to a subsequence of that key sequence. Primarily to allow - arrow keys to be bound in readline vi insert mode, while preserving - the ESC function to switch to command mode. - -lib/readline/{input.c,rlprivate.h} - - new function, _rl_input_queued(T), does a check with select or - FIONREAD with a timeout of `T' (which is generally 0) - -lib/readline/readline.c - - change _rl_dispatch_subseq to test for input in the queue if we - get ESC while in vi insertion mode if the keymap entry type for - ESC is ISKMAP. If _rl_input_queued returns non-zero, we assume - that an arrow key sequence has been pressed and go ahead with the - subsequence. If it returns zero, we assume that the user pressed - ESC to switch into command mode, and dispatch to that right away. - This avoids forcing the user to press another key before switching - into command mode - - 11/21 - ----- -lib/readline/readline.c - - bind common arrow key sequences in vi insertion keymap - -lib/readline/terminal.c - - bind termcap definition's arrow keys in vi insertion keymap - -lib/readline/bind.c - - check for rl_vi_movement_mode in _rl_bind_if_unbound, so - binding the arrow keys can work - -lib/readline/readline.c - - since _rl_bind_if_unbound does the check of what's currently - bound to the key sequence, the check in bind_arrow_keys_internal - was redundant - - bind_arrow_keys_internal now takes a Keymap argument and handles - saving and restoring _rl_keymap; changed bind_arrow_keys - accordingly - -builtins/fc.def - - fix from Paul Eggert to substitute the nearest history number in - range if an out-of-range value is supplied. POSIX requires this - -lib/sh/pathcanon.c - - fix from Corrina Vinschen for the special `cygdrive' prefix on - Cygwin - -bashhist.c - - split the history adding code into more pieces: - check_history_control (char *line) checks LINE against the value - of HISTCONTROL, returning 1 if LINE should be saved and 0 if not - - check_add_history (char *line) calls check_history_control and - history_should_ignore (line) and saves the line with - bash_add_history if the checks indicate that it should be saved - - maybe_add_history just calls check_add_history to set the value - of first_line_saved - -bashhist.h - - extern declaration for check_add_history() - -shell.c - - don't call load_history() from the interactive shell startup - code if history_lines_this_session is > 0, indicating that we've - already saved some lines in the history and that we probably - don't want to overwrite them - -builtins/history.def - - call check_add_history from push_history, so `history -s xx' - works even when in a compound command whose first line has not - been saved. (Caveat: in a compound command when the first - line has been saved, the line supplied to history -s will become - part of the compound command's history entry. Of course, the - delete_history call could remove the compound command from the - history entirely) - -bashline.c - - use sh_makepath instead of xmalloc/sprintf in - command_word_completion_function - -lib/readline/complete.c - - get_y_or_n now takes an int FOR_PAGER argument; caller changed - If FOR_PAGER is non-zero, get_y_or_n returns appropriate values - for a more-like pager: `newline' or `return' return 2; `q' or - `Q' return 0 - - there is now a mini internal more-like pager for displaying a - list of completions that exceeds the screen height (new function - _rl_internal_pager, called from rl_display_match_list) - - 11/24 - ----- -command.h - - new flag, W_TILDEEXP, says to do tilde expansion on an - assignment word - -execute_cmd.c - - fix_assignment_words now sets W_TILDEEXP for assignment word - arguments to `assignment builtins' - -general.c - - bash_tilde_expand now takes a second argument indicating whether - or not it's being invoked in an `assignment context' - -general.h - - change extern declaration for bash_tilde_expand - -{bashline,execute_cmd,findcmd,general,variables}.c -builtins/evalfile.c -lib/sh/makepath.c - - fix callers of bash_tilde_expand appropriately - -subst.c - - fix callers of bash_tilde_expansion appropriately - - add (currently commented-out) code that would tilde expand assignment - statement arguments to assignment builtins (W_TILDEEXP flag set) - even when the shell is in posix mode - -bashline.c - - fix attempt_shell_completion to turn off - rl_filename_completion_desired when doing command name completion, - so no slash gets appended to the name if there happens to be a - directory with the same name in the current directory - - 11/26 - ----- -lib/readline/rltech.texinfo - - a couple of additions to the rl_stuff_char description - -parse.y - - turn off echo_input_at_read in parse_string_to_word_list, so `set -v' - doesn't give extra lines of output when doing compound array - assignment - -subst.c - - fix split_at_delims to handle skipping over a `\n' if it's a - delimiter (use spctabnl(c) instead of whitespace(c)) - - 11/27 - ----- -support/config.{guess,sub} - - updated (with bash changes) to latest version from gnu.org - -sig.h - - add prototype for set_signal_handler declaration - -builtins/setattr.def - - add prototype to extern declaration of declare_builtin - -builtins/times.def - - add no_options call, since times takes no options - -lib/sh/spell.c - - add prototypes to forward declarations for midist and spdist - -lib/sh/strtrans.c - - add explicit int return type to ansic_shouldquote declaration - -lib/readline/rldefs.h, lib/readline/{macro,readline,util,undo}.c - - move define for SWAP to rldefs.h, removed from various C files - -lib/readline/vi_mode.c - - removed define for exchange(), changed to use SWAP instead - -lib/readline/bind.c - - added some static forward function declarations - - find_boolean_var, find_string_var now take a `const char *' argument - -lib/readline/signals.c - - added static forward declaration for rl_maybe_set_sighandler - -lib/readline/readline.c - - add some common key bindings for the HOME and END keys in - bind_arrow_keys_internal - -lib/readline/terminal.c - - fetch the `@7' termcap string; it's sent by the END key - - attempt to bind the terminal's END key to rl_end_of_line in - bind_termcap_arrow_keys; I don't know why I was using `kH' - instead of `@7' - -doc/builtins.1 - - remove `case', `for', `if', `until', `while' from NAME section; - those are not shell builtins - - 11/28 - ----- -stringlib.c - - new function, find_token_in_alist, takes a token value and an - ALIST argument, and returns the string correspoinding to the - token if found in the alist - -externs.h - - new extern declaration for find_token_in_alist() - -subst.c - - string_list_internal is no longer static - -subst.h - - new extern declaration for string_list_internal() - -parse.y - - new alist array of other tokens returned by read_token which are - not reserved words in word_token_alist[] - - reworked error reporting: new functions print_offending_line, - which prints the line containing the syntax error, - error_token_from_token, which takes the current token and tries to - figure out its textual representation, and error_token_from_text, - which does the old job of finding the bad token by analyzing the - text of shell_input_line at the current index - - report_syntax_error now tries to figure out the token that caused - the syntax error by first looking at current_token and falling - back to the old method of textual analysis if that fails - - report_syntax_error doesn't say the token resulting from the textual - analysis of the input line is an `unexpected token'; it just - says there is a `syntax error near xxx' - - changed conditional command error reporting to use the value - returned by error_token_from_token if it's not null instead of - just using the token value in the message, since current_token - ends up being set to -1, and the text of the message from - report_syntax_error might not be exactly right - - change parse_string_to_word_list to set current_token to the - offending token returned by read_token before calling yyerror() - to make the error reporting do the right thing - -aclocal.m4 - - fixed typo in BASH_CHECK_LIB_TERMCAP - -configure.in - - add check for isinf(3); define HAVE_ISINF_IN_LIBC if found - -config.h.in - - add define for HAVE_ISINF_IN_LIBC - -lib/sh/snprintf.c - - check for Inf and NaN, using isinf and isnan if they're found in - libc - - use the current locale for thousands separator and decimal point - - recognize "'" flag; not implemented yet - - fix for snprintf/vsnprintf with length of 0 and string argument of - 0 with non-zero length - -builtins/read.def - - TMOUT is now the default timeout for `read' (and select) if set, - like ksh93 when reading from the terminal - - edit_line (called by read -e) now just does readline's filename - completion by setting rl_attempted_completion_function to NULL, - since e.g., doing command completion for the first word on the - line wasn't really useful - -execute_cmd.c - - changed select_command to return failure status if select_query - returns NULL, indicating that read_builtin returned - EXECUTION_FAILURE - -doc/{bash.1,bashref.texi} - - documented new TMOUT behavior - - slight change to the description of the test `-ef' option - -doc/bashref.texi - - added item to posix mode section describing failure behavior of - cd when invoked in logical mode and the pathname formed by - combining $PWD and the directory argument does not refer to an - existing directory - - 11/29 - ----- -execute_cmd.c - - fix execute_function to call dispose_function_env after - merge_function_env if the shell is in posix mode (fixes debian - bash bug #117673) - -lib/readline/readline.c - - rl_forward -> rl_forward_char; rl_forward function for compatibility - - rl_backward -> rl_backward_char; rl_forward function for - compatibility - - new functions, rl_forward_byte, rl_backward_byte, for future use - -lib/readline/readline.h - - extern declarations for rl_forward_char, rl_backward_char, - rl_forward_byte, rl_backward_byte - -lib/readline/{emacs_keymap,funmap,vi_keymap,vi_mode - - rl_forward -> rl_forward_char - - rl_backward -> rl_backward_char - -lib/readline/funmap.c - - new bindable names, `backward-byte' and `forward-byte' - -aclocal.m4 - - new function, BASH_CHECK_MULTIBYTE, encapsulates checks for - multibyte code - -config.h.in - - add necessary defines for multibyte include files and functions - -configure.in - - add call to BASH_CHECK_MULTIBYTE - -config-bot.h - - add code to define HANDLE_MULTIBYTE if prerequisites are met - -lib/sh/xstrchr.c - - new file, xstrchr() is strchr(3) that handles multibyte characters - -bashhist.c - - first_line_saved -> current_command_first_line_saved; variable is - now global - -bashhist.h - - extern declaration for current_command_first_line_saved - - 11/30 - ----- -bashhist.c - - break the code that actually calls add_history out of - bash_add_history into a new function, really_add_history; - bash_add_history now calls really_add_history - - check_add_history takes a second `force' argument telling it - whether to call bash_add_history (force == 0) or really_add_history - (force != 0) - -builtins/history.def - - in push_history, call delete_last_history if the current command - has more than one line, the first line was saved, and - command-oriented history is active. This takes care of deleting - the right history element if `history -s' is used within a - compound or multiline command - - in push_history, call check_add_history with second argument of 1 - to skip check of current_command_line_count and add the arguments - to history -s as a single separate history entry - - 12/3 - ---- -lib/readline/complete.c - - append a slash to completed names which are symlinks to directories - if the new variable _rl_complete_mark_symlink_dirs is non-zero - -lib/readline/rlprivate.h - - extern declaration for _rl_complete_mark_symlink_dirs - -lib/readline/bind.c - - new bindable variable, `mark-symlinked-directories', mirrors the - value of _rl_complete_mark_symlink_dirs - -doc/bash.1, lib/readline/doc/{readline.3,rluser.texinfo} - - documented new `mark-symlinked-directories' variable - - 12/4 - ---- -variables.[ch] - - set_pipestatus_array now takes a second argument with the number - of processes in the array - - changed set_pipestatus_array to just modify the value in place if - the existing array has one element and the new array has one - element, and to modify existing values in place if new array has - more elements than existing array - -variables.c, jobs.c - - changed set_pipestatus_array callers - -jobs.c - - moved call to setjstatus() from set_job_status_and_cleanup to - wait_for, since set_job_status_and_cleanup is part of the SIGCHLD - signal handler call path, and race conditions accessing the - PIPESTATUS array will result for things like - - while true; do date; done | cat > /dev/null - - 12/5 - ---- -xmalloc.h - - don't redefine xmalloc, xrealloc, and xfree if DISABLE_MALLOC_WRAPPERS - is #defined - -config.h.in - - #undef for DISABLE_MALLOC_WRAPPERS - -configure.in - - define DISABLE_MALLOC_WRAPPERS if the --with-purify option is - supplied - -lib/malloc/trace.c - - new function, malloc_trace_bin(N), traces allocations and frees - to bucket N (uses the same type of bitmap as `busy') - -lib/malloc/table.c - - fix wraparound search problem in find_entry when searching for a - free entry when the table is full - - 12/6 - ---- -lib/malloc/table.c - - keep an `overflow bucket' around to use when the table is full, - so find_entry always returns a valid pointer when FIND_ALLOC - is set - - new static variable to keep a count of the number of MT_ALLOC - entries in the mem_table - -lib/sh/{oslib,clktck}.c - - if HAVE_LIMITS_H is defined, include - -lib/sh/oslib.c - - new function, getmaxgroups() returns max number of simultaneous - groups - - new function, getmaxchild(), returns max number of simultaneous - user processes - -general.c - - removed forest of #defines for getmaxgroups() - -externs.h - - new extern declaration for getmaxgroups() - - new extern declaration for getmaxchild() - - new extern declaration for isnetconn() - -lib/sh/netconn.c,shell.c - - new file, isnetconn() from shell.c moved here - -Makefile.in, lib/sh/Makefile.in - - necessary changes for netconn.c - -builtins/ulimit.def - - changed getmaxuprc() to just call getmaxchild() and massage the - return value appropriately - -{jobs,nojobs}.c - - use the value returned by getmaxchild() in - mark_dead_jobs_as_notified instead of static CHILD_MAX - -jobs.c - - new function, compact_jobs_list, removes some number of jobs from - the jobs table and reallocates the table, copying the jobs that - are left from the old table to the new. Compaction happens from - the beginning of the list and removes dead jobs, and we make sure - to keep the last CHILD_MAX jobs as POSIX.2 requires - - call compact_jobs_list from stop_pipeline if we're in a subshell, - there are no free jobs in the jobs table, and the jobs table is - at or above some maximum limit - -execute_cmd.c - - change eval_arith_for_expr to set this_command_name to `((' before - calling evalexp, since it might be changed by evaluating the - loop body between evalexp calls - -trap.c - - change reset_signal to turn off the SIG_TRAPPED flag for the - given signal, so shell builtins and functions running in command - substitutions don't run the signal handlers (traps are not supposed - to be inherited by command substitutions) - -parse.y - - changed parse_string_to_word_list to turn off alias expansion - while parsing the array assignment - - 12/9 - ---- -alias.c - - fix add_alias so that redefining an alias's value also resets the - EXPANDNEXT flag - - 12/10 - ----- -parse.y - - new function, token_is_assignment, called to check whether the text - before `=' makes up a valid assignment token before trying to parse - a compound assignment statement - - new function, parse_compound_assignment, to parse a compound - assignment statement instead of using parse_matched_pair; handles - comments and error reporting in the parser instead of waiting until - expansion time - - changed parse_compound_assignment and parse_string_to_word_list to - allow reserved words in compound array assignments - -lib/readline/doc/rltech.texinfo - - changed the documentation for rl_callback_read_char and - rl_callback_handler_remove to say what happens to the terminal - settings and what needs to be done to reset them - - 12/11 - ----- -bashline.c - - add emacs_edit_and_execute_command, bound to C-xC-e, like vi-mode - `v' command - - add bindable command name `edit-and-execute-command', bound to - run emacs_edit_and_execute_command() - -lib/glob/strmatch.c - - add support for ksh93-like [:word:] character class (isalnum + `_') - -doc/{bash.1,bashref.texi} - - add note to section describing lists to clarify that a sequence of - one or more newlines may be used to delimit a command, equivalent - to a semicolon - - document new [:word:] pattern matching character class - -doc/bash.1, lib/readline/doc/rluser.texinfo - - document `edit-and-execute-command' and its default emacs-mode - binding - -include/chartypes.h - - add defines for TOCTRL and UNCTRL if they're not already defined - -lib/readline/chardefs.h - - #undef UNCTRL if it's defined to avoid cpp redefinition warnings - -lib/sh/strtrans.c - - add \cX (Control-X) escape for $'...' to ansicstr() - - change ansic_quote() to allocate at least four chars for each char - in the string argument, to account for \0xx octal values - - change ansic_quote() to no longer call sprintf for non-printable - characters; just translate the string to octal directly - -print_cmd.c - - change xtrace_print_word_list to call ansic_quote() if - ansic_shouldquote() indicates that there are nonprinting characters - in a word - -builtins/type.def - - changed deprecated long option parsing to just replace the word - in the list with the equivalent short option (-type -> -t) instead - of removing words from the list - - changed describe_command to take a single flags argument instead - of two int args; changed caller - - type now has two new options: -f suppresses function lookup (like - command), and -P forces a PATH search for the name(s) - -builtins/common.h - - flags for describe_command are here - - changed extern declaration of describe_command - -builtins/command.def - - changed call to describe_command to use flags from common.h, and - the right number of arguments - -doc/{bash.1,bashref.texi} - - documented new -f and -P options to `type' - - 12/12 - ----- -lib/readline/rldefs.h - - fixed prototype for _rl_strnicmp - -execute_cmd.c - - select_query now takes a new argument, an int flag saying whether - or not to print the menu the first time through the loop. An - empty line in response to the prompt will always cause the menu - to be reprinted - - changed execute_select_command to cause select_query to reprint - the menu only if REPLY is set to NULL, if KSH_COMPATIBLE_SELECT - is defined - -config-top.h - - define KSH_COMPATIBLE_SELECT, with a comment about its meaning - -lib/readline/readline.c - - change rl_insert_comment to toggle if given an explicit numeric - argument: if the first characters on the line don't specify a - comment, insert one; if they do, delete the comment text - -doc/bash.1, lib/readline/doc/{readline.3,rluser.texinfo} - - documented new behavior of insert-comment with a numeric argument - - 12/13 - ----- -lib/malloc/watch.c - - new file, implements watchpoint functions - -lib/malloc/watch.h - - new file, define some `events' for watchpoints and extern function - and variable declarations for watchpoint code - -lib/malloc/imalloc.h - - #define MALLOC_WATCH if MALLOC_DEBUG is defined - - add __P define as in include/stdc.h if not already defined - -lib/malloc/malloc.c - - remove __P define, now in imalloc.h - - include watch.h if MALLOC_WATCH is defined - - added calls to _malloc_ckwatch in internal_malloc, internal_free, - and internal_realloc - -include/stdc.h - - augment __P define to allow prototypes if PROTOTYPES is defined - -lib/readline/rlstdc.h - - augment PARAMS define to allow prototypes if PROTOTYPES is defined - -lib/malloc/Makefile.in, Makefile.in - necessary changes to include watch.c in libmalloc - -lib/readline/readline.c - - fix rl_delete_text to make sure that the starting position is >= 0 - - _rl_init_line_state (called by readline via readline_initialize) - now sets rl_mark to 0 - - rl_get_{next,previous}_history set rl_mark to 0 if rl_point is at - the end of the line and rl_end otherwise in emacs mode - -lib/readline/kill.c - - rl_yank_nth_arg_internal and rl_paste_clipboard now set the mark - at point before calling rl_insert_text, like rl_yank - - rl_kill_full_line now resets rl_mark to 0 - - rl_kill_line and rl_backward_kill_line now set rl_mark to the - point after the kill in emacs mode - - rl_kill_word and rl_backward_kill_word now set rl_mark to the - point after the kill in emacs mode - - rl_unix_word_rubout and rl_unix_line_discard now set rl_mark to - the point after the kill in emacs mode - -lib/readline/search.c - - noninc_search saves and restores the mark, since it can be changed - while reading the search string - - noninc_dosearch sets the mark at the end of the line, making the - region bound the `inserted' text since rl_point is set to 0 - - rl_history_search_internal sets the mark at the end of the line, - for the same reason - -lib/readline/isearch.c - - rl_search_history now saves and restores the mark - - if no matching lines are found at all when doing an isearch, leave - point where it was instead of moving it to the end of the line - - 12/17 - ----- -lib/readline/rlmbutil.h - - new file, place for multi-byte character defines and extern - declarations - -lib/readline/{bind.c,readline.c,rlprivate.h} - - new bindable variable, `byte-oriented', tracks value of - rl_byte_oriented variable - -lib/readline/mbutil.c - - new file, with multibyte char utility functions - -lib/readline/{complete,display,readline,util,vi_mode}.c - - new code for multibyte characters, derived from IBM patch - - 12/18 - ----- -lib/sh/tmpfile.c - - include posixtime.h for time() extern declaration - -support/bashversion.c - - include if it's available - -lib/readline/{histexpand,input,isearch,search}.c - - new code for multibyte characters, derived from IBM patch - -lib/readline/readline.h - - include rltypedefs.h - - 12/19 - ----- -lib/readline/complete.c - - slight change to mark-directories code to avoid adding a slash if - point is at the end of the line (rl_line_buffer[rl_point] == '\0') - and the previous character was a slash - - change printable_part to not return empty pathnames, which could - happen when completing filenames and a filename with a trailing - slash was passed as the argument. If the portion following the - trailing slash is NULL, ignore it and look for a previous slash. - If there's no previous slash, just return the filename argument - - new variable, rl_completion_mark_symlink_dirs, mirrors the value - of (user-settable with a variable) _rl_complete_mark_symlink_dirs - but may be modified by application-specific completion functions - when appropriate (set in rl_complete_internal and rl_menu_complete) - -lib/readline/readline.h - - extern declaration for rl_completion_mark_symlink_dirs - -pcomplete.c - - if one of the actions is CA_DIRECTORY, set - rl_completion_mark_symlink_dirs to indicate that we want the - trailing slash (might have to relax this) - -lib/readline/doc/rltech.texinfo - - documented rl_completion_mark_symlink_dirs variable - -lib/readline/doc/rluser.texinfo, doc/bash.1 - - documented the fact that `complete -d' and `complete -o dirnames' - force readline to append a slash to symlinks to directories - -builtins/enable.def - - changed enable_shell_builtin to disallow enabling disabled - builtins in a restricted shell - -doc/{bash.1,bashref.texi} - - documented new enable behavior in restricted shells - -doc/Makefile.in - - new rule to make an `RBASH' file documenting the restrictions - imposed by a restricted shell - -expr.c - - broke the code that evaluates variables and returns results out - of readtok() into a new function: expr_streval() - - expr_streval() now performs the standard unset variable error - behavior if `set -u' has been executed and it's asked to look - up an unset variable - - broke the code that frees up the expression context stack into - a new function: expr_unwind() - -variables.c - - fixed bind_int_variable so it handles array element assignment, - so expressions like `b[7]++' and `b[0] = 42' work right - - new function, get_variable_value, returns the string value of - the SHELL_VAR * passed as an argument - - get_string_value now calls get_variable_value with a non-null - result from find_variable - - 12/20 - ----- -lib/readline/rlmbutil.h, mbutil.c - - combined _rl_find_next_mbchar and _rl_find_next_nonzero_mbchar into - a single function - - combined _rl_find_prev_mbchar and _rl_find_prev_nonzero_mbchar into - a single function - -lib/readline/{display,readline,vi_mode}.c - - changed callers of _rl_find_next_mbchar and - _rl_find_next_nonzero_mbchar - -lib/readline/{complete,display,histexpand,readline,vi_mode}.c - - changed callers of _rl_find_prev_mbchar and - _rl_find_prev_nonzero_mbchar - - 12/20 - ----- -lib/sh/mktime.c - - new file, from glibc/gawk, compiled in if system doesn't have a - working mktime(3) - -lib/sh/strftime.c - - new file, from gawk, compiled in if system doesn't have a - working strftime(3) - -lib/sh/Makefile.in, Makefile.in - - changes for mktime.c, strftime.c - -configure.in - - call AC_FUNC_MKTIME, AC_STRUCT_TM, AC_STRUCT_TIMEZONE - - call AC_REPLACE_FUNC(strftime) - -config.h.in - - add defines for TM_IN_SYS_TIME, HAVE_TZSET, HAVE_TM_ZONE, - HAVE_STRUCT_TM_TM_ZONE, HAVE_STRFTIME - -externs.h - - provide an extern declaration for strftime if HAVE_STRFTIME is - not defined and NEED_STRFTIME_DECL is - -lib/tilde/tilde.h - - header files should not include - -parse.y - - replace code in decode_prompt_string that chops up value returned - by ctime(3) with calls to strftime -- as a result, the expansion - of \@ has changed slightly (since it depends on the locale) - - added new \D{format} prompt string escape; `format' is passed to - strftime(3). Empty format is the same as `%X' (locale-specific - representation of the current time) - - combined cases for '\\', '\a', '\e', and '\r' in same case branch - in decode_prompt_string - -doc/{bash.1,bashref.texi} - - documented new \D{format} prompt string expansion - -builtins/printf.def - - use ISO C PRIdMAX instead of INTMAX_CONV - - pass length of format modifiers to mklong instead of computing it - with strlen() - -lib/sh/{fmtulong,fmtullong}.c - - changes from Paul Eggert to make more general - -arrayfunc.c - - when converting a variable to an array, make sure to unset the - dynamic_value and assign_func members of the struct variable, - since they're not valid anymore - - 12/27 - ----- -configure.in - - use AC_HELP_STRING in AC_ARG_WITH and AC_ARG_ENABLE - - remove AC_ARG_ENABLE for largefile, since AC_SYS_LARGEFILE adds - one - - 1/2/2002 - -------- -{alias,bashline,execute_cmd,general,shell,subst,variables,arrayfunc}.c,general.h - - changed some calls to strchr to calls to xstrchr for multibyte - characters - -include/shmbutil.h - - add extern declaration for xstrchr to avoid including externs.h - where it's not appropriate - -{braces,make_cmd,pathexp,subst,arrayfunc}.c, lib/sh/xstrchr.c - - include shmbutil.h - -{stringlib,subst}.c, {externs,subst}.h - - moved substring() from subst.c to stringlib.c, moved declaration - from subst.h to externs.h - -lib/sh/xmbsrtowcs.c - - new file, replacement function for mbsrtowcs - -lib/sh/Makefile.in - - add entries for xmbsrtowcs.c - -Makefile.in - - add dependencies on shmbutil.h to appropriate object files - -lib/glob/strmatch.c - - break character-class testing out into separate function: - is_cclass, in prep for multibyte changes - -{braces,make_cmd}.c - - changes for multibyte characters - -builtins/printf.def - - changes from Paul Eggert to just use intmax_t everywhere an - int/long/quad is needed and print with "%ld" if the number - fits in a long and %PRIdMAX otherwise - - remove getlong, getulong, getllong, getullong, since they're - no longer needed - - use a new type `floatmax_t' to print floating point numbers, the - widest-available floating point type (like `intmax_t'); new - function `getfloatmax' that calls strtold or strtod as appropriate - - remove getdouble, getldouble, since they're no longer needed - -lib/sh/fmtumax.c - - new file, string-to-[u]intmax_t conversion, just includes - fmtulong.c with the right defines - -Makefile.in, lib/sh/Makefile.in - - additions for fmtumax.c - -bashtypes.h - - include if it's available - -expr.c - - arithmetic is now in intmax_t instead of long - -externs.h - - extern declaration for fmtumax - - change extern declarations for evalexp, itos, inttostr, - uitos, uinttostr since they now return or use intmax_t instead - of long - -{execute_cmd,general,mailcheck,subst,variables}.c, parse.y -{array,general,subst,test,variables}.h -lib/sh/{itos,netopen}.c -builtins/{bashgetopt,common}.c, builtins/common.h -builtins/{break,fc,history,jobs,let,printf,pushd,read,shift,wait}.def - - changes for intmax_t shell arithmetic conversion - -doc/{bashref.texi,bash.1} - - documented long->intmax_t shell arithmetic conversion - -sig.c - - in initialize_terminating_signals, if we've already trapped a - terminating signal, don't reset the signal handler for it - - 1/3 - --- -{arrayfunc,pathexp}.c, parse.y - - changes for multibyte chars - -parse.y, lib/sh/strtrans.c - - moved ansiexpand from parse.y to lib/sh/strtrans.c - -parse.y, locale.c - - moved mk_msgstr and localeexpand from parse.y to locale.c - -parse.y - - new function, yy_input_name, returns name of input file from - bash_input.name - - broke the code that parses ((...)) constructs out of read_token - into a new function, parse_dparen() - -externs.h - - new extern declaration for ansiexpand(), mk_msgstr(), and - localeexpand() - -input.h - - new extern declaration for yy_input_name() - -{error,locale}.c - - use yy_input_name for error and other messages - -execute_cmd.c - - change shell_execve to make sure that the file is executable - before looking at the interpreter to find out why the execve() - failed (avoids misleading error message) - -lib/glob/glob.c - - move code that matches leading `.' and skips those filenames into - a separate function: skipname(), so there can be unibyte and - multibyte versions of that function - - 1/7 - --- -subst.c - - more changes for multibyte characters - -print_cmd.c - - change semicolon() so it doesn't output a `;' immediately after a - newline, since that results in a null command, which is a syntax - error - -variables.c - - fix indirection_level_string to turn off set -x while evaluating - PS4 - - 1/8 - --- -builtins/set.def - - make -o options into one struct, instead of separate structs for - option names corresponding to flags and non-flag option names. - This has the side effect of sorting the option names in output - -lib/glob/glob.c - - new function, mbskipname(), multibyte char version of skipname() - - removed all #ifndef SHELL code, this will never be used outside - the shell - -include/posixdir.h - - move REAL_DIR_ENTRY define here from lib/glob/glob.c - -lib/glob/glob_loop.c - - new file, included in glob.c for unibyte and multibyte versions of - glob_pattern_p - - added some forward static function declarations with prototypes - - more changes for multibyte character handling - -lib/glob/Makefile.in - - make glob.c depend on glob_loop.c - - changes for xmbsrtowcs.[co] - -lib/glob/xmbsrtowcs.c - - moved here from lib/sh, since the matching functions use it, and - libglob.a is linked after libsh.a - - 1/9 - --- -lib/glob/smatch.c - - new file, with strmatch (now xstrmatch) and associated functions, - with changes for multibyte chars - -lib/glob/sm_loop.c - - new file, included by smatch.c, with `generic' versions of matching - functions that are compiled twice: once each for single-byte and - multibyte characters - -lib/glob/strmatch.c - - strip out everything except strmatch(), which either calls fnmatch - (if HAVE_LIBC_FNM_EXTMATCH is defined) or xstrmatch - -lib/glob/collsyms.c - - changes for multibyte chars - -lib/glob/Makefile.in, Makefile.in - - changes for new source files - - 1/10 - ---- -lib/readline/complete.c - - new function, rl_completion_mode (rl_command_func_t *func), returns - the appropriate value to pass to rl_complete_internal depending on - FUNC and the value of `show-all-if-ambiguous'. This allows - application completion functions to present the same interface as - rl_complete - -lib/readline/readline.h - - new extern declaration for rl_completion_mode() - -lib/readline/doc/rltech.texinfo - - documented rl_completion_mode - -lib/readline/readline.[ch] - - bumped the version number to 4.3, changing the relevant cpp defines - -configure.in - - require that an installed readline version be at least readline-4.3 - -bashline.c - - converted bash-specific completion functions to use - rl_completion_mode instead of passing TAB unconditionally - -builtins/bashgetopt.c - - the `#' option specifier now means a required numeric argument, - not an optional one - -builtins/type.def - - when converting [-]-{path,type,all} to -[pta], don't bother - freeing and reallocating the option string; just change opt[1] - and null opt[2] - -lib/sh/snprintf.c - - support %ls/%S and %lc/%C for wide strings and characters, - respectively, if HANDLE_MULTIBYTE is defined - -mailcheck.c - - don't print a message about new mail if the file has not grown, - even if the access time is less than the modification time - - 1/14 - ---- -lib/readline/readline.c - - new function, rl_replace_line, to replace the readline line buffer - with the text supplied as an argument - - new function, rl_replace_from_history, replaces readline line - buffer with text from history entry passed as argument (undocumented, - not in readline.h because it requires a definition of - HIST_ENTRY for the prototype) - -lib/readline/readlne.h - - new extern declaration for rl_replace_line - -lib/readline/doc/rltech.texinfo - - documented rl_replace_line - -lib/readline/{isearch,readline,search}.c - - use rl_replace_line and rl_replace_from_history where appropriate - -lib/readline/readline.c - - broke the code that sets point after moving through the history - (_rl_history_preserve_point and _rl_history_saved_point) out - into a separate function, _rl_history_set_point() - -lib/readline/{complete.c,rlprivate.h} - - find_completion_word -> _rl_find_completion_word - - free_match_list -> _rl_free_match_list - -lib/readline/complete.c - - postprocess_matches and _rl_free_match_list now return immediately - if passed a null match list - -variables.c - - new function, find_local_variable, finds a local variable by name - at the current variable context - - in find_variable_internal, call find_local_variable before searching - any of the temporary environments if variable_context > 0 (meaning - we're in a shell function). This lets a local variable - override a variable whose value was passed in the `function - environment' - - 1/15 - ---- -variables.h, execute_cmd.c - - declare variables describing the temporary environments in - variables.h instead of in C files - -findcmd.c, builtins/setattr.def - - instead of calling find_tempenv_variable, use find_variable_internal - and check whether the returned SHELL_VAR * has the tempvar - attribute - -variables.c - - tentative change to lookup order in find_variable_internal so that - function local variables are found before variables in - function_env when executing a shell function - - change make_local_variable to handle making a local variable when - a variable with the same name already appears in one of the - temporary environments - - broke the body of make_var_array out into a new function: - static char **make_env_array_from_var_list (SHELL_VAR **vars) - - new function, make_var_array_internal, takes a hash table to look - in and a pointer to a mapping function and returns a char ** - environment-style list - - make_var_array now just calls make_var_array_internal - - new mapping function, local_and_exported, returns all local variables - in the current variable context with the export attribute set - - new function, make_local_export_array, returns an environment-style - char ** array of exported local variables in current context - - change environment creation order in maybe_make_export_env to - add variables to the environment in opposite order that - find_variable_internal uses. This means that local variables in - shell functions override variables with the same name in the - function_env - - change make_local_variable to set the initial value of the - variable it creates to NULL to make the `is set' and `is null' - tests that the expansion code does work right - - change make_local_variable to inherit the value of a variable with - the same name from the temporary enviroment - - 1/16 - ---- -Makefile.in - - link bashversion with buildversion.o instead of version.o, for - cross-compiling. version.o is for the target system; - buildversion.o is for the build system - -error.c - - add line numbers to internal_error() messages if the shell is - not interactive and running a shell script or a -c command - - report_error now prints non-zero line numbers for non-interactive - shells - -test.c - - test_syntax_error now calls builtin_error() instead of printing - its own messages - -builtins/common.c - - builtin_error now prints line numbers if a non-interactive shell - is running a shell script or a -c command - -print_cmd.c - - in cprintf, remove free_argp, since it's not used - -builtins/history.def - - make `history -n' increment the number of history lines in this - session by the number of lines read from the history file - -arrayfunc.c - - fix array_value_internal to expand the subscript even if the - variable is unset, so side effects produced by the arithmetic - evaluation will take place - -lib/readline/doc/{rluser,rltech}.texinfo - - some fixes for printing in @smallbook format from Brian - Youmans - - 1/17 - ---- -jobs.h - - new PRUNNING, PSTOPPED, PDEADPROC defines for PROCESSes, analogous - to RUNNING, STOPPED, and DEADJOB defines for jobs - -jobs.c - - use PS_RUNNING, PS_DONE, PS_STOPPED values for `running' field - of a PROCESS - - find_pipeline and find_job now take an additional flags argument - that, if non-zero, means to find only running processes; changed - all callers - - changed calls to find_pipeline and find_job made from waitchld - to find only running processes - - find_pipeline takes a third argument: an int *. If it looks in - the jobs list to find the pid, and the arg is non-null, it passes - the job index back to the caller. Used to avoid calls to - find_pipeline immediately followed by find_job with the same PID - -nojobs.c - - a couple of changes to make sure that set_pid_status is never - called with a pid argument of 0 or -1 - -trap.c - - change trap_handler to longjmp to wait_intr_buf (set by wait_builtin) - if a signal is received for which a trap has been set during - execution of the wait builtin (need to include builtins.h and - builtins/builtext.h and declare some extern variables for the - right things to check) - - new variable to keep track of which signal caused the longjmp to - wait_intr_buf, set by trap_handler (wait_signal_received) - -builtins/wait.def - - set the return value of wait when a longjmp(wait_intr_buf, 1) is - done to 128 + wait_signal_received - -{jobs,nojobs}.c - - set wait_signal_received to SIGINT in wait_sigint_handler before - the longjmp(wait_intr_buf, 1) - - 1/18 - ---- -bashline.c - - turn off rl_filename_completion_desired when completing a command - name with a single match only if the first char of that match is - not a `/' - - if there are multiple identical matches for a command name in - attempt_shell_completion, turn off rl_filename_completion_desired - if the first char is not a `/' to avoid readline appending a - slash if there's a directory with the same name in the current - directory - - 1/22 - ---- -lib/readline/complete.c - - new variable, _rl_page_completions, to control whether we want to - run the internal pager when listing completions (defaults to 1) - -lib/readline/rlprivate.h - - extern declaration for _rl_page_completions - -lib/readline/bind.c - - new bindable variable, `page-completions', controls value of - _rl_page_completions - -lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 - - documented `page-completions' variable - -Makefile.in - - use $(INSTALL_SCRIPT) instead of $(INSTALL_PROGRAM) to install - `bashbug' - -aclocal.m4 - - fix small quoting problem in RL_LIB_READLINE_VERSION macro - -lib/readline/terminal.c - - fetch and save terminal's `vs' and `ve' cursor control attributes - - fetch and save terminal's `kI' attribute (string sent by Insert) - - new function, _rl_set_cursor, sets cursor to normal (insert mode) - or very visible (overwrite mode) - -lib/readline/readline.c - - new global variable, rl_insert_mode - - new function to toggle overwrite mode, rl_overwrite_mode - - each new line starts in insert mode - - switching to vi mode or emacs mode resets to insert mode - - reset cursor to normal before returning line - - _rl_replace_text now returns the number of characters inserted, - the return value from rl_insert_text - - new function, _rl_insert_or_replace_text (const char *string, int insert), - either inserts STRING or replaces the number of chars in STRING - with STRING starting at rl_point, depending on value of INSERT - - renamed rl_insert to _rl_insert_char, rl_insert just calls - _rl_insert_char with the same arguments when in insert mode - - new function, _rl_overwrite_char, handles self-insert in overwrite - mode. Does multibyte chars by reading an entire multibyte character - before entering overwrite loop - - new function, _rl_overwrite_rubout, handles RUBOUT when in - overwrite mode, called from rl_rubout - - new function, _rl_rubout_char, old body of rl_rubout; rl_rubout - calls this when not in overwrite mode - -lib/readline/readline.h - - extern declarations for rl_insert_mode and rl_overwrite_mode() - -lib/readline/rldefs.h - - define constants for values of rl_insert_mode - -lib/readline/rlprivate.h - - extern declarations for _rl_set_cursor and _rl_set_insert_mode - - change type of _rl_replace_text to return int - - extern declarations for _rl_insert_char, _rl_rubout_char - -lib/readline/funmap.c - - new bindable name `overwrite-mode', bound to rl_overwrite_mode - -lib/readline/rlconf.h - - define CURSOR_MODE if you want the cursor to show insert or - overwrite mode (only available if both `vs' and `ve' capabilities - are present) - -lib/readline/{complete,parens,readline,search,vi_mode}.c - - change calls to rl_insert to _rl_insert_char - -lib/readline/{readline,search}.c - - change calls to rl_rubout to _rl_rubout_char to avoid overwrite - mode problems - -lib/readline/vi_mode.c - - fix rl_vi_overstrike to just call _rl_overwrite_char, which - handles multibyte chars - -lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 - - document new `overwrite-mode' command - - 1/23 - ---- -lib/readline/readline.c - - return 0 immediately from rl_insert_text if the string to insert - is NULL or "" - -bashline.c - - if a numeric argument is given to one of the bash-specific glob - pattern completion functions (including TAB), append a `*' to - the word before generating matches - - in attempt_shell_completion, when doing glob completion, only - set the match list to NULL if rl_completion_type == TAB and - there is more than one completion. This permits listing completions - with double tabs and displaying ambiguous completions - - new function, bash_glob_complete_word, appends a `*' to the word - to be completed and then globs it. It uses a new filename - quoting function (bash_glob_quote_filename) to avoid quoting - globbing characters in the filename if there are no matches or - multiple matches - -lib/readline/complete.c - - set completion_changed_buffer to 0 in rl_complete_internal if - no matches were produced by the completion generator function - - new variable, rl_completion_suppress_append, suppresses appending - of rl_completion_append_character. Settable by application - completion functions, always 0 when application completion - functions are called (set to 0 by rl_complete_internal and - rl_menu_complete) - - broke the code that assigns default values to readline completion - variables out of rl_complete_internal and rl_menu_complete into - a new function, set_completion_defaults (int what_to_do) - -lib/readline/readline.h - - extern declaration for rl_completion_suppress_append - -lib/readline/doc/rluser.texinfo, doc/bash.1 - - documented behavior of glob-expand-word and glob-list-expansions - when supplied a numeric argument - - documented glob-complete-word - -lib/readline/doc/rltech.texinfo - - documented rl_completion_suppress_append - - 1/24 - ---- -lib/readline/text.c - - new file, text and character handling functions from readline.c - -lib/readline/misc.c - - new file, miscellanous bindable functions and their supporting - code from readline.c - -Makefile.in, lib/readline/Makefile.in - - changes for text.c, misc.c - -lib/readline/bind.c - - change ISKMAP case of rl_invoking_keyseqs_in_map to output - ESC as "\M-" instead of "\e" -- it's closer to the documentation - - change _rl_get_keyname to output ESC as \e instead of \C-[ - (it's easier to understand) - -pcomplete.h - - new flag, COPT_NOSPACE - -builtins/complete.def - - new `-o nospace' option for complete and compgen (though it doesn't - really do anything for compgen, since that doesn't hand anything - off to readline) - -bashline.c - - if a programmable completion specifies COPT_NOSPACE, set - rl_completion_suppress_append = 1 - -lib/readline/doc/rluser.texinfo - - documented new `-o nospace' option to complete and compgen - -doc/{bash.1,bashref.texi} - - documented $'\cX' escape sequence (forgot to before) - - 1/28 - ---- -variables.c - - make_new_variable now takes the HASH_TABLE * as its second - argument; changed callers - - new function, bind_variable_in_table, takes the HASH_TABLE * as - its third paramter; bind_variable calls bind_variable_in_table - with shell_variables as third argument - -variables.h - - new struct var_context, variable context (per-scope -- global, - function local, etc.) - -variables.[ch],builtins/common.[ch] - - moved functions that push and pop a variable context from - builtins/common.c to variables.c; move extern function - declarations to variables.h - - new function, all_local_variables - - variable_in_context is now static, used only by all_local_variables - -variables.[ch],execute_cmd.c - - push_context now takes the function name as an argument for - future use - - push_context takes an indication of whether or not the function is - executing in a subshell and saves the positional parameters only - if not in a subshell - - new functions for managing a stack of variable contexts and - scopes: new_var_context, dispose_var_context, push_var_context, - pop_var_context, push_scope, pop_scope - -builtins/declare.def - - call all_local_variables instead of map_over (...) in declare_internal - - don't call make_local_variable if we're looking at functions - ((flags_on & att_function) != 0), since it's wasted - - make sure VAR is set to NULL if check for variable_context fails - and we didn't just create or fetch a local variable in - declare_internal - - in non-function branch of declare_internal, only call find_variable - if VAR is NULL -- if it's not null, we just created or fetched a - local variable and don't need to do it again - - 1/29 - ---- -variables.[ch] - - the temporary environments (temporary_env, builtin_env, function_env) - are now HASH_TABLEs instead of argv-style arrays of strings (this - is an intermediate step on the way to the new lcc-inspired symbol - table scope structure) - - new internal attribute for variables: att_propagate. This means - to propagate the value out of the temporary environment up the - (for now implicit) chain of variable scopes when the containing - temporary environment is deleted - -variables.c - - assign_in_env now adds to the HASH_TABLE temporary_env instead - of making environment-style strings in an array of strings - - changed the way the temporary environments are merged into the - shell variable table to account for the new HASH_TABLE temp - environments - - changed the way the export environment is created due to the new - structure of the temporary environments - - new function, bind_variable_internal (name, value, table), binds - NAME to have VALUE in TABLE without searching the temporary - environments - - removed: shell_var_from_env_string, bind_name_in_env_array - - variable_in_context now checks the att_local attribute and makes - sure the variable is not invisible - - local_and_exported now makes sure the variable is not invisible - -execute_cmd.c - - we no longer need to copy the temporary environment to function_env - or builtin_env, we can simply use variable assignments - -{findcmd,subst,variables}.c, builtins/{declare,setattr}.def - - since variables from the temporary environments are no longer turned - into SHELL_VARs on the fly, don't dispose the SHELL_VAR returned - by find_variable or find_variable_internal - - need to savestring() the value returned by find_variable if it has - the tempvar attribute before calling bind_variable on it, because - bind_variable will search and bind into the temporary environments - and will free the old value before binding the new. For temporary - environments, these two pointers will be the same, and - bind_tempenv_variable will end up using freed memory - -builtins/{declare,setattr}.def - - set the att_propagate attribute when exporting or making readonly - variables from the temp environment (i.e., `var=value declare -x var' - or `var=value export var' sets the propagate attribute on the entry - for `var' in the temporary environment HASH_TABLE) - -lib/readline/isearch.c - - ^W when reading isearch string yanks the current word out of the - current line into the search string, skipping the portion already - matched - - ^Y when reading isearch string yanks the rest of the current line - into the search string, skipping the portion already matched - - 1/30 - ---- -{print_cmd,variables}.c - - moved indirection_level_string() from variables.c to print_cmd.c - -{externs,variables}.h - - moved extern declaration of indirection_level_string to externs.h - -{general,variables}.c - - moved assignment() from variables.c to general.c - -{general,variables}.h - - moved extern declaration of assignment() to general.h - -{externs,input}.h - - moved extern declaration of decode_prompt_string to externs.h - -print_cmd.c - - include flags.h, don't include stdc.h - -variables.c - - moved some functions around to group functions better - - changed new_shell_variable to explicitly initialize each member - of the created struct variable instead of calling bzero() - - make_new_variable now just calls new_shell_variable instead - of duplicating what it does - - removed some code in bind_function that duplicated what - new_variable does on the newly-created SHELL_VAR - - since there are no local function variables (functions are always - made at the global scope), kill_all_local_variables() doesn't - need to consider functions - - 1/31 - ---- -variables.c - - sort the array of special variables - - short-circuit the search in stupidly_hack_special_variables if - the passed name can't be found in the rest of the array - (that is, if name[0] < special_vars[i].name[0]) - -lib/readline/history.c - - unstifle_history() was returning values exactly opposite of - the documentation - -lib/readline/doc/{hsuser.texinfo,history.3} - - clarified the unstifle_history() documentation a little - - 2/4 - --- -variables.c - - in bind_variable, don't call bind_tempenv_variable after a - find_tempenv_variable succeeds -- just change the value inline. - There's no reason to look it up twice - - change makunbound to only call stupidly_hack_special_variables - if we're not unsetting a function - -variables.[ch] - - new function, unbind_function, like makunbound but doesn't mess - with previous contexts or calling stupidly_hack_special_variables - -builtins/set.def - - change unset_builtin to call either unbind_func or unbind_variable - -builtins/getopts.def - - call unbind_variable(name) instead of makunbound(name, shell_variables) - - 2/5 - --- -lib/glob/sm_loop.c - - use malloc instead of xmalloc in BRACKMATCH and handle failures - -error.c - - add extern declaration of executing_line_number with prototype, - since execute_cmd.h can't be included without including other - files - -lib/readline/parens.c - - include - -lib/malloc/stats.c - - include - - add extern declaration of malloc_free_blocks() with prototype - -pathexp.c - - added some forward declarations with prototypes for static functions - -lib/readline/rlprivate.h - - removed declarations of rl_untranslate_keyseq, rl_discard_argument, - rl_stop_output, rl_alphabetic since they appear in readline.h - - 2/6 - --- -{arrayfunc,execute_cmd,pcomplete,shell}.c - - change calls to makunbound(name, shell_variables) to - unbind_variable (name) - - 2/7 - --- -builtins/getopt.c - - don't defer incrementing of OPTIND when an invalid option is - encountered until the next call to sh_getopt() -- what if OPTIND - is reset before that next call? This means that OPTIND is always - incremented to the next option to be handled when an option is - returned, whether it's valid or not. This is what POSIX-2002 - says to do. - -syntax.h - - new #define, CSUBSTOP - -mksyntax.c - - add "-=?+" with value CSUBSTOP to the syntax table. These are the - valid expansion operators OP in ${param[:]OPword} - -subst.c - - use table lookup for CSUBSTOP in VALID_PARAM_EXPAND_CHAR - - new flags for the string extraction functions: EX_NOALLOC. This - indicates that the functions are being used only to skip over - strings and the result won't be used, so the substring shouldn't - be allocated, copied, and freed - - new flag for string_extract: EX_VARNAME. This serves the same - purpose as the old `varname' parameter. parameter_brace_expand() - changed appropriately - - extract_delimited_string and extract_dollar_brace_string now take - an additional `flags' argument, which may include EX_NOALLOC - - changed callers of extract_delimited_string and - extract_dollar_brace_string appropriately - - string_extract now understands EX_NOALLOC; callers changed - - some smaller code cleanups - - converted char_is_quoted(), unclosed_pair(), and skip_to_delim() - to understand multibyte characters - - 2/11 - ---- -variables.[ch] - - moved to a symbol organization inspired by lcc. The basic structure - is no longer a HASH_TABLE, but a VAR_CONTEXT, which includes a hash - table as one of its members. VAR_CONTEXTs are linked together to do - variable scoping. One nice thing about this is that the entire - symbol table doesn't need to be searched at function scope exit to - remove local variables. Fixes problems with only one instance of - builtin_env and function_env, even though it really is a stack - - shell_variables is now a VAR_CONTEXT *, with a global_variables - variable that points to the bottom of the stack for fast access - - function-scope local variables (assignments specified on the command - line before a function call) and function-local variables (declared - with the `local' builtin) have been unified in the same variable - context, replacing function_env - - assignment statements preceding the `.' and `eval' builtins are now - a separate variable scope VAR_CONTEXT, replacing builtin_env - - temporary_env (a HASH_TABLE) is now the only separate environment - - changes to export environment creation, variable binding, variable - lookup, local variable propagation all changed to work with the - new symbol table/scope structure - - a SHELL_VAR no longer has a `prev_context' member; it's not needed - -execute_cmd.c - - changes to push_context calls to include any temporary variables in - temporary_env; pop_context takes care of propagating any temporary - variables if necessary - - calls to push_scope if `eval' or `.' is called with a list of - preceding variable assignments, and pop_scope called at end of - builtin's execution. pop_scope takes care of merging temporary - variables into the shell environment when appropriate - -builtins/{setattr,declare}.def - - changes to account for variable assignments preceding `local', - `export', `readonly', `declare', etc. to work with the new - variable scoping implementation - -shell.c - - since shell_variables is now a VAR_CONTEXT, call - delete_all_contexts() when the shell is reinitializing instead of - delete_all_variables() - -builtins/common.c - - new function, get_job_by_name(), used by execute_simple_command() - for the `auto_resume' stuff and get_job_spec() - -builtins/common.h - - new set of #defined constants for flags argument to - get_job_by_name() - - 2/12 - ---- -command.h - - new redirection operator: r_reading_string for `here strings' - -parse.y - - new token, LESS_LESS_LESS, for new redirection `here string' - operator: [N]<<< word - - recognize LESS_LESS_LESS and create the appropriate redirection - -{dispose_cmd,copy_cmd,make_cmd,print_cmd}.c - - recognize r_reading_string and do the right thing (dispose_redirects, - copy_redirect, print_redirection, and make_redirection, respectively) - -redir.c - - here_document_to_fd now takes the redirection operator as its - second argument - - new function, write_here_string, expands a here string and writes it - to the here document file descriptor - - here_document_to_fd calls write_here_string for r_reading_string - operator - - handle r_reading_string in do_redirection_internal() and - stdin_redirection() - - 2/18 - ---- -doc/{bash.1,bashref.texi} - - documented here strings - -{configure,Makefile}.in - - bumped version number up to bash-2.05b and the release status - to alpha1 - -expr.c - - make expr_streval understand that variables with the `invisible' - attribute are really unset, and accessing such a variable when - `set -u' is set should be an error - -variables.h - - new accessor macros: var_isset(var) and var_isnull(var), test - whether var->value is NULL - -{eval,subst,variables}.c, builtins/{declare,setattr}.def - - be more consistent about using value_cell(var) instead of - directly referencing var->value - - use var_isset and var_isnull where appropriate - -builtins/help.def - - augmented a couple of help strings with pointers to `info' and - `man -k' - - 2/14 - ---- -variables.h - - new macros to use when setting variable values directly instead of - through bind_variable and its siblings - -{arrayfunc,variables}.c - - use var_setarray and other lvalue macros instead of assigning to - var->value directly - -builtins/setattr.def - - change show_var_attributes to show function definitions separately - from function attributes. This allows the output of `declare -f' - (with other flags), `export -f', and `readonly -f' to be reused as - shell input, instead of the old - - declare -f[flags] func() - { - foo - } - - which has syntax errors. When in posix mode, `export -fp' and - `readonly -fp' still don't print function definitions - - 2/16 - ---- -parse.y - - comment out calls to discard_parser_constructs; no need to call - empty functions - - 2/18 - ---- -lib/sh/memset.c - - replacement function for memset(3) - -lib/sh/Makefile.in, Makefile.in - - additions for memset.c - -configure.in,config.h.in - - check for memset, define HAVE_MEMSET if found, add memset.o to - LIBOBJS if not - -lib/malloc/malloc.c - - removed zmemset(), replaced with calls to memset(3) - -{subst,execute_cmd,lib/sh/netopen}.c - - replaced calls to bzero with calls to memset - -subst.c - - word_split() now takes a second argument: the value of $IFS, so - it doesn't have to look up IFS every time - - word_list_split() now calls getifs() and passes the result to - each call to word_split() as its second arg - - do a quick scan for CTLNUL in remove_quoted_nulls before allocating - new string, copying old string to it, copying over original string - and freeing new string - -eval.c - - don't bother calling dispose_used_env_vars if temporary_env is NULL - -execute_cmd.c - - fix fix_assignment_words to only look up the builtin corresponding - to the first word if one of the words in the list is marked as - W_ASSIGNMENT - -hashlib.c - - renamed hash_string to hash_bucket, which better reflects what it - does - - extracted the portion of hash_bucket that computes the hash out - into a new hash_string() - - made new body of hash_bucket into a macro HASH_BUCKET; function - just calls the macro - - calls to hash_bucket in this file now call HASH_BUCKET macro - - in add_hash_item, just add a new item at the front of the appropriate - bucket list instead of at the end - -hashcmd.h - - reduced FILENAME_HASH_BUCKETS to 53 from 107 - - 2/19 - ---- -hashlib.[ch] - - find_hash_item, remove_hash_item, add_hash_item all take a new - third `flags' argument - - add_hash_item doesn't call find_hash_item if HASH_NOSRCH passed in - flags arg - - find_hash_item will create a new hash table entry if HASH_CREATE is - passed in flags arg - - new function, hash_walk, takes a pointer to a function and a table - and calls the function for each item in the table. If the function - returns < 0, the walk is terminated - - fixed flush_hash_table to set table->nentries to 0 after freeing - all entries - - BUCKET_CONTENTS now has a new `khash' member, what key hashes to; - set by HASH_BUCKET macro (which calls hash_string), assigned in - find_hash_item (HASH_CREATE) and add_hash_item - - find_hash_item and remove_hash_item check `khash' against the - hash of the string argument before calling strcmp - -{alias,hashlib,hashcmd,pcomplib,variables}.c - - changed all calls to {find,remove,add}_hash_item - -builtins/hash.def - - return immediately from print_hashed_commands if there are no - entries in the hash table (this eliminates need for `any_printed' - variable) - - change print_hashed_commands to use hash_walk - -alias.c - - short-circuit all_aliases and map_over_aliases if - HASH_ENTRIES(aliases) == 0 - - simplify map_over_aliases by just allocating enough room in the - returned list for all entries in the aliases hash table, instead - of doing the check and xrealloc - - add_alias now calls add_hash_item with HASH_NOSRCH argument - -pcomplete.h - - sh_csprint_func_t is no more; use hash_wfunc instead - -pcomplib.c - - short-circuit print_all_compspecs if HASH_ENTRIES(prog_completes) - is 0 - - print_all_compspecs now takes a `hash_wfunc *' argument - - print_all_compspecs now just calls hash_walk - -builtins/complete.def - - new function, print_compitem, takes a BUCKET_CONTENTS *, extracts - the right info, and calls print_one_completion - -variables.c - - short-circuit map_over_funcs if HASH_ENTRIES(shell_functions) == 0 - - short-circuit flatten if the passed table has no entries - - bind_variable_internal takes a new fourth argument: `hflags', - to pass to hash table functions - - make_new_variable now passes HASH_NOSRCH flag to add_hash_item - - set_if_not now calls bind_variable_internal and passes - HASH_NOSRCH as flags argument - - bind_function now calls add_hash_item with HASH_NOSRCH argument - - fixed make_local_variable: old_var == 0 && was_tmpvar can never - be true - - if we didn't find an old variable in make_local_variable, call - bind_variable_internal with HASH_NOSRCH argument - - fix push_temp_var to reset variable context to 0 if binding into - global_variables->table - -parse.y - - fix to parse_compound_assignment to avoid core dumps on empty - compound array assignments - -subst.c - - getifs() is now global so read_builtin can call it - -subst.h - - extern declaration for getifs() - - 2/20 - ---- -hashlib.c - - changed hash_string to use a better hash function - - changed HASH_BUCKET to use masking rather than modulus to hash a - string to a bucket -- HASH TABLES MUST NOW BE SIZED BY POWERS - OF TWO - -hashlib.h - - DEFAULT_HASH_BUCKETS is now 64 - -hashcmd.h - - FILENAME_HASH_BUCKETS is now 64 - -pcomplib.c - - COMPLETE_HASH_BUCKETS is now 32 - -variables.c - - TEMPENV_HASH_BUCKETS is now 4 - -alias.c - - new define, ALIAS_HASH_BUCKETS, set to 16, used to size alias table - -hashlib.c - - removed initialize_hash_table; folded code into make_hash_table - - fixed copy_bucket_array to copy the `khash' member of an item - - renamed functions to be more systematic and easier for me: - make_hash_table -> hash_create - hash_table_nentries -> hash_size - copy_hash_table -> hash_copy - find_hash_item -> hash_search - remove_hash_item -> hash_remove - add_hash_item -> hash_insert - flush_hash_table -> hash_flush - dispose_hash_table -> hash_dispose - print_table_stats -> hash_pstats - get_hash_bucket -> hash_items - - changed hash_search to short-circuit if table->nentries == 0 and - HASH_CREATE has not been passed in the flags argument - -{alias,variables,hashcmd,pcomplib}.c - - renamed calls to all renamed functions from hashlib.c - -builtins/kill.def - - don't drop a leading `-' in a pid argument - - call kill_pid with an explicit third argument of 1 if the pid - argument to kill is < -1, rather than rely on the behavior of - kill(2) - - 2/21 - ---- -subst.c - - quoted_strchr is no longer declared `inline' - - skip_double_quoted is no longer declared `inline' - - string_extract_double_quoted is no longer declared `inline' - -lib/readline/input.c - - rl_gather_tyi is now an `int' valued function; returns the number - of characters read (0 or 1) or -1 on error - - if rl_gather_tyi() returns -1 to rl_read_key(), set rl_done to 1 - and return a newline; something is wrong with the input fd - - 2/25 - ---- -variables.[ch] - - IFS is now a special variable - - new special var function, sv_ifs(), called when IFS is set or unset - - call setifs() when IFS is first set in initialize_shell_variables - - call setifs() from make_local_variable and assign_in_env if - appropriate - - if assign_in_env() is called with a var assignment like `VAR=', - make the value in the new SHELL_VAR created be "" like - do_assignment_internal does, since certain parts of the shell use - a NULL value as evidence that the variable is unset (though - attributes may have been assigned) - - if push_temp_var pushes something up to the global_variables table, - make sure that the context is set to 0 - - new function dispose_temporary_env, called by both - dispose_used_env_vars and merge_temporary_env with different `free - func' function pointers; calls sv_ifs after disposing the temporary - environment - - push_exported_var now calls bind_variable_internal instead of - bind_variable - - pop_scope and pop_context now call sv_ifs - -subst.[ch] - - new global variables used to keep track of IFS state, to avoid - having to call find_variable("IFS") all the time: - - ifs_var the SHELL_VAR for IFS - ifs_value ifs_var ? value_cell (ifs_var) : " \t\n" - ifs_cmap bitmap of characters in ifs_value - ifs_firstc first character in ifs_value - - - new function setifs(), sets the aforementioned ifs variables each - time IFS is set or unset, and at nested scope exit - - instead of calling getifs() from inside subst.c, use ifs_value - - getifs() now just returns ifs_value - - use ifs_firstc in string_list_dollar_star() - - only call member() in issep() if separators is more than one char - - don't cache a bitmap every time expand_word_internal() is called; - use ifs_cmap instead - - new macro, isifs(c), checks whether C is in ifs_cmap - -builtins/read.def - - use issep() and isifs() macros instead of looking at $IFS directly - -syntax.h - - make sure macros that access sh_syntaxtab cast the argument to - `unsigned char' before array access - - new macros: issyntype(c, type) and notsyntype(c, type), check - sh_syntaxtab[c] for a particular flag value `type' - - 2/26 - ---- -hashlib.h - - the `data' member of a `BUCKET_CONTENTS' is now a PTR_T - -{hashlib,alias,variables,hashcmd,pcomplib}.c - - removed some casts when assigning to and using `data' member of a - `BUCKET_CONTENTS' - -subst.c - - in split_at_delims, call make_word_list instead of allocating and - initializing a WORD_LIST * directly - -make_cmd.[ch] - - add_string_to_list is now just a macro that calls make_word_list - - make_simple_command now calls make_word_list instead of allocating - a WORD_LIST * directly - - 2/27 - ---- -copy_cmd.c - - copy_word now calls make_bare_word to allocate the copy - - copy_word_list now calls make_word_list to allocate the copy - -shell.h - - include `ocache.h' for simple object caching - - call cmd_init() to initialize the WORD_DESC and WORD_LIST object - caches - -{make,dispose}_cmd.c - - allocate WORD_DESC * and WORD_LIST * vars from their respective - ocaches, and return them to the cache when disposing - -jobs.c - - renamed old `waiting_for_job' variable to `queue_sigchld', which - better reflects its intent: sigchld_handler does not call waitchld - if `queue_sigchld' is non-zero, it simply increments the count of - waiting children - - cleanup_dead_jobs now just sets and clears queue_sigchld instead of - blocking and unblocking SIGCHLD; it calls waitchld at the end if - `sigchld' is non-zero, but that's not really necessary - - in setjstatus, only call xrealloc if `statsize' is less than the - number of processes passed -- no reason to do it if they're the - same - - 2/28 - ---- -sig.[ch] - - reinitialize_signals is no more; initialize_signals takes an - argument saying whether or not we are reinitializing - -builtins/exec.def - - reinitialize_signals() -> initialize_signals(1) - -test.c - - fix filecomp() to work right when one file has a non-positive - timestamp and the other file does not exist - -doc/{bash.1,bashref.texi} - - document what happens for test's -nt and -ot operators when one - file operand exists and the other does not - -jobs.c - - if we haven't messed with SIGTTOU, just manipulate queue_sigchld - in notify_of_job_status instead of calling sigprocmask() - - list_one_job now calls pretty_print_job directly instead of going - through print_job - - pretty_print_job now must be called with SIGCHLD blocked or held - instead of blocking SIGCHLD itself - - changed start_job so that it doesn't call UNBLOCK_CHILD and then - immediately call BLOCK_CHILD again (explicitly or via last_pid()), - call find_last_pid instead of last_pid and then UNBLOCK_CHILD - - changed wait_for_job the same way - - find_last_pid now takes a second argument: block; uses BLOCK_CHILD - if `block' is 1, not otherwise. Changed existing calls: - find_last_pid(j) -> find_last_pid(j, 0) - last_pid(j) -> find_last_pid(j, 1) - `last_pid()' is now gone - - rewrote wait_for_background_pids(); it was a little strange - -copy_cmd.c - - copy_if_command: don't copy null false_case commands - - copy_simple_command: don't copy a null redirection list - -subst.c - - in get_word_from_string and list_string, just check for " \t\n" - directly rather than calling strcmp - - in get_word_from_string and strip_trailing_ifs_whitespace, use - isifs() instead of issep(), since they're never called with - separators != $IFS - - change issep() to call isifs if separators is longer than one - character, since it's never called with anything but "", " ", - or $IFS - - 3/1 - --- -sig.h - - enclose the BLOCK_SIGNAL macro in a do {...} while (0) loop, at it - should have been all along - -lib/readline/doc/rltech.texinfo - - document that readline defaults to stdin/stdout if rl_instream/ - rl_outstream are NULL - -lib/readline/terminal.c - - if an application is using a custom redisplay function, - rl_resize_terminal just calls rl_forced_update_display to tell - (*rl_redisplay_func) to update the display, otherwise call - _rl_redisplay_after_sigwinch - -lib/readline/readline.c - - change readline_internal_setup() so the change to vi insertion mode - happens even if readline_echoing_p is 0 - - don't print the prompt to rl_outstream in readline_internal_setup - if we're not echoing and the caller has defined a custom redisplay - function -- let the redisplay function deal with it - -configure.in - - new option: --enable-mem-scramble, controls memory scrambling on - free() (on by default; only affects use of bash malloc) - -config.h.in - - new option MEMSCRAMBLE, controlled by --enable-mem-scramble - - 3/5 - --- -parse.y - - added ksh-like behavior of [...] to read_token_word: if a `[' is - seen in an assignment context and the previous characters in the - token form a valid identifier, parse the [...] with - parse_matched_pair to allow spaces (and newlines) in the subscript - -bashline.c - - new function bash_servicename_completion_function, for completing - service names from /etc/services - -bashline.h - - new extern declaration for bash_servicename_completion_function - -builtins/complete.def - - allow new `-s/-A service' option to complete and compgen builtins - -pcomplete.h - - new CA_SERVICE define, new ITEMLIST variable it_services - -pcomplete.c - - add callback to bash_servicename_completion_function to generate - list of matching service names for completion - -doc/bash.1,lib/readline/doc/rluser.texinfo - - documented new `-s/-A service' option to complete and compgen - - 3/6 - --- -builtins/read.def - - change hard-coded `0' to new variable `fd' (initially 0) in - preparation for adding `-u fd' option - -bashline.c - - bash_directory_completion_hook calls expand_prompt_string instead - of expand_string (it does the right thing). This keeps expansion - errors from causing a longjmp, which shouldn't happen because of - completion - - command_subst_completion_function was augmented very slightly to - do filename completion on a non-command-word in a command - substitution - - command_subst_completion_function now skips over the lcd that - rl_completion_matches puts in matches[0] if there is more than - one possible completion - - 3/7 - --- -builtins/read.def - - only add the unwind_protect to free `rlbuf' if `edit' is non-zero, - since we won't be using readline otherwise - -lib/sh/zread.c - - renamed zread1 -> zreadintr - -redir.c - - small change to redirection_error() to make a slightly better - guess about the invalid file descriptor if the redirection op is - r_duplicating_input or r_duplicating_output - -include/stdc.h - - new macro, SH_VA_START, to encapsulate the difference between - stdarg va_start and varargs va_start - -{error,pcomplete,print_cmd}.c,builtins/common.c,lib/sh/snprintf.c - - use SH_VA_START - - 3/8 - --- -builtins/read.def - - support for the ksh-like `-u fd' option - -general.c - - new function sh_validfd(fd), returns 1 if fd is a valid open file - descriptor - -general.h - - extern decl for sh_validfd - -bashline.c - - don't call posix_readline_initialize() from initialize_readline(); - sv_strict_posix() should already have taken care of it - - 3/11 - ---- -{error,pcomplete,print_cmd}.c, builtins/common.c - - removed non-varargs versions of functions - -builtins/printf.def - - if the string argument to %q has non-printing characters, call - ansic_quote to quote it rather than sh_backslash_quote - -variables.h - - new attribute: att_trace (and corresponding trace_p() macro). - Functions with this attribute will inherit the DEBUG trap. - Currently ignored for variables - -builtins/declare.def - - new `-t' option to declare/typeset toggle the `att_trace' attribute - -builtins/setattr.def - - check for att_trace and output `-t' flag in show_var_attributes - -execute_cmd.c - - if a function is being traced (it has the `-t' attribute set), - don't turn off the DEBUG trap when it executes - -doc/{bash.1,bashref.texi} - - document the new `-t' option to declare/typeset - - 3/12 - ---- -execute_cmd.c - - don't execute the debug trap in the `cm_simple:' case of - execute_command_internal; run it in execute_simple_command so we - get the line number information right when executing in a shell - function - - run a DEBUG trap before executing ((...)) arithmetic commands, - like ksh93 - - run a DEBUG trap before executing [[...]] conditional commands, - like ksh93 - -eval.c - - add a static forward declaration for alrm_catcher() - -general.c - - add static forward declarations for bash_special_tilde_expansions, - unquoted_tilde_word, initialize_group_array - -variables.h - - add extern declarations for sh_get_env_value, map_over_funcs, - local_exported_variables - -variables.c - - add static forward declarations for dispose_temporary_env, - make_func_export_array - -bashhist.c - - add static forward declaration for check_history_control - -configure.in - - add a call to AC_CHECK_DECLS for strcpy - -config.h.in - - add placeholder for HAVE_DECL_STRCPY define, set by configure - -general.h - - don't declare strcpy if HAVE_DECL_STRCPY is defined with a non-zero - value - -sig.h - - add prototype to typedef of SigHandler - -lib/readline/histlib.h - - removed extern declaration of strcpy() - - include string.h/strings.h directly in histlib.h instead of source - files - -lib/readline/{histexpand,histfile,history,histsearch}.c - - don't include string.h/strings.h now that histlib.h includes it - -lib/tilde/tilde.c - - removed extern declaration of strcpy(), rely on string.h/strings.h - -command.h - - four new redirection types: r_move_input, r_move_output, - r_move_input_word, r_move_output_word, for - [N]<&word- and [N]>&word- from ksh93 - -print_cmd.c - - changes to print r_move_input[_word] and r_move_output[_word] - -copy_cmd.c - - changes to copy r_move_input[_word] and r_move_output[_word] - -dispose_cmd.c - - changes to dispose r_move_input_word and r_move_output_word - -make_cmd.c - - changes to make r_move_input[_word] and r_move_output[_word] from - r_duplicating_{input,output}_word, which is how the new redirs - are passed by the parser - -redir.c - - changes to make r_move_input[_word] and r_move_output[_word] do - the right thing when executed - -builtins/read.def - - print an error message and return failure immediately if zread/zreadc - return < 0 - -doc/{bash.1,bashref.texi} - - documented new [n]<&word- and [n]>&word- redirections - - 3/13 - ---- -lib/readline/isearch.c - - enabled code to allow chars bound to rl_rubout to delete characters - from the incremental search string - -shell.c - - add `-l' invocation option to parse_shell_options; equivalent to - `--login' - - fixed set_login_shell to check first char of base pathname of argv0 - for `-', like other shells - - move the check for make_login_shell after the call to - parse_shell_options because the `-l' option might set it - -doc/{bash.1,bashref.texi} - - documented new `-l' invocation option - -array.c - - new function, array_shift, shifts an array left by a specified - number of elements - - array_walk is now compiled in by default - - array_to_assignment_string now takes a second argument: int quoted. - If non-zero, the result is single-quoted before being returned - - quoted_array_assignment_string has been removed - -array.[ch] - - renamed most of the array functions so that all have an array_ - prefix and are more systematically named - - array_slice now preserves the indicies from the original array - - change array_to_assign to use a static buffer for expanding the - array indices, instead of malloc/free - -{arrayfunc,subst,variables}.c, builtins/read.def - - changed calls to various array functions to use new names - -lib/sh/stringvec.c, externs.h - - renamed all of the functions to have a strvec_ prefix and to have - a more sensible name scheme - - strvec_search's arguments are now supplied in reverse order, so - the char **array is first, like the other functions - - new function, strvec_resize, xrealloc for strvecs - -{alias,array,bracecomp,braces,bashline,execute_cmd,findcmd,general,pathexp, -pcomplete,variables}.c -lib/sh/stringlist.c -builtins/{bind,complete,exec,getopts,pushd,set}.def - - change calls to all functions from lib/sh/stringvec.c - - use strvec_resize where appropriate - -externs.h - - only declare dup2() if HAVE_DUP2 is undefined or DUP2_BROKEN is - defined - -lib/readline/{macro,readline,util}.c, lib/readline/rlprivate.h - - _rl_defining_kbd_macro is gone, use RL_ISSTATE(RL_STATE_MACRODEF) - -lib/readline/readline.h - - new struct readline_state, encapsulates most of readline's internal - state in case you need reentrancy or nested calls to readline() - - extern declarations for rl_save_state, rl_restore_state - -lib/readline/readline.c - - add (undocumented) int rl_save_state (struct readline_state *), - int rl_restore_state (struct readline_state *) - - 3/14 - ---- -array.[ch] - - new function, array_rshift, shifts an array right by a specified - number of elements, optionally inserting a new element 0 - -examples/bashdb/bashdb - - new single-file version of bash debugger, originally modified from - version in bash-2.04 by Gary Vaughan (the old debugger still - appears in examples/obashdb). This version has a more gdb-like - command set - -examples/bashdb/bashdb.el - - new emacs bashdb debugger mode from Masatake YAMATO - -execute_cmd.c - - don't make $LINENO relative to function start unless the shell is - currently interactive -- this is what ksh93 does and what I - believe to be the intent of POSIX.2 (this required changing some - of the test checks because the output has changed) - - run the debug trap for each command in an arithmetic for expression, - like ksh93 does - -lib/readline/vi_mode.c - - redid rl_vi_subst (binding func for `s' and `S') in terms of - rl_vi_change_to: `S' == `cc' and `s' == `c '. This makes undo - work right - - 3/18 - ---- -hashlib.c - - fixed hash_walk to return if the item function returns < 0, instead - of breaking out of the current hash chain - -array.c - - fixed array_walk to return if the item function returns < 0, like - hash_walk - -lib/sh/stringlist.c, externs.h - - new function: strlist_walk, takes a stringlist and a pointer to an - item func. Like other _walk funcs, if item func returns < 0 the - walk is cancelled - - new function: strlist_flush, frees items in the contained list - with strvec_flush - - renamed functions to have a strlist_ prefix and be more systematic - -pcomplib.c,pcomplete.h - - removed redundant `progcomp_initialized' variable - - renamed functions to have `progcomp_' or `compspec_' prefixes - like the hash library - -{bashline,pcomplete}.c,builtins/complete.def - - fixed calls to stringlist functions to use new names - - fixed calls to functions in pcomplib.c to use new names - -pcomplete.c - - made the debugging code #ifdef DEBUG -- it should be mature enough - -builtins/hash.def,parse.y - - use REVERSE_LIST(x, t) instead of (t)reverse_list(x) - -list.c,{externs,general}.h - - renamed the list functions to have a list_ prefix, changed callers - -externs.h,{execute_cmd,stringlib,subst}.c,builtins/common.c,lib/sh/stringvec.c - - word_list_to_argv -> strvec_from_word_list - - argv_to_word_list -> strvec_to_word_list - - moved functions to lib/sh/stringvec.c - -lib/sh/stringvec.c - - changed name of second argument to strvec_from_word_list from `copy' - to `alloc' so the use of `copy' between strvec_from_word_list and - strvec_to_word_list isn't as confusing - - changed name and sense of second argument to - strvec_to_word_list from `copy' to `alloc' for the same reason -- - now both functions agree on semantics of second argument - -lib/sh/stringlist.c - - ditto for strlist_from_word_list and strlist_to_word_list - -subst.c - - changed callers of strvec_to_word_list - - 3/19 - ---- -builtins/hash.def - - added `-l' option to list table or individual targets in reusable - format - - added `-d' option to remove one or more names from the table of - hashed commands (provides `unhash' or `unalias -t' functionality) - -doc/{bash.1,bashref.texi} - - documented new `-l' and `-d' options to `hash' - -hashcmd.[ch] - - renamed functions to have a `phash_' prefix and follow new naming - convention - - phash_remove now returns an int: 1 if command not in hash table, - 0 if filename removed OK - -{findcmd,variables}.c, builtins/{hash,type}.def - - changed callers to use new names from hashcmd.c - -builtins/common.[ch] - - new function, sh_notfound(s), prints standard `not found' message - - new function, sh_invalidid(s), prints standard `invalid identifier' - message - - new function, sh_restricted(s), prints standard `restricted' message - for restricted shells - - new function, sh_invalidnum(s), prints standard `invalid number' - message - - renamed bad_option to sh_invalidopt, changed to print - `invalid option' instead of `unknown option' - - new function, sh_invalidoptname, prints standard `invalid option - name' for long options - - new function, sh_badjob (s), prints standard `no such job' message - - new function, sh_invalidsig (s), prints standard `invalid signal - specification' message - - new function, sh_nojobs (s), prints standard `no job control' message - - new function, sh_needarg (s), prints standard `option requires an - argument' message - - new function, sh_neednumarg (s), prints standard `numeric - argument required' message - - new function, sh_badpid(s), prints standard `not a pid...' message - - new function, sh_erange (s, desc) prints standard `out of range' - message, optionally using `desc' to say what the argument is - -builtins/{alias,command,declare,exec,hash,type}.def - - call sh_notfound() instead of calling builtin_error directly - -builtins/{declare,getopts,read,set,setattr}.def - - call sh_invalidid() instead of calling builtin_error directly - -builtins/{cd,command,enable,exec,hash,source}.def - - call sh_restricted() instead of calling builtin_error directly - -builtins/{printf,read,ulimit}.def, builtins/common.c - - call sh_invalidnum instead of calling builtin_error directly - -builtins/{complete,declare,pushd,set}.def, builtins/bashgetopt.c - - call sh_invalidopt instead of bad_option or builtin_error directly - -builtins/{complete,set,shopt}.def - - call sh_invalidoptname instead of builtin_error directly - -builtins/{fg_bg,jobs,kill,wait}.def - - call sh_badjob instead of calling builtin_error directly - -builtins/common.c, builtins/{kill,signal}.def - - call sh_invalidsig instead of calling builtin_error directly - -builtins/{fg_bg,suspend,wait}.def - - call sh_nojobs instead of calling builtin_error directly - -builtins/{common,bashgetopt}.c, builtins/{hash,kill}.def - - call sh_neednumarg and sh_needarg where required - -builtins/{kill,wait}.def - - call sh_badpid where required - -builtins/{break,fc,history,pushd,shift,ulimit,umask}.def - - call sh_erange where appropriate - -builtins/printf.def - - new static function, printf_erange, prints standard out-of-range - warning message - -builtins/set.def - - changed so that calls to sh_invalidopt always include the leading - `+' or `-' - -builtins/shopt.def - - changed SHOPT_ERROR macro to shopt_error function - -builtins/bind.def - - regularized error messages to `bind: object: error string' like - other error messages - -builtins.h - - the `short_doc' member of a `struct builtin' is now of type - `const char *' - - the strings in `long_doc' array of a struct builtin are now const - -builtins/mkbuiltins.c - - changes for new `const' members of struct builtin - - 3/20 - ---- -lib/readline/histfile.c - - use pointers instead of indexing into buffer when reading the - contents of the history file in read_history_range and - history_truncate_file - - 3/21 - ---- -lib/readline/histfile.c - - new file, with code to mmap the history file for reading and - writing (depends on HAVE_MMAP, currently nothing checks for that) - - 3/25 - ---- -error.[ch] - - new function, err_badarraysub(s), calls report_error with standard - `bad array subscript' message - - new function, err_unboundvar(s), calls report_error with standard - `unbound variable' message - - new function, err_readonly(s), calls report_error with standard - `readonly variable' message - -{arrayfunc,subst}.c - - call err_badarraysub where appropriate - -{expr,subst}.c - - call err_unboundvar where appropriate - -{arrayfunc,variables}.c - - call err_readonly where appropriate - -shell.c - - changed text of bad option error messages to be the same as that - printed for builtin errors - -builtins/common.c - - changed sh_invalidopt to print the invalid option before the rest - of the error message (required some tests to be modified) - - new function, sh_readonly, calls builtin_error with standard - `readonly variable' message - -variables.c,builtins/declare.def - - call sh_readonly where appropriate - -lib/sh/stringvec.c - - added strvec_remove (sv, s), removes S from SV and shuffles rest of - elements down 1 - -lib/sh/stringlist.c - - added strlist_remove(sl, s), just calls strvec_remove on the - component list - -externs.h - - new extern declarations for strvec_remove and strlist_remove - - fixed extern declaration for strvec_search; the arguments were - reversed (unimportant, it's not compiled into the shell) - -subst.c - - change param_expand to call quote_escapes on values retrieved when - expanding the positional parameters - - change parameter_brace_expand_word to quote escapes on values - retrieved when expanding the positional parameters - - fix parameter_brace_substring to quote escape characters on unquoted - substrings extracted from variable values (needed to separate case - VT_VARIABLE from VT_ARRAYMEMBER for this, since, because - get_var_and_type calls array_value for VT_ARRAYMEMBER, we need to - skip over quoted characters in an already-appropriately-quoted - string to find the substring we want) - - fix parameter_brace_substring to quote escape characters in the - value returned by pos_params when expanding subsets of the - positional parameters and not within double quotes (in which case - pos_params() quotes the string for us) - - fix parameter_brace_substring to quote escape characters in the - value returned by array_subrange when expanding subsets of an - array and not within double quotes (in which case - array_subrange() quotes the string for us) - - new function, quoted_strlen(s), does strlen(s) while skipping over - characters quoted with CTLESC (#ifdef INCLUDE_UNUSED, since it's - not used yet) - - changed pos_params() so it always returns a list whose members are - quoted strings if (quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) != 0 - -arrayfunc.c - - fix array_value to consistently call quote_escapes, even when a - non-array variable is being subscripted with element 0, in which - case we return the variable value - -lib/sh/strtrans.c - - make the for_echo parameter to ansicstr a `flags' parameter that - has its old `for echo' meaning if flags&1 is non-zero (which is - consistent with the old code) - - Added code to the `flags' parameter to ansicstr so that if flags&2 - is non-zero, CTLESC and CTLNUL are escaped with CTLESC in the - expanded string - - change ansiexpand() to call ansicstr with a `flags' parameter of 2 - - 3/26 - ---- -lib/readline/histfile.c - - when reading and writing the history file, use malloc instead of - xmalloc and handle failures gracefully, so the application doesn't - abort if the history file or history list is too big - - 3/27 - ---- -arrayfunc.c - - changed array_value_internal to take an additional `int *' - parameter, in which is returned the type of array indexing - performed (array[@] vs. array or array[index]) - - changed array_value and get_array_value to take a corresponding - extra parameter and pass it to array_value_internal - - changed array_value_internal to no longer return newly-allocated - memory or quote CTLESC and CTLNUL in the returned string if - `simple' array indexing (subscript not `@' or `*') is being - performed. This makes it more like a variable lookup - -arrayfunc.h - - changed prototypes for array_value and get_array_value - -expr.c - - added new parameter to call to get_array_value in expr_streval - - don't need to free memory returned by get_array_value any more - -subst.c - - quote_escapes now works with multibyte characters - - dequote_string now works with multibyte characters - - dequote_escapes is now needed, so it's compiled in, and it - now works with multibyte characters - - remove_quoted_escapes now just calls dequote_escapes and copies the - result over the argument string - - remove_quoted_nulls now returns its char * argument, parallels - remove_quoted_escapes - - parameter_brace_expand_word now passes the new argument to - array_value and quotes CTLESC and CTLNUL in the result if it's a - `simple' array expansion by calling quote_escapes - - get_var_and_type now returns VT_ARRAYMEMBER for references like - ${array} where `array' is an array variable (just like ${array[0]}). - Documented (in comment) that a VT_VARIABLE return value means that - quote_escapes has been called at some point - - changed callers of get_var_and_type to no longer free value if - VT_ARRAYMEMBER is returned as type - - changed parameter_brace_substring and parameter_brace_patsub to - call dequote_escapes on the value from get_var_and_type if the - type is VT_VARIABLE, since the substring and pattern substitution - code doesn't understand CTLESC quoting - - parameter_brace_substring no longer needs to call quoted_substring - for the VT_ARRAYMEMBER case - - changed parameter_brace_patsub to call quote_escapes on the result - of pat_subst for the VT_VARIABLE and VT_ARRAYMEMBER cases, and to - quote the returned string in the VT_ARRAYVAR and VT_POSPARAMS cases - if the `MATCH_QUOTED' flag isn't set (if it is, the pattern - substitution functions perform any necessary quoting) - - quoted_substring is no longer used; it's now #ifdef INCLUDE_UNUSED - -lib/malloc/mstats.h - - new member in _malstats: u_bits32_t bytesreq, the total number of - bytes requested by the caller via calls to malloc() and realloc() - -lib/malloc/stats.c - - print bytesreq member in _print_malloc_stats - - don't print statistics for buckets for which nmal == 0 (no mallocs) - -lib/malloc/malloc.c - - modified internal_malloc, internal_realloc to keep running total of - number of bytes requested by calling application - -shell.c - - sh_exit is now compiled in; exit_shell calls sh_exit - -error.c - - changed fatal_error, report_error, parser_error to call sh_exit - - 3/28 - ---- -subst.[ch] - - changed Q_NOQUOTE to Q_PATQUOTE; it makes the intent more clear - -subst.c - - moved code from parameter_brace_expand into a new function that - dispatches for pattern substitution: parameter_brace_remove_pattern - - changed structure of parameter_brace_remove_pattern to be like - parameter_brace_patsub and its ilk: call get_var_and_type to - isolate the variable name, move the pattern isolation code out of - the various *_remove_pattern functions into - parameter_brace_remove_pattern and pass the results to the various - functions, use a switch on the return value from get_var_and_type - to decide which function to call, regularized the arguments to the - separate pattern removal functions - - parameter_brace_remove_pattern now properly quotes escape chars in - the returned value - - changed get_var_and_type to call dequote_escapes on the `value' - parameter for case VT_VARIABLE and return the result in *valp, - so the calling functions don't have to do it themselves; changed - callers appropriately - - fixed getpattern() where it broke posix compliance: if you enclose - a pattern removal spec in double quotes, the outer double quotes - have no effect on the pattern (POSIX.1-200x 2.6.2). This uncovered - a bug in the test suite (!) - -pathexp.c - - fixed a problem with quote_string_for_globbing where it would change - consecutive CTLESC chars all to \ instead of changing every other - quoted char - - 3/31 - ---- -lib/malloc/{malloc,stats}.c - - moved declaration of _mstats to malloc.c so stats.o doesn't get - linked into the shell if the stats functions aren't called - - 4/2 - --- -lib/glob/smatch.c - - introduce `XCHAR' define, which is the type of arguments passed to - strcoll/strcmp/strlen and their wide-character equivalents, added - appropriate casts - - static arrays in single-byte version of rangecmp() are `char', not - `unsigned char', so compilers don't complain about calls to strcoll - -lib/glob/sm_loop.c - - casts for `XCHAR' and `XCHAR *' arguments to libc functions - - use prototype declaration for BRACKMATCH if `PROTOTYPES' is defined - to avoid problems with type promotion (unsigned char -> int) - -lib/glob/collsyms.h - - `name' member of struct _COLLSYM is now of type `XCHAR *', since - some compilers don't like `unsigned char *' initializers from - constant strings - -[bash-2.05b-alpha1 released] - - 4/3 - --- -builtins/{evalstring.c,common.h} - - new flag for parse_and_execute, SEVAL_NOFREE, means to not free - the argument string when finished - -lib/readline/text.c - - fixed a trivial typo in _rl_insert_char when reading multibyte - char sequences - - replace calls to ding() with rl_ding() - -include/chartypes.h - - remove SIGN_EXTEND_CHAR and TOASCII macros; they're unused - -make_cmd.c - - include dispose_cmd.h for extern function declarations - -lib/glob/glob.c - - include `shmbutil.h' and `xmalloc.h' for extern function declarations - -lib/glob/smatch.c - - include `xmalloc.h' for extern function declarations - -shell.c - - fix maybe_make_restricted to use its argument instead of global - `shell_name' - -version.c - - update copyright message to include this year - -lib/readline/display.c - - fixes from Jiro SEKIBA to fix autowrapping - when using multibyte characters - -lib/glob/sm_loop.c - - fixed a problem in BRACKMATCH where not enough memory was allocated - to hold a multibyte character when parsing POSIX.2 char class names - -support/config.{guess,sub} - - updated via patch from Paul Eggert with latest GNU additions - -variables.c - - var_lookup should use its `vcontext' argument instead of - unconditionally using `shell_variables' - - 4/4 - --- -builtins/bind.def,doc/{bash.1,bashref.texi} - - changed the usage summary and help text to make it clear that any - readline command that may appear in ~/.inputrc may be supplied as - one of the non-option arguments to `bind' - -builtins/mkbuiltins.c - - added support for `-H' option, which means to write long documentation - for each builtin to a separate file in the `helpfiles' directory - -builtins/Makefile.in - - new target `helpdoc', just creates long doc files in helpfiles - directory - -lib/sh/zcatfd.c - - new file, with zcatfd(int fd, int ofd, char *fn); dumps data from - FD to OFD - -Makefile.in,lib/sh/Makefile.in - - added zcatfd.c, zcatfd.o member of libsh.a - -builtins/evalstring.c - - changed cat_file to call zcatfd(fd, 1, fn) - -builtins/{shopt,colon}.def - - removed the $DOCNAME directive for `shopt', `true', and `false'; - just use the names - - changed $DOCNAME for `:' to just be `colon' instead of - `colon_builtin' - -builtins/reserved.def - - added help entries for ((, [[, `for ((' - -builtins/let.def - - add id++, id--, ++id, --id, ** to help text - - 4/8 - --- -builtins/bashgetopt.[ch] - - changed to allow options beginning with `+', enabled by a leading - `+' in the option string - - new variable, list_opttype, set to `-' or `+' - -builtins/{common.c,{builtin,eval,exit,fg_bg,let,printf,pushd,return,source,wait}.def - - changes to allow a `--' option for every builtin that accepts - operands but not options, as per posix.1-2001 - -builtins/{declare,setattr}.def - - use internal_getopt for parsing options, now that it supports `+' - -builtins/set.def - - use internal_getopt for initial option parse, now that it supports - a leading `+' - - -{configure,Makefile}.in, builtins/{Makefile.in,help.def,mkbuiltins.c} - - support for a new configure option, ``--enable-separate-helpfiles'', - moves the `long' help text to separate help files, installed by - default into ${datadir}/bash, one file per builtin. Off by - default -- it saves 47K, but it's only 47K, and it's in the text - segment - -flags.c - - build internal_getopt() option string argument from flags array at - runtime in shell.c - -shell.c - - new variable to control writing malloc stats at exit: - malloc_trace_at_exit, 0 by default - -lib/malloc/malloc.c - - heavily updated: - o partial page allocated on first call to malloc to make - subsequent sbrks page-aligned no longer wasted - o begin and end range guards are now the same value: the chunk - requested - o coalescing code was changed to attempt to coalesce first two - adjacent blocks on the free list; enabled by default - o blocks of size 32 are now candidates for larger block - splitting, since 32 is the most popular size - o blocks of size 32 are now candidates for smaller block - coalescing - o the IN_BUCKET check was changed to just make sure that the - size isn't too big for the bucket, since the `busy block' - checking code may increase the bucket by one or more, - meaning that the old check would fail and cause a panic when - a chunk allocated in such a way was freed - o bin sizes are now precomputed and looked up in an array - rather than being computed at runtime - o moved the _mstats declaration here to avoid the stats code - being linked in even when no stats functions were called - (only matters if MALLOC_DEBUG is defined) - o malloc now keeps track of the address of the top of the heap - and will return large chunks to the system with calls to - sbrk with a negative argument when freeing the top chunk. - Two thresholds: LESSCORE_FRC means to unconditionally return - memory to the system; LESSCORE_MIN means to return memory if - there's at least one block already on the free list - -lib/malloc/mstats.h - - stats struct now keeps track of number of block coalesces by bin, - and the number of times memory was returned to the system by bin - -lib/malloc/stats.c - - trace_malloc_stats now takes a second argument: the name of the file - to write to. The first `%p' in the template file name is replaced - by the pid - - 4/9 - --- -lib/malloc/imalloc.h - - added some macros derived from dlmalloc and glibc malloc to inline - memcpy and memset if the requested size is <= 32 bytes - -lib/malloc/malloc.c - - use MALLOC_MEMSET instead of memset in internal_{malloc,free} - -include/ocache.h - - use OC_MEMSET (variant of MALLOC_MEMSET) in ocache_free - -configure.in, config.h.in - - check for getservent(), define HAVE_GETSERVENT if found - -bashline.c - - punt immediately from bash_servicename_completion_function if - HAVE_GETSERVENT is not defined (cygwin seems to not define it) - - include "input.h" for extern save_token_state() and - restore_token_state() declarations - - change bash_execute_unix_command to call parse_and_execute with - SEVAL_NOHIST flag so the command doesn't get saved on the history - list - - change bash_execute_unix_command to save and restore the current - command line count and the token state (last_read_token, etc.). - Everything else is saved by either parse_and_execute directly or - the call it makes to push_stream(). The shell_input_line stuff - doesn't need to be saved and restored; it's not computed until - readline() returns - - 4/10 - ---- -lib/glob/glob.[ch] - - glob_filename and glob_vector now take an additional `flags' arg - - define GX_MARKDIRS as possible flag value for glob_filename and - glob_vector - -lib/sh/snprintf.c - - fixed some bugs with handling of `g' and `G' formats - - make sure numtoa returns the fractional part correctly when passed 0 - - implemented thousands grouping for `'' flag character - -lib/sh/rename.c - - a few changes to make it more bulletproof - - 4/11 - ---- -lib/glob/glob.c - - added the couple of dozen lines of code to glob_dir_to_array to - finish implementing GX_MARKDIRS - -builtins/set.def - - changed unset builtin so that it no longer considers unsetting an - unset variable or function to be an error - -lib/readline/display.c - - fix to rl_redisplay for a problem which caused display to be messed - up when the last line of a multi-line prompt (possibly containing - invisible characters) was longer than the screen width - - 4/15 - ---- -aclocal.m4 - - use AC_DEFINE_UNQUOTED in BASH_SYS_DEFAULT_MAIL_DIR instead of - enumerating all of the possible values and using AC_DEFINE - - 4/16 - ---- -Makefile.in, {builtins,support}/Makefile.in - - new variables, CFLAGS_FOR_BUILD and CPPFLAGS_FOR_BUILD, substituted - by `configure' - - changed CCFLAGS_FOR_BUILD to BASE_CCFLAGS, removing $(CPPFLAGS); - CCFLAGS and CCFLAGS_FOR_BUILD now include $(BASE_CCFLAGS) with - (possibly) different values for CPPFLAGS and CFLAGS - - GCC_LINT_CFLAGS now includes $(BASE_CCFLAGS) and $(CPPFLAGS) - instead of CCFLAGS_FOR_BUILD - - new variable, LDFLAGS_FOR_BUILD, right now equivalent to LDFLAGS - - remove $(CPPFLAGS) from recipes for buildversion, mksignames, and - mksyntax - -configure.in - - compute and substitute CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and - LDFLAGS_FOR_BUILD - - changed qnx to use LOCAL_LDFLAGS and LOCAL_LIBS instead of putting - everything in LOCAL_LDFLAGS - -builtins/Makefile.in - - remove $(PROFILE_FLAGS) from recipe for building `mkbuiltins' - - use LDFLAGS_FOR_BUILD instead of LDFLAGS in recipe for building - `mkbuiltins' - -Makefile.in - - use $(CC_FOR_BUILD) and $(CCFLAGS_FOR_BUILD) to build auxiliary - test programs (printenv, recho, zecho) - -support/Makefile.in - - use CC_FOR_BUILD and CCFLAGS_FOR_BUILD in recipe for building - `man2html' - -lib/tilde/Makefile.in - - substitute PROFILE_FLAGS, use PROFILE_FLAGS in $(CCFLAGS) - - 4/25 - ---- -Makefile.in, configure.in - - moved RELSTATUS to configure.in; configure substitutes it into - the generated Makefile - -lib/sh/snprintf.c - - fix wchars() to deal with systems where MB_CUR_MAX is not a - constant expression - - 5/2 - --- -lib/sh/shquote.c - - add `,' to list of chars that are backslash-quoted. It doesn't - hurt normal usage and prevents filenames with commas from being - inappropriately split by brace expansion after using - complete-into-braces - - 5/6 - --- -lib/sh/xstrchr.c - - we only need the check of MB_CUR_MAX and the slow code for a - few encodings, and even then only for a subset of the charset - -arrayfunc.c - - some speedups for skipsubscript and multibyte chars from Bruno Haible - -locale.c - - changed set_lang to call setlocale(LC_ALL, ...) if LC_ALL doesn't - already have a value, but doesn't change any shell variables - -include/shmbutil.h - - major speedups from Bruno Haible, mostly concerned with reducing - the number of strlen(3) calls - -subst.c - - change callers of macros in shmbutil.h to add extra argument as - necessary - - skip_single_quoted and skip_double_quoted take another argument: - the length of the string; mostly useful when using multibyte chars - - many speedups from precomputing string lengths at function start - - fixed a small bug in de_backslash in the midst of rewriting for - better efficiency - -{braces,make_cmd,pathexp}.c - - change callers of macros in shmbutil.h to add extra argument as - necessary - -pathexp.c - - fix a one-too-far problem with multibyte chars in - unquoted_glob_pattern_p - -braces.c - - brace_gobbler takes a new argument, the length of the passed string - - expand_amble takes a new argument, the length of the passed string - - 5/7 - --- -subst.c - - modified remove_quoted_nulls to eliminate the memory allocation and - do the copy in place using the same strategy as de_backslash - -lib/readline/{rldefs.h,complete.c} - - new define RL_QF_OTHER_QUOTE, so _rl_find_completion_word can note - that it found a quoting character other than \'" that appears in - rl_completer_quote_characters - - 5/9 - --- -jobs.c - - save and restore old value of jobs_list_frozen when calling trap - handlers from set_job_status_and_cleanup to avoid seg faults when - running recursive trap handlers - - 5/10 - ---- -builtins/common.h - - new #defines to use for value of changed_dollar_vars (provides - information about the caller who wants to blow away the old dollar - variables) - -builtins/common.c - - changed set_dollar_vars_changed to set changed_dollar_vars to one - of the ARGS_* values depending on the caller and environment - -builtins/source.def - - source restores the positional parameters unless the `set' builtin - was called to specify a new set while not executing a shell function - - 5/13 - ---- -POSIX - - new file, was in CWRU/POSIX.NOTES - -doc/{Makefile.in,Makefile} - - changed `posix' rule to modify ../POSIX - -doc/mkposix - - write to `POSIX' by default - -lib/sh/strtrans.c - - when ansicstr is parsing a format string for `echo -e' (or the - equivalent xpg_echo option is enabled), obey the POSIX-2001/SUSv3 - standard and accept 0-3 octal digits after a leading `0' - -doc/{bash.1,bashref.texi} - - updated `echo' description to note that up to three octal digits - are now accepted following `\0' - - 5/16 - ---- -doc/Makefile.in - - remove the generated documentation on `make distclean' if the - build directory and source directory are not the same - -Makefile.in - - descend into `support' subdirectory on a `make clean' and - `make distclean' - - remove parser-built, y.tab[ch] on a `make distclean' if the build - directory and source directory are not the same - -support/Makefile.in - - support various `clean' targets and remove man2html.o and man2html - -{configure,Makefile}.in - - move values for DEBUG and MALLOC_DEBUG into configure.in; on by - default for development versions; off by default for releases - (off for profiling, too) - - 5/21 - ---- -parse.y - - modified the grammar to allow a simple_list followed by yacc_EOF - to terminate a command. This fixes problems with things like - a backslash-newline at the end of an `eval'd string - - change handle_eof_input_unit() to reset the token state before - calling prompt_again(), in case the prompt to be evaluated contains - a command substitution - - 5/23 - ---- -lib/readline/vi_mode.c - - fix `r' command (rl_vi_change_char) when HANDLE_MULTIBYTE is defined - but MB_CUR_MAX == 1 - - 5/24 - ---- -lib/malloc/watch.c - - don't try to print `file' argument to _watch_warn if it's null - -lib/malloc/malloc.c - - changed guard checking code in internal_{malloc,free,realloc} to - access memory as (char *) and copy into a union instead of - casting and dereferencing a pointer to u_bits32_t, since that - results in unaligned accesses which will cause Sparcs to upchuck - - 5/30 - ---- -[bash-2.05b-beta1 released] - -lib/readline/text.c - - fixed a problem with rl_transpose_chars on systems supporting - multibyte characters with a locale that doesn't have any multibyte - chars - - 6/4 - --- -expr.c - - fix a/=0 and a%=0 to throw evaluation errors rather than core dumps - -lib/readline/display.c - - fix core dump when line wrapping a multibyte character (line - accidentally dropped from the original patch) - -lib/readline/mbutil.c - - fix reversed return value from _rl_is_mbchar_matched; fixes problem - with backward-char-search - - 6/10 - ---- -lib/sh/getenv.c - - fix getenv to not free value returned by find_tempenv_variable - - add setenv, putenv, unsetenv for completeness - - 6/12 - ---- -shell.c - - change init_noninteractive to init expand_aliases to the value of - posixly_correct - - don't initialize expand_aliases to posixly_correct anywhere else. - This allows the -O expand_aliases invocation option to work correctly - -general.c - - fix move_to_high_fd to not try the dup2 unless the fd loop results - in an fd > 3; just return the passed file descriptor otherwise - - use HIGH_FD_MAX, defined in general.h, instead of hard-coded 256 - as highest file descriptor to try - -subst.c - - in process_substitute, call move_to_high_fd with `maxfd' parameter - of -1 instead of 64, so move_to_high_fd will use its maximum - - 6/21 - ---- -lib/malloc/malloc.c - - don't bother calling MALLOC_MEMSET if the requested size is 0 - -builtins/setattr.def - - note in short doc that export and readonly can take assignment - statements as arguments - -error.c - - new function, error_prolog(), to capture common error message - prefix code (except for parser errors) - - 6/25 - ---- -aclocal.m4 - - add tests for standard-conforming declarations for putenv and - unsetenv in system header files - -{configure,config.h}.in - - call BASH_FUNC_STD_PUTENV and BASH_FUNC_STD_UNSETENV, define - HAVE_STD_GETENV and HAVE_STD_UNSETENV, respectively, if they - succeed - -lib/sh/getenv.c - - change putenv and unsetenv to take differing prototypes in - stdlib.h into account - - 6/27 - ---- -[bash-2.05b-beta2 released] - - 6/28 - ---- -builtins/common.c - - fix get_job_spec so that %N works when N is the size of the jobs - list (%8 means job 8, but the 7th member of the jobs array, so - it's OK if N == job_slots because the function returns N-1) - - 7/1 - --- -shell.c - - turn off line editing if $EMACS is set to `t' - - 7/10 - ---- -builtins/set.def - - remove mention of `-i' from long help doc, since it has no effect - - 7/17 - ---- -[bash-2.05b released] - - 7/18 - ---- - -lib/malloc/malloc.c - - make sure that the `free_return' label has a non-empty statement - to branch to - - 7/19 - ---- -locale.c - - only call setlocale() from set_lang() if HAVE_SETLOCALE is defined; - otherwise just return 0 - -lib/readline/mbutil.c - - only try to memset `ps' in _rl_get_char_len if it's non-NULL. Ditto - for _rl_adjust_point - - 7/23 - ---- -execute_cmd.c - - fix for executing_line_number() when compiling without conditional - commands, dparen arithmetic or the arithmetic for command - - - 7/24 - ---- -support/Makefile.in - - fix maintainer-clean, distclean, mostlyclean targets - -builtins/common.c - - fix bug in sh_nojobs where it doesn't pass the right number of args - to builtin_error - -bashline.c - - when using command completion and trying to avoid appending a slash - if there's a directory with the same name in the current directory, - use absolute_pathname() instead of just checking whether the first - char of the match is a slash to catch things like ./ and ../ - -examples/complete/bashcc-1.0.1.tar.gz - - a package of completions for Clear Case, from Richard S. Smith - (http://www.rssnet.org/bashcc.html) - -input.c - - fix check_bash_input to call sync_buffered_stream if the passed fd - is 0 and the shell is currently reading input from fd 0 -- all it - should cost is maybe an additional read system call, and it fixes - the bug where an input redirection to a builtin inside a script - which is being read from stdin causes the already-read-and-buffered - part of the script to be thrown away, e.g.: - - bash < x1 - - where x1 is - - hostname - read Input < t.in - echo $Input - echo xxx - -execute_cmd.c - - in initialize_subshell(), call unset_bash_input (0) to not mess with - fd 0 if that's where bash thinks it's reading input from. Fixes - bug reported by jg@cs.tu-berlin.de on 17 July 2002. Should be a way - to check whether or not the current fd 0 at the time of the call has - not been redirected, like in the bug report. Also might eventually - want to throw in a sync_buffered_stream if bash is reading input - from fd 0 in a non-interactive shell into a buffered stream, so the - stream is sync'd -- might be necessary for some uses - - 7/25 - ---- -lib/readline/signals.c - - make sure rl_catch_sigwinch is declared even if SIGWINCH is not - defined, so the readline state saving and restoring functions in - readline.c are always the same size even if SIGWINCH is not defined, - and undefined references don't occur when SIGWINCH is not defined - - 7/30 - ---- -bashline.c - - augment patch from 7/24 to not disable rl_filename_completion_desired - if the first char of the match is `~' - -lib/readline/bind.c - - when creating `shadow' keymaps `bound' to ANYOTHERKEY, don't bind - a key whose type is ISFUNC but whose function is the `fake' - rl_do_lowercase_version (fixes debian bash bug #154123) - -lib/readline/readline.c - - don't call _rl_vi_set_last from _rl_dispatch_subseq if - key == ANYOTHERKEY (when truncated to `sizeof(char)', it will be 0, - which strchr will find in `vi_textmod') - - 7/31 - ---- -lib/readline/input.c - - fix rl_gather_tyi to only slurp up one line of available input, even - if more than one line is available (fixes debian bash bug #144585) - - 8/3 - --- -bashline.c - - better fix for command completion problem -- test for directory - explicitly with test_for_directory before turning off - rl_filename_completion_desired, since that's the case we're trying - to protect against - - 8/5 - --- -include/shmbutil.h - - fix ADVANCE_CHAR macro to advance the string pointer if mbrlen - returns 0, indicating that the null wide character (wide string - terminator) was found (debian bash bug #155436) - -lib/readline/mbutil.c - - fix _rl_adjust_point to increment the string pointer if mbrlen - returns 0 - -support/shobj-conf - - fix for the `-install_name' value in SHLIB_XLDFLAGS assignment for - Darwin from the fink folks - - 8/6 - --- -builtins/exit.def - - broke code that runs ~/.bash_logout out into a separate function: - bash_logout() - -builtins/common.h - - extern declaration for bash_logout() - -eval.c - - call bash_logout() from alrm_catcher(), so timed-out login shells - run ~/.bash_logout before processing the exit trap - -lib/sh/strtrans.c - - implemented $'\x{hexdigits}' expansion from ksh93 - -configure.in - - define RECYCLES_PIDS in LOCAL_CFLAGS for cygwin; don't bother to - link with -luser32 - -examples/loadables/strftime.c - - new loadable builtin, interface to strftime(3) - - 8/7 - --- -parse.y - - parse_arith_cmd now takes a second argument, a flag saying whether - or not to add double quotes to a parsed arithmetic command; changed - callers - - changed parse_dparen so it tells parse_arith_cmd to not add the - double quotes and therefore doesn't need to remove them - - change parse_dparen to add W_NOGLOB|W_NOSPLIT|W_QUOTED flags to word - created when parsing (( ... )) arithmetic command, since the double - quotes are no longer added - -make_cmd.c - - in make_arith_for_expr, set the flags on the created word to - W_NOGLOB|W_NOSPLIT|W_QUOTED - -execute_cmd.c - - change execute_arith_command to expand the expression with - expand_words_no_vars, like the arithmetic for command code does - - fix execute_arith_command to handle the case where the expanded - expression results in a NULL word without crashing - -tests/{arith-for,cprint}.tests - - change expected output to account for no longer adding quotes to - ((...)) commands - - 8/8 - --- -print_cmd.c - - take out the space after printing the `((' and before printing the - `))' in print_arith_command, print_arith_for_command, and - xtrace_print_arith_cmd - -tests/{arith-for,cprint}.tests - - change expected output to account for no longer adding leading and - trailing spaces when printing ((...)) and arithmetic for commands - - 8/17 - ---- -subst.c - - fix issep() define to handle case where separators[0] == '\0', in - which case it always returns false - -lib/readline/histexpand.c - - fix off-by-one error in history_expand_internal when using the `g' - modifier that causes it to skip every other match when matching a - single character (reported by gjyun90@resl.auto.inha.ac.kr) - -doc/{bash.1,bashref.texi} - - make sure that the name=word form of argument to declare/typeset, - export, and readonly is documented in the description - - 8/30 - ---- -lib/readline/histexpand.c - - make history_expand_internal understand double quotes, because - single quotes are not special inside double quotes, according to - our shell-like quoting conventions. We don't want unmatched - single quotes inside double-quoted strings inhibiting history - expansion - - make `a' modifier equivalent to `g' modifier for compatibility with - the BSD csh - - add a `G' modifier that performs a given substitution once per word - (tokenized as the shell would do it) like the BSD csh `g' modifier - - 8/31 - ---- -braces.c - - when compiling for the shell, treat ${...} like \{...} instead of - trying to peek backward when we see a `{'. This makes it easier - to handle things like \${, which should be brace expanded because - the $ is quoted - - 9/7 - --- -aclocal.m4 - - redirect stdin from /dev/null in BASH_CHECK_DEV_FD before testing - the readability of /dev/fd/0, so we're dealing with a known quantity - - 9/11 - ---- -[prayers for the victims of 9/11/01] - -shell.c - - fix maybe_make_restricted to handle a restricted login shell with a - base pathname of `-rbash' and skip over any leading `-' - - 9/13 - ---- -builtins/evalstring.c - - in parse_and_execute, make sure we don't try to run unwind-protects - back to `pe_dispose' after a longjmp back to top_level if the - pe_dispose frame hasn't been initialized - -lib/readline/display.c - - fix problem with prompt overwriting previous output when the output - doesn't contain a newline in a multi-byte locale. This also should - fix the problem of bash slowing down drastically on long lines when - using a multi-byte locale, because it no longer tries to rewrite the - entire line each time. Patch from Jiro SEKIBA - -parse.y - - move the typedef for alias_t that is compiled in if ALIAS is not - defined up before the prototype for push_string, since that takes - an alias_t * parameter - -lib/readline/terminal.c - - bind the termcap description's left and right arrow keys to - rl_backward_char and rl_forward_char, respectively, instead of - rl_forward and rl_backward (which are just there for backwards - compatibility) - -aclocal.m4 - - when testing readability of /dev/stdin, redirect stdin from /dev/null - to make sure it's a readable file - - 9/17 - ---- -config-bot.h - - don't test __STDC__ when deciding whether or not to use stdarg.h; - just use it if it's present - -tests/read2.sub - - redirect from /dev/tty when using `read -t' - - 9/20 - ---- -builtins/history.def - - when reading `new' entries from the history file with `history -n', - fix increment of history_lines_this_session by taking any change - in history_base into account - -lib/sh/pathphys.c - - changes to sh_physpath to deal with pathnames that end up being - longer than PATH_MAX without dumping core - -lib/readline/doc/{history.3,hsuser.texinfo},doc/ bash.1 - - documented new `a' and `G' history modifiers - - 9/25 - ---- -lib/readline/misc.c - - when traversing the history list with arrow keys in vi insertion - mode, put the cursor at the end of the line (like in emacs mode) - -mksyntax.c - - don't try to use \a and \v unless __STDC__ is defined; use the - ascii integer equivalents otherwise - - include "config.h" in the generated syntax.c file for a possible - definition of `const' - -doc/{bash.1,bashref.texi} - - document the meaning of a null directory in $PATH - - 9/26 - ---- -parse.y - - fix set_line_mbstate to handle case where mbrlen() returns 0, - indicating the null wide character - - fix set_line_mbstate so we don't directly compare a char variable - to EOF, since char can (and is) unsigned on some machines - -bashline.c - - change bash_execute_unix_command to save a little bit more state: - last_shell_builtin, this_shell_builtin, last_command_exit_value - - 9/27 - ---- -execute_cmd.c - - tentative change to execute_simple_command to avoid freeing freed - memory in the case where bash forks early but still ends up calling - execute_disk_command, without passing newly-allocated memory to - make_child. This may fix the core dumps with the linux-from-scratch - folks - - 9/28 - ---- -Makefile.in,{builtins,lib/sh}/Makefile.in - - fix up dependencies, mostly on ${BUILD_DIR}/version.h, so that - parallel makes work with GNU and BSD makes - -shell.h - - new struct to save partial parsing state when doing things like - bash_execute_unix_command and other operations that execute - commands while a line is being entered and parsed - -parse.y - - new functions, save_parser_state() and restore_parser_state(), to - save and restore partial parsing state - -bashline.c - - change bash_execute_unix_command to call {save,restore}_parser_state - -builtins/jobs.def - - change execute_list_with_replacements to eliminate a run_unwind_frame - in favor of calling the cleanup explicitly and discarding the frame - -execute_cmd.c - - change execute_for_command to avoid a run_unwind_frame in the case - where the loop variable is readonly or otherwise not assignable - - change execute_select_command and execute_simple_command to use - discard_unwind_frame by running the cleanup code explicitly, instead - of using run_unwind_frame - - make sure execute_select_command decreases loop_level even on error - - 9/30 - ---- -doc/{bash.1,bashref.texi} - - fixed description of `unset' now that unsetting a previously-unset - variable is no longer an error - - 10/3 - ---- -{configure,config.h}.in - - augment check for strtold with additional check to detect the - horribly broken hp/ux 11.x implementation that returns `long_double'; - defines STRTOLD_BROKEN if so - -builtins/printf.def - - define floatmax_t as `double' if STRTOLD_BROKEN is defined - - 10/5 - ---- -lib/readline/keymaps.c - - don't automatically bind uppercase keys to rl_do_lowercase_version - in rl_make_bare_keymap - -lib/readline/readline.c - - explicitly check for ANYOTHERKEY binding to rl_do_lowercase_version - and dispatch to lowercase of key when a prefix is not matched - - 10/12 - ----- -bashline.c - - set COMP_WORDBREAKS in enable_hostname_completion to the value - of rl_completer_word_break_characters - -variables.c - - new special variable COMP_WORDBREAKS, controls the value of - rl_completer_word_break_characters - -variables.h - - new extern declaration for sv_comp_wordbreaks() - -subst.c - - change split_at_delims to behave more like shell word splitting if - the passed value for the delimiters is NULL, indicating that the - function is to use $IFS to split - -{execute_cmd,jobs,test,findcmd,input,make_cmd,redir,shell}.c -builtins/mkbuiltins.c,builtins/{fc,history,source,umask}.def -lib/sh/netconn.c -lib/termcap/termcap.c -lib/readline/histfile.c - - make sure all inclusions of are protected by - HAVE_SYS_FILE_H - -bashline.c - - don't turn off rl_filename_completion_desired in - attempt_shell_completion if the partial pathname contains a slash. - This still doesn't solve the problem of partial pathname completion - starting with a directory in the current directory without a - leading `./'. There's no way to tell the difference between that - and a file found in $PATH (which may contain `.') at the point that - attempt_shell_completion acts - - 10/18 - ----- -locale.c - - don't set lc_all to the default locale when LC_ALL is being unset - - new function, reset_locale_vars(), called to recompute the correct - locale variable values when LC_ALL is unset - - changed set_lang to not set LC_ALL, which it never should have been - doing in the first place, and to maintain a local variable `lang' - corresponding to $LANG - - change get_locale_var to use the precedence posix.2 specifies: - LC_ALL overrides individual variables; LANG, if set, is the default - - change set_locale_var to call get_locale_var to get the appropriate - value for the variable being set or unset - - call get_locale_var instead of using passed value in set_locale_var - to get the defaulting and precedence right - -lib/readline/nls.c - - new function, _rl_get_locale_var(), which does the same thing as - locale.c:get_locale_var(), with the right precedence and defaulting, - using sh_get_env_value to get the right bash variable values - - if HAVE_SETLOCALE is defined, _rl_init_eightbit first calls - _rl_get_locale_var to get the right value for LC_CTYPE, and uses - that in the call to setlocale. If _rl_get_locale_var returns NULL, - call setlocale() to get the current international environment, and, - finally, if that returns null, call setlocale with a second argument - of "" to force the implementation's `native' environment - -pcomplete.c - - change gen_wordlist_completions to dequote the text before comparing - it against the expanded word list - - changed gen_matches_from_itemlist to do the same thing - -bashline.c - - new global function, bash_dequote_word, calls bash_dequote_filename - on the text passed. Used by the programmable completion code - -lib/readline/histfile.c - - make sure that whenever read_history_range returns a non-zero value - that it sets errno to some useful value - - 10/19 - ----- -variables.c - - COMP_WORDBREAKS is now a dynamic variable, mirroring value of - rl_completer_word_break_characters. Makes sure that the variable - always points to dynamic memory if it's not null or the readline - default - -bashline.c - - change enable_hostname_completion to manage a dynamic value of - rl_completer_word_break_characters, since assignments to - COMP_WORDBREAKS can change its value unpredictably - -lib/readline/{complete.c,readline.h} - - rl_completer_word_break_characters no longer has `const' attribute - -bashline.c - - clean up necessary places due to rl_completer_word_break_characters - no longer being `const' - -doc/{bash.1,bashref.texi} - - document new COMP_WORDBREAKS variable - - 10/21 - ----- -print_cmd.c - - fix indirection_level_string to handle the case where the decoded - $PS4 is null without seg faulting - - 10/22 - ----- -builtins/shift.def - - make sure that there is actually an argument when reporting a shift - count that exceeds the number of positional paramters and - shift_verbose is enabled - -lib/readline/rltty.c - - change SET_SPECIAL to call a new function, set_special_char, since - it contains a block. It's called infrequently, so the performance - impact of making it a function should be negligible, and it helps - debugging - - 10/29 - ----- -bashline.c - - make sure the editor in VI_EDIT_COMMAND and EMACS_EDIT_COMMAND is - quoted; it might contain spaces (e.g., `emacs -nw') - -aclocal.m4 - - cache ac_cv_rl_version in RL_LIB_READLINE_VERSION macro - -configure.in - - change logic that sets RL_INCLUDEDIR so that it doesn't try to set - a bogus include path if the argument to --with-installed-readline - is `yes' -- helps with cross-compiling - -lib/readline/histexpand.c - - fix history_tokenize_word so that it handles <( and >( better - - 10/30 - ----- -redir.c - - fix write_here_string so it handles the case where `herestr' expands - to NULL without seg faulting - - 10/31 - ----- -mailcheck.c - - reverse logic flip from bash-2.05 that handled systems that don't - change the atime when the mailbox is accessed; make sure the file - is bigger before we report new mail. This is the case in the vast - majority of cases. Reported by jim@jtan.com - - 11/5 - ---- -parse.y - - change action for `for x; { list; }' and corresponding `select' - production to use \"$@\" instead of just $@, as it is with all the - other actions - - 11/9 - ---- -parse.y - - new flag for parse_matched_pair: P_DQUOTE, indicating that the - pair of characters being matched is between double quotes - - parse_matched_pair now passes P_DQUOTE down to recursive calls: - if the open char to be matched is a `"' or the passed-in flags - include P_DQUOTE, set the local `rflags' variable to P_DQUOTE and - pass `rflags' down to recursive calls - - if `rflags' includes P_DQUOTE, don't try to ansiexpand $'...' or - locale expand $"..."; consistent with other quoting constructs - - 11/11 - ----- -doc/{bash.1,bashref.texi} - - explicitly note that variables referenced in arithmetic expressions - without using `$' evaluate to 0 if they are null or unset - - note that a null variable value evaluates to 0 when used in an - arithmetic context, like when a variable with the `-i' attribute is - assigned a null value - - document the ${!prefix@} expansion as equivalent to ${!prefix*} - - 11/12 - ----- -doc/{bash.1,bashref.texi} - - note that the value of an arithmetic expression is as in C - - change the wording to note that `arithmetic evaluation' (not - arithmetic expansion, which has a different meaning) is performed - on the value assigned to a variable whose integer attribute is set - - 11/13 - ----- -execute_cmd.c - - fix execute_disk_command so it calls exit() after printing the error - message in a restricted shell context if the shell has already forked - (nofork != 0 && there are no pipes) - - 11/19 - ----- -builtins/type.def - - don't report on aliases unless expand_aliases is set and the parser - is performing alias expansion; changed tests/type.tests and - tests/type.right accordingly - - 11/25 - ----- -general.c - - fix for full pathnames including drive letters on cygwin from - Corinna (convert to posix-style paths, which the rest of the - code handles much better) - -lib/readline/text.c - - fixes to overwrite mode from jimmy@is-vn.bg: - o in _rl_overwrite_char, do the overwrite mode self-insert - as one group, even when overwriting more than 1 char - o in _rl_overwrite_char, do the insert before the delete so - that an undo positions the cursor on the character restored, - not to the right of it - o in _rl_overwrite_rubout, don't do rl_insert_char(' ') unless - rl_point < rl_end. Since overwrite-mode self-insert acts as - in insert-mode when at eol, make rubout behave like - insert-mode rubout - - 11/30 - ----- -lib/readline/misc.c - - call rl_replace_line with `1' as second parameter if we're going to - immediately overwrite the undo list - -lib/readline/search.c - - in make_history_line_current, use _rl_replace_text to make the line - replacement an undoable operation. Affects all non-incremental - search functions. - -parse.y - - make behavior introduced on 11/9 dependent on extended_quote - variable, controllable by extquote shopt option. Default setting is - on for backwards compatibility - -builtins/shopt.def - - new `extquote' option to control extended_quote variable - - 12/3 - ---- -jobs.c - - change message printed when attempting to put a background job in - the background with `bg' to include the job id and make the - statement declarative - - 12/10 - ----- -bashhist.h - - define explicit flag values for history_control - -variables.c - - change sv_history_control to use new flag values - - change sv_history_control to parse $HISTCONTROL as a colon-separated - list of values for the history_control variable - -bashhist.c - - change check_history_control to use new flag values and restructure - to remove case statement - - new function hc_erasedups(line); removes all entries matching LINE - from the history list - - call hc_erasedups() from check_add_history after we've determined - that we're saving the line - -doc/{bash.1,bashref.texi} - - documented new options available for $HISTCONTROL and that it can - be a colon-separated list of history control options - - 12/11 - ----- -subst.c - - fix pat_subst() to not increment `e' (pointer to the end of the - matched portion of the string) until after we're sure we're going - around the loop again; fixes problem with empty replacements for - a pattern that doesn't match (bug reported by Don Coleman - ) - - 12/17 - ----- -lib/readline/display.c - - fixes to multibyte redisplay from jir@yamato.ibm.com (Jiro SEKIBA): - o speed up calculation of first difference between old and new - lines in the common case - o don't try to see if we're in the middle of a multbyte char - in update_line (we'll see how this one works out) - - 12/18 - ----- -doc/bashref.texi - - make it clear that the `command-list' function definition may be - terminated by an ampersand before the closing brace - - 12/28 - ----- -redir.c - - set `expanding_redir' flag when expanding words in a redirection - -subst.c - - new function, exp_jump_to_top_level(), to do any word expansion - cleanup before a call to jump_to_top_level from within that file; - sets expanding_redir back to 0 before jump_to_top_level - -variables.c - - in find_variable(), don't call find_variable_internal with a second - parameter of 1 if expanding_redir is non-zero - - in find_variable_internal(), don't search the temporary env if - subshell_environment includes SUBSHELL_FORK (indicating a simple - command) and expanding_redir is non-zero - -parse.y - - increment line_number when we read a \ pair - -array.c - - added array_unshift_element and array_shift_element (which just call - array_shift and array_rshift, respectively), for bash debugger - support - - 1/4/2003 - -------- -doc/{bash.1,bashref.texi} - - note in the section describing the execution environment passed to - children that subshells inherit shell functions marked for export - - note in the section describing shell functions the possibility - that exported functions may result in two entries in the environment - with the same name - -parse.y - - when pushing an alias expansion onto the pushed_string list, append - a space to the expanded definition to make the parser's lookahead - work without using the `mustpop' hack in shell_getc - - 1/8 - --- -shell.c - - change calls to exit() with EX_USAGE as a parameter to use - EX_BADUSAGE instead, since EX_USAGE is defined as 258 and is - technically out of range - - 1/14 - ---- -aclocal.m4 - - check for the termcap functions in libc first: if we don't have - to link in another library, let's not do it - - change the test for mbstate_t to use AC_TRY_COMPILE instead of - AC_TRY_RUN - -doc/{bash.1,bashref.texi} - - document that bash turns line editing off if environment variable - EMACS is set to `t' when it starts up - -doc/bash.1 - - minor change to give the ftp url for the latest version of bash in - the bug reports section - -lib/readline/histexpand.c - - in get_history_event, cast a couple of `const char *' variables to - `char *' in function call parameter lists to avoid compiler warnings - - 1/21 - ---- -builtins/cd.def - - change `cd -' so it prints the current working directory after a - successful chdir even when the shell is not interactive - - 1/31 - ---- -lib/readline/doc/rltech.texinfo - - clarified exactly what is meant by the term `application-specific - completion function', made its use consistent, and documented - what variables are changed before such a function is called - -lib/readline/input.c - - new function, _rl_pushed_input_available(), returns non-zero if - there are characters in the input queue managed by rl_get_char - and _rl_unget_char - -lib/readline/rlprivate.h - - new extern declaration for _rl_pushed_input_available - -lib/readline/callback.c - - change rl_callback_read_char to check _rl_pushed_input_available - and loop if there's something there, so characters don't languish - until more keyboard input is read - -execute_cmd.c - - new variable, last_command_exit_signal, non-zero if - last_command_exit_value result from wait_for was result of a signal - -nojobs.c - - keep track of whether or not a given pid was killed by a signal with - a new flag in the pid_list array - - new function int find_termsig_by_pid(pid_t pid) to get the - terminating signal, if any, for a particular pid - - new function int get_termsig(WAIT status) returns the terminating - signal corresponding to status - - set last_command_exit_signal in wait_for and the various wait_for_xx - functions - -jobs.c - - new functions, process_exit_signal and job_exit_signal, return the - signal that killed a given process or job, if a signal caused its - death - - set last_command_exit_signal in wait_for by calling job_exit_signal - or process_exit_signal appropriately - -subst.c - - don't resend SIGINT to ourselves unless last_command_exit_signal is - SIGINT and last_command_exit_value == 128 + SIGINT. This fixes the - $(exit 130) bug reported by Paul Jarc - -expr.c - - new function, expr_bind_variable, calls bind_int_variable and - then stupidly_hack_special_variables. This fixes the - `let OPTIND=1' bug - -bashline.c - - change history_and_alias_expand_line and shell_expand_line to call - history_expand_line_internal so calls to pre_process_line are - localized - - change history_expand_line_internal and cleanup_expansion_error to - temporarily turn off hist_verify before calling pre_process_line - to avoid the effects described by teirllm@dms.auburn.edu - -parse.y - - don't unconditionally turn off PST_ALEXPNEXT in push_string. This - fixes the multiple alias expansion bug reported by Paul Jarc. - -lib/readline/vi_mode.c - - change rl_vi_subst to push `l' instead of ` ' -- it should be - equivalent, but this has been reported to fix a problem in multibyte - locales - -lib/readline/readline.h - - new state flag value RL_STATE_TTYCSAVED, indicates that save_tty_chars - has been called. Since it's only used and visible internally, it's - undocumented - -lib/readline/rltty.h - - changed all of the members of _rl_tty_chars struct to `unsigned char' - -lib/readline/rltty.c - - set the RL_STATE_TTYCSAVED after save_tty_chars is called - - new function, rl_tty_unset_default_bindings(), resets bindings for - everything rl_tty_set_default_bindings() messes with back to - rl_insert, so rl_tty_set_default_bindings can be called again with - possible changes - - new function that does the bulk of the work for - rltty_set_default_bindings: _rl_bind_tty_special_chars() - - change prepare_terminal_settings so that it can track changes to the - terminal special chars made by stty(1): unset the bindings with - rl_tty_unset_default_bindings before calling save_tty_chars, and - _rl_tty_set_default_bindings after, with the new values from - get_tty_settings(). This implements a long-standing request, most - recently made by Tim Waugh of Red Hat. - -lib/readline/readline.h - - extern declaration for rl_tty_unset_default_bindings() - -lib/readline/readline.c - - new function, reset_default_bindings, calls - rl_tty_unset_default_bindings() to reset the terminal special chars - back to rl_insert and then read the new ones - -lib/readline/doc/rltech.texinfo - - documented rl_tty_unset_default_bindings() - - 2/1 - --- -[prayers and condolences to the families of the space shuttle crew members] - -aclocal.m4 - - add checks for mbrtowc and mbrlen in BASH_CHECK_MULTIBYTE - - new check, BASH_FUNC_CTYPE_NONASCII, checks whether or not the ctype - functions handle non-ascii characters correctly - -config.h.in - - add HAVE_MBRTOWC and HAVE_MBRLEN - - add NO_MULTIBYTE_SUPPORT for new configure argument - - add CTYPE_NON_ASCII - -config-bot.h, lib/readline/rlmbutil.h - - make sure that mbrtowc, mbrlen, and wcwidth are all present before - turning on HANDLE_MULTIBYTE - - turn off multibyte chars if NO_MULTIBYTE_SUPPORT is defined - -configure.in - - new argument --enable-multibyte (enabled by default), allows - multibyte support to be turned off even on systems that support it - -lib/readline/chardefs.h - - define NON_NEGATIVE as 1 if CTYPE_NON_ASCII is defined - - 2/3 - --- -config.h.in - - add HAVE_WCTOMB - -aclocal.m4 - - check for wctomb in BASH_CHECK_MULTIBYTE - - 2/4 - --- -lib/readline/vi_mode.c - - in _rl_vi_change_mbchar_case, make sure the result from wctomb() - is NULL-terminated before trying to insert it with rl_insert_text() - - 2/5 - --- -lib/readline/display.c - - fix to update_line to avoid problems on systems with multibyte - characters when moving between history lines when the new line - has more glyphs but fewer bytes (twaugh@redhat.com) - -lib/readline/vi_mode.c - - use wcrtomb() instead of wctomb() in _rl_vi_change_mbchar_case - -pcomplete.c - - fix init_itemlist_from_varlist to handle the case where the - `varlist' is NULL - -doc/{bash.1,bashref.texi} - - clarified when a simple command may fail without the shell exiting - when -e is set - - 2/13 - ---- -parse.y - - when bash is started with --nolineediting, ignore \[ and \] when - decoding the prompt string - -subst.c - - fix remove_quoted_nulls so that a string with a CTLESC appearing - after a CTLNUL (which was removed) does not leave characters in - the string inappropriately - - 2/14 - ---- -builtins/common.h - - new flag value for parse_and_execute(): SEVAL_RESETLINE, which - allows the caller to specify whether or not the internal idea - of the line number should be reset to 1 - -builtins/evalstring.c - - parse_and_execute() now tells push_string to reset the line - number only if the SEVAL_RESETLINE flag is set by the caller - - 2/15 - ---- -builtins/evalfile.c - - pass SEVAL_RESETLINE from _evalfile() to parse_and_execute() - -subst.c - - if the shell is currently interactive, pass SEVAL_RESETLINE to - parse_and_execute() when doing command substitution - -jobs.c - - add SEVAL_RESETLINE to parse_and_execute while running SIGCHLD trap - -command.h - - add `line' members to case_com, for_com, select_com - - rearranged order of members in some of the command structs, so - `flags' and `line' are first - - added a `source_file' member to the function_def struct; keeps - track of where the function was defined - -doc/Makefile.in - - add some new suffix rules: .dvi.ps - -doc/{bash.1,bashref.texi} - - added text to the description of the `trap' builtin tightening up - the language describing when the ERR trap will be run - -error.c - - if $BASH_SOURCE (internally-maintained) exists, use BASH_SOURCE[0] - in get_name_for_error if the shell is not interactive - -array.h - - new convenience defines: array_push and array_pop - -variables.c - - change get_funcname to return this_shell_function->name only if - arrays have not been compiled into the shell - - change init_funcname_var to initialize FUNCNAME as an array variable - if we have arrays - - new function: get_self(SHELL_VAR *self), a degenerate `dynamic_value' - function for dynamic variables - - new function: init_dynamic_array_var(), a generic dynamic array - variable initializer to handle the common case - - use init_dynamic_array_var() instead of explicit init_dirstack_var() - - use init_dynamic_array_var() instead of explicit init_groups_var() - - new dynamic array variables: BASH_ARGC, BASH_ARGV, BASH_SOURCE, - BASH_LINENO, initialized with init_dynamic_array_var - -shell.c - - initialize BASH_LINENO, BASH_SOURCE, FUNCNAME in open_shell_script - -{execute_cmd,trap}.c - - take out trap_line_number, since parse_and_execute doesn't reset the - line number any more when running the trap commands - -make_cmd.c - - augment make_function_def to get source file name and call - bind_function_def to save the entire FUNCTION_DEF - -variables.c - - new hash table: shell_function_defs, keeps table of shell function - definitions including source file and line number info corresponding - to shell_functions table - - new functions: find_function_def and bind_function_def to manage - the shell_function_defs hash table - - new function: unbind_function_def to remove a function definition - from the shell_function_defs table (right now uncalled) - -variables.h - - extern declaration for bind_function_def, find_function_def - - new extern declaration for unbind_function_def - -execute_cmd.c - - in function prologue and epilogue, push and pop FUNCNAME, - BASH_SOURCE, and BASH_LINENO information - -dispose_cmd.c - - broke the code that disposes a FUNCTION_DEF out into two new - functions: dispose_function_def and dispose_function_def_contents - -dispose_cmd.h - - new extern declarations for dispose_function_def_contents and - dispose_function_def - -copy_cmd.c - - move body of copy_function_def (other than allocating a new - FUNCTION_DEF) to copy_function_def_contents - - make sure to copy the new source_file member of a function_def in - copy_function_def_contents - - copy_function_def is no longer static, copy_function_def_contents - is not either - -command.h - - new extern declaration for copy_function_def_contents and - copy_function_def - -parse.y - - keep a stack of line numbers where case, select, and for commands - start, with a maximum nesting level of 128; increment when reading - word after `for', `select' or `case' in read_token_word; decrement - in grammar actions after parsing a complete for, arith_for, select, - or case command - - create for, case, arith_for, and select commands with an extra - line number (word_lineno[word_top]) argument - -make_cmd.c - - make_for_or_select, make_for_command, make_case_command, and - make_select_command all take an extra `line_number' argument - -make_cmd.h - - corresponding changes to extern declarations for those functions - - 2/16 - ---- -{execute_cmd,shell,variables}.c - - follow each call to remember_args with a call to push_args or - pop_args to manage the BASH_ARGV and BASH_ARGC arrays. Only set - when the shell is started to run shell script or runs a shell - function. Doesn't handle `set' or `shift' yet, nor `source'. - -execute_cmd.c - - keep track of the level of subshells with a new variable, manipulated - in execute_in_subshell - - set currently_executing_command in execute_command_internal(), - even if we're running a trap - - better line number management when executing simple commands, - conditional commands, for commands in execute_command_internal() - and the various functions that implement the commands - (execute_cond_command, execute_for_command, execute_etc.) - -variables.c - - new dynamic variable BASH_SUBSHELL, with new get_subshell and - assign_subshell functions to manipulate it - - new functions push_args (WORD_LIST *list) and pop_args (void) to - manage the BASH_ARGC and BASH_ARGV dynamic array variables - -variables.h - - new extern declarations for push_args and pop_args - -builtins/evalfile.c - - in _evalfile, do appropriate things to the FUNCNAME, BASH_ARGV, - BASH_ARGC, BASH_SOURCE, and BASH_LINENO variables - -support/mksignames.c - - add another fake signal for `trap'; make NSIG+2 == `RETURN' - -trap.c - - _run_trap_internal now returns an int: the exit value of the command - run as the result of the trap - - run_debug_trap now returns an int: the exit value of the command - run as the result of the trap - - RETURN is a new special trap - - new function: set_return_trap(char *command) interface for the rest - of the shell, like set_{debug,error}_trap - - new function: run_return_trap() - - command substitution and other child processes don't inherit the - return trap - -trap.h - - new extern declaration for set_return_trap() and run_return_trap - - new defines for RETURN_TRAP; increment BASH_NSIG - - change extern declaration for run_debug_trap() since it now returns - an int - -shell.c - - new invocation long option: --debugger, turns on debugging and - sets internal `debugging_mode' variable - -execute_cmd.c - - new code to save return trap when executing a shell function, so - shell functions don't inherit it - - run debug trap before binding the variable and running the action - list in a `for' command - - run debug trap before binding the selection variable and running - the query in a `select' command - - run debug trap before running matcher in a `case' command - -builtins/set.def - - new `set -o functrace' (set -T), causes DEBUG trap to be inherited - by shell functions - - new `set -o errtrace' (set -E), causes ERR trap to be inherited - by shell functions - -flags.c - - new flags -E and -T, control error_trace_mode and - function_trace_mode respectively - -flags.h - - new extern declarations for error_trace_mode and function_trace_mode - - 2/17 - ---- -doc/bashref.texi - - changed the `dircategory' as per Karl Berry's suggestion - -doc/texinfo.tex - - update to version of 2003/02/04 from texinfo.org - -support/texi2dvi - - update to version 1.14 from texinfo-4.5 distribution - - 2/20 - ---- -support/config.{guess,sub} - - update to versions of 2002/11/30 - -lib/readline/doc/manvers.texinfo - - renamed to version.texi to match other GNU software - - UPDATE-MONTH variable is now `UPDATED-MONTH' - -lib/readline/doc/{hist,rlman,rluserman}.texinfo - - include version.texi - -doc/version.texi - - new file, with standard stuff matching other GNU distributions - -{doc,lib/readline/doc}/Makefile.in - - include right stuff for `version.texi' - -lib/readline/doc/{rluserman,rlman,hist}.texinfo - - use @copying and @insertcopying and @ifnottex instead of @ifinfo - - add FDL as an appendix entitled `Copying This Manual' - -lib/readline/doc/{rltech,rluser,hstech,hsuser}.texi - - changed the suffix from `texinfo' to `texi' - -lib/readline/doc/{rlman,rluserman}.texinfo, doc/bashref.texi - - include rltech.texi,rluser.texi,hstech.texi, and hsuser.texi - -lib/readline/doc/Makefile.in,doc/Makefile.in - - made appropriate changes for {{rl,hs}tech,{rl,hs}user}.texi - -lib/readline/doc/{rlman,rluserman}.texinfo - - changed the suffix from `texinfo' to `texi' - -lib/readline/doc/hist.texinfo - - renamed to history.texi - - 2/25 - ---- -pathnames.h.in - - moved pathnames.h here so value of DEBUGGER_START_FILE can be - substituted by configure - -aclocal.m4 - - added AM_PATH_LISPDIR for debugger - -configure.in - - added some variables: `bashvers', `relstatus' to use info in more - than one place - - call AM_PATH_LISPDIR - - new option: --enable-debugger, sets DEBUGGER cpp option - - new option with AC_ARG_VAR: DEBUGGER_START_FILE - - make `pathnames.h' a file generated by configure - -Makefile.in - - add rule to create pathnames.h - -builtins/declare.def - - added extra line number and source file name to `declare -F' output - if `--debugger' is used at startup - -builtins/evalfile.c - - call run_return_trap from source_file before returning the result - from _evalfile() - -execute_cmd.c - - call run_return_trap in execute_function before restoring the old - context - -builtins/source.def - - arrange to save and restore DEBUG traps when sourcing files if - function_trace_mode (set -o functrace) is not set - -print_cmd.c - - broke print_for_command, print_select_command, print_case_command - into two functions each: one to print the `header' and one for - the body - - print_cond_command is no longer static - - print_arith_command now takes a WORD_LIST *, since it doesn't - actually do anything with the ARITH_COM it's passed except print - the enclosed WORD_LIST - - print_arith_command is no longer static - -externs.h - - extern declarations for print_{for,select,case}_command_head, - print_cond_command, print_arith_command - -{.,builtins,lib/sh}/Makefile.in - - corrected dependencies on pathnames.h, since it's now created in - the build directory - - 3/5 - --- -lib/glob/glob.c - - handle alloca() failing (it's supposed to return NULL) - - use malloc() (with its attendent bookkeeping) instead of alloca() - in glob_filename() - -subst.c - - check whether shell_glob_filename returns NULL in - glob_expand_word_list - - change parameter_brace_expand_rhs to handle cases like - ${a[2]:=value} by properly creating the array element instead of a - variable named `a[2]' (reported by ) - -variables.c - - change bind_int_variable to use valid_array_reference instead - of looking for `[' - -lib/readline/vi_mode.c - - check for `a' in _rl_vi_done_inserting so the text inserted by an - `a' command can be reinserted with a `.' - -lib/readline/readline.c - - when entering vi insertion mode in readline_internal_setup(), make - sure that _rl_vi_last_key_before_insert is set to `i' so that undo - groups and redo work better (reported by ) - -lib/glob/sm_loop.c - - handle ?(...) in a pattern immediately following a `*', instead of - ignoring the `(' and treating the `?' as a single-char match, as - long as FNM_EXTFLAG is set (reported by ) - -aclocal.m4 - - new test for presence of struct timezone, BASH_STRUCT_TIMEZONE - -config.h.in - - add HAVE_STRUCT_TIMEZONE - -configure.in - - call BASH_STRUCT_TIMEZONE - -execute_cmd.c - - don't try to use `struct timezone' in calls to gettimeofday unless - HAVE_STRUCT_TIMEZONE is defined; use (void *)NULL otherwise - - 3/20 - ---- -execute_cmd.c - - new variable, the_printed_command_except_trap, saves the command - being executed before a trap is executed, for the debugger - -trap.c - - if in debugging mode, let command substitutions and other child - processes inherit the DEBUG and ERR traps if the `functrace' - (which is really a bad name, given this semantic) or `errtrace' - options, respectively, have been set - -shell.c - - local_pending_command renamed to command_execution_string; no longer - static - -variables.c - - new dynamic variable, BASH_COMMAND, set to the command string - currently executing, or the one that caused a trap to execute - (mapped to the_printed_command_except_trap) - - new variable, BASH_EXECUTION_STRING, set to the argument to the - -c invocation option, if the shell was started that way - - 3/22 - ---- -execute_cmd.c - - changed execute_for_command, eval_arith_for_expr, - execute_select_command, execute_arith_command, execute_cond_command, - execute_simple_command to implement new DEBUG trap semantics - for the debugger: if the DEBUG trap commands return a non-zero - status and debugging_mode is non-zero, we skip the command to be - executed - -trap.c - - change run_debug_trap for the debugger: if we're in the debugger - and the DEBUG trap returns 2 while we're in a function or sourced - script, we force a `return' - -shell.c - - new function, start_debugger(), that sources the debugger start file - and turns the debugger on - -builtins/shopt.def - - new settable option, `extdebug', turns on debugging_mode, as if - --debugger had been supplied at invocation (but does not source - debugger startup file) - -trap.c - - make sure that run_exit_trap arranges for `returns' to come back - there, too, so a `return' executed by an `exit' invoked within a - shell function behaves correctly - -support/shobj-conf - - change darwin/MacOS X stanza based on advice from mac os x developers - -lib/sh/mailstat.c - - set the atime member of the synthesized stat struct to 0 if `cur/' - is empty, rather than leaving it undefined - - 3/24 - ---- -builtins/caller.def - - new builtin to provide a call stack for the debugger - -builtins/evalfile.c - - added a second `flags' argument to source_file() - - new flag value for flags argument to _evalfile(): FEVAL_NOPUSHARGS. - If included in flags arg, it means to not manipulate the BASH_ARGV - and BASH_ARGC arrays - -builtins/common.h - - change prototype for source_file() - -builtins/source.def - - add flag value to call to source_file(): set to 1 if we replaced - the positional parameters - - add call to push_args if additional arguments supplied to the - source builtin - - add call to pop_args in maybe_pop_dollar_vars - -execute_cmd.c - - run the debug trap in execute_function so the debugger can stop - before the first command in a function body is executed - - modify subshell_level before executing a builtin or function in a - subshell - - print `for', `select', `case' command heads when set -x is enabled - -print_cmd.c - - `xtrace_print_word_list' now takes an additional flags argument, - which, if non-zero, says to print indirection_level_string() - - new functions to print for, select, and case command heads when - set -x is enabled - - add spaces after `((' and before `))' in xtrace_print_arith_command - -externs.h - - changed extern declaration for xtrace_print_word_list - - new declarations for xtrace_print_{for,case,select}_command_head() - -subst.c - - modify subshell_level when executing a command substitution - - 3/25 - ---- -execute_cmd.c - - use `line_number' in executing_line_number instead of looking into - the current command if it's a simple command; rearrange code to - make this simpler to compile in and out - - need to save and restore value of currently_executing_command around - calls to debug trap and return trap in execute_function - -make_cmd.c - - make sure make_arith_for_command() disposes the WORD_LIST * it is - passed, since nothing else does and it's not used directly - - 3/28 - ---- -Makefile.in - - fixed dependencies for `error.o' on shell.h and version.h -- makes - parallel makes (gmake -j 4) work correctly - -doc/{bash.1,bashref.texi} - - documented all new features added to support the debugger - - 4/1 - --- -lib/sh/shquote.c - - make sure CTLESC and CTLNUL characters are escaped with CTLESC - by sh_double_quote, sh_backslash_quote and - sh_backslash_quote_for_double_quotes - Fixes vulnerability reported by svdb@stack.nl - -shell.h - - new `pipestatus' member of sh_parser_state_t, to save and restore - $PIPESTATUS - -parse.y - - changes to save_parser_state and restore_parser_state to save and - restore $PIPESTATUS - -builtins/read.def - - add a call to word_list_remove_quoted_nulls before assigning the - word list read from standard input to an array variable. Fixes - bug reported by holzhey@ppprs1.phy.tu-dresden.de - - 4/3 - --- -execute_cmd.c - - in execute_null_command, if redirections are supplied, make sure - things like 3 for possible definitions of intmax_t, uintmax_t - (reported by ro@techfak.uni-bielefeld.de) - - 7/30 - ---- -parse.y - - remove checking for `time' reserved word from special_case_tokens(); - use regular mechanism in CHECK_FOR_RESERVED_WORD. This allows `time' - to be aliased. (Reported by Glenn Morris - ) - - 7/31 - ---- -lib/readline/history.h - - extern declaration for history_write_timestamps - -lib/readline/histfile.c - - don't write timestamps to the history file in history_do_write - unless history_write_timestamps is set to non-zero by the application - (set to 0 by default) - -lib/readline/doc/{hstech.texi,history.3} - - document history_write_timestamps - -variables.[ch] - - new special variable function, HISTTIMEFORMAT; special function - sets history_write_timestamps to 1 if HISTTIMEFORMAT is set - - 8/4 - --- -builtins/history.def - - added support for printing time stamps based on the value of the - HISTTIMEFORMAT variable when displaying history entries - -doc/{bash.1,bashref.texi} - - added description of new HISTTIMEFORMAT variable - - 8/5 - --- -config-top.h - - remove /usr/ucb from any default paths - -mailcheck.c - - make_default_mailpath now returns NULL if DEFAULT_MAIL_DIRECTORY - is not defined - - remember_mail_dates now returns if make_default_mailpath returns - NULL - -config-bot.h - - reorganized the sections; provide an explicit placeholder for - builders to #undef any feature defines they don't want that - configure creates for them, like the default mail path - - 8/9 - --- -config.h.in - - add HAVE_REGEX_H, HAVE_REGCOMP, HAVE_REGEXEC for detection of POSIX.2 - regular expression functions - - add COND_REGEXP define to enable and disable the =~ operator for - matching extended regular expressions in [[...]] commands - -configure.in - - new option, --enable-cond-regexp, enables =~ and code to perform - regular expression matching in [[...]] - -config-bot.h - - undef COND_REGEXP if the OS doesn't provide posix regexp support - -doc/bashref.texi - - documnent new --enable-cond-regexp option to configure - - 8/18 - ---- -support/shobj-conf - - support for shared objects on FreeBSD-gnu (from Robert Millan) - - 8/25 - ---- -lib/sh/shmatch.c - - new file, shell interface to posix extended regular expression - matching - -externs.h - - new extern declarations for functions in shmatch.c - -execute_cmd.c - - incorporate code into execute_cond_node that does extended regular - expression matching for the =~ operator - -parse.y - - add `=~' to the list of binary operators accepted by the conditional - command parser - -doc/{bash.1,bashref.texi} - - documented =~ conditional binary operator and the BASH_REMATCH - variable - - 8/27 - ---- -lib/readline/display.c - - take multibyte characters into account when looking for quoted - substrings on which to do completion (fix from jir@yamato.ibm.com) - -lib/readline/util.c - - fix typo in _rl_strpbrk - -lib/readline/rldefs.h - - use function version of _rl_strpbrk in multibyte locales, because - it understands to skip over special characters in multibyte - character sequences - - 8/28 - ---- -jobs.c - - in wait_for, check for window size changes if a job that exits due - to a signal or is stopped was in the foreground, not just if it's - the current job - - 9/10 - ---- -support/config.{guess,sub} - - add support to recognize FreeBSD running on the amd64 - -subst.c - - if the new `fail_glob_expansion' variable is non-zero, globbing that - fails to match anything causes an expansion error - -builtins/shopt.def - - new `failglob' expansion: if enabled, failed globs cause an error - -test/shopt.right - - take `failglob' into account - -doc/{bash.1,bashref.texi} - - documented new `failglob' option and its effects - - 9/12 - ---- -findcmd.c - - fix file_status to treat the mode bits and uid right -- in particular, - don't assume the `other' bits always apply. Bug reported by - ; fix inspired by - -command.h - - new word flag: W_NOCOMSUB, meaning to not perform command - substitution on a word - -subst.c - - new flag for param_expand: PF_NOCOMSUB. If non-zero, $(...) - command substitutions are not expanded, but returned unchanged - - change expand_word_internal to pass through `` command substitutions - unchanged if (word->flags & W_NOCOMSUB) != 0 - - change expand_word_internal to pass PF_NOCOMSUB to param_expand - if (word->flags & W_NOCOMSUB) != 0 - -builtins/shopt.def - - rename set_interactive_comments to set_shellopts_after_change, which - more accurately reflects its purpose - -syntax.h - - add a define for isblank() in case the system doesn't provide one - -jobs.c - - change raw_job_exit_status to understand `pipefail', using the new - `pipefail_opt' variable - -flags.[ch] - - declare pipefail_opt - - reset pipefail_opt to 0 in reset_shell_flags - -builtins/set.def - - add `set -o pipefail' and document it in help output - -doc/{bash.1,bashref.texi} - - document `set -o pipefail' and the effect of the pipefail option - -mksyntax.c,syntax.h - - sh_syntaxtab is no longer `const' - - new generated variable, sh_syntabsiz, set to number of entries in - sh_syntaxtab, written to generated syntax.c - -locale.c - - new function, locale_setblanks(), sets each member of the current - locale's class to have the CSHBRK flag in sh_syntaxtab - - 9/17 - ---- -arrayfunc.c - - change convert_var_to_array to not set array[0] to a NULL value - (if the scalar variable had no value; e.g., after being created - with `local arrayvar') - -lib/readline/display.c - - save and restore the value of prompt_invis_chars_first_line in - rl_{save,restore}_prompt, and reinitialize it to 0 before printing - something in the message area - -lib/readline/bind.c - - new functions: rl_bind_keyseq_if_unbound_in_map(ks, func, kmap); - binds key sequence KS to function FUNC in keymap KMAP, and - rl_bind_keyseq_if_unbound (ks, func); binds key sequence KS to - function FUNC in the current keymap - -lib/readline/readline.h - - extern function declarations for rl_bind_keyseq_if_unbound_in_map and - rl_bind_keyseq_if_unbound - -lib/readline/{readline,terminal}.c - - _rl_bind_if_unbound -> rl_bind_keyseq_if_unbound - -lib/readline/{bind.c,rlprivate.h} - - remove _rl_bind_if_unbound - - 9/18 - ---- -lib/readline/doc/rltech.texi - - document rl_bind_keyseq_if_unbound and - rl_bind_keyseq_if_unbound_in_map - - 9/19 - ---- -lib/readline/bind.c - - new functions rl_bind_key_if_unbound_in_map and - rl_bind_key_if_unbound; analogous to (and implemented in terms of) - keyseq functions - - rl_bind_keyseq_in_map: a new function, equivalent to rl_set_key - (which remains for backwards compatibility); changed callers to - use it - - new function, rl_bind_keyseq, equivalent to rl_bind_keyseq_in_map - with a third argument of _rl_keymap - -lib/readline/readline.h - - extern declarations for rl_bind_key_if_unbound_in_map and - rl_bind_key_if_unbound - - extern declarations for rl_bind_keyseq_in_map and rl_bind_keyseq - -lib/readline/doc/rltech.texi - - document rl_bind_keyseq and rl_bind_keyseq_in_map - -configure.in - - require at least readline-5.0 - -config-bot.h - - define SYS_SIGLIST_DECLARED if it's not defined, but - HAVE_DECL_SYS_SIGLIST is, to deal with differences between - autoconf versions - -bashline.c - - use rl_bind_key_if_unbound_in_map when binding bash keybindings in - initialize_readline(), so inputrc files can override them - - 9/22 - ---- -lib/readline/histsearch.c - - do better bounds checking for history_offset and history_length in - history_search_internal - -builtins/history.def - - in delete_last_history(), make sure we don't leave the history - offset longer than the history length after calling delete_histent - - 9/23 - ---- -jobs.c - - small change to notify_of_job_status so job status messages get - printed even if the shell was started to run `-c command'. The - old behavior was intentional, but I cannot remember why, so we'll - try it the other way for a while (debian bash bug #211693) - - 9/24 - ---- -jobs.c - - slightly modify change from 9/23 so that jobs started to run - command substitutions don't print job status messages - - 9/25 - ---- -lib/readline/search.c - - when reading a non-incremental search string from the terminal, - use a separate undo list rather than chaining it to the undo list - from the rest of the line, since the whole undo list will get - freed when the search string is complete - -lib/readline/readline.h - - changed the defines guarding the stdarg prototype for rl_message to - match what's actually used in display.c, where it's defined - - 9/26 - ---- -[bash-3.0-alpha released] - - 9/29 - ---- -lib/sh/shmatch.c - - fix to build correctly when arrays are not compiled into the shell - -subst.c - - fix command substitution to run any exit trap defined in the - command substitution before returning; the exit trap is not inherited - from the calling shell - -lib/readline/shell.c - - change sh_set_lines_and_columns to free the memory allocated and - passed to setenv(), since setenv is specified by POSIX to allocate - new memory and copy its arguments - -jobs.c - - change logic in make_child so that every child process attempts to - set the terminal's process group to the pipeline's process group - when PGRP_PIPE is defined, just like when it's undefined. This is - reported to fix some tricky synchronization problems on Red Hat - Enterprise Linux 3. Fix from Ernie Petrides . - - 9/30 - ---- -builtins/printf.def - - tescape no longer needs a `trans_squote' argument, since it's the - same as the `sawc' argument. The `sawc' argument now means to do - the %b argument processing if non-null - - fix processing of octal constants for %b arguments (\0 followed by - up to three octal digits) and other escape sequences (\ followed by - up to three octal digits) - - hex constants `\xHHH' are now allowed to contain any positive - number of digits; previously they were restricted to two [removed] - - allow two new escape sequences: \" and \?, for compatibility with - ksh93 and ANSI C - -doc/{bash.1,bashref.texi} - - documented processing that printf performs for arguments to %b - escape sequences - -lib/sh/strtrans.c - - add \" and \? to escape sequences recognized by `echo -e' - - 10/1 - ---- -version.c - - use snprintf instead of sprintf if configure tells us we have it - - 10/3 - ---- -subst.c - - in list_remove_pattern, take into account the fact that one of the - list elements may be NULL, and don't free the result of - remove_pattern() without checking - - in remove_pattern, return savestring(param) if *param == '\0', - since callers expect to free() non-null return values - - 10/4 - ---- -subst.c - - change verify_substring_values to make it clearer that the first - offset deals with array indices and the second deals with numbers - of elements, when doing array subranges with ${a[@]:e1:e2} - -array.c - - change array_subrange to make it explicit that the second offset - argument is a count of the desired number of elements, not an - ending index. This deals with sparse arrays correctly. - - 10/6 - ---- -variables.c - - fix memory leak in assign_in_env - - 10/8 - ---- -subst.c - - in parameter_brace_expand, check that the last characters are `]}' - before checking for ${!array[@]} - -execute_cmd.c,builtins/source.def - - push and pop the args (BASH_ARGV and BASH_ARGC) when executing a - shell function or sourcing a script only when in debugging mode - - 10/11 - ----- -arrayfunc.c - - make sure array_variable_name returns values for the SUBP and LENP - arguments if they're non-null, since callers expect to use them - even if the array subscript is bad - -error.c - - call exit_shell instead of sh_exit from parser_error and - report_error so the right things happen (running exit trap, doing - the right interactive cleanup, etc.) - -lib/readline/complete.c - - new variable, rl_completion_quote_character, set to any quote char - readline thinks it finds before any application completion - function is called - - new variable, rl_completion_suppress_quote, settable by an - application-specific completion function. If set to non-zero, the - completion code does not append a closing quote in append_to_match - -lib/readline/readline.h - - extern declarations for rl_completion_quote_character and - rl_completion_suppress_quote - -bashline.c - - set rl_completion_suppress_quote in command_subst_completion_function - because that would be inserted before any closing "`" or ")", which - is somewhat disconcerting - -lib/readline/doc/rltech.texi - - documented rl_completion_suppress_quote and - rl_completion_quote_character - - 10/13 - ----- -bashhist.c - - use sv_histchars instead of setting history_comment_char directly in - bash_initialize_history so assignments to $histchars made in - ~/.bashrc are honored - - 10/21 - ----- -trap.c - - make sure run_exit_trap sets `running_trap' appropriately - - new variable, trap_saved_exit_value, set to last_command_exit_value - before running any trap commands; available to the rest of the - shell; use trap_saved_exit_value to replace some function-local - variables - -builtins/exit.def - - if the shell is running the exit trap, and no argument is given - to `exit', use trap_saved_exit_value as the exit status instead - of the last command exit value (which could be the previous command - run in the exit trap), as required by POSIX.2 - - 10/25 - ----- -doc/{bash.1,bashref.texi} - - add `alias' to the list of documented `assignment statement' builtins - - 11/1 - ---- -doc/bash.1 - - remove the `.' from the sample $PATH value - -parse.y - - make sure parse_compound_assignment prompts with $PS2 if it reads - a newline while parsing the compound assignment statement. Bug - reported by Stephane Chazelas - - parse_string_to_word_list now takes a new second argument: `int flags' - - new parser state flag: PST_COMPASSIGN; indicates that the shell is - parsing a compound assignment statement - - parse_string_to_word_list turns on PST_COMPASSIGN if `flags' arg - has low bit set - - turn PST_COMPASSIGN on and off in parse_compound_assignment - -externs.h - - change prototype declaration for parse_string_to_word_list - -arrayfunc.c - - change call to parse_string_to_word_list to add new flags arg - -general.c - - assignment() takes a new `flags' second argument - - if `flags' is non-zero, accept `[' as a legal assignment statement - starter character (for parsing compound array assignments) - -general.h - - add new argument to prototype declaration for assignment() - -parse.y,{subst,variables}.c, builtins/{setattr,declare}.def - - change calls to assignment() (parse.y calls with flags == 1 when - parser_state inlcudes PST_COMPASSIGN) - -arrayfunc.c - - in assign_array_var_from_string(), don't treat an expanded word - of the form [ind]=value specially unless the W_ASSIGNMENT flag is - set. This means that words that are the result of expansions but - happen to have the same format as compound assignment statement - words will not be treated as such. For instance - - v='[12]=foobar' - a=( $v ) - - will result in a[0]='[12]=foobar' instead of a[12]=foobar. This - is closer to how `regular' assignment statements are treated and - compatible with ksh93. Bug reported by Stephane Chazelas - -shell.c - - new --protected argument, disables command substitution when used - with --wordexp (like --wordexp, it remains undocumented) - - change run_wordexp to turn on the W_NOCOMSUB flag in each word - to be expanded if protected_mode is set - - 11/7 - ---- -doc/{bash.1,bashref.texi} - - clarified the language concerning inherited signal dispositions and - when traps are run - -support/shobj-conf - - slight changes to the darwin (Mac OS X) stanza for MacOS X 10.3 - (for the readline shared library builds, which shares this script) - -lib/readline/histexpand.c - - change to make `^' behave as equivalent to word one, as csh does, - and as the documentation states - -lib/readline/display.c - - in update_line, make sure to use col_lendiff in all calculations - where the cursor position is concerned (like when calculating - the value of _rl_last_c_pos). Fixes bug reported by Andreas - Schwab - - 11/12 - ----- -trap.c - - make _run_trap_internal catch `return' builtin longjmps and clean - up before longjmping on to where the return was intended to go - (fixes bug with not turning off SIG_INPROGRESS flag when `return' - executed in trap command) - - 11/18 - ----- -builtins/cd.def - - in posix mode, set errno to ENOTDIR if canonicalization fails, - unless the canonicalization functions leave it set to ENOENT - - 11/25 - ----- -make_cmd.c - - in make_simple_command, don't blindly dereference element.redirect - -parse.y - - the list_terminator production now has an `int' value so it can be - used in other grammar productions - - add a rule that makes `time' on a line by itself time a null - command (this is iffy) - - 11/28 - ----- -subst.c - - change the pattern substitution code (${var//pat/rep}) to use the - same pattern expansion function (getpattern()) as the pattern - removal expansions. This has the effect of no longer performing - quote removal on the pattern before trying to match it. This - fixes an incompatibility with ksh93 reported on comp.unix.shell - -nojobs.c - - add replacement function for siginterrupt on the off chance that a - system has posix signals but lacks siginterrrupt - -lib/readline/display.c - - fix from Tim Waugh at Red Hat to speed up inserting characters into - long lines in a UTF-8 environment by optimizing the calculation of - the first difference between old and new lines by checking to see - whether the old line is a subset of the new - - 11/29 - ----- -lib/malloc/stats.c - - break code that opens file (and interprets %p) into separate function - _imalloc_fopen(char *s, char *fn, char *def, char *defbuf, size_t defsiz) - for use by rest of library - - default stats file is now `stats.PID' - -lib/malloc/trace.c - - new function, malloc_set_tracefn (char *s, char *fn), sets tracing - to the file named by FN (with %p interpolated as the pid), using - some default if FN is NULL - -lib/malloc/shmalloc.h - - new extern declaration for malloc_set_tracefn - - 12/4 - ---- -execute_cmd.c - - combined several common strings from do_piping() into one - dup_error() function - -builtins/common.[ch] - - new function, `sh_notbuiltin(s)' prints error message about s not - being a shell builtin - -builtins/{builtin,enable}.def - - call sh_notbuiltin instead of using literal string - -{arrayfunc,expr,error}.c - - use one string variable for `bad array subscript' error message; use - in calls to various error reporting functions - -Makefile.in - - add variables for localedir and the PACKAGE_* variables, auto-set - by configure - -configure.in - - un-cache values for gettext, textdomain, and bindtextdomain if they're - not in libc but in libintl so the right variables get set - -bashintl.h - - add necessary defines for marking strings to be translated using - gettext - -locale.c - - set textdomain and directory in set_default_locale - - don't call textdomain with the value of $TEXTDOMAIN, since we don't - want to override the default domain ("bash") - - don't call bindtextdomain unless default_domain already has a value - - when translating $"..." strings, use dgettext with the script's - default domain (value of $TEXTDOMAIN) - - 12/9 - ---- -builtins/mkbuiltins.c - - include "bashintl.h" in the generated "builtins.c" - -support/{config.rpath,mkinstalldirs} - - new files to support gettext i18n - -ABOUT-NLS - - new readme file for gettext internationalization - -po/{Makefile.in.in,Rules-quot,boldquot.sed,en@boldquot.header,en@quot.header,insert-header.sin,quot.sed,remove-potcdate.sin} -po/{POTFILES.in,bash.pot} - - new files for gettext - -lib/intl - - new directory, with libintl stuff from gettext - -aclocal.m4 - - add m4 files from gettext distribution needed by libintl - -configure.in - - create po/Makefile.in and lib/intl/Makefile in AC_OUTPUT - - add call to AM_GNU_GETTEXT to initialize gettext stuff - -Makefile.in - - use mkinstalldirs instead of mkdirs in the `installdirs' target - - changes for intl/ and po/ subdirectories in build and install - - changes to have libintl linked in, as determined by configure - - changes to have libintl built, just in case it's used (though I'd - rather not) - - 12/10 - ----- -config.h.in - - additional #defines required by the libintl library - - add ENABLE_NLS define for AM_GNU_GETTEXT - - take out defines for HAVE_{BINDTEXTDOMAIN,GETTEXT,TEXTDOMAIN} - -configure.in - - removed old tests for libintl and gettext/textdomain/bindtextdomain - -locale.c - - remove HAVE_GETTEXT code; we have gettext unconditionally now - -bashintl.h - - change to include "gettext.h" and remove the conditional code based - on whether or not gettext is present - - 12/16 - ----- -lib/readline/vi_mode.c - - fix problem with rl_vi_eWord that caused it to skip over the last - character of a word if invoked while point was on the next-to-last - character - - 12/18 - ----- -{arrayfunc,bashhist,bashline,error,eval,execute_cmd,expr,general,input,jobs}.c -{mailcheck,make_cmd,nojobs,pcomplete,pcomplib,print_cmd,redir,shell,sig}.c -{subst,test,trap,variables,version,xmalloc}.c -parse.y -builtins/{common,evalfile,getopt}.c -builtins/{bind,break,caller,cd,complete,declare,enable,exec,exit,fc,fg_bg}.def -builtins/{hash,help,history,jobs,kill,printf,pushd,read,return,set,setattr}.def -builtins/{shift,shopt,source,suspend,type,ulimit,umask}.def -lib/sh/{fmtulong,netopen}.c - - include "bashintl.h" for gettext defines - -Makefile.in - - add `-DBUILDTOOL' to CFLAGS for buildversion.o - -bashintl.h - - if `BUILDTOOL' is defined, define ENABLE_NLS to 0 so we don't have - to compile and link in the gettext stuff - -Makefile.in,lib/sh/Makefile.in,builtins/Makefile.in - - update dependencies on bashintl.h and include/gettext.h - - 12/19 - ----- -{arrayfunc,bashhist,bashline,error,eval,execute_cmd,expr,general,input,jobs}.c -{mailcheck,make_cmd,nojobs,pcomplete,pcomplib,print_cmd,redir,shell,sig}.c -{subst,test,trap,variables,version,xmalloc}.c -builtins/{common,evalfile,getopt}.c -builtins/{bind,break,caller,cd,complete,declare,enable,exec,exit,fc,fg_bg}.def -builtins/{hash,help,history,jobs,kill,let,printf,pushd,read,return,set}.def -builtins/{setattr,shift,shopt,source,suspend,type,ulimit,umask}.def -lib/sh/{fmtulong,netopen}.c -lib/malloc/{malloc,stats,table,watch}.c - - mark up strings in source files for gettext processing - -lib/malloc/imalloc.h - - include "bashintl.h" if SHELL is defined, otherwise make _(x) an - identity define - -lib/malloc/Makefile.in - - add dependencies on ${topdir}/bashintl.h and ${BASHINCDIR}/gettext.h - - 12/21 - ----- -bashline.c - - make sure we index into rl_line_buffer with indexes > 0 in - attempt_shell_completion - - 12/31 - ----- -Makefile.in - - descend into `po' and run make recursively for the various clean - targets - - 1/4 - --- -include/shmbutil.h - - two new macros: BACKUP_CHAR(str, strsize, i), which backs up one - multibyte character in STR starting at index I, and - BACKUP_CHAR_P(str, strsize, p), which backs up one multibyte - character in STR starting at P, which is a char * - - 1/6 - --- -pcomplete.c - - in pcomp_filename_completion_function, use the quote character - readline found (and assigned to rl_complete_quote_character) when - dequoting the filename by a completion call from readline (when - rl_dispatching != 0) - -bashline.c - - ditto for bash_directory_completion_matches - - 1/7 - --- -lib/readline/complete.c - - new variable, rl_completion_found_quote, set to non-zero value if - readline finds what it thinks is quoting in the word to be completed - -lib/readline/readline.h - - extern declaration for rl_completion_found_quote - - 1/8 - --- -lib/readline/doc/rltech.texi - - documented rl_completion_found_quote - -lib/readline/complete.c - - in compute_lcd_of_matches, if it looks like what the user typed was - dequoted before generating filename matches, dequote the user's - text again before figuring out the case-insensitive lcd - - 1/9 - --- -lib/readline/display.c - - fix from Edward Catmur to logic that handles - invisible characters in prompt string. Original code was wrong - about local_prompt_prefix; it gave incorrect results when prompt - contained invisible characters after a line break - - 1/10 - ---- -subst.c - - new function, mb_substring(), does character (possibly multibyte) - oriented rather than strictly byte-oriented substring extraction. - The passed indices, rather than strictly indexing into the string, - indicate character positions that need to be calculated. From - Tim Waugh - - change parameter_brace_substring to use mb_substring if necessary - -included/shmbutil.h - - new define SADD_MBQCHAR_BODY, common code for adding a quoted - (preceded by CTLESC) multibyte character to an accumulating string - in the subst.c expansion code - -subst.c - - use SADD_MBQCHAR_BODY in expand_word_internal - - new static function, mb_getcharlens, allocates and returns an array - of character lengths for (possibly multibyte) characters in the - argument string - - change pattern matching operations to use while loops instead of - for loops to handle multibyte characters better (no more simple - increment or decrement) - - change pattern matching operations to use multibyte character - operations instead of simple increments and decrements. Don't - use BACKUP_CHAR_P -- use the mblen array instead, because that - avoids the N**2 behavior of having to count from the beginning - of the string each time you want to back up one character. Changes - to remove_pattern and match_pattern - - 1/12 - ---- -lib/readline/display.c - - make expand_prompt count multbyte characters in the prompt string - by using _rl_find_next_mbchar (and copying possibly more than one - byte) instead of a simple increment and single byte copy - - 1/13 - ---- -lib/readline/display.c - - expand_prompt takes a new reference argument -- it returns - the actual count of (possibly multibyte) characters displayed - on the screen - - don't short-circuit in expand_prompt unless we're not going to - be using any multibyte characters - - change calls to expand_prompt to pass an argument for the - number of physical characters the prompt occupies - (prompt_physical_chars) - - initialize `lpos' (the physical cursor position) from - prompt_physical_chars in rl_redisplay - -lib/readline/mbutil.c - - in _rl_find_prev_mbchar_internal, if mbrtowc returns -1 or -2, and - we assume that the character is a single-byte char, make sure we - update `prev' so it doesn't get lost. Fixes problems encountered - when a non-ascii char is the last char on the line and we're moving - back past it with ^B, and other display problems caused by the same - situation - - 1/15 - ---- -lib/readline/doc/rltech.texi - - document RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE in the - description of rl_expand_prompt() - - 1/20 - ---- -bashline.c - - in initialize_readline, make sure M-C-j and M-C-m are still bound to - vi-editing-mode before unbinding them -- they may have been rebound - in an inputrc - -variables.c - - in unbind_variable, unset attributes other than `local' and exported - (if the variable came from a temporary environment) when unsetting a - local variable inside a function - - 1/21 - ---- -configure.in - - add libintl build directory to the list of include directories if - it's being built (using INTL_BUILDDIR) - -Makefile.in,{builtins,lib/{sh,malloc}}/Makefile.in - - substitute LIBBUILD as ${BUILD_DIR}/${LIBSUBDIR} - - define INTL_BUILDDIR as ${LIBBUILD}/intl - -{builtins,lib/sh}/Makefile.in - - make sure INTL_INC is added to the list of include directories - - make sure INTL_LIBSRC is defined with the correct value - -{configure,Makefile,{builtins,lib/sh}/Makefile}.in - - substitute LIBINTL_H as ${INTL_BUILDDIR}/libintl.h - -Makefile.in,builtins/Makefile.iin - - all files depending on bashintl.h also depend on ${LIBINTL_H} - (which may be empty) - -Makefile.in - - make a rule telling how to build lib/intl/libintl.h if necessary - - 1/24 - ---- -builtins/read.def - - make sure that the array name supplied as an argument to -a is a - valid identifier - -parse.y - - make the \W expansion abbreviate $HOME with a ~ (seems to be more - useful) - -doc/{bash.1,bashref.texi} - - document new behavior of \W - -subst.c - - make sure parameter_brace_expand_rhs uses the first character of - $IFS when making the string to return from the expanded word - (which, in the case of "$@" or $@, contains multiple words that - need to be separated) - - 1/25 - ---- -builtins/common.c - - change get_job_spec to make `%' by itself or an empty argument - return NO_JOB - -jobs.h - - new possible value for a job spec return value: BAD_JOBSPEC - (for syntactically invalid specs, like the empty string) - -shell.c - - in open_shell_script, check to see whether or not we can find and - open the filename argument before setting dollar_vars[0] or - manipulating BASH_SOURCE, so the error messages come out better - -subst.c - - in string_list_internal, short-circuit right away to savestring() - if the list only has a single element - - 1/28 - ---- -lib/readline/rltypedefs.h - - new set of typedefs for functions returning char * with various - arguments (standard set) - -lib/readline/complete.c - - new function pointer, rl_completion_word_break_hook, called by - _rl_find_completion_word, used to set word break characters at - completion time, allowing them to be position-based - -lib/readline/doc/rltech.texi - - documented rl_completion_word_break_hook - -lib/readline/kill.c - - added new rl_unix_filename_rubout, which deletes one filename - component in a Unix pathname backward (delimiters are whitespace - and `/') - -lib/readline/readline.h - - extern declaration for rl_unix_filename_rubout - -lib/readline/funmap.c - - new bindable readline command `unix-filename-rubout' - -lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 - - documented `unix-filename-rubout' - - 1/29 - ---- -lib/readline/histexpand.c - - change history_tokenize_internal to handle non-whitespace delimiter - characters by creating separate fields (like the shell does when - splitting on $IFS) - - 1/30 - ---- -lib/glob/xmbsrtowcs.c - - new function, xdupmbstowcs, for convenience: calls xmbsrtowcs - while allocating memory for the new wide character string - - some small efficiency improvments to xmbsrtowcs - -include/shmbutil.h - - extern declaration for xdupmbstowcs - -lib/glob/strmatch.h - - include config.h for definition of HANDLE_MULTIBYTE - - remove the HAVE_LIBC_FNM_EXTMATCH tests - - new extern declaration for wcsmatch(whchar_t *, wchar_t *, int) - -configure.in - - remove call to BASH_FUNC_FNMATCH_EXTMATCH; it's no longer used - -lib/glob/smatch.c - - simplify xstrmatch() by using xdupmbstowcs() instead of inline code - -lib/glob/glob.c - - modify mbskipname() to avoid the use of alloca - - simplify mbskipname() by using xdupmbstowcs() instead of inline code - - simplify glob_pattern_p() by using xdupmbstowcs() instead of - inline code - - fix memory leak in wdequote_pathname - - simplify wdequote_pathname() by using xdupmbstowcs() instead of - inline code - -lib/glob/strmatch.c - - new function, wcsmatch(), `exported' wide-character equivalent of - strmatch() - -subst.c - - old match_pattern is now match_upattern - - match_pattern now either calls match_upattern or converts - mbstrings to wide chars and calls match_wpattern - - match_upattern reverted to old non-multibyte code - - new function: match_pattern_wchar, wide character version of - match_pattern_char - - 2/1 - --- -subst.c - - old remove_pattern is now remove_upattern - - remove_upattern reverted to old non-multibyte code (pre-Waugh patch) - - new multibyte version of remove_pattern: remove_wpattern - - remove_pattern now calls either remove_upattern or converts a - multibyte string to a wide character string and calls - remove_wpattern - - new function, wcsdup, wide-character version of strdup(3) - - 2/4 - --- -print_cmd.c - - temporarily translate a >&filename redirection from - r_duplicating_output_word to r_err_and_out (as the expansion code - in redir.c does) so it prints without a leading `1' (file - descriptor) - - 2/5 - --- -aclocal.m4 - - add a check for wcsdup to BASH_CHECK_MULTIBYTE - -config.h.in - - add HAVE_WCSDUP define - - 2/9 - --- -builtins/shift.def - - fix a call to sh_erange that possibly dereferences a NULL pointer - - 2/12 - ---- -general.c - - start at a general set of file property checking functions: - file_isdir(), file_iswdir() (is writable directory) - -general.h - - extern declarations for new functions - -lib/sh/tmpfile.c - - use file_iswdir() to make sure the temporary directory used for - here documents and other temp files is writable in get_sys_tmpdir() - - 2/17 - ---- -bashline.c - - fix conditional binding of emacs-mode M-~ -- there is a default - binding for it (rl_tilde_expand), so a straight call to - rl_bind_key_if_unbound_in_map doesn't do the right thing - - 2/27 - ---- -[bash-3.0-beta1 released] - - 2/29 - ---- -subst.c - - fixed expansion so referencing $a, when a is an array variable - without an element assigned to index 0, exits the shell when - `-u' is enabled - -expr.c - - make the exponentiation operator (**) associative, so things like - 2**3**4 work right (change `if' to `while') - - 3/3 - --- -lib/sh/strftime.c - - SCO Unix 3.2, like Solaris, requires that the system's `timezone' - variable be declared as long - -lib/readline/{bind,histfile,input,parens}.c - - changes for Tandem (including `floss.h' (?)) - - 3/4 - --- -subst.c - - change param_expand to quote the entire expanded string instead - of just the escape characters if the expansion appears between - double quotes or in a here-document (for simple variable expansions - or expansions of positional parameters) - - 3/8 - --- -subst.c - - analogous changes to parameter_brace_expand_word to fix the same - quoting problem as on 3/4; fix callers to understand that the - value returned might be quoted now and should be dequoted if - necessary - - add a `quoted' argument to get_var_and_type, change callers - - change today's fix and fix from 3/4 to not call quote_string if the - value is "" (because quote_string turns that into CTLNUL\0) - - 3/9 - --- -builtins/cd.def - - resetpwd() now takes a `caller' argument so it can be used by pwd - as well as cd - - change pwd_builtin to call resetpwd() if sh_physpath() fails to - return a valid pathname - - 3/14 - ---- -expr.c - - reworked exp0 and readtok() to make post-increment and post-decrement - into real tokens, which may be separated from their accompanying - variables by whitesapce - - made analogous changes to readtok() to make pre-increment and - pre-decrement work when separated from their accompanying identifier - by whitespace - - 3/18 - ---- -lib/readline/misc.c - - in rl_maybe_unsave_line, don't force rl_replace_line to clear - the undo_list, since it might point directly at an undo list - from a history entry (to which we have no handle) - - 3/19 - ---- -lib/readline/display.c - - rl_save_prompt and rl_restore_prompt now save and restore the value - of prompt_physical_chars - - set prompt_physical_chars in rl_redisplay when expand_prompt has - not been called (e.g., when rl_display_prompt is set and is not - equal to rl_prompt, like when searching) - -lib/readline/histexpand.c - - don't call add_history in history_expand if the `:p' modifier is - supplied; leave that to the calling application. This means that - `history -p', for example, will not add anything to the history - list (as documented), nor will history expansions invoked by - emacs-mode M-C-e line editing - -config-bot.h - - check whether HAVE_DECL_SYS_SIGLIST is defined to 1 rather than just - defined, to work around newer versions of autoconf defining it to 0 - -config.h.in - - change default status of HAVE_MALLOC to #undef instead of #define - -bashhist.c - - extern declarations for rl_done and rl_dispatching - - don't call re_edit from pre_process_line unless rl_dispatcing is zero, - so we don't call it from something like shell-expand-line - - change pre_process_line to add an expanded history specification - that returned `print only' to the history list, since history_expand - no longer does it (and, when using readline, do it only when - rl_dispatching is zero) - - 3/22 - ---- -config.h.in,aclocal.m4 - - change bash-specific functions that look in struct dirent to define - HAVE_STRUCT_DIRENT_xxx, like AC_CHECK_MEMBERS does (though the - functions are otherwise the same) - - new function, BASH_STRUCT_DIRENT_D_NAMLEN, define - HAVE_STRUCT_DIRENT_D_NAMLEN if struct dirent has a `d_namlen' member - -configure.in - - call BASH_STRUCT_DIRENT_D_NAMLEN - -include/posixdir.h - - use new and renamed HAVE_STRUCT_DIRENT_D_xxx defines - - 4/7 - --- -builtins/cd.def - - ensure that we print out a non-null pathname after getting a - directory from CDPATH and canonicalizing it (e.g., if the result - exceeds PATH_MAX in length and the_current_working_directory is - set to NULL) - - 4/12 - ---- -print_cmd.c - - new function to print out assignment statements when `set -x' has - been enabled: xtrace_print_assignment - -externs.h - - extern declaration for xtrace_print_assignment - - 4/13 - ---- -{subst,variables}.c - - call xtrace_print_assignment instead of using inline code - -jobs.c - - if turning on job control when it was previously off, set - pipeline_pgrp to 0 in set_job_control so make_child puts - subsequent children in their own process group - - 4/14 - ---- -general.c - - new function, legal_alias_name, called to decide whether an - argument to add_alias is a valid alias name -- essentially any - character except one which must be quoted to the shell parser - and `/' - -general.h - - new extern declaration for legal_alias_name - -builtins/alias.def - - `unalias' now returns failure status if no NAME arguments are - supplied and -a is not given - - call legal_alias_name to make sure alias name is valid before - calling add_alias from alias_builtin - - 4/19 - ---- -include/shmbutil.h - - include for definition of HANDLE_MULTIBYTE rather than - duplicating logic - - 4/20 - ---- - -doc/{bash.1,bashref.texi} - - make sure $0 is consistently referred to as a `special parameter' - - document which characters are now not allowed in alias names - - 4/23 - ---- - -builtins/{jobs,kill,wait}.def - - removed requirement that job control be enabled to use job control - notation, as SUSv3 implies - -subst.c - - based on a message from David Korn, change param_expand to not call - string_list_dollar_star if the only quoting is Q_HERE_DOCUMENT -- - quoted here documents are like double quoting, but not exactly - - analogous changes to list_remove_pattern and pos_params - - 4/24 - ---- -lib/readline/doc/rluser.texi - - fix error in description of emacs-mode C-xC-e command (uses $VISUAL - instead of $FCEDIT) - - 4/28 - ---- -support/bashbug.sh - - integrate a patch from Stefan Nordhausen - that reduces race conditions - by using a temporary directory inside $TMPDIR and creating the - temp files in that - - 4/30 - ---- -builtins/common.c - - use pathconf(".", _PC_PATH_MAX) where available to size the argument - to getcwd() rather than using a straight PATH_MAX - -builtins/cd.def - - if get_working_directory fails and returns null (causing resetpwd - to return NULL), use set_working_directory to set $PWD to the - absolute pathname for which chdir just succeeded - - 5/1 - --- -lib/readline/vi_mode.c - - in rl_vi_change_to, call _rl_vi_set_last with rl_numeric_arg instead - of `last', since they're equal at call time and rl_vi_domove can - change rl_numeric_arg (which vi apparently updates). Fixes redo bug - of `c2....' reported by Marion Berryman - - 5/4 - --- -parse.y - - fix decode_prompt_string to properly deal with strftime() returning 0 - - 5/6 - --- -variables.c - - in make_local_array_variable, return an already-existing local array - variable immediately rather than creating a new array (causing a - memory leak) - - 5/8 - --- -lib/readline/vi_mode.c - - change rl_vi_domove to set rl_explicit_arg before calling - rl_digit_loop1 so that multi-digit numeric arguments work right - - _rl_vi_last_command is no longer static - -lib/readline/rlprivate.h - - new extern declaration for _rl_vi_last_command - -lib/readline/text.c - - change rl_newline to only call _rl_vi_reset_last if the last command - (_rl_vi_last_command) is not a text modification command. This lets - the last-command and last-argument work across command lines - - 5/13 - ---- -builtins/common.c - - use getcwd(0,0) rather than providing a fixed pathname with a fixed - length (PATH_MAX) so getcwd() will allocate sufficient memory - -aclocal.m4 - - change BASH_FUNC_GETCWD to check whether or not getcwd(0,0) will - allocate memory for the returned value -- nobody implements that - and getcwd-via-popen, so it should capture the old test as well - - 5/27 - ---- - -builtins/trap.def - - the historical behavior of assuming that a signal's handling should - be set to its original disposition is only in effect if a single - argument is given, otherwise the first argument is assumed to be a - command to execute - - when in posix mode, if trap gets a single argument, display an - error message and return EX_USAGE - - change the help message and usage string to better explain trap's - behavior - -doc/{bash.1,bashref.texi} - - describe the new default behavior when the first argument is a - signal spec - - note that signal names are case insensitive and the SIG prefix is - optional in arguments to `trap' - - note that signal name arguments to `kill' are case-insensitive - -lib/readline/display.c - - make sure rl_on_new_line_with_prompt sets rl_display_prompt to - rl_prompt (just to make sure it's set) - - have rl_on_new_line_with_prompt use local_prompt if it's set - - 6/2 - --- -subst.c - - in string_extract_double_quoted, cope with extract_delimited_string - returning NULL, as it can when attempting completion on an unclosed - command substitution - - 6/24 - ---- -lib/readline/complete.c - - change print_filename to add a `/' to listed directory names if - `mark-directories' has been enabled - -builtins/umask.def - - make sure that the mask passed to parse_symbolic_mode has all but - the operative low eight bits masked off, to avoid complementing - all 0s to -1, which is the error return code. This makes things - like `a=rwx' and `ugo=rwx' work and turn off the umask - - 6/26 - ---- -builtins/getopts.def - - when `getopts' reaches the end of options, unset OPTARG before - returning EOF. In response to a bug report from Apple - -configure.in - - when cross-compiling, don't set CPPFLAGS_FOR_BUILD and - LDFLAGS_FOR_BUILD from CPPFLAGS and LDFLAGS, respectively, since - those are for the target instead of the build platform (report - from robert@schwebel.de) - -shell.c - - a shell whose standard error (but not standard output) is directed - to a terminal should be interactive, according to POSIX/SUS. This - means that sh > sh.out will start an interactive shell. Bug report - from llattanzi@apple.com - -doc/{bash.1,bashref.texi} - - change mention of standard output to standard error in definition - of interactive shell - -lib/readline/vi_mode.c - - new convenience function, rl_vi_start_inserting, calls - _rl_vi_set_last to save the last textmod command state and then calls - rl_vi_insertion_mode to enter insert mode - - change functions to use rl_vi_start_inserting - -lib/readline/readline.h - - extern declaration for rl_vi_start_inserting - -bashline.c - - new function for vi-mode completion, bash_vi_complete. Does - filename expansion as POSIX specifies, unlike the default readline - bindings (which don't know about globbing). Bound to `\', `*', - and `=' in vi command keymap. Internals very similar to - rl_vi_complete; just calls bash glob expansion functions - -lib/readline/vi_mode.c - - change rl_vi_change_char so that an entire change is a single - undoable event, rather than each individual change in a [count]r - command - - fix rl_vi_change_char so that replacing characters up to EOL works - rather than generating rl_ding - - fix rl_vi_change_case so that replacing characters up to EOL works - rather than generating rl_ding - - 6/28 - ---- -builtins/echo.def - - call clearerr(stdout) before writing anything and testing its - failure or success - - 6/29 - ---- -bashline.c - - only set rl_explicit_arg in bash_glob_complete_word if readline is - in emacs mode; let bash_vi_complete take care of setting it in vi - mode - - fix bash_vi_complete to only set rl_explicit_arg unless the posix - conditions are met: no globbing characters in the vi `bigword' - being completed - - 6/30 - ---- -[bash-3.0-rc1 released] - - 7/1 - --- -lib/readline/complete.c - - make sure `extension_char' is initialized before deciding whether - or not the append a `/' to a possible completion when visible-stats - is not enabled - - 7/2 - --- -subst.c - - fix a boundary overrun in string_extract_double_quoted that could - occur when the word completion code attempts to expand an incomplete - construct (like a quoted unclosed command substitution) - - 7/4 - --- -subst.c - - set tempenv_assign_error to non-zero if an assignment to the - temporary environment fails for some reason (e.g., attempted - assignment to a readonly variable) - -execute_cmd.c - - fix execute_simple_command to force a non-interactive shell in - POSIX mode to exit if an assignment to the temporary environment - preceding a special builtin fails (bug report from - llattanzi@apple.com) - - 7/5 - --- -bashline.c - - in bash_directory_completion_hook, don't perform word expansions - if the filename appears to have been completed from the file - system rather than typed in by the user. Bug reported by Tim - Waugh - - 7/7 - --- -lib/readline/misc.c - - if _rl_maybe_save_line is being asked to save a line other than - what's already saved, free up the current saved line and save the - current contents of rl_line_buffer. Bug reported by - llattanzi@apple.com - - 7/12 - ---- -lib/readline/input.c - - do better EOF detection in rl_gather_tyi -- if a read returns 0 when - the fd is in non-blocking mode, stuff an EOF into the input stream - (reported by mattias@virtutech.se) - - 7/13 - ---- -lib/readline/vi_mode.c - - make sure rl_vi_put honors `count' arguments and yanks things - multiple times if requested - - 7/16 - ---- -builtins/umask.def - - make sure that the `who' part of the umask symbolic mode argument - defaults to `a' if it's missing - -flags.c - - make sure that maybe_make_restricted only gets called after the - shell is initialized, so `bash -r' doesn't result in inappropriate - error messages diff --git a/CWRU/old/set.def.save b/CWRU/old/set.def.save deleted file mode 100644 index 87b78d7cc..000000000 --- a/CWRU/old/set.def.save +++ /dev/null @@ -1,544 +0,0 @@ -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, posixly_correct; -#if defined (READLINE) -extern int rl_editing_mode, no_line_editing; -#endif /* READLINE */ - -$BUILTIN set -$FUNCTION set_builtin -$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-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 same as -B -#if defined (READLINE) - emacs use an emacs-style line editing interface -#endif /* READLINE */ - errexit same as -e - histexpand same as -H - 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 (BRACE_EXPANSION) - -B the shell will perform brace expansion -#endif /* BRACE_EXPANSION */ -#if defined (BANG_HISTORY) - -H Enable ! style history substitution. This flag is on - by default. -#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' }, -#if defined (BRACE_EXPANSION) - { "braceexpand",'B' }, -#endif - { "errexit", 'e' }, - { "histexpand", 'H' }, - { "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, "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, "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 == '?') - builtin_usage (); - return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - } - list = list->next; - } - list = save_list; - } - - /* Do the set command. While the list consists of words starting with - '-' or '+' treat them as flags, otherwise, start assigning them to - $1 ... $n. */ - while (list) - { - 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 == '?') - { - builtin_usage (); - 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); - builtin_usage (); - 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 - -#define NEXT_VARIABLE() any_failed++; list = list->next; continue; - -unset_builtin (list) - WORD_LIST *list; -{ - int unset_function, unset_variable, unset_array, opt, any_failed; - char *name; - - unset_function = unset_variable = unset_array = any_failed = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "fv")) != -1) - { - switch (opt) - { - case 'f': - unset_function = 1; - break; - case 'v': - unset_variable = 1; - break; - default: - builtin_usage (); - 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) - { - SHELL_VAR *var; - int tem; -#if defined (ARRAY_VARS) - char *t; -#endif - - name = list->word->word; - -#if defined (ARRAY_VARS) - if (!unset_function && valid_array_reference (name)) - { - t = strchr (name, '['); - *t++ = '\0'; - unset_array++; - } -#endif - - var = unset_function ? find_function (name) : find_variable (name); - - if (var && !unset_function && non_unsettable_p (var)) - { - builtin_error ("%s: cannot unset", name); - NEXT_VARIABLE (); - } - - /* Posix.2 says that unsetting readonly variables is an error. */ - if (var && readonly_p (var)) - { - builtin_error ("%s: cannot unset: readonly %s", - name, unset_function ? "function" : "variable"); - NEXT_VARIABLE (); - } - - /* Unless the -f option is supplied, the name refers to a variable. */ -#if defined (ARRAY_VARS) - if (var && unset_array) - { - if (array_p (var) == 0) - { - builtin_error ("%s: not an array variable", name); - NEXT_VARIABLE (); - } - else - tem = unbind_array_element (var, t); - } - else -#endif /* ARRAY_VARS */ - tem = makunbound (name, unset_function ? shell_functions : shell_variables); - - /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v - is specified, the name refers to a variable; if a variable by - that name does not exist, a function by that name, if any, - shall be unset.'' */ - if ((tem == -1) && !unset_function && !unset_variable) - tem = makunbound (name, shell_functions); - - if (tem == -1) - any_failed++; - else if (!unset_function) - stupidly_hack_special_variables (name); - - list = list->next; - } - - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); -} diff --git a/CWRU/save/unwind_prot.h.save b/CWRU/save/unwind_prot.h.save deleted file mode 100644 index 998fd72b6..000000000 --- a/CWRU/save/unwind_prot.h.save +++ /dev/null @@ -1,50 +0,0 @@ -/* 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. */ -extern void begin_unwind_frame (); -extern void discard_unwind_frame (); -extern void run_unwind_frame (); -extern void add_unwind_protect (); -extern void remove_unwind_protect (); -extern void run_unwind_protects (); -extern void unwind_protect_var (); - -/* 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 (procenv_t)) - -#endif /* _UNWIND_PROT_H */ diff --git a/MANIFEST~ b/MANIFEST~ deleted file mode 100644 index 6dff94fd9..000000000 --- a/MANIFEST~ +++ /dev/null @@ -1,955 +0,0 @@ -# -# Master distribution manifest for bash -# -# -# Filename type -# -CWRU d -CWRU/misc d -builtins d -cross-build d -doc d -examples d -examples/bashdb d -examples/obashdb d -examples/complete d -examples/functions d -examples/scripts d -examples/scripts.v2 d -examples/scripts.noah d -examples/startup-files d -examples/startup-files/apple d -examples/misc d -examples/loadables d -examples/loadables/perl d -include d -lib d -lib/glob d -lib/glob/doc d -lib/intl d -lib/malloc d -lib/readline d -lib/readline/doc d -lib/readline/examples d -lib/sh d -lib/termcap d -lib/termcap/grot d -lib/tilde d -lib/tilde/doc d -po d -support d -tests d -tests/misc d -ABOUT-NLS f -CHANGES f -COMPAT f -COPYING f -INSTALL f -MANIFEST f -NEWS f -NOTES f -POSIX f -README f -RBASH f -AUTHORS f -Y2K f -configure.in f -configure f -Makefile.in f -config-top.h f -config-bot.h f -config.h.in f -aclocal.m4 f -array.c f -arrayfunc.c f -eval.c f -print_cmd.c f -general.c f -list.c f -locale.c f -stringlib.c f -variables.c f -make_cmd.c f -copy_cmd.c f -unwind_prot.c f -dispose_cmd.c f -bashhist.c f -hashcmd.c f -hashlib.c f -parse.y f -pathexp.c f -subst.c f -shell.c f -trap.c f -sig.c f -siglist.c f -version.c f -flags.c f -jobs.c f -input.c f -mailcheck.c f -test.c f -expr.c f -alias.c f -execute_cmd.c f -findcmd.c f -redir.c f -bashline.c f -braces.c f -bracecomp.c f -nojobs.c f -error.c f -xmalloc.c f -pcomplete.c f -pcomplib.c f -mksyntax.c f -alias.h f -builtins.h f -bashhist.h f -bashline.h f -conftypes.h f -patchlevel.h f -variables.h f -array.h f -arrayfunc.h f -jobs.h f -findcmd.h f -hashlib.h f -quit.h f -flags.h f -shell.h f -syntax.h f -pathexp.h f -parser.h f -pcomplete.h f -sig.h f -test.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 -hashcmd.h f -bashansi.h f -bashjmp.h f -bashintl.h f -make_cmd.h f -execute_cmd.h f -redir.h f -bashtypes.h f -mailcheck.h f -xmalloc.h f -y.tab.c f -y.tab.h f -parser-built f -pathnames.h.in f -builtins/Makefile.in f -builtins/alias.def f -builtins/bind.def f -builtins/break.def f -builtins/builtin.def f -builtins/caller.def f -builtins/cd.def f -builtins/colon.def f -builtins/command.def f -builtins/complete.def f -builtins/common.c f -builtins/declare.def f -builtins/echo.def f -builtins/enable.def f -builtins/eval.def f -builtins/evalfile.c f -builtins/evalstring.c f -builtins/exec.def f -builtins/exit.def f -builtins/fc.def f -builtins/fg_bg.def f -builtins/getopt.c f -builtins/getopt.h f -builtins/getopts.def f -builtins/hash.def 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/printf.def f -builtins/pushd.def f -builtins/read.def f -builtins/reserved.def f -builtins/return.def f -builtins/set.def f -builtins/setattr.def f -builtins/shift.def f -builtins/shopt.def f -builtins/source.def f -builtins/suspend.def f -builtins/test.def f -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 -cross-build/cygwin32.cache f -cross-build/win32sig.h f -cross-build/x86-beos.cache f -cross-build/beos-sig.h f -cross-build/opennt.cache f -include/ansi_stdlib.h f -include/chartypes.h f -include/filecntl.h f -include/gettext.h f -include/maxpath.h f -include/memalloc.h f -include/ocache.h f -include/posixdir.h f -include/posixjmp.h f -include/posixstat.h f -include/posixtime.h f -include/posixwait.h f -include/shmbutil.h f -include/shtty.h f -include/stdc.h f -include/systimes.h f -include/typemax.h f -include/unionwait.h f -lib/glob/Makefile.in f -lib/glob/sm_loop.c f -lib/glob/smatch.c f -lib/glob/strmatch.c f -lib/glob/strmatch.h f -lib/glob/glob.c f -lib/glob/glob.h f -lib/glob/glob_loop.c f -lib/glob/xmbsrtowcs.c f -lib/glob/collsyms.h f -lib/glob/doc/Makefile f -lib/glob/doc/glob.texi f -lib/glob/ndir.h f -lib/intl/ChangeLog f -lib/intl/Makefile.in f -lib/intl/VERSION f -lib/intl/bindtextdom.c f -lib/intl/config.charset f -lib/intl/dcgettext.c f -lib/intl/dcigettext.c f -lib/intl/dcngettext.c f -lib/intl/dgettext.c f -lib/intl/dngettext.c f -lib/intl/eval-plural.h f -lib/intl/explodename.c f -lib/intl/finddomain.c f -lib/intl/gettext.c f -lib/intl/gettextP.h f -lib/intl/gmo.h f -lib/intl/hash-string.h f -lib/intl/intl-compat.c f -lib/intl/l10nflist.c f -lib/intl/libgnuintl.h.in f -lib/intl/loadinfo.h f -lib/intl/loadmsgcat.c f -lib/intl/localcharset.c f -lib/intl/localcharset.h f -lib/intl/locale.alias f -lib/intl/localealias.c f -lib/intl/localename.c f -lib/intl/log.c f -lib/intl/ngettext.c f -lib/intl/os2compat.c f -lib/intl/os2compat.h f -lib/intl/osdep.c f -lib/intl/plural-exp.c f -lib/intl/plural-exp.h f -lib/intl/plural.c f -lib/intl/plural.y f -lib/intl/ref-add.sin f -lib/intl/ref-del.sin f -lib/intl/relocatable.c f -lib/intl/relocatable.h f -lib/intl/textdomain.c f -lib/malloc/Makefile.in f -lib/malloc/getpagesize.h f -lib/malloc/imalloc.h f -lib/malloc/mstats.h f -lib/malloc/shmalloc.h f -lib/malloc/table.h f -lib/malloc/watch.h f -lib/malloc/alloca.c f -lib/malloc/malloc.c f -lib/malloc/stats.c f -lib/malloc/table.c f -lib/malloc/trace.c f -lib/malloc/watch.c f -lib/malloc/xmalloc.c f -lib/malloc/xleaktrace f 755 -lib/malloc/stub.c f -lib/malloc/i386-alloca.s f -lib/malloc/x386-alloca.s f -lib/readline/COPYING f -lib/readline/Makefile.in f -lib/readline/ChangeLog f -lib/readline/README f -lib/readline/STANDALONE f -lib/readline/readline.c f -lib/readline/vi_mode.c f -lib/readline/emacs_keymap.c f -lib/readline/vi_keymap.c f -lib/readline/history.c f -lib/readline/histexpand.c f -lib/readline/histsearch.c f -lib/readline/histfile.c f -lib/readline/funmap.c f -lib/readline/keymaps.c f -lib/readline/util.c f -lib/readline/terminal.c f -lib/readline/xmalloc.c f -lib/readline/search.c f -lib/readline/isearch.c f -lib/readline/parens.c f -lib/readline/rltty.c f -lib/readline/compat.c f -lib/readline/complete.c f -lib/readline/bind.c f -lib/readline/display.c f -lib/readline/signals.c f -lib/readline/kill.c f -lib/readline/text.c f -lib/readline/undo.c f -lib/readline/macro.c f -lib/readline/input.c f -lib/readline/callback.c f -lib/readline/mbutil.c f -lib/readline/misc.c f -lib/readline/nls.c f -lib/readline/shell.c f -lib/readline/savestring.c f -lib/readline/tilde.c f -lib/readline/tilde.h f -lib/readline/rldefs.h f -lib/readline/rlconf.h f -lib/readline/rlmbutil.h f -lib/readline/rlshell.h f -lib/readline/rltty.h f -lib/readline/rltypedefs.h f -lib/readline/rlwinsize.h f -lib/readline/readline.h f -lib/readline/tcap.h f -lib/readline/keymaps.h f -lib/readline/history.h f -lib/readline/histlib.h f -lib/readline/chardefs.h f -lib/readline/posixdir.h f -lib/readline/posixjmp.h f -lib/readline/posixstat.h f -lib/readline/ansi_stdlib.h f -lib/readline/rlstdc.h f -lib/readline/rlprivate.h f -lib/readline/xmalloc.h f -lib/readline/doc/Makefile f -lib/readline/doc/version.texi f -lib/readline/doc/rlman.texi f -lib/readline/doc/rltech.texi f -lib/readline/doc/rluser.texi f -lib/readline/doc/rluserman.texi f -lib/readline/doc/history.texi f -lib/readline/doc/hstech.texi f -lib/readline/doc/hsuser.texi f -lib/readline/doc/fdl.texi f -lib/readline/examples/Makefile f -lib/readline/examples/excallback.c f -lib/readline/examples/fileman.c f -lib/readline/examples/manexamp.c f -lib/readline/examples/histexamp.c f -lib/readline/examples/rltest.c f -lib/readline/examples/rl.c f -lib/readline/examples/rlcat.c f -lib/readline/examples/Inputrc f -lib/sh/Makefile.in f -lib/sh/clktck.c f -lib/sh/clock.c f -lib/sh/fmtullong.c f -lib/sh/fmtulong.c f -lib/sh/fmtumax.c f -lib/sh/getcwd.c f -lib/sh/getenv.c f -lib/sh/inet_aton.c f -lib/sh/itos.c f -lib/sh/mailstat.c f -lib/sh/makepath.c f -lib/sh/memset.c f -lib/sh/mktime.c f -lib/sh/netconn.c f -lib/sh/netopen.c f -lib/sh/oslib.c f -lib/sh/pathcanon.c f -lib/sh/pathphys.c f -lib/sh/rename.c f -lib/sh/setlinebuf.c f -lib/sh/shmatch.c f -lib/sh/shquote.c f -lib/sh/shtty.c f -lib/sh/snprintf.c f -lib/sh/spell.c f -lib/sh/strcasecmp.c f -lib/sh/strerror.c f -lib/sh/strftime.c f -lib/sh/strindex.c f -lib/sh/stringlist.c f -lib/sh/stringvec.c f -lib/sh/strpbrk.c f -lib/sh/strstr.c f -lib/sh/strtod.c f -lib/sh/strtoimax.c f -lib/sh/strtol.c f -lib/sh/strtoll.c f -lib/sh/strtoul.c f -lib/sh/strtoull.c f -lib/sh/strtoumax.c f -lib/sh/strtrans.c f -lib/sh/times.c f -lib/sh/timeval.c f -lib/sh/tmpfile.c f -lib/sh/vprint.c f -lib/sh/xstrchr.c f -lib/sh/zcatfd.c f -lib/sh/zread.c f -lib/sh/zwrite.c f -lib/termcap/Makefile.in f -lib/termcap/ltcap.h 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/README f -lib/tilde/Makefile.in f -lib/tilde/doc/tilde.texi f -lib/tilde/doc/Makefile f -lib/tilde/tilde.c f -lib/tilde/tilde.h f -lib/tilde/shell.c f -po/LINGUAS f -po/Makefile.in.in f -po/Makevars f -po/POTFILES.in f -po/Rules-builtins f -po/Rules-quot f -po/bash.pot f -po/boldquot.sed f -po/builtins.pot f -po/en@quot.header f -po/en@boldquot.header f -po/en@quot.po f -po/en@boldquot.po f -po/en@quot.gmo f -po/en@boldquot.gmo f -po/insert-header.sin f -po/quot.sed f -po/remove-potcdate.sin f -CWRU/misc/open-files.c f -CWRU/misc/sigs.c f -CWRU/misc/sigstat.c f -CWRU/misc/bison f -CWRU/misc/errlist.c f -CWRU/misc/hpux10-dlfcn.h f -CWRU/PLATFORMS f -CWRU/README f -CWRU/changelog f -CWRU/sh-redir-hack f -CWRU/mh-folder-comp f -doc/FAQ f -doc/Makefile.in f -doc/bash.1 f -doc/bashbug.1 f -doc/builtins.1 f -doc/rbash.1 f -doc/README f -doc/INTRO f -doc/texinfo.tex f -doc/bashref.texi f -doc/version.texi f -doc/bashref.info f -doc/article.ms f -doc/htmlpost.sh f 755 -doc/infopost.sh f 755 -doc/fdl.texi f -doc/fdl.txt f -support/Makefile.in f -support/bashversion.c f -support/config.guess f -support/config.rpath f 755 -support/config.sub f -support/printenv.sh f 755 -support/printenv.c f -support/bash.xbm f -support/missing f 755 -support/mkclone f 755 -support/mkconffiles f 755 -support/mkdirs f 755 -support/mkinstalldirs f 755 -support/mkversion.sh f 755 -support/mksignames.c f -support/bashbug.sh f -support/man2html.c f -support/recho.c f -support/zecho.c f -support/SYMLINKS f -support/fixlinks f 755 -support/install.sh f 755 -support/texi2dvi f 755 -support/texi2html f 755 -support/xenix-link.sh f 755 -support/shobj-conf f 755 -support/rlvers.sh f 755 -examples/bashdb/PERMISSION f -examples/bashdb/bashdb f -examples/bashdb/bashdb.el f -examples/obashdb/PERMISSION f -examples/obashdb/README f -examples/obashdb/bashdb f -examples/obashdb/bashdb.fns f -examples/obashdb/bashdb.pre f -examples/complete/complete-examples f -examples/complete/complete.ianmac f -examples/complete/complete2.ianmac f -examples/complete/complete.freebsd f -examples/complete/complete.gnu-longopt f -examples/complete/bashcc-1.0.1.tar.gz f -examples/loadables/README f -examples/loadables/template.c f -examples/loadables/Makefile.in f -examples/loadables/necho.c f -examples/loadables/hello.c f -examples/loadables/print.c f -examples/loadables/realpath.c f -examples/loadables/sleep.c f -examples/loadables/strftime.c f -examples/loadables/truefalse.c f -examples/loadables/getconf.h f -examples/loadables/getconf.c f -examples/loadables/finfo.c f -examples/loadables/cat.c f -examples/loadables/cut.c f -examples/loadables/logname.c f -examples/loadables/basename.c f -examples/loadables/dirname.c f -examples/loadables/tty.c f -examples/loadables/pathchk.c f -examples/loadables/tee.c f -examples/loadables/rmdir.c f -examples/loadables/head.c f -examples/loadables/printenv.c f -examples/loadables/push.c f -examples/loadables/id.c f -examples/loadables/whoami.c f -examples/loadables/uname.c f -examples/loadables/sync.c f -examples/loadables/mkdir.c f -examples/loadables/ln.c f -examples/loadables/unlink.c f -examples/loadables/perl/Makefile.in f -examples/loadables/perl/README f -examples/loadables/perl/bperl.c f -examples/loadables/perl/iperl.c f -examples/functions/array-stuff f -examples/functions/array-to-string f -examples/functions/autoload f -examples/functions/autoload.v2 f -examples/functions/autoload.v3 f -examples/functions/basename f -examples/functions/basename2 f -examples/functions/coproc.bash f -examples/functions/coshell.README f -examples/functions/coshell.bash f -examples/functions/csh-compat f -examples/functions/dirfuncs f -examples/functions/dirname f -examples/functions/emptydir f -examples/functions/exitstat f -examples/functions/external f -examples/functions/fact f -examples/functions/fstty f -examples/functions/func f -examples/functions/gethtml f -examples/functions/getoptx.bash f -examples/functions/inetaddr f -examples/functions/inpath f -examples/functions/isnum.bash f -examples/functions/isnum2 f -examples/functions/isvalidip f -examples/functions/jdate.bash f -examples/functions/jj.bash f -examples/functions/keep f -examples/functions/ksh-cd f -examples/functions/ksh-compat-test f -examples/functions/kshenv f -examples/functions/login f -examples/functions/lowercase f -examples/functions/manpage f -examples/functions/mhfold f -examples/functions/notify.bash f -examples/functions/pathfuncs f -examples/functions/recurse f -examples/functions/repeat2 f -examples/functions/repeat3 f -examples/functions/seq f -examples/functions/seq2 f -examples/functions/shcat f -examples/functions/shcat2 f -examples/functions/sort-pos-params f -examples/functions/substr f -examples/functions/substr2 f -examples/functions/term f -examples/functions/whatis f -examples/functions/whence f -examples/functions/which f -examples/functions/xalias.bash f -examples/functions/xfind.bash f -examples/scripts/adventure.sh f -examples/scripts/bcsh.sh f -examples/scripts/cat.sh f -examples/scripts/center f -examples/scripts/dd-ex.sh f -examples/scripts/fixfiles.bash f -examples/scripts/hanoi.bash f -examples/scripts/inpath f -examples/scripts/krand.bash f -examples/scripts/line-input.bash f -examples/scripts/nohup.bash f -examples/scripts/precedence f -examples/scripts/randomcard.bash f -examples/scripts/scrollbar f -examples/scripts/scrollbar2 f -examples/scripts/self-repro f -examples/scripts/showperm.bash f -examples/scripts/shprompt f -examples/scripts/spin.bash f -examples/scripts/timeout f -examples/scripts/vtree2 f -examples/scripts/vtree3 f -examples/scripts/vtree3a f -examples/scripts/websrv.sh f -examples/scripts/xterm_title f -examples/scripts/zprintf f -examples/startup-files/README f -examples/startup-files/Bashrc.bfox 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/startup-files/apple/README f -examples/startup-files/apple/aliases f -examples/startup-files/apple/bash.defaults f -examples/startup-files/apple/environment f -examples/startup-files/apple/login f -examples/startup-files/apple/logout f -examples/startup-files/apple/rc f -examples/misc/suncmd.termcap f -examples/misc/aliasconv.sh f -examples/misc/aliasconv.bash f -examples/misc/cshtobash f -tests/README f -tests/alias.tests f -tests/alias.right f -tests/arith-for.tests f -tests/arith-for.right f -tests/arith.tests f -tests/arith.right f -tests/array.tests f -tests/array.right f -tests/array-at-star f -tests/array2.right f -tests/braces.tests f -tests/braces.right f -tests/builtins.tests f -tests/builtins.right f -tests/builtins1.sub f -tests/builtins2.sub f -tests/source1.sub f -tests/source2.sub f -tests/source3.sub f -tests/source4.sub f -tests/source5.sub f -tests/cond.tests f -tests/cond.right f -tests/cprint.tests f -tests/cprint.right f -tests/dbg-support.right f -tests/dbg-support.sub f -tests/dbg-support.tests f -tests/dbg-support2.right f -tests/dbg-support2.tests f -tests/dollar-at-star f -tests/dollar-star1.sub f -tests/dollar.right f -tests/dstack.tests f -tests/dstack.right f -tests/dstack2.tests f -tests/dstack2.right f -tests/errors.tests f -tests/errors.right f -tests/execscript f -tests/exec.right f -tests/exec1.sub f 755 -tests/exec2.sub f -tests/exec3.sub f -tests/exec4.sub f -tests/exec5.sub f -tests/exec6.sub f -tests/exec7.sub f -tests/exp-tests f -tests/exp.right f -tests/extglob.tests f -tests/extglob.right f -tests/extglob2.tests f -tests/extglob2.right f -tests/func.tests f -tests/func.right f -tests/func1.sub f -tests/func2.sub f -tests/func3.sub f -tests/getopts.tests f -tests/getopts.right f -tests/getopts1.sub f -tests/getopts2.sub f -tests/getopts3.sub f -tests/getopts4.sub f -tests/getopts5.sub f -tests/getopts6.sub f -tests/getopts7.sub f -tests/glob-test f -tests/glob1.sub f -tests/glob.right f -tests/heredoc.tests f -tests/heredoc.right f -tests/herestr.tests f -tests/herestr.right f -tests/histexp.tests f -tests/histexp.right f -tests/history.tests f -tests/history.right f -tests/history.list f -tests/ifs.tests f -tests/ifs.right f -tests/input-line.sh f -tests/input-line.sub f -tests/input.right f -tests/invert.tests f -tests/invert.right f -tests/jobs.tests f -tests/jobs1.sub f -tests/jobs2.sub f -tests/jobs3.sub f -tests/jobs.right f -tests/more-exp.tests f -tests/more-exp.right f -tests/new-exp.tests f -tests/new-exp1.sub f -tests/new-exp2.sub f -tests/new-exp3.sub f -tests/new-exp4.sub f -tests/new-exp.right f -tests/nquote.tests f -tests/nquote.right f -tests/nquote1.tests f -tests/nquote1.right f -tests/nquote2.tests f -tests/nquote2.right f -tests/nquote3.tests f -tests/nquote3.right f -tests/nquote4.tests f -tests/nquote4.right f -tests/posix2.tests f -tests/posix2.right f -tests/posixpat.tests f -tests/posixpat.right f -tests/prec.right f -tests/precedence f -tests/printf.tests f -tests/printf.right f -tests/quote.tests f -tests/quote.right f -tests/read.tests f -tests/read.right f -tests/read1.sub f -tests/read2.sub f -tests/read3.sub f -tests/read4.sub f -tests/redir.tests f -tests/redir.right f -tests/redir1.sub f -tests/redir2.sub f -tests/redir3.sub f -tests/redir3.in1 f -tests/redir3.in2 f -tests/redir4.sub f -tests/redir4.in1 f -tests/redir5.sub f -tests/redir6.sub f -tests/rhs-exp.tests f -tests/rhs-exp.right f -tests/rsh.tests f -tests/rsh.right f -tests/run-all f -tests/run-minimal f -tests/run-alias f -tests/run-arith-for f -tests/run-arith f -tests/run-array f -tests/run-array2 f -tests/run-braces f -tests/run-builtins f -tests/run-cond f -tests/run-cprint f -tests/run-dbg-support f -tests/run-dbg-support2 f -tests/run-dirstack f -tests/run-dollars f -tests/run-errors f -tests/run-execscript f -tests/run-exp-tests f -tests/run-extglob f -tests/run-extglob2 f -tests/run-func f -tests/run-getopts f -tests/run-glob-test f -tests/run-heredoc f -tests/run-herestr f -tests/run-histexpand f -tests/run-history f -tests/run-ifs f -tests/run-input-test f -tests/run-invert f -tests/run-jobs f -tests/run-more-exp f -tests/run-new-exp f -tests/run-nquote f -tests/run-nquote1 f -tests/run-nquote2 f -tests/run-nquote3 f -tests/run-nquote4 f -tests/run-posix2 f -tests/run-posixpat f -tests/run-precedence f -tests/run-printf f -tests/run-quote f -tests/run-read f -tests/run-redir f -tests/run-rhs-exp f -tests/run-rsh f -tests/run-set-e f -tests/run-set-x f -tests/run-shopt f -tests/run-strip f -tests/run-test f -tests/run-tilde f -tests/run-trap f -tests/run-type f -tests/run-varenv f -tests/set-e-test f -tests/set-e.right f -tests/set-x.tests f -tests/set-x.right f -tests/shopt.tests f -tests/shopt.right f -tests/strip.tests f -tests/strip.right f -tests/test.tests f -tests/test.right f -tests/tilde-tests f -tests/tilde.right f -tests/trap.tests f -tests/trap.right f -tests/trap1.sub f 755 -tests/trap2.sub f 755 -tests/trap2a.sub f 755 -tests/type.tests f -tests/type.right f -tests/varenv.right f -tests/varenv.sh f -tests/varenv1.sub f -tests/varenv2.sub f -tests/version f -tests/version.mini f -tests/misc/dev-tcp.tests f -tests/misc/perf-script f -tests/misc/perftest f -tests/misc/read-nchars.tests f -tests/misc/redir-t2.sh f -tests/misc/run-r2.sh f -tests/misc/sigint-1.sh f -tests/misc/sigint-2.sh f -tests/misc/sigint-3.sh f -tests/misc/sigint-4.sh f -tests/misc/test-minus-e.1 f -tests/misc/test-minus-e.2 f -tests/misc/wait-bg.tests f -examples/scripts.v2/PERMISSION f -examples/scripts.v2/README f -examples/scripts.v2/arc2tarz f -examples/scripts.v2/bashrand f -examples/scripts.v2/cal2day.bash f -examples/scripts.v2/cdhist.bash f -examples/scripts.v2/corename f -examples/scripts.v2/fman f -examples/scripts.v2/frcp f -examples/scripts.v2/lowercase f -examples/scripts.v2/ncp f -examples/scripts.v2/newext f -examples/scripts.v2/nmv f -examples/scripts.v2/pages f -examples/scripts.v2/pf f -examples/scripts.v2/ren f -examples/scripts.v2/rename f -examples/scripts.v2/repeat f -examples/scripts.v2/untar f -examples/scripts.v2/uudec f -examples/scripts.v2/uuenc f -examples/scripts.v2/vtree f -examples/scripts.v2/where f -examples/scripts.v2/pmtop f -examples/scripts.v2/shprof f -examples/scripts.noah/PERMISSION f -examples/scripts.noah/README f -examples/scripts.noah/aref.bash f -examples/scripts.noah/bash.sub.bash f -examples/scripts.noah/bash_version.bash f -examples/scripts.noah/meta.bash f -examples/scripts.noah/mktmp.bash f -examples/scripts.noah/number.bash f -examples/scripts.noah/prompt.bash f -examples/scripts.noah/remap_keys.bash f -examples/scripts.noah/require.bash f -examples/scripts.noah/send_mail.bash f -examples/scripts.noah/shcat.bash f -examples/scripts.noah/source.bash f -examples/scripts.noah/string.bash f -examples/scripts.noah/stty.bash f -examples/scripts.noah/y_or_n_p.bash f diff --git a/Makefile.in~ b/Makefile.in~ deleted file mode 100644 index 75f489baf..000000000 --- a/Makefile.in~ +++ /dev/null @@ -1,1435 +0,0 @@ -# Makefile for bash-3.0, version 2.152 -# -# Copyright (C) 1996-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -# Make sure the first target in the makefile is the right one -all: .made - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = $(datadir)/locale - -mandir = @mandir@ -manpfx = man - -man1ext = .1 -man1dir = $(mandir)/$(manpfx)1 -man3ext = .3 -man3dir = $(mandir)/$(manpfx)3 - -htmldir = @htmldir@ - -# Support an alternate destination root directory for package building -DESTDIR = - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -top_builddir = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -@SET_MAKE@ -CC = @CC@ -CC_FOR_BUILD = @CC_FOR_BUILD@ -YACC = @YACC@ -SHELL = @MAKE_SHELL@ -CP = cp -RM = rm -f -AR = @AR@ -ARFLAGS = @ARFLAGS@ -RANLIB = @RANLIB@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALLMODE= -m 0755 -INSTALLMODE2 = -m 0555 - -TESTSCRIPT = @TESTSCRIPT@ - -#If you have purify, and want to use it, uncomment this definition or -# run the make as `make PURIFY=purify' -# or run configure with the --with-purify argument. -PURIFY = @PURIFY@ - -# Here is a rule for making .o files from .c files that does not -# force the type of the machine (like -M_MACHINE) into the flags. -.c.o: - $(RM) $@ - $(CC) $(CCFLAGS) -c $< - -EXEEXT = @EXEEXT@ -OBJEXT = @OBJEXT@ - -# The name of this program and some version information. -VERSPROG = bashversion$(EXEEXT) -VERSOBJ = bashversion.$(OBJEXT) - -Program = bash$(EXEEXT) -Version = @BASHVERS@ -PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` -RELSTATUS = @RELSTATUS@ - -Machine = @host_cpu@ -OS = @host_os@ -VENDOR = @host_vendor@ -MACHTYPE = @host@ - -# comment out for release -DEBUG = @DEBUG@ -MALLOC_DEBUG = @MALLOC_DEBUG@ - -THIS_SH = $(BUILD_DIR)/$(Program) - -# PROFILE_FLAGS is either -pg, to generate profiling info for use -# with gprof, or nothing (the default). -PROFILE_FLAGS= @PROFILE_FLAGS@ - -CFLAGS = @CFLAGS@ -CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LOCALE_DEFS = -DLOCALEDIR='"$(localedir)"' -DPACKAGE='"$(PACKAGE)"' - -LOCAL_LIBS = @LOCAL_LIBS@ -LIBS = $(BUILTINS_LIB) $(LIBRARIES) @LIBS@ -STATIC_LD = @STATIC_LD@ -LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ - -SYSTEM_FLAGS = -DPROGRAM='"$(Program)"' -DCONF_HOSTTYPE='"$(Machine)"' -DCONF_OSTYPE='"$(OS)"' -DCONF_MACHTYPE='"$(MACHTYPE)"' -DCONF_VENDOR='"$(VENDOR)"' $(LOCALE_DEFS) - -BASE_CCFLAGS = $(PROFILE_FLAGS) $(SYSTEM_FLAGS) $(LOCAL_DEFS) \ - $(DEFS) $(LOCAL_CFLAGS) $(INCLUDES) - -CCFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS) - -CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) - -LDFLAGS = @LDFLAGS@ $(STATIC_LD) $(LOCAL_LDFLAGS) $(PROFILE_FLAGS) $(CFLAGS) -LDFLAGS_FOR_BUILD = $(LDFLAGS) - -INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC) - -GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ - -Wcast-align -Wstrict-prototypes -Wconversion \ - -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic - -GCC_LINT_CFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(GCC_LINT_FLAGS) - -# -# Support libraries -# - -dot = . - -LIBSUBDIR = lib -LIBSRC = $(srcdir)/$(LIBSUBDIR) - -LIBBUILD = ${BUILD_DIR}/${LIBSUBDIR} - -SUBDIR_INCLUDES = -I. @RL_INCLUDE@ -I$(topdir) -I$(topdir)/$(LIBSUBDIR) - -BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ -USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ - -# the bash library -# the library is a mix of functions that the C library does not provide on -# some platforms and general shell utility functions -SH_LIBSRC = $(LIBSRC)/sh -SH_LIBDIR = $(dot)/${LIBSUBDIR}/sh -SH_ABSSRC = ${topdir}/${SH_LIBSRC} - -SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \ - ${SH_LIBSRC}/getenv.c ${SH_LIBSRC}/oslib.c \ - ${SH_LIBSRC}/setlinebuf.c \ - ${SH_LIBSRC}/strcasecmp.c ${SH_LIBSRC}/strerror.c \ - ${SH_LIBSRC}/strtod.c ${SH_LIBSRC}/strtol.c \ - ${SH_LIBSRC}/strtoul.c ${SH_LIBSRC}/vprint.c \ - ${SH_LIBSRC}/itos.c ${SH_LIBSRC}/rename.c \ - ${SH_LIBSRC}/zread.c ${SH_LIBSRC}/zwrite.c \ - ${SH_LIBSRC}/shtty.c ${SH_LIBSRC}/inet_aton.c \ - ${SH_LIBSRC}/netopen.c ${SH_LIBSRC}/strpbrk.c \ - ${SH_LIBSRC}/timeval.c ${SH_LIBSRC}/clock.c \ - ${SH_LIBSRC}/makepath.c ${SH_LIBSRC}/pathcanon.c \ - ${SH_LIBSRC}/pathphys.c ${SH_LIBSRC}/stringlist.c \ - ${SH_LIBSRC}/stringvec.c ${SH_LIBSRC}/tmpfile.c \ - ${SH_LIBSRC}/spell.c ${SH_LIBSRC}/strtrans.c \ - ${SH_LIBSRC}/strindex.c ${SH_LIBSRC}/shquote.c \ - ${SH_LIBSRC}/snprintf.c ${SH_LIBSRC}/mailstat.c \ - ${SH_LIBSRC}/fmtulong.c ${SH_LIBSRC}/fmtullong.c \ - ${SH_LIBSRC}/strtoll.c ${SH_LIBSRC}/strtoull.c \ - ${SH_LIBSRC}/strtoimax.c ${SH_LIBSRC}/strtoumax.c \ - ${SH_LIBSRC}/fmtumax.c ${SH_LIBSRC}/netconn.c \ - ${SH_LIBSRC}/mktime.c ${SH_LIBSRC}/strftime.c \ - ${SH_LIBSRC}/memset.c ${SH_LIBSRC}/xstrchr.c \ - ${SH_LIBSRC}/zcatfd.c ${SH_LIBSRC}/shmatch.c - -SHLIB_LIB = -lsh -SHLIB_LIBNAME = libsh.a -SHLIB_LIBRARY = ${SH_LIBDIR}/${SHLIB_LIBNAME} -SHLIB_LDFLAGS = -L${SH_LIBDIR} -SHLIB_DEP = ${SHLIB_LIBRARY} - -# we assume for now that readline source is being shipped with bash -RL_LIBSRC = $(LIBSRC)/readline -RL_LIBDOC = $(RL_LIBSRC)/doc -RL_LIBDIR = @RL_LIBDIR@ -RL_ABSSRC = ${topdir}/$(RL_LIBDIR) - -RL_INCLUDEDIR = @RL_INCLUDEDIR@ - -READLINE_LIB = @READLINE_LIB@ -READLINE_LIBRARY = $(RL_LIBDIR)/libreadline.a -READLINE_LDFLAGS = -L${RL_LIBDIR} -READLINE_DEP = @READLINE_DEP@ - -# The source, object and documentation of the GNU Readline library. -READLINE_SOURCE = $(RL_LIBSRC)/rldefs.h $(RL_LIBSRC)/rlconf.h \ - $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/tcap.h \ - $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/keymaps.h \ - $(RL_LIBSRC)/history.h $(RL_LIBSRC)/histlib.h \ - $(RL_LIBSRC)/posixstat.h $(RL_LIBSRC)/tilde.h \ - $(RL_LIBSRC)/rlstdc.h ${RL_LIBSRC}/xmalloc.h \ - $(RL_LIBSRC)/rlshell.h ${RL_LIBSRC}/rlprivate.h \ - $(RL_LIBSRC)/funmap.c $(RL_LIBSRC)/emacs_keymap.c \ - $(RL_LIBSRC)/search.c $(RL_LIBSRC)/vi_keymap.c \ - $(RL_LIBSRC)/keymaps.c $(RL_LIBSRC)/parens.c \ - $(RL_LIBSRC)/vi_mode.c $(RL_LIBSRC)/callback.c \ - $(RL_LIBSRC)/readline.c $(RL_LIBSRC)/tilde.c \ - $(RL_LIBSRC)/rltty.c $(RL_LIBSRC)/complete.c \ - $(RL_LIBSRC)/bind.c $(RL_LIBSRC)/isearch.c \ - $(RL_LIBSRC)/display.c $(RL_LIBSRC)/signals.c \ - $(RL_LIBSRC)/util.c $(RL_LIBSRC)/kill.c $(RL_LIBSRC)/text.c \ - $(RL_LIBSRC)/undo.c $(RL_LIBSRC)/macro.c \ - $(RL_LIBSRC)/terminal.c $(RL_LIBSRC)/nls.c \ - $(RL_LIBSRC)/input.c $(RL_LIBSRC)/xmalloc.c \ - $(RL_LIBSRC)/shell.c $(RL_LIBSRC)/savestring.c \ - $(RL_LIBSRC)/misc.c $(RL_LIBSRC)/mbutil.c $(RL_LIBSRC)/compat.c \ - $(RL_LIBSRC)/histexpand.c $(RL_LIBSRC)/history.c \ - $(RL_LIBSRC)/histsearch.c $(RL_LIBSRC)/histfile.c - -READLINE_OBJ = $(RL_LIBDIR)/readline.o $(RL_LIBDIR)/funmap.o \ - $(RL_LIBDIR)/parens.o $(RL_LIBDIR)/search.o \ - $(RL_LIBDIR)/keymaps.o $(RL_LIBDIR)/xmalloc.o \ - $(RL_LIBDIR)/rltty.o $(RL_LIBDIR)/complete.o \ - $(RL_LIBDIR)/bind.o $(RL_LIBDIR)/isearch.o \ - $(RL_LIBDIR)/display.o $(RL_LIBDIR)/signals.o \ - $(RL_LIBDIR)/tilde.o $(RL_LIBDIR)/util.o \ - $(RL_LIBDIR)/kill.o $(RL_LIBDIR)/undo.o $(RL_LIBDIR)/nls.o \ - $(RL_LIBDIR)/macro.o $(RL_LIBDIR)/input.o \ - $(RL_LIBDIR)/terminal.o $(RL_LIBDIR)/callback.o \ - $(RL_LIBDIR)/shell.o $(RL_LIBDIR)/savestring.o \ - $(RL_LIBDIR)/mbutil.o $(RL_LIBDIR)/compat.o \ - $(RL_LIBDIR)/history.o $(RL_LIBDIR)/histexpand.o \ - $(RL_LIBDIR)/histsearch.o $(RL_LIBDIR)/histfile.o - -HIST_LIBSRC = $(LIBSRC)/readline -HIST_LIBDIR = @HIST_LIBDIR@ -HIST_ABSSRC = ${topdir}/$(HIST_LIBDIR) - -HISTORY_LIB = @HISTORY_LIB@ -HISTORY_LIBRARY = $(HIST_LIBDIR)/libhistory.a -HISTORY_LDFLAGS = -L$(HIST_LIBDIR) -HISTORY_DEP = @HISTORY_DEP@ - -# The source, object and documentation of the history library. -HISTORY_SOURCE = $(HIST_LIBSRC)/history.c $(HIST_LIBSRC)/histexpand.c \ - $(HIST_LIBSRC)/histsearch.c $(HIST_LIBSRC)/histfile.c \ - $(HIST_LIBSRC)/shell.c \ - $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/histlib.h -HISTORY_OBJ = $(HIST_LIBDIR)/history.o $(HIST_LIBDIR)/histexpand.o \ - $(HIST_LIBDIR)/histsearch.o $(HIST_LIBDIR)/histfile.o \ - $(HIST_LIBDIR)/shell.o - -# You only need termcap (or curses) if you are linking with GNU Readline. -TERM_LIBSRC = $(LIBSRC)/termcap -TERM_LIBDIR = $(dot)/$(LIBSUBDIR)/termcap -TERM_ABSSRC = ${topdir}/$(TERM_LIBDIR) - -TERMCAP_LIB = @TERMCAP_LIB@ -TERMCAP_LIBRARY = $(TERM_LIBDIR)/libtermcap.a -TERMCAP_LDFLAGS = -L$(TERM_LIBDIR) -TERMCAP_DEP = @TERMCAP_DEP@ - -TERMCAP_SOURCE = $(TERM_LIBSRC)/termcap.c $(TERM_LIBSRC)/tparam.c -TERMCAP_OBJ = $(TERM_LIBDIR)/termcap.o $(TERM_LIBDIR)/tparam.o - -GLOB_LIBSRC = $(LIBSRC)/glob -GLOB_LIBDIR = $(dot)/$(LIBSUBDIR)/glob -GLOB_ABSSRC = ${topdir}/$(GLOB_LIBDIR) - -GLOB_LIB = -lglob -GLOB_LIBRARY = $(GLOB_LIBDIR)/libglob.a -GLOB_LDFLAGS = -L$(GLOB_LIBDIR) -GLOB_DEP = $(GLOB_LIBRARY) - -GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/strmatch.c \ - $(GLOB_LIBSRC)/smatch.c $(GLOB_LIBSRC)/xmbsrtowcs.c \ - $(GLOB_LIBSRC)/glob_loop.c $(GLOB_LIBSRC)/sm_loop.c \ - $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -GLOB_OBJ = $(GLOB_LIBDIR)/glob.o $(GLOB_LIBDIR)/strmatch.o \ - $(GLOB_LIBDIR)/smatch.o $(GLOB_LIBDIR)/xmbsrtowcs.o - -# The source, object and documentation for the GNU Tilde library. -TILDE_LIBSRC = $(LIBSRC)/tilde -TILDE_LIBDIR = $(dot)/$(LIBSUBDIR)/tilde -TILDE_ABSSRC = ${topdir}/$(TILDE_LIBDIR) - -TILDE_LIB = -ltilde -TILDE_LIBRARY = $(TILDE_LIBDIR)/libtilde.a -TILDE_LDFLAGS = -L$(TILDE_LIBDIR) -TILDE_DEP = $(TILDE_LIBRARY) - -TILDE_SOURCE = $(TILDE_LIBSRC)/tilde.c $(TILDE_LIBSRC)/tilde.h -TILDE_OBJ = $(TILDE_LIBDIR)/tilde.o - -# libintl -INTL_LIBSRC = $(LIBSRC)/intl -INTL_LIBDIR = $(dot)/$(LIBSUBDIR)/intl -INTL_ABSSRC = ${topdir}/$(INTL_LIB) -INTL_BUILDDIR = ${LIBBUILD}/intl - -INTL_LIB = @LIBINTL@ -INTL_LIBRARY = $(INTL_LIBDIR)/libintl.a -INTL_DEP = @INTL_DEP@ -INTL_INC = @INTL_INC@ - -LIBINTL_H = @LIBINTL_H@ - -# tests -LIBINTL = @LIBINTL@ -LTLIBINTL = @LTLIBINTL@ -INTLLIBS = @INTLLIBS@ -INTLOBJS = @INTLOBJS@ - -# Our malloc. -MALLOC_TARGET = @MALLOC_TARGET@ - -# set to alloca.o if we are using the C alloca in lib/malloc -ALLOCA = @ALLOCA@ - -ALLOC_LIBSRC = $(LIBSRC)/malloc -ALLOC_LIBDIR = $(dot)/$(LIBSUBDIR)/malloc -ALLOC_ABSSRC = ${topdir}/$(ALLOC_LIBDIR) - -MALLOC_SRC = @MALLOC_SRC@ -MALLOC_OTHERSRC = ${ALLOC_LIBSRC}/trace.c ${ALLOC_LIBSRC}/stats.c \ - ${ALLOC_LIBSRC}/table.c ${ALLOC_LIBSRC}/watch.c -MALLOC_SOURCE = ${ALLOC_LIBSRC}/${MALLOC_SRC} ${MALLOC_OTHERSRC} -MALLOC_CFLAGS = -DRCHECK -Dbotch=programming_error ${MALLOC_DEBUG} - -MALLOC_LIB = @MALLOC_LIB@ -MALLOC_LIBRARY = @MALLOC_LIBRARY@ -MALLOC_LDFLAGS = @MALLOC_LDFLAGS@ -MALLOC_DEP = @MALLOC_DEP@ - -ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \ - $(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \ - $(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h - -$(MALLOC_LIBRARY): ${MALLOC_SOURCE} ${ALLOC_HEADERS} config.h - @(cd $(ALLOC_LIBDIR) && \ - $(MAKE) $(MFLAGS) \ - MALLOC_CFLAGS="$(MALLOC_CFLAGS)" ${MALLOC_TARGET} ) || exit 1 - -BASHINCDIR = ${srcdir}/include -BASHINCFILES = $(BASHINCDIR)/posixstat.h $(BASHINCDIR)/ansi_stdlib.h \ - $(BASHINCDIR)/filecntl.h $(BASHINCDIR)/posixdir.h \ - $(BASHINCDIR)/memalloc.h $(BASHINCDIR)/stdc.h \ - $(BASHINCDIR)/posixjmp.h $(BASHINCDIR)/posixwait.h \ - $(BASHINCDIR)/posixtime.h $(BASHINCDIR)/systimes.h \ - $(BASHINCDIR)/unionwait.h $(BASHINCDIR)/maxpath.h \ - $(BASHINCDIR)/shtty.h $(BASHINCDIR)/typemax.h \ - $(BASHINCDIR)/ocache.h - -LIBRARIES = $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ - $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LOCAL_LIBS) - -LIBDEP = $(SHLIB_DEP) $(INTL_DEP) $(READLINE_DEP) $(HISTORY_DEP) $(TERMCAP_DEP) $(GLOB_DEP) \ - $(TILDE_DEP) $(MALLOC_DEP) - -LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(GLOB_LDFLAGS) \ - $(TILDE_LDFLAGS) $(MALLOC_LDFLAGS) $(SHLIB_LDFLAGS) - -# -# The shell itself -# - -# The main source code for the Bourne Again SHell. -CSOURCES = shell.c eval.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \ - dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \ - expr.c copy_cmd.c flags.c subst.c hashcmd.c hashlib.c mailcheck.c \ - test.c trap.c alias.c jobs.c nojobs.c $(ALLOC_FILES) braces.c \ - input.c bashhist.c array.c arrayfunc.c sig.c pathexp.c \ - unwind_prot.c siglist.c bashline.c bracecomp.c error.c \ - list.c stringlib.c locale.c findcmd.c redir.c \ - pcomplete.c pcomplib.c syntax.c xmalloc.c - -HSOURCES = shell.h flags.h trap.h hashcmd.h hashlib.h jobs.h builtins.h \ - general.h variables.h config.h $(ALLOC_HEADERS) alias.h \ - quit.h unwind_prot.h syntax.h ${GRAM_H} \ - command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \ - subst.h externs.h siglist.h bashhist.h bashline.h bashtypes.h \ - array.h arrayfunc.h sig.h mailcheck.h bashintl.h bashjmp.h \ - execute_cmd.h parser.h pathexp.h pathnames.h pcomplete.h \ - $(BASHINCFILES) - -SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) - -# header files chosen based on running of configure -SIGNAMES_H = @SIGNAMES_H@ - -# object files chosen based on running of configure -JOBS_O = @JOBS_O@ -SIGLIST_O = @SIGLIST_O@ - -# Matching object files. -OBJECTS = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ - dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \ - expr.o flags.o $(JOBS_O) subst.o hashcmd.o hashlib.o mailcheck.o \ - trap.o input.o unwind_prot.o pathexp.o sig.o test.o version.o \ - alias.o array.o arrayfunc.o braces.o bracecomp.o bashhist.o \ - bashline.o $(SIGLIST_O) list.o stringlib.o locale.o findcmd.o redir.o \ - pcomplete.o pcomplib.o syntax.o xmalloc.o - -# Where the source code of the shell builtins resides. -BUILTIN_SRCDIR=$(srcdir)/builtins -DEFSRC=$(BUILTIN_SRCDIR) -BUILTIN_ABSSRC=${topdir}/builtins -DEFDIR = $(dot)/builtins -DEBUGGER_DIR = $(dot)/debugger - -BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \ - $(DEFSRC)/builtin.def $(DEFSRC)/cd.def $(DEFSRC)/colon.def \ - $(DEFSRC)/command.def ${DEFSRC}/complete.def \ - $(DEFSRC)/caller.def $(DEFSRC)/declare.def \ - $(DEFSRC)/echo.def $(DEFSRC)/enable.def $(DEFSRC)/eval.def \ - $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \ - $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \ - $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \ - $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \ - $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \ - $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \ - $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \ - $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \ - $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \ - $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def $(DEFSRC)/printf.def -BUILTIN_C_SRC = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \ - $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \ - $(DEFSRC)/bashgetopt.c $(GETOPT_SOURCE) -BUILTIN_C_OBJ = $(DEFDIR)/common.o $(DEFDIR)/evalstring.o \ - $(DEFDIR)/evalfile.o $(DEFDIR)/bashgetopt.o -BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \ - $(DEFDIR)/builtin.o $(DEFDIR)/cd.o $(DEFDIR)/colon.o \ - $(DEFDIR)/command.o $(DEFDIR)/caller.o $(DEFDIR)/declare.o \ - $(DEFDIR)/echo.o $(DEFDIR)/enable.o $(DEFDIR)/eval.o \ - $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \ - $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \ - $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \ - $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \ - $(DEFDIR)/return.o $(DEFDIR)/shopt.o $(DEFDIR)/printf.o \ - $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \ - $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \ - $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \ - $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \ - $(DEFDIR)/getopts.o $(BUILTIN_C_OBJ) -GETOPT_SOURCE = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h -PSIZE_SOURCE = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c - -BUILTINS_LIBRARY = $(DEFDIR)/libbuiltins.a -BUILTINS_LIB = -lbuiltins -BUILTINS_LDFLAGS = -L$(DEFDIR) -BUILTINS_DEP = $(BUILTINS_LIBRARY) - -# Documentation for the shell. -DOCSRC = $(srcdir)/doc -DOCDIR = $(dot)/doc - -# Translations and other i18n support files -PO_SRC = $(srcdir)/po/ -PO_DIR = $(dot)/po/ - -SIGNAMES_SUPPORT = $(SUPPORT_SRC)mksignames.c - -SUPPORT_SRC = $(srcdir)/support/ -SDIR = $(dot)/support/ - -TESTS_SUPPORT = recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) -CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \ - tests/recho$(EXEEXT) tests/zecho$(EXEEXT) \ - tests/printenv$(EXEEXT) mksignames$(EXEEXT) lsignames.h \ - mksyntax${EXEEXT} syntax.c $(VERSPROG) $(VERSOBJ) \ - buildversion.o -CREATED_CONFIGURE = config.h config.cache config.status config.log \ - stamp-h po/POTFILES -CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ - lib/readline/Makefile lib/glob/Makefile \ - lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ - lib/termcap/Makefile examples/loadables/Makefile \ - examples/loadables/perl/Makefile support/Makefile \ - lib/intl/Makefile po/Makefile po/Makefile.in - -# Keep GNU Make from exporting the entire environment for small machines. -.NOEXPORT: - -.made: $(Program) bashbug - @echo "$(Program) last made for a $(Machine) running $(OS)" >.made - -$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) - $(RM) $@ - $(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) - ls -l $(Program) - size $(Program) - -.build: $(SOURCES) config.h Makefile version.h $(VERSPROG) - @echo - @echo " ***********************************************************" - @echo " * *" - @echo " * `$(BUILD_DIR)/$(VERSPROG) -l`" - @echo " * *" - @echo " ***********************************************************" - @echo - -bashbug: $(SUPPORT_SRC)bashbug.sh config.h Makefile $(VERSPROG) - @sed -e "s%!MACHINE!%$(Machine)%" -e "s%!OS!%$(OS)%" \ - -e "s%!CFLAGS!%$(CCFLAGS)%" -e "s%!CC!%$(CC)%" \ - -e "s%!RELEASE!%$(Version)%" -e "s%!PATCHLEVEL!%$(PatchLevel)%" \ - -e "s%!MACHTYPE!%$(MACHTYPE)%" -e "s%!RELSTATUS!%$(RELSTATUS)%" \ - $(SUPPORT_SRC)bashbug.sh > $@ - @chmod a+rx bashbug - -strip: $(Program) .made - strip $(Program) - ls -l $(Program) - size $(Program) - -lint: - ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made - -version.h: $(SOURCES) config.h Makefile - $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o newversion.h \ - && mv newversion.h version.h - -bashversion$(EXEEXT): patchlevel.h conftypes.h version.h buildversion.o $(SUPPORT_SRC)bashversion.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)bashversion.c buildversion.o - -buildversion.o: version.h conftypes.h patchlevel.h $(srcdir)/version.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c -o $@ $(srcdir)/version.c - -# old rules -GRAM_H = parser-built -y.tab.o: y.tab.c ${GRAM_H} command.h ${BASHINCDIR}/stdc.h input.h -${GRAM_H}: y.tab.h - @-if test -f y.tab.h ; then \ - cmp -s $@ y.tab.h 2>/dev/null || cp -p y.tab.h $@; \ - fi -y.tab.c y.tab.h: parse.y -# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi - $(YACC) -d $(srcdir)/parse.y - touch parser-built -# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; else cp -p y.tab.h ${GRAM_H}; fi - -# experimental new rules - work with GNU make but not BSD (or OSF) make -#y.tab.o: y.tab.c y.tab.h -#y.tab.c y.tab.h: parse.y command.h ${BASHINCDIR}/stdc.h input.h -# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi -# $(YACC) -d $(srcdir)/parse.y -# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi - -$(READLINE_LIBRARY): config.h $(READLINE_SOURCE) - @echo making $@ in ${RL_LIBDIR} - @( { test "${RL_LIBDIR}" = "${libdir}" && exit 0; } || \ - cd ${RL_LIBDIR} && $(MAKE) $(MFLAGS) libreadline.a) || exit 1 - -$(HISTORY_LIBRARY): config.h $(HISTORY_SOURCE) - @echo making $@ in ${HIST_LIBDIR} - @( { test "${HIST_LIBDIR}" = "${libdir}" && exit 0; } || \ - cd ${HIST_LIBDIR} && $(MAKE) $(MFLAGS) libhistory.a) || exit 1 - -$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) - @echo making $@ in ${GLOB_LIBDIR} - @(cd ${GLOB_LIBDIR} && \ - $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libglob.a) || exit 1 - -$(TILDE_LIBRARY): config.h $(TILDE_SOURCE) - @echo making $@ in ${TILDE_LIBDIR} - @(cd ${TILDE_LIBDIR} && \ - $(MAKE) $(MFLAGS) libtilde.a) || exit 1 - -$(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} - @echo making $@ in ${TERM_LIBDIR} - @(cd ${TERM_LIBDIR} && \ - $(MAKE) $(MFLAGS) libtermcap.a) || exit 1 - -$(SHLIB_LIBRARY): config.h ${SHLIB_SOURCE} - @echo making $@ in ${SH_LIBDIR} - @(cd ${SH_LIBDIR} && \ - $(MAKE) $(MFLAGS) DEBUG=${DEBUG} ${SHLIB_LIBNAME}) || exit 1 - -${INTL_LIBRARY}: config.h ${INTL_LIBDIR}/Makefile - @echo making $@ in ${INTL_LIBDIR} - @(cd ${INTL_LIBDIR} && \ - $(MAKE) $(MFLAGS) libintl.a) || exit 1 - -${LIBINTL_H}: ${INTL_LIBRARY} - -mksignames$(EXEEXT): $(SUPPORT_SRC)mksignames.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)mksignames.c - -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h syntax.h ${BASHINCDIR}/chartypes.h - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c - -# make a list of signals for the local system -- this is done when we're -# *not* cross-compiling -lsignames.h: mksignames$(EXEEXT) - $(RM) $@ - ./mksignames $@ - -# copy the correct signames header file to signames.h -signames.h: $(SIGNAMES_H) - -if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi - -syntax.c: mksyntax${EXEEXT} $(srcdir)/syntax.h - $(RM) $@ - ./mksyntax -o $@ - -$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BASHINCDIR}/memalloc.h version.h - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libbuiltins.a ) || exit 1 - -# these require special rules to circumvent make builtin rules -${DEFDIR}/common.o: $(BUILTIN_SRCDIR)/common.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} common.o) || exit 1 - -${DEFDIR}/bashgetopt.o: $(BUILTIN_SRCDIR)/bashgetopt.c - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} bashgetopt.o) || exit 1 - -${DEFDIR}/builtext.h: $(BUILTIN_DEFS) - @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 - -# For the justification of the following Makefile rules, see node -# `Automatic Remaking' in GNU Autoconf documentation. - -Makefile makefile: config.status $(srcdir)/Makefile.in - CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status - -pathnames.h: config.status $(srcdir)/Makefile.in - CONFIG_HEADERS= $(SHELL) ./config.status - -Makefiles makefiles: config.status $(srcdir)/Makefile.in - @for mf in $(CREATED_MAKEFILES); do \ - CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status ; \ - done - -config.h: stamp-h - -stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h - CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status - -config.status: $(srcdir)/configure - $(SHELL) ./config.status --recheck - -# comment out for distribution -$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in - cd $(srcdir) && autoconf - -# for chet -reconfig: force - sh $(srcdir)/configure - -#newversion: mkversion -# $(RM) .build -# ./mkversion -dir $(srcdir) -dist -# mv -f newversion.h version.h -# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -doc documentation: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) - -info dvi ps: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) - -force: - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -# Targets that actually do things not part of the build - -installdirs: - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(bindir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(man1dir) - @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(infodir) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install: .made installdirs - $(INSTALL_PROGRAM) $(INSTALLMODE) $(Program) $(DESTDIR)$(bindir)/$(Program) - $(INSTALL_SCRIPT) $(INSTALLMODE2) bashbug $(DESTDIR)$(bindir)/bashbug - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(DEFDIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -install-strip: - $(MAKE) $(MFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ - prefix=${prefix} exec_prefix=${exec_prefix} \ - DESTDIR=$(DESTDIR) install - -uninstall: .made - $(RM) $(DESTDIR)$(bindir)/$(Program) $(DESTDIR)$(bindir)/bashbug - -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ - man1dir=$(man1dir) man1ext=$(man1ext) \ - man3dir=$(man3dir) man3ext=$(man3ext) \ - infodir=$(infodir) htmldir=$(htmldir) DESTDIR=$(DESTDIR) $@ ) - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -.PHONY: basic-clean clean realclean maintainer-clean distclean mostlyclean maybe-clean - -LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ - ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} - -basic-clean: - $(RM) $(OBJECTS) $(Program) bashbug - $(RM) .build .made version.h pathnames.h - -clean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_SUPPORT) - -mostlyclean: basic-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - -distclean: basic-clean maybe-clean - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - -( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) tags TAGS - $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) - -maintainer-clean: basic-clean - @echo This command is intended for maintainers to use. - @echo It deletes files that may require special tools to rebuild. - $(RM) y.tab.c y.tab.h parser-built tags TAGS - ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - ( cd builtins && $(MAKE) $(MFLAGS) $@ ) - ( cd $(SDIR) && $(MAKE) $(MFLAGS) $@ ) - -for libdir in ${LIB_SUBDIRS}; do \ - (cd $$libdir && test -f Makefile && $(MAKE) $(MFLAGS) $@) ;\ - done - -( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ ) - $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES) - $(RM) $(CREATED_SUPPORT) Makefile - -maybe-clean: - -if test "X$(topdir)" != "X$(BUILD_DIR)" ; then \ - $(RM) parser-built y.tab.c y.tab.h ; \ - fi - -recho$(EXEEXT): $(SUPPORT_SRC)recho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)recho.c - -zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)zecho.c - -printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)printenv.c - -test tests check: force $(Program) $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - PATH=$$PATH:$(BUILD_DIR)/tests THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) - -symlinks: - $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) - -dist: force - @echo Bash distributions are created using $(srcdir)/support/mkdist. - @echo Here is a sample of the necessary commands: - @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${PACKAGE} $(PACKAGE_VERSION) - @echo tar cf $(PACKAGE)-${PACKAGE_VERSION}.tar ${PACKAGE}-$(PACKAGE_VERSION) - @echo gzip $(PACKAGE)-$(PACKAGE_VERSION).tar - -depend: depends - -depends: force - $(Program) $(SUPPORT_SRC)mkdep -c ${CC} -- ${CCFLAGS} ${CSOURCES} - -#### PRIVATE TARGETS #### -hashtest: hashlib.c - $(CC) -DTEST_HASHING $(CCFLAGS) -o $@ $(srcdir)/hashlib.c - -############################ DEPENDENCIES ############################### - -# Files that depend on the definitions in config-top.h, which are not meant -# to be changed -shell.o: config-top.h -input.o: config-top.h -y.tab.o: config-top.h -jobs.o: config-top.h -nojobs.o: config-top.h -execute_cmd.o: config-top.h -variables.o: config-top.h -builtins/command.o: config-top.h -builtins/common.o: config-top.h -builtins/break.o: config-top.h -builtins/echo.o: config-top.h -builtins/evalstring.o: config-top.h -builtins/exit.o: config-top.h -builtins/kill.o: config-top.h - -# shell basics -copy_cmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -copy_cmd.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -copy_cmd.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -copy_cmd.o: make_cmd.h subst.h sig.h pathnames.h externs.h -dispose_cmd.o: bashansi.h ${BASHINCDIR}/ansi_stdlib.h -dispose_cmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h -dispose_cmd.o: error.h general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -dispose_cmd.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -dispose_cmd.o: make_cmd.h subst.h sig.h pathnames.h externs.h -dispose_cmd.o: ${BASHINCDIR}/ocache.h -error.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h flags.h ${BASHINCDIR}/stdc.h error.h -error.o: command.h general.h xmalloc.h externs.h input.h bashhist.h -error.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -error.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -error.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -error.o: make_cmd.h subst.h sig.h pathnames.h externs.h -error.o: input.h execute_cmd.h -eval.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h trap.h flags.h ${DEFSRC}/common.h -eval.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -eval.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -eval.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -eval.o: make_cmd.h subst.h sig.h pathnames.h externs.h -eval.o: input.h execute_cmd.h -execute_cmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -execute_cmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -execute_cmd.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -execute_cmd.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -execute_cmd.o: make_cmd.h subst.h sig.h pathnames.h externs.h -execute_cmd.o: ${BASHINCDIR}/memalloc.h ${GRAM_H} flags.h builtins.h jobs.h quit.h siglist.h -execute_cmd.o: execute_cmd.h findcmd.h redir.h trap.h test.h pathexp.h -execute_cmd.o: $(DEFSRC)/common.h ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/strmatch.h -execute_cmd.o: ${BASHINCDIR}/posixtime.h ${BASHINCDIR}/chartypes.h -expr.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -expr.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -expr.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -expr.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -expr.o: make_cmd.h subst.h sig.h pathnames.h externs.h -expr.o: ${BASHINCDIR}/chartypes.h -findcmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h ${BASHINCDIR}/posixstat.h bashansi.h -findcmd.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/memalloc.h shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h -findcmd.o: ${BASHINCDIR}/stdc.h error.h general.h xmalloc.h variables.h arrayfunc.h conftypes.h quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h -findcmd.o: dispose_cmd.h make_cmd.h subst.h sig.h pathnames.h externs.h -findcmd.o: flags.h hashlib.h pathexp.h hashcmd.h -findcmd.o: ${BASHINCDIR}/chartypes.h -flags.o: config.h flags.h -flags.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -flags.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -flags.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -flags.o: make_cmd.h subst.h sig.h pathnames.h externs.h bashhist.h -general.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -general.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -general.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -general.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -general.o: make_cmd.h subst.h sig.h pathnames.h externs.h -general.o: ${BASHINCDIR}/maxpath.h ${BASHINCDIR}/posixtime.h -general.o: ${BASHINCDIR}/chartypes.h -hashcmd.o: config.h ${BASHINCDIR}/posixstat.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -hashcmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -hashcmd.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashcmd.h -hashcmd.o: execute_cmd.h findcmd.h ${BASHINCDIR}/stdc.h hashlib.h -hashlib.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -hashlib.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -hashlib.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -hashlib.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -hashlib.o: make_cmd.h subst.h sig.h pathnames.h externs.h -input.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -input.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h input.h error.h externs.h -list.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -list.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -list.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -list.o: make_cmd.h subst.h sig.h pathnames.h externs.h -locale.o: config.h bashtypes.h bashintl.h ${LIBINTL_H} bashansi.h ${BASHINCDIR}/ansi_stdlib.h -locale.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -locale.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -locale.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -locale.o: make_cmd.h subst.h sig.h pathnames.h externs.h -locale.o: ${BASHINCDIR}/chartypes.h -mailcheck.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -mailcheck.o: ${BASHINCDIR}/posixtime.h -mailcheck.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -mailcheck.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -mailcheck.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -mailcheck.o: make_cmd.h subst.h sig.h pathnames.h externs.h -mailcheck.o: execute_cmd.h mailcheck.h -make_cmd.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashansi.h -make_cmd.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h error.h flags.h make_cmd.h -make_cmd.o: variables.h arrayfunc.h conftypes.h array.h hashlib.h subst.h input.h externs.h -make_cmd.o: jobs.h quit.h siglist.h syntax.h dispose_cmd.h -make_cmd.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/ocache.h -y.tab.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/memalloc.h -y.tab.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -y.tab.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -y.tab.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -y.tab.o: make_cmd.h subst.h sig.h pathnames.h externs.h test.h -y.tab.o: trap.h flags.h parser.h input.h mailcheck.h $(DEFSRC)/common.h -y.tab.o: $(DEFDIR)/builtext.h bashline.h bashhist.h jobs.h siglist.h alias.h -pathexp.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -pathexp.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -pathexp.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -pathexp.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -pathexp.o: make_cmd.h subst.h sig.h pathnames.h externs.h -pathexp.o: pathexp.h flags.h -pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/strmatch.h -pathexp.o: ${BASHINCDIR}/shmbutil.h -print_cmd.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -print_cmd.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -print_cmd.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -print_cmd.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -print_cmd.o: make_cmd.h subst.h sig.h pathnames.h externs.h -print_cmd.o: ${GRAM_H} $(DEFSRC)/common.h -redir.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/filecntl.h -redir.o: ${BASHINCDIR}/memalloc.h shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -redir.o: general.h xmalloc.h variables.h arrayfunc.h conftypes.h array.h hashlib.h quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h -redir.o: dispose_cmd.h make_cmd.h subst.h sig.h pathnames.h externs.h -redir.o: flags.h execute_cmd.h redir.h input.h -shell.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/filecntl.h -shell.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -shell.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -shell.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -shell.o: make_cmd.h subst.h sig.h pathnames.h externs.h -shell.o: flags.h trap.h mailcheck.h builtins.h $(DEFSRC)/common.h -shell.o: jobs.h siglist.h input.h execute_cmd.h findcmd.h bashhist.h -shell.o: ${GLOB_LIBSRC}/strmatch.h ${BASHINCDIR}/posixtime.h -sig.o: config.h bashtypes.h -sig.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -sig.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -sig.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -sig.o: make_cmd.h subst.h sig.h pathnames.h externs.h -sig.o: jobs.h siglist.h trap.h $(DEFSRC)/common.h bashline.h bashhist.h -siglist.o: config.h bashtypes.h siglist.h trap.h -stringlib.o: bashtypes.h ${BASHINCDIR}/chartypes.h -stringlib.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -stringlib.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -stringlib.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -stringlib.o: make_cmd.h subst.h sig.h pathnames.h externs.h -stringlib.o: ${GLOB_LIBSRC}/glob.h ${GLOB_LIBSRC}/strmatch.h -subst.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/posixstat.h -subst.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -subst.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -subst.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -subst.o: make_cmd.h subst.h sig.h pathnames.h externs.h -subst.o: flags.h jobs.h siglist.h execute_cmd.h ${BASHINCDIR}/filecntl.h trap.h pathexp.h -subst.o: mailcheck.h input.h $(DEFSRC)/getopt.h $(DEFSRC)/common.h -subst.o: bashline.h bashhist.h ${GLOB_LIBSRC}/strmatch.h -subst.o: ${BASHINCDIR}/chartypes.h -subst.o: ${BASHINCDIR}/shmbutil.h -test.o: bashtypes.h ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -test.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -test.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -test.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -test.o: make_cmd.h subst.h sig.h pathnames.h externs.h test.h -test.o: ${DEFSRC}/common.h -trap.o: config.h bashtypes.h trap.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -trap.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -trap.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -trap.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -trap.o: make_cmd.h subst.h sig.h pathnames.h externs.h -trap.o: signames.h $(DEFSRC)/common.h -trap.o: ${DEFDIR}/builtext.h -unwind_prot.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h command.h ${BASHINCDIR}/stdc.h -unwind_prot.o: general.h xmalloc.h unwind_prot.h quit.h sig.h -variables.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -variables.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -variables.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -variables.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -variables.o: make_cmd.h subst.h sig.h pathnames.h externs.h -variables.o: flags.h execute_cmd.h mailcheck.h input.h $(DEFSRC)/common.h -variables.o: findcmd.h bashhist.h hashcmd.h pathexp.h -variables.o: pcomplete.h ${BASHINCDIR}/chartypes.h -variables.o: ${BASHINCDIR}/posixtime.h -version.o: conftypes.h patchlevel.h version.h -xmalloc.o: config.h bashtypes.h ${BASHINCDIR}/ansi_stdlib.h error.h - -# job control - -jobs.o: config.h bashtypes.h trap.h ${BASHINCDIR}/filecntl.h input.h ${BASHINCDIR}/shtty.h -jobs.o: bashansi.h ${BASHINCDIR}/ansi_stdlib.h -jobs.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -jobs.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -jobs.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -jobs.o: make_cmd.h subst.h sig.h pathnames.h externs.h -jobs.o: jobs.h flags.h $(DEFSRC)/common.h $(DEFDIR)/builtext.h -jobs.o: ${BASHINCDIR}/posixwait.h ${BASHINCDIR}/unionwait.h -jobs.o: ${BASHINCDIR}/posixtime.h -nojobs.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashjmp.h ${BASHINCDIR}/posixjmp.h -nojobs.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h jobs.h quit.h siglist.h externs.h -nojobs.o: sig.h error.h ${BASHINCDIR}/shtty.h input.h - -# shell features that may be compiled in - -array.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -array.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -array.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -array.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -array.o: make_cmd.h subst.h sig.h pathnames.h externs.h -array.o: $(DEFSRC)/common.h -arrayfunc.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -arrayfunc.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -arrayfunc.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -arrayfunc.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -arrayfunc.o: make_cmd.h subst.h sig.h pathnames.h externs.h -arrayfunc.o: $(DEFSRC)/common.h -arrayfunc.o: ${BASHINCDIR}/shmbutil.h -braces.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -braces.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -braces.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -braces.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -braces.o: make_cmd.h subst.h sig.h pathnames.h externs.h -braces.o: ${BASHINCDIR}/shmbutil.h -alias.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h command.h ${BASHINCDIR}/stdc.h -alias.o: general.h xmalloc.h bashtypes.h externs.h alias.h -alias.o: pcomplete.h -alias.o: ${BASHINCDIR}/chartypes.h - -pcomplib.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h bashtypes.h -pcomplib.o: ${BASHINCDIR}/stdc.h hashlib.h pcomplete.h shell.h syntax.h -pcomplib.o: bashjmp.h command.h general.h xmalloc.h error.h variables.h arrayfunc.h conftypes.h quit.h -pcomplib.o: unwind_prot.h dispose_cmd.h make_cmd.h subst.h sig.h pathnames.h -pcomplib.o: externs.h ${BASHINCDIR}/maxpath.h - -pcomplete.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h bashtypes.h -pcomplete.o: ${BASHINCDIR}/stdc.h hashlib.h pcomplete.h shell.h syntax.h -pcomplete.o: bashjmp.h command.h general.h xmalloc.h error.h variables.h arrayfunc.h conftypes.h quit.h -pcomplete.o: unwind_prot.h dispose_cmd.h make_cmd.h subst.h sig.h pathnames.h -pcomplete.o: externs.h ${BASHINCDIR}/maxpath.h execute_cmd.h - -# library support files - -bashhist.o: config.h bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/posixstat.h -bashhist.o: ${BASHINCDIR}/filecntl.h -bashhist.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -bashhist.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -bashhist.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -bashhist.o: make_cmd.h subst.h sig.h pathnames.h externs.h -bashhist.o: flags.h input.h parser.h pathexp.h $(DEFSRC)/common.h bashline.h -bashhist.o: $(GLOB_LIBSRC)/strmatch.h -bashline.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -bashline.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -bashline.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -bashline.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -bashline.o: make_cmd.h subst.h sig.h pathnames.h externs.h -bashline.o: builtins.h bashhist.h bashline.h execute_cmd.h findcmd.h pathexp.h -bashline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h alias.h -bashline.o: pcomplete.h ${BASHINCDIR}/chartypes.h input.h -bracecomp.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -bracecomp.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h command.h ${BASHINCDIR}/stdc.h error.h -bracecomp.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h array.h hashlib.h -bracecomp.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -bracecomp.o: make_cmd.h subst.h sig.h pathnames.h externs.h -bracecomp.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h command.h hashlib.h builtins.h general.h xmalloc.h -bracecomp.o: quit.h alias.h config.h variables.h arrayfunc.h conftypes.h -bracecomp.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h - -# library dependencies - -bashline.o: $(RL_LIBSRC)/rlconf.h -bashline.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h -bashline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h -bracecomp.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -bracecomp.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -y.tab.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h -subst.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h -subst.o: $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/rlstdc.h - -shell.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -subst.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bashline.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -bashhist.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h -y.tab.o: $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/rlstdc.h - -execute_cmd.o: $(TILDE_LIBSRC)/tilde.h -general.o: $(TILDE_LIBSRC)/tilde.h -mailcheck.o: $(TILDE_LIBSRC)/tilde.h -shell.o: $(TILDE_LIBSRC)/tilde.h -subst.o: $(TILDE_LIBSRC)/tilde.h -variables.o: $(TILDE_LIBSRC)/tilde.h - -# libintl dependencies -arrayfunc.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -bashhist.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -bashline.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -braces.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -error.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -eval.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -execute_cmd.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -expr.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -general.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -input.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -jobs.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -mailcheck.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -make_cmd.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -nojobs.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -parse.y: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -pcomplete.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -pcomplib.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -print_cmd.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -redir.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -shell.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -sig.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -siglist.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -subst.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -test.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -trap.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -variables.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -version.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -xmalloc.o: bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h - -# XXX - dependencies checked through here - -# builtin c sources -builtins/bashgetopt.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -builtins/bashgetopt.o: shell.h syntax.h config.h bashjmp.h command.h general.h xmalloc.h error.h -builtins/bashgetopt.o: variables.h arrayfunc.h conftypes.h quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -builtins/bashgetopt.o: make_cmd.h subst.h sig.h pathnames.h externs.h -builtins/bashgetopt.o: $(DEFSRC)/common.h -builtins/bashgetopt.o: ${BASHINCDIR}/chartypes.h -builtins/common.o: bashtypes.h ${BASHINCDIR}/posixstat.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -builtins/common.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h command.h -builtins/common.o: ${BASHINCDIR}/memalloc.h variables.h arrayfunc.h conftypes.h input.h siglist.h -builtins/common.o: quit.h unwind_prot.h ${BASHINCDIR}/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 ${BASHINCDIR}/stdc.h general.h xmalloc.h error.h pathnames.h -builtins/common.o: ${DEFDIR}/builtext.h -builtins/common.o: ${BASHINCDIR}/chartypes.h -builtins/evalfile.o: bashtypes.h ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -builtins/evalfile.o: shell.h syntax.h config.h bashjmp.h command.h general.h xmalloc.h error.h -builtins/evalfile.o: variables.h arrayfunc.h conftypes.h quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -builtins/evalfile.o: make_cmd.h subst.h sig.h pathnames.h externs.h -builtins/evalfile.o: jobs.h builtins.h flags.h input.h execute_cmd.h -builtins/evalfile.o: bashhist.h $(DEFSRC)/common.h -builtins/evalstring.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -builtins/evalstring.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h command.h siglist.h -builtins/evalstring.o: ${BASHINCDIR}/memalloc.h variables.h arrayfunc.h conftypes.h input.h -builtins/evalstring.o: quit.h unwind_prot.h ${BASHINCDIR}/maxpath.h jobs.h builtins.h -builtins/evalstring.o: dispose_cmd.h make_cmd.h subst.h externs.h -builtins/evalstring.o: jobs.h builtins.h flags.h input.h execute_cmd.h -builtins/evalstring.o: bashhist.h $(DEFSRC)/common.h -builtins/getopt.o: config.h ${BASHINCDIR}/memalloc.h -builtins/getopt.o: shell.h syntax.h bashjmp.h command.h general.h xmalloc.h error.h -builtins/getopt.o: variables.h arrayfunc.h conftypes.h quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -builtins/getopt.o: make_cmd.h subst.h sig.h pathnames.h externs.h -builtins/getopt.o: $(DEFSRC)/getopt.h -builtins/mkbuiltins.o: config.h bashtypes.h ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -builtins/mkbuiltins.o: bashansi.h ${BASHINCDIR}/ansi_stdlib.h - -# builtin def files -builtins/alias.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/alias.o: quit.h $(DEFSRC)/common.h -builtins/alias.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h command.h ${BASHINCDIR}/stdc.h unwind_prot.h -builtins/alias.o: dispose_cmd.h make_cmd.h subst.h externs.h variables.h arrayfunc.h conftypes.h -builtins/bind.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/bind.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/bind.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/bind.o: $(DEFSRC)/bashgetopt.h -builtins/break.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/break.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/break.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/builtin.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/builtin.o: quit.h $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h -builtins/builtin.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/builtin.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/caller.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/caller.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/caller.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/caller.o: $(DEFSRC)/common.h quit.h -builtins/caller.o: ${BASHINCDIR}/chartypes.h bashtypes.h -builtins/caller.o: ${DEFDIR}/builtext.h -builtins/cd.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/cd.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/cd.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/cd.o: $(DEFSRC)/common.h quit.h -builtins/command.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/command.o: quit.h $(DEFSRC)/bashgetopt.h -builtins/command.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/command.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/declare.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/declare.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/declare.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/declare.o: $(DEFSRC)/bashgetopt.h -builtins/echo.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/echo.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/echo.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/enable.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/enable.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/enable.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/enable.o: pcomplete.h -builtins/eval.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/eval.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/eval.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/exec.o: bashtypes.h -builtins/exec.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/exec.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/exec.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h -builtins/exec.o: findcmd.h flags.h quit.h $(DEFSRC)/common.h ${BASHINCDIR}/stdc.h -builtins/exit.o: bashtypes.h -builtins/exit.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/exit.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/exit.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/fc.o: bashtypes.h ${BASHINCDIR}/posixstat.h -builtins/fc.o: bashansi.h ${BASHINCDIR}/ansi_stdlib.h builtins.h command.h ${BASHINCDIR}/stdc.h -builtins/fc.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/fc.o: flags.h unwind_prot.h variables.h arrayfunc.h conftypes.h shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h -builtins/fc.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h quit.h -builtins/fc.o: $(DEFSRC)/bashgetopt.h bashhist.h -builtins/fc.o: ${BASHINCDIR}/chartypes.h -builtins/fg_bg.o: bashtypes.h $(DEFSRC)/bashgetopt.h -builtins/fg_bg.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/fg_bg.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/fg_bg.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/getopts.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/getopts.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/getopts.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/hash.o: bashtypes.h -builtins/hash.o: builtins.h command.h findcmd.h ${BASHINCDIR}/stdc.h $(DEFSRC)/common.h -builtins/hash.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/hash.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/help.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/help.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/help.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/help.o: $(GLOB_LIBSRC)/glob.h -builtins/history.o: bashtypes.h -builtins/history.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/history.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/history.o: ${BASHINCDIR}/filecntl.h shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h -builtins/history.o: bashhist.h variables.h arrayfunc.h conftypes.h -builtins/inlib.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/inlib.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h quit.h -builtins/inlib.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/jobs.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/jobs.o: quit.h $(DEFSRC)/bashgetopt.h -builtins/jobs.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/kill.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/kill.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/kill.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h trap.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/let.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/let.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/printf.o: config.h ${BASHINCDIR}/memalloc.h bashjmp.h command.h error.h -builtins/printf.o: general.h xmalloc.h quit.h dispose_cmd.h make_cmd.h subst.h -builtins/printf.o: externs.h sig.h pathnames.h shell.h syntax.h unwind_prot.h -builtins/printf.o: variables.h arrayfunc.h conftypes.h ${BASHINCDIR}/stdc.h $(DEFSRC)/bashgetopt.h -builtins/printf.o: ${BASHINCDIR}/chartypes.h -builtins/pushd.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/pushd.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/pushd.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/pushd.o: $(DEFSRC)/common.h -builtins/read.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/read.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/read.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/return.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/return.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/return.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/set.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/set.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/set.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h flags.h -builtins/setattr.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/setattr.o: quit.h $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h -builtins/setattr.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/setattr.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/shift.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/shift.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/shift.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/shift.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/shopt.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h -builtins/shopt.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h -builtins/shopt.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h unwind_prot.h variables.h arrayfunc.h conftypes.h ${BASHINCDIR}/maxpath.h -builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h -builtins/source.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/source.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/source.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/source.o: findcmd.h $(DEFSRC)/bashgetopt.h flags.h trap.h -builtins/suspend.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/suspend.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/suspend.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/test.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/test.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/test.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/test.o: test.h -builtins/times.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/times.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/times.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/trap.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/trap.o: quit.h $(DEFSRC)/common.h -builtins/trap.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/trap.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/type.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/type.o: quit.h $(DEFSRC)/common.h findcmd.h -builtins/type.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/type.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/ulimit.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/ulimit.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/ulimit.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/umask.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/umask.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/umask.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/umask.o: ${BASHINCDIR}/chartypes.h -builtins/wait.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/wait.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/wait.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/wait.o: ${BASHINCDIR}/chartypes.h - -builtins/complete.o: config.h shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h -builtins/complete.o: unwind_prot.h variables.h arrayfunc.h conftypes.h -builtins/complete.o: bashtypes.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -builtins/complete.o: builtins.h -builtins/complete.o: pcomplete.h -builtins/complete.o: ${DEFSRC}/common.h ${DEFSRC}/bashgetopt.h - -# libintl dependencies -builtins/bind.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/break.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/caller.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/cd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/common.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/complete.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/declare.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/enable.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/evalfile.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/exec.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/exit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/fc.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/fg_bg.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/getopt.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/hash.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/help.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/history.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/mkbuiltins.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/pushd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/read.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/return.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/set.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/setattr.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/shift.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/shopt.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/source.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/suspend.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/type.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/ulimit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/umask.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h - -# builtin library dependencies -builtins/bind.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h -builtins/bind.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/rlstdc.h - -builtins/bind.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h -builtins/fc.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h -builtins/history.o: $(HIST_LIBSRC)/history.h $(RL_LIBSRC)/rlstdc.h - -builtins/common.o: $(TILDE_LIBSRC)/tilde.h -builtins/cd.o: $(TILDE_LIBSRC)/tilde.h - -builtins/alias.o: $(DEFSRC)/alias.def -builtins/bind.o: $(DEFSRC)/bind.def -builtins/break.o: $(DEFSRC)/break.def -builtins/builtin.o: $(DEFSRC)/builtin.def -builtins/caller.o: $(DEFSRC)/caller.def -builtins/cd.o: $(DEFSRC)/cd.def -builtins/colon.o: $(DEFSRC)/colon.def -builtins/command.o: $(DEFSRC)/command.def -builtins/complete.o: $(DEFSRC)/complete.def -builtins/declare.o: $(DEFSRC)/declare.def -builtins/echo.o: $(DEFSRC)/echo.def -builtins/enable.o: $(DEFSRC)/enable.def -builtins/eval.o: $(DEFSRC)/eval.def -builtins/exec.o: $(DEFSRC)/exec.def -builtins/exit.o: $(DEFSRC)/exit.def -builtins/fc.o: $(DEFSRC)/fc.def -builtins/fg_bg.o: $(DEFSRC)/fg_bg.def -builtins/getopts.o: $(DEFSRC)/getopts.def -builtins/hash.o: $(DEFSRC)/hash.def -builtins/help.o: $(DEFSRC)/help.def -builtins/history.o: $(DEFSRC)/history.def -builtins/inlib.o: $(DEFSRC)/inlib.def -builtins/jobs.o: $(DEFSRC)/jobs.def -builtins/kill.o: $(DEFSRC)/kill.def -builtins/let.o: $(DEFSRC)/let.def -builtins/pushd.o: $(DEFSRC)/pushd.def -builtins/read.o: $(DEFSRC)/read.def -builtins/reserved.o: $(DEFSRC)/reserved.def -builtins/return.o: $(DEFSRC)/return.def -builtins/set.o: $(DEFSRC)/set.def -builtins/setattr.o: $(DEFSRC)/setattr.def -builtins/shift.o: $(DEFSRC)/shift.def -builtins/shopt.o: $(DEFSRC)/shopt.def -builtins/source.o: $(DEFSRC)/source.def -builtins/suspend.o: $(DEFSRC)/suspend.def -builtins/test.o: $(DEFSRC)/test.def -builtins/times.o: $(DEFSRC)/times.def -builtins/trap.o: $(DEFSRC)/trap.def -builtins/type.o: $(DEFSRC)/type.def -builtins/ulimit.o: $(DEFSRC)/ulimit.def -builtins/umask.o: $(DEFSRC)/umask.def -builtins/wait.o: $(DEFSRC)/wait.def diff --git a/NEWS~ b/NEWS~ deleted file mode 100644 index ba5feab35..000000000 --- a/NEWS~ +++ /dev/null @@ -1,1097 +0,0 @@ -This is a terse description of the new features added to bash-3.0 since -the release of bash-2.05b. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. ANSI string expansion now implements the \x{hexdigits} escape. - -b. There is a new loadable `strftime' builtin. - -c. New variable, COMP_WORDBREAKS, which controls the readline completer's - idea of word break characters. - -d. The `type' builtin no longer reports on aliases unless alias expansion - will actually be performed. - -e. HISTCONTROL is now a colon-separated list of values, which permits - more extensibility and backwards compatibility. - -f. HISTCONTROL may now include the `erasedups' option, which causes all lines - matching a line being added to be removed from the history list. - -g. `configure' has a new `--enable-multibyte' argument that permits multibyte - character support to be disabled even on systems that support it. - -h. New variables to support the bash debugger: BASH_ARGC, BASH_ARGV, - BASH_SOURCE, BASH_LINENO, BASH_SUBSHELL, BASH_EXECUTION_STRING, - BASH_COMMAND - -i. FUNCNAME has been changed to support the debugger: it's now an array - variable. - -j. for, case, select, arithmetic commands now keep line number information - for the debugger. - -k. There is a new `RETURN' trap executed when a function or sourced script - returns (not inherited child processes; inherited by command substitution - if function tracing is enabled and the debugger is active). - -l. New invocation option: --debugger. Enables debugging and turns on new - `extdebug' shell option. - -m. New `functrace' and `errtrace' options to `set -o' cause DEBUG and ERR - traps, respectively, to be inherited by shell functions. Equivalent to - `set -T' and `set -E' respectively. The `functrace' option also controls - whether or not the DEBUG trap is inherited by sourced scripts. - -n. The DEBUG trap is run before binding the variable and running the action - list in a `for' command, binding the selection variable and running the - query in a `select' command, and before attempting a match in a `case' - command. - -o. New `--enable-debugger' option to `configure' to compile in the debugger - support code. - -p. `declare -F' now prints out extra line number and source file information - if the `extdebug' option is set. - -q. If `extdebug' is enabled, a non-zero return value from a DEBUG trap causes - the next command to be skipped, and a return value of 2 while in a - function or sourced script forces a `return'. - -r. New `caller' builtin to provide a call stack for the bash debugger. - -s. The DEBUG trap is run just before the first command in a function body is - executed, for the debugger. - -t. `for', `select', and `case' command heads are printed when `set -x' is - enabled. - -u. There is a new {x..y} brace expansion, which is shorthand for {x.x+1, - x+2,...,y}. x and y can be integers or single characters; the sequence - may ascend or descend; the increment is always 1. - -v. New ksh93-like ${!array[@]} expansion, expands to all the keys (indices) - of array. - -w. New `force_fignore' shopt option; if enabled, suffixes specified by - FIGNORE cause words to be ignored when performing word completion even - if they're the only possibilities. - -x. New `gnu_errfmt' shopt option; if enabled, error messages follow the `gnu - style' (filename:lineno:message) format. - -y. New `-o bashdefault' option to complete and compgen; if set, causes the - whole set of bash completions to be performed if the compspec doesn't - result in a match. - -z. New `-o plusdirs' option to complete and compgen; if set, causes directory - name completion to be performed and the results added to the rest of the - possible completions. - -aa. `kill' is available as a builtin even when the shell is built without - job control. - -bb. New HISTTIMEFORMAT variable; value is a format string to pass to - strftime(3). If set and not null, the `history' builtin prints out - timestamp information according to the specified format when displaying - history entries. If set, bash tells the history library to write out - timestamp information when the history file is written. - -cc. The [[ ... ]] command has a new binary `=~' operator that performs - extended regular expression (egrep-like) matching. - -dd. `configure' has a new `--enable-cond-regexp' option (enabled by default) - to enable the =~ operator and regexp matching in [[ ... ]]. - -ee. Subexpressions matched by the =~ operator are placed in the new - BASH_REMATCH array variable. - -ff. New `failglob' option that causes an expansion error when pathname - expansion fails to produce a match. - -gg. New `set -o pipefail' option that causes a pipeline to return a failure - status if any of the processes in the pipeline fail, not just the last - one. - -hh. printf builtin understands two new escape sequences: \" and \?. - -ii. `echo -e' understands two new escape sequences: \" and \?. - -jj. The GNU `gettext' package and libintl have been integrated; the shell's - messages can be translated into different languages. - -kk. The `\W' prompt expansion now abbreviates $HOME as `~', like `\w'. - -ll. The error message printed when bash cannot open a shell script supplied - as argument 1 now includes the name of the shell, to better identify - the error as coming from bash. - -mm. A bug that caused here documents to not work if the directory the shell - used for the temporary files was not writable has been fixed. - -nn. The parameter pattern removal and substitution expansions are now much - faster and more efficient when using multibyte characters. - -oo. Fixed a bug in the `shift' builtin that could cause core dumps when - reporting an out-of-range argument. - -pp. The `jobs', `kill', and `wait' builtins now accept job control notation - even if job control is not enabled. - -qq. The historical behavior of `trap' that allows a missing `action' argument - to cause each specified signal's handling to be reset to its default is - now only supported when `trap' is given a single non-option argument. - -2. New Features in Readline - -a. History expansion has a new `a' modifier equivalent to the `g' modifier - for compatibility with the BSD csh. - -b. History expansion has a new `G' modifier equivalent to the BSD csh `g' - modifier, which performs a substitution once per word. - -c. All non-incremental search operations may now undo the operation of - replacing the current line with the history line. - -d. The text inserted by an `a' command in vi mode can be reinserted with - `.'. - -e. New bindable variable, `show-all-if-unmodified'. If set, the readline - completer will list possible completions immediately if there is more - than one completion and partial completion cannot be performed. - -f. There is a new application-callable `free_history_entry()' function. - -g. History list entries now contain timestamp information; the history file - functions know how to read and write timestamp information associated - with each entry. - -h. Four new key binding functions have been added: - - rl_bind_key_if_unbound() - rl_bind_key_if_unbound_in_map() - rl_bind_keyseq_if_unbound() - rl_bind_keyseq_if_unbound_in_map() - -i. New application variable, rl_completion_quote_character, set to any - quote character readline finds before it calls the application completion - function. - -j. New application variable, rl_completion_suppress_quote, settable by an - application completion function. If set to non-zero, readline does not - attempt to append a closing quote to a completed word. - -k. New application variable, rl_completion_found_quote, set to a non-zero - value if readline determines that the word to be completed is quoted. - Set before readline calls any application completion function. - -l. New function hook, rl_completion_word_break_hook, called when readline - needs to break a line into words when completion is attempted. Allows - the word break characters to vary based on position in the line. - -m. New bindable command: unix-filename-rubout. Does the same thing as - unix-word-rubout, but adds `/' to the set of word delimiters. - -n. When listing completions, directories have a `/' appended if the - `mark-directories' option has been enabled. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.05b since -the release of bash-2.05a. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. If set, TMOUT is the default timeout for the `read' builtin. - -b. `type' has two new options: `-f' suppresses shell function lookup, and - `-P' forces a $PATH search. - -c. New code to handle multibyte characters. - -d. `select' was changed to be more ksh-compatible, in that the menu is - reprinted each time through the loop only if REPLY is set to NULL. - The previous behavior is available as a compile-time option. - -e. `complete -d' and `complete -o dirnames' now force a slash to be - appended to names which are symlinks to directories. - -f. There is now a bindable edit-and-execute-command readline command, - like the vi-mode `v' command, bound to C-xC-e in emacs mode. - -g. Added support for ksh93-like [:word:] character class in pattern matching. - -h. The $'...' quoting construct now expands \cX to Control-X. - -i. A new \D{...} prompt expansion; passes the `...' to strftime and inserts - the result into the expanded prompt. - -j. The shell now performs arithmetic in the largest integer size the - machine supports (intmax_t), instead of long. - -k. If a numeric argument is supplied to one of the bash globbing completion - functions, a `*' is appended to the word before expansion is attempted. - -l. The bash globbing completion functions now allow completions to be listed - with double tabs or if `show-all-if-ambiguous' is set. - -m. New `-o nospace' option for `complete' and `compgen' builtins; suppresses - readline's appending a space to the completed word. - -n. New `here-string' redirection operator: <<< word. - -o. When displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -p. There is a new configuration option `--enable-mem-scramble', controls - bash malloc behavior of writing garbage characters into memory at - allocation and free time. - -q. The `complete' and `compgen' builtins now have a new `-s/-A service' - option to complete on names from /etc/services. - -r. `read' has a new `-u fd' option to read from a specified file descriptor. - -s. Fix the completion code so that expansion errors in a directory name - don't cause a longjmp back to the command loop. - -t. Fixed word completion inside command substitution to work a little more - intuitively. - -u. The `printf' %q format specifier now uses $'...' quoting to print the - argument if it contains non-printing characters. - -v. The `declare' and `typeset' builtins have a new `-t' option. When applied - to functions, it causes the DEBUG trap to be inherited by the named - function. Currently has no effect on variables. - -w. The DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops. - -x. The expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires. - -y. The bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better. Code - from Gary Vaughan. - -z. New [n]<&word- and [n]>&word- redirections from ksh93 -- move fds (dup - and close). - -aa. There is a new `-l' invocation option, equivalent to `--login'. - -bb. The `hash' builtin has a new `-l' option to list contents in a reusable - format, and a `-d' option to remove a name from the hash table. - -cc. There is now support for placing the long help text into separate files - installed into ${datadir}/bash. Not enabled by default; can be turned - on with `--enable-separate-helpfiles' option to configure. - -dd. All builtins that take operands accept a `--' pseudo-option, except - `echo'. - -ee. The `echo' builtin now accepts \0xxx (zero to three octal digits following - the `0') in addition to \xxx (one to three octal digits) for SUSv3/XPG6/ - POSIX.1-2001 compliance. - - -2. New Features in Readline - -a. Support for key `subsequences': allows, e.g., ESC and ESC-a to both - be bound to readline functions. Now the arrow keys may be used in vi - insert mode. - -b. When listing completions, and the number of lines displayed is more than - the screen length, readline uses an internal pager to display the results. - This is controlled by the `page-completions' variable (default on). - -c. New code to handle editing and displaying multibyte characters. - -d. The behavior introduced in bash-2.05a of deciding whether or not to - append a slash to a completed name that is a symlink to a directory has - been made optional, controlled by the `mark-symlinked-directories' - variable (default is the 2.05a behavior). - -e. The `insert-comment' command now acts as a toggle if given a numeric - argument: if the first characters on the line don't specify a - comment, insert one; if they do, delete the comment text - -f. New application-settable completion variable: - rl_completion_mark_symlink_dirs, allows an application's completion - function to temporarily override the user's preference for appending - slashes to names which are symlinks to directories. - -g. New function available to application completion functions: - rl_completion_mode, to tell how the completion function was invoked - and decide which argument to supply to rl_complete_internal (to list - completions, etc.). - -h. Readline now has an overwrite mode, toggled by the `overwrite-mode' - bindable command, which could be bound to `Insert'. - -i. New application-settable completion variable: - rl_completion_suppress_append, inhibits appending of - rl_completion_append_character to completed words. - -j. New key bindings when reading an incremental search string: ^W yanks - the currently-matched word out of the current line into the search - string; ^Y yanks the rest of the current line into the search string, - DEL or ^H deletes characters from the search string. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.05a since -the release of bash-2.05. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Added support for DESTDIR installation root prefix, so you can do a - `make install DESTDIR=bash-root' and do easier binary packaging. - -b. Added support for builtin printf "'" flag character as per latest POSIX - drafts. - -c. Support for POSIX.2 printf(1) length specifiers `j', `t', and `z' (from - ISO C99). - -d. New autoconf macro, RL_LIB_READLINE_VERSION, for use by other applications - (bash doesn't use very much of what it returns). - -e. `set [-+]o nolog' is recognized as required by the latest POSIX drafts, - but ignored. - -f. New read-only `shopt' option: login_shell. Set to non-zero value if the - shell is a login shell. - -g. New `\A' prompt string escape sequence; expands to time in 24 HH:MM format. - -h. New `-A group/-g' option to complete and compgen; does group name - completion. - -i. New `-t' option to `hash' to list hash values for each filename argument. - -j. New [-+]O invocation option to set and unset `shopt' options at startup. - -k. configure's `--with-installed-readline' option now takes an optional - `=PATH' suffix to set the root of the tree where readline is installed - to PATH. - -l. The ksh-like `ERR' trap has been added. The `ERR' trap will be run - whenever the shell would have exited if the -e option were enabled. - It is not inherited by shell functions. - -m. `readonly', `export', and `declare' now print variables which have been - given attributes but not set by assigning a value as just a command and - a variable name (like `export foo') when listing, as the latest POSIX - drafts require. - -n. `bashbug' now requires that the subject be changed from the default. - -o. configure has a new `--enable-largefile' option, like other GNU utilities. - -p. `for' loops now allow empty word lists after `in', like the latest POSIX - drafts require. - -q. The builtin `ulimit' now takes two new non-numeric arguments: `hard', - meaning the current hard limit, and `soft', meaning the current soft - limit, in addition to `unlimited' - -r. `ulimit' now prints the option letter associated with a particular - resource when printing more than one limit. - -s. `ulimit' prints `hard' or `soft' when a value is not `unlimited' but is - one of RLIM_SAVED_MAX or RLIM_SAVED_CUR, respectively. - -t. The `printf' builtin now handles the %a and %A conversions if they're - implemented by printf(3). - -u. The `printf' builtin now handles the %F conversion (just about like %f). - -v. The `printf' builtin now handles the %n conversion like printf(3). The - corresponding argument is the name of a shell variable to which the - value is assigned. - -2. New Features in Readline - -a. Added extern declaration for rl_get_termcap to readline.h, making it a - public function (it was always there, just not in readline.h). - -b. New #defines in readline.h: RL_READLINE_VERSION, currently 0x0402, - RL_VERSION_MAJOR, currently 4, and RL_VERSION_MINOR, currently 2. - -c. New readline variable: rl_readline_version, mirrors RL_READLINE_VERSION. - -d. New bindable boolean readline variable: match-hidden-files. Controls - completion of files beginning with a `.' (on Unix). Enabled by default. - -e. The history expansion code now allows any character to terminate a - `:first-' modifier, like csh. - -f. New bindable variable `history-preserve-point'. If set, the history - code attempts to place the user at the same location on each history - line retrived with previous-history or next-history. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.05 since -the release of bash-2.04. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. - -b. The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. - -c. `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces - -d. A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. - -e. When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -f. Bash-2.05 once again honors the current locale setting when processing - ranges within pattern matching bracket expressions (e.g., [A-Z]). - -2. New Features in Readline - -a. The blink timeout for paren matching is now settable by applications, - via the rl_set_paren_blink_timeout() function. - -b. _rl_executing_macro has been renamed to rl_executing_macro, which means - it's now part of the public interface. - -c. Readline has a new variable, rl_readline_state, which is a bitmap that - encapsulates the current state of the library; intended for use by - callbacks and hook functions. - -d. New application-callable function rl_set_prompt(const char *prompt): - expands its prompt string argument and sets rl_prompt to the result. - -e. New application-callable function rl_set_screen_size(int rows, int cols): - public method for applications to set readline's idea of the screen - dimensions. - -f. New function, rl_get_screen_size (int *rows, int *columns), returns - readline's idea of the screen dimensions. - -g. The timeout in rl_gather_tyi (readline keyboard input polling function) - is now settable via a function (rl_set_keyboard_input_timeout()). - -h. Renamed the max_input_history variable to history_max_entries; the old - variable is maintained for backwards compatibility. - -i. The list of characters that separate words for the history tokenizer is - now settable with a variable: history_word_delimiters. The default - value is as before. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.04 since -the release of bash-2.03. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. The history builtin has a `-d offset' option to delete the history entry - at position `offset'. - -b. The prompt expansion code has two new escape sequences: \j, the number of - active jobs; and \l, the basename of the shell's tty device name. - -c. The `bind' builtin has a new `-x' option to bind key sequences to shell - commands. - -d. There is a new shell option, no_empty_command_completion, which, when - enabled, disables command completion when TAB is typed on an empty line. - -e. The `help' builtin has a `-s' option to just print a builtin's usage - synopsis. - -f. There are several new arithmetic operators: id++, id-- (variable - post-increment/decrement), ++id, --id (variable pre-increment/decrement), - expr1 , expr2 (comma operator). - -g. There is a new ksh-93 style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done - -h. The `read' builtin has a number of new options: - -t timeout only wait timeout seconds for input - -n nchars only read nchars from input instead of a full line - -d delim read until delim rather than newline - -s don't echo input chars as they are read - -i. The redirection code now handles several filenames specially: - /dev/fd/N, /dev/stdin, /dev/stdout, and /dev/stderr, whether or - not they are present in the file system. - -j. The redirection code now recognizes pathnames of the form - /dev/tcp/host/port and /dev/udp/host/port, and tries to open a socket - of the appropriate type to the specified port on the specified host. - -k. The ksh-93 ${!prefix*} expansion, which expands to the names of all - shell variables with prefix PREFIX, has been implemented. - -l. There is a new dynamic variable, FUNCNAME, which expands to the name of - a currently-executing function. Assignments to FUNCNAME have no effect. - -m. The GROUPS variable is no longer readonly; assignments to it are silently - discarded. This means it can be unset. - -n. A new programmable completion facility, with two new builtin commands: - complete and compgen. - -o. configure has a new option, `--enable-progcomp', to compile in the - programmable completion features (enabled by default). - -p. `shopt' has a new option, `progcomp', to enable and disable programmable - completion at runtime. - -q. Unsetting HOSTFILE now clears the list of hostnames used for completion. - -r. configure has a new option, `--enable-bash-malloc', replacing the old - `--with-gnu-malloc' (which is still present for backwards compatibility). - -s. There is a new manual page describing rbash, the restricted shell. - -t. `bashbug' has new `--help' and `--version' options. - -u. `shopt' has a new `xpg_echo' option, which controls the behavior of - `echo' with respect to backslash-escaped characters at runtime. - -v. If NON_INTERACTIVE_LOGIN_SHELLS is defined, all login shells read the - startup files, even if they are not interactive. - -w. The LC_NUMERIC variable is now treated specially, and used to set the - LC_NUMERIC locale category for number formatting, e.g., when `printf' - displays floating-point numbers. - -2. New features in Readline - -a. Parentheses matching is now always compiled into readline, and enabled - or disabled when the value of the `blink-matching-paren' variable is - changed. - -b. MS-DOS systems now use ~/_inputrc as the last-ditch inputrc filename. - -c. MS-DOS systems now use ~/_history as the default history file. - -d. history-search-{forward,backward} now leave the point at the end of the - line when the string to search for is empty, like - {reverse,forward}-search-history. - -e. history-search-{forward,backward} now leave the last history line found - in the readline buffer if the second or subsequent search fails. - -f. New function for use by applications: rl_on_new_line_with_prompt, used - when an application displays the prompt itself before calling readline(). - -g. New variable for use by applications: rl_already_prompted. An application - that displays the prompt itself before calling readline() must set this to - a non-zero value. - -h. A new variable, rl_gnu_readline_p, always 1. The intent is that an - application can verify whether or not it is linked with the `real' - readline library or some substitute. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.03 since -the release of bash-2.02. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. New `shopt' option, `restricted_shell', indicating whether or not the - shell was started in restricted mode, for use in startup files. - -b. Filename generation is now performed on the words between ( and ) in - array assignments (which it probably should have done all along). - -c. OLDPWD is now auto-exported, as POSIX.2 seems to require. - -d. ENV and BASH_ENV are read-only variables in a restricted shell. - -e. A change was made to the startup file code so that any shell begun with - the `--login' option, even non-interactive shells, will source the login - shell startup files. - -2. New Features in Readline - -a. Many changes to the signal handling: - o Readline now catches SIGQUIT and cleans up the tty before returning; - o A new variable, rl_catch_signals, is available to application writers - to indicate to readline whether or not it should install its own - signal handlers for SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, - SIGTTIN, and SIGTTOU; - o A new variable, rl_catch_sigwinch, is available to application - writers to indicate to readline whether or not it should install its - own signal handler for SIGWINCH, which will chain to the calling - applications's SIGWINCH handler, if one is installed; - o There is a new function, rl_free_line_state, for application signal - handlers to call to free up the state associated with the current - line after receiving a signal; - o There is a new function, rl_cleanup_after_signal, to clean up the - display and terminal state after receiving a signal; - o There is a new function, rl_reset_after_signal, to reinitialize the - terminal and display state after an application signal handler - returns and readline continues - -b. There is a new function, rl_resize_terminal, to reset readline's idea of - the screen size after a SIGWINCH. - -c. New public functions: rl_save_prompt and rl_restore_prompt. These were - previously private functions with a `_' prefix. - -d. New function hook: rl_pre_input_hook, called just before readline starts - reading input, after initialization. - -e. New function hook: rl_display_matches_hook, called when readline would - display the list of completion matches. The new function - rl_display_match_list is what readline uses internally, and is available - for use by application functions called via this hook. - -f. New bindable function, delete-char-or-list, like tcsh. - -g. A new variable, rl_erase_empty_line, which, if set by an application using - readline, will cause readline to erase, prompt and all, lines on which the - only thing typed was a newline. - -h. New bindable variable: `isearch-terminators'. - -i. New bindable function: `forward-backward-delete-char' (unbound by default). - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.02 since -the release of bash-2.01.1. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. A new version of malloc, based on the older GNU malloc, that has many - changes, is more page-based, is more conservative with memory usage, - and does not `orphan' large blocks when they are freed. - -b. A new version of gmalloc, based on the old GLIBC malloc, with many - changes and range checking included by default. - -c. A new implementation of fnmatch(3) that includes full POSIX.2 Basic - Regular Expression matching, including character classes, collating - symbols, equivalence classes, and support for case-insensitive pattern - matching. - -d. ksh-88 egrep-style extended pattern matching ([@+*?!](patlist)) has been - implemented, controlled by a new `shopt' option, `extglob'. - -e. There is a new ksh-like `[[' compound command, which implements - extended `test' functionality. - -f. There is a new `printf' builtin, implemented according to the POSIX.2 - specification. - -g. There is a new feature for command substitution: $(< filename) now expands - to the contents of `filename', with any trailing newlines removed - (equivalent to $(cat filename)). - -h. There are new tilde prefixes which expand to directories from the - directory stack. - -i. There is a new `**' arithmetic operator to do exponentiation. - -j. There are new configuration options to control how bash is linked: - `--enable-profiling', to allow bash to be profiled with gprof, and - `--enable-static-link', to allow bash to be linked statically. - -k. There is a new configuration option, `--enable-cond-command', which - controls whether or not the `[[' command is included. It is on by - default. - -l. There is a new configuration option, `--enable-extended-glob', which - controls whether or not the ksh extended globbing feature is included. - It is enabled by default. - -m. There is a new configuration #define in config.h.top that, when enabled, - will cause all login shells to source /etc/profile and one of the user- - specific login shell startup files, whether or not the shell is - interactive. - -n. There is a new invocation option, `--dump-po-strings', to dump - a shell script's translatable strings ($"...") in GNU `po' format. - -o. There is a new `shopt' option, `nocaseglob', to enable case-insensitive - pattern matching when globbing filenames and using the `case' construct. - -p. There is a new `shopt' option, `huponexit', which, when enabled, causes - the shell to send SIGHUP to all jobs when an interactive login shell - exits. - -q. `bind' has a new `-u' option, which takes a readline function name as an - argument and unbinds all key sequences bound to that function in a - specified keymap. - -r. `disown' now has `-a' and `-r' options, to limit operation to all jobs - and running jobs, respectively. - -s. The `shopt' `-p' option now causes output to be displayed in a reusable - format. - -t. `test' has a new `-N' option, which returns true if the filename argument - has been modified since it was last accessed. - -u. `umask' now has a `-p' option to print output in a reusable format. - -v. A new escape sequence, `\xNNN', has been added to the `echo -e' and $'...' - translation code. It expands to the character whose ascii code is NNN - in hexadecimal. - -w. The prompt string expansion code has a new `\r' escape sequence. - -x. The shell may now be cross-compiled for the CYGWIN32 environment on - a Unix machine. - -2. New Features in Readline - -a. There is now an option for `iterative' yank-last-arg handline, so a user - can keep entering `M-.', yanking the last argument of successive history - lines. - -b. New variable, `print-completions-horizontally', which causes completion - matches to be displayed across the screen (like `ls -x') rather than up - and down the screen (like `ls'). - -c. New variable, `completion-ignore-case', which causes filename completion - and matching to be performed case-insensitively. - -d. There is a new bindable command, `magic-space', which causes history - expansion to be performed on the current readline buffer and a space to - be inserted into the result. - -e. There is a new bindable command, `menu-complete', which enables tcsh-like - menu completion (successive executions of menu-complete insert a single - completion match, cycling through the list of possible completions). - -f. There is a new bindable command, `paste-from-clipboard', for use on Win32 - systems, to insert the text from the Win32 clipboard into the editing - buffer. - -g. The key sequence translation code now understands printf-style backslash - escape sequences, including \NNN octal escapes. These escape sequences - may be used in key sequence definitions or macro values. - -h. An `$include' inputrc file parser directive has been added. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.01 since -the release of bash-2.0. As always, the manual page (doc/bash.1) is the -place to look for complete descriptions. - -1. New Features in Bash - -a. There is a new builtin array variable: GROUPS, the set of groups to which - the user belongs. This is used by the test suite. - -2. New Features in Readline - -a. If a key sequence bound to `universal-argument' is read while reading a - numeric argument started with `universal-argument', it terminates the - argument but is otherwise ignored. This provides a way to insert multiple - instances of a digit string, and is how GNU emacs does it. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-2.0 since -the release of bash-1.14.7. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. There is a new invocation option, -D, that dumps translatable strings - in a script. - -b. The `long' invocation options must now be prefixed with `--'. - -c. New long invocation options: --dump-strings, --help, --verbose - -d. The `nolineediting' invocation option was renamed to `noediting'. - -e. The `nobraceexpansion' and `quiet' long invocation options were removed. - -f. The `--help' and `--version' long options now work as the GNU coding - standards specify. - -g. If invoked as `sh', bash now enters posix mode after reading the - startup files, and reads and executes commands from the file named - by $ENV if interactive (as POSIX.2 specifies). A login shell invoked - as `sh' reads $ENV after /etc/profile and ~/.profile. - -h. There is a new reserved word, `time', for timing pipelines, builtin - commands, and shell functions. It uses the value of the TIMEFORMAT - variable as a format string describing how to print the timing - statistics. - -i. The $'...' quoting syntax expands ANSI-C escapes in ... and leaves the - result single-quoted. - -j. The $"..." quoting syntax performs locale-specific translation of ... - and leaves the result double-quoted. - -k. LINENO now works correctly in functions. - -l. New variables: DIRSTACK, PIPESTATUS, BASH_VERSINFO, HOSTNAME, SHELLOPTS, - MACHTYPE. The first three are array variables. - -m. The BASH_VERSION and BASH_VERSINFO variables now include the shell's - `release status' (alpha[N], beta[N], release). - -n. Some variables have been removed: MAIL_WARNING, notify, history_control, - command_oriented_history, glob_dot_filenames, allow_null_glob_expansion, - nolinks, hostname_completion_file, noclobber, no_exit_on_failed_exec, and - cdable_vars. Most of them are now implemented with the new `shopt' - builtin; others were already implemented by `set'. - -o. Bash now uses some new variables: LC_ALL, LC_MESSAGES, LC_CTYPE, - LC_COLLATE, LANG, GLOBIGNORE, HISTIGNORE. - -p. The shell now supports integer-indexed arrays of unlimited length, - with a new compound assignment syntax and changes to the appropriate - builtin commands (declare/typeset, read, readonly, etc.). The array - index may be an arithmetic expression. - -q. ${!var}: indirect variable expansion, equivalent to eval \${$var}. - -r. ${paramter:offset[:length]}: variable substring extraction. - -s. ${parameter/pattern[/[/]string]}: variable pattern substitution. - -t. The $[...] arithmetic expansion syntax is no longer supported, in - favor of $((...)). - -u. Aliases can now be expanded in shell scripts with a shell option - (shopt expand_aliases). - -v. History and history expansion can now be used in scripts with - set -o history and set -H. - -w. All builtins now return an exit status of 2 for incorrect usage. - -x. Interactive shells resend SIGHUP to all running or stopped children - if (and only if) they exit due to a SIGHUP. - -y. New prompting expansions: \a, \e, \H, \T, \@, \v, \V. - -z. Variable expansion in prompt strings is now controllable via a shell - option (shopt promptvars). - -aa. Bash now defaults to using command-oriented history. - -bb. The history file ($HISTFILE) is now truncated to $HISTFILESIZE after - being written. - -cc. The POSIX.2 conditional arithmetic evaluation syntax (expr ? expr : expr) - has been implemented. - -dd. Each builtin now accepts `--' to signify the end of the options, except - as documented (echo, etc.). - -ee. All builtins use -p to display values in a re-readable format where - appropriate, except as documented (echo, type, etc.). - -ff. The `alias' builtin has a new -p option. - -gg. Changes to the `bind' builtin: - o has new options: -psPSVr. - o the `-d' option was renamed to `-p' - o the `-v' option now dumps variables; the old `-v' is now `-P' - -hh. The `bye' synonym for `exit' was removed. - -ii. The -L and -P options to `cd' and `pwd' have been documented. - -jj. The `cd' builtin now does spelling correction on the directory name - by default. This is settable with a shell option (shopt cdspell). - -kk. The `declare' builtin has new options: -a, -F, -p. - -ll. The `dirs' builtin has new options: -c, -p, -v. - -mm. The new `disown' builtin removes jobs from the shell's jobs table - or inhibits the resending of SIGHUP when the shell receives a - SIGHUP. - -nn. The `echo' builtin has a new escape character: \e. - -oo. The `enable' builtin can now load new builtins dynamically from shared - objects on systems with the dlopen/dlsym interface. There are a number - of examples in the examples/loadables directory. There are also - new options: -d, -f, -s, -p. - -pp. The `-all' option to `enable' was removed in favor of `-a'. - -qq. The `exec' builtin has new options: -l, -c, -a. - -rr. The `hash' builtin has a new option: -p. - -ss. The `history' builtin has new options: -c, -p, -s. - -tt. The `jobs' builtin has new options: -r, -s. - -uu. The `kill' builtin has new options: -n signum, -l signame. - -vv. The `pushd' and `popd' builtins have a new option: -n. - -ww. The `read' builtin has new options: -p prompt, -e, -a. - -xx. The `readonly' builtin has a new -a option, and the -n option was removed. - -yy. Changes to the `set' builtin: - o new options: -B, -o keyword, -o onecmd, -o history - o options removed: -l, -d, -o nohash - o options changed: +o, -h, -o hashall - o now displays variables in a format that can be re-read as input - -zz. The new `shopt' builtin controls shell optional behavior previously - done by setting and unsetting certain shell variables. - -aaa. The `test' builtin has new operators: -o option, s1 == s2, s1 < s2, - and s1 > s2, where s1 and s2 are strings. - -bbb. There is a new trap, DEBUG, executed after every simple command. - -ccc. The `trap' builtin has a new -p option. - -ddd. The `ulimit' builtin has a new -l option on 4.4BSD-based systems. - -eee. The PS1, PS2, PATH, and IFS variables may now be unset. - -fff. The restricted shell mode has been expanded and is now documented. - -ggg. Security improvements: - o functions are not imported from the environment if running setuid - or with -p - o no startup files are sourced if running setuid or with -p - -hhh. The documentation has been overhauled: the texinfo manual was - expanded, and HTML versions of the man page and texinfo manual - are included. - -iii. Changes to Posix mode: - o Command lookup now finds special builtins before shell functions. - o Failure of a special builtin causes a non-interactive shell to - exit. Failures are defined in the POSIX.2 specification. - o If the `cd' builtin finds a directory to change to using $CDPATH, - the value assigned to PWD when `cd' completes does not contain - any symbolic links. - o A non-interactive shell exits if a variable assignment error - occurs when no command name follows the assignment statements. - o A non-interactive shell exits if the interation variable in a - `for' statement or the selection variable in a `select' statement - is read-only or another variable assignment error occurs. - o The `<>' redirection operator now opens a file for both stdin and - stdout by default, not just when in posix mode. - o Assignment statements preceding special builtins now persist in - the shell's environment when the builtin completes. - - Posix mode is now completely POSIX.2-compliant (modulo bugs). When - invoked as sh, bash should be completely POSIX.2-compliant. - -jjj. The default value of PS1 is now "\s-\v\$ ". - -kkk. The ksh-like ((...)) arithmetic command syntax has been implemented. - This is exactly equivalent to `let "..."'. - -lll. Integer constants have been extended to base 64. - -mmm. The `ulimit' builtin now sets both hard and soft limits and reports the - soft limit by default. - -2. New Features in Readline - -a. New variables: enable-keypad, input-meta (new name for meta-flag), - mark-directories, visible-stats (now documented), disable-completion, - comment-begin. - -b. New bindable commands: kill-region, copy-region-as-kill, - copy-backward-word, copy-forward-word, set-mark, exchange-point-and-mark, - character-search, character-search-backward, insert-comment, - glob-expand-word, glob-list-expansions, dump-variables, dump-macros. - -c. New emacs keybindings: delete-horizontal-space (M-\), - insert-completions (M-*), possible-completions (M-=). - -d. The history-search-backward and history-search-forward commands were - modified to be the same as previous-line and next-line if point is at - the start of the line. - -e. More file types are available for the visible-stats mode. - -3. Changes of interest in the Bash implementation - -a. There is a new autoconf-based configuration mechanism. - -b. More things have been moved from Posix mode to standard shell behavior. - -c. The trace output (set -x) now inserts quotes where necessary so it can - be reused as input. - -d. There is a compile-time option for a system-wide interactive shell - startup file (disabled by default). - -e. The YACC grammar is smaller and tighter, and all 66 shift-reduce - conflicts are gone. Several parsing bugs have been fixed. - -f. Builtin option parsing has been regularized (using internal_getopt()), - with the exception of `echo', `type', and `set'. - -g. Builtins now return standard usage messages constructed from the - `short doc' used by the help builtin. - -h. Completion now quotes using backslashes by default, but honors - user-supplied quotes. - -i. The GNU libc malloc is available as a configure-time option. - -j. There are more internationalization features; bash uses gettext if - it is available. The $"..." translation syntax uses the current - locale and gettext. - -k. There is better reporting of job termination when the shell is not - interactive. - -l. The shell is somewhat more efficient: it uses a little less memory and - makes fewer system calls. - -4. Changes of interest in the Readline implementation - -a. There is now support for readline `callback' functions. - -b. There is now support for user-supplied input, redisplay, and terminal - preparation functions. - -c. Most of the shell-specific code in readline has been generalized or - removed. - -d. Most of the annoying redisplay bugs have been fixed, notably the problems - with incremental search and excessive redrawing when special characters - appear in the prompt string. - -e. There are new library functions and variables available to application - writers, most having to do with completion and quoting. - -f. The NEWLINE character (^J) is now treated as a search terminator by the - incremental search functions. diff --git a/README~ b/README~ deleted file mode 100644 index 33ddd7550..000000000 --- a/README~ +++ /dev/null @@ -1,90 +0,0 @@ -Introduction -============ - -This is GNU Bash, version 3.0. Bash is the GNU Project's Bourne -Again SHell, a complete implementation of the POSIX.2 shell spec, -but also with interactive command line editing, job control on -architectures that support it, csh-like features such as history -substitution and brace expansion, and a slew of other features. -For more information on the features of Bash that are new to this -type of shell, see the file `doc/bashref.texi'. There is also a -large Unix-style man page. The man page is the definitive description -of the shell's features. - -See the file CWRU/POSIX.NOTES for a discussion of how Bash differs -from the POSIX.2 spec and a description of the Bash `posix mode'. - -There are some user-visible incompatibilities between this version -of Bash and the previous widely-distributed version, bash-1.14. -For details, see the file COMPAT. The NEWS file tersely lists -features that are new in this release. - -Bash is free software, distributed under the terms of the [GNU] -General Public License, version 2. For more information, see the -file COPYING. - -A number of frequently-asked questions are answered in the file -`doc/FAQ'. - -To compile Bash, try typing `./configure', then `make'. Bash -auto-configures the build process, so no further intervention -should be necessary. Bash builds with `gcc' by default if it is -available. If you want to use `cc' instead, type - - CC=cc ./configure - -if you are using a Bourne-style shell. If you are not, the following -may work: - - env CC=cc ./configure - -Read the file INSTALL in this directory for more information about how -to customize and control the build process. The file NOTES contains -platform-specific installation and configuration information. - -If you are a csh user and wish to convert your csh aliases to Bash -aliases, you may wish to use the script `examples/misc/alias-conv.sh' -as a starting point. The script `examples/misc/cshtobash' is a -more ambitious script that attempts to do a more complete job. - -Reporting Bugs -============== - -Bug reports for bash should be sent to: - - bug-bash@gnu.org - -using the `bashbug' program that is built and installed at the same -time as bash. - -The discussion list `bug-bash@gnu.org' 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, please use the `bashbug' program that is -built at the same time as bash. If bash fails to build, try building -bashbug directly with `make bashbug'. If you cannot build `bashbug', -please send mail to bug-bash@gnu.org with the following information: - - * the version number and release status of Bash (e.g., 2.05a-release) - * the machine and OS that it is running on (you may run - `bashversion -l' from the bash build directory for this information) - * a list of the compilation flags or the contents of `config.h', if - appropriate - * a description of the bug - * a recipe for recreating the bug reliably - * a fix for the bug if you have one! - -The `bashbug' program includes much of this automatically. - -If you would like to contact the Bash maintainers directly, send mail -to bash-maintainers@gnu.org. - -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/Y2K~ b/Y2K~ deleted file mode 100644 index aa7ac311f..000000000 --- a/Y2K~ +++ /dev/null @@ -1,5 +0,0 @@ -Since Bash does not manipulate date strings, it is Y2K-safe. - -The only thing that Bash does with date strings is manipulate the string -returned by ctime(3) in the prompt customization code. In all cases, -it discards the year. diff --git a/aclocal.m4.orig b/aclocal.m4.orig deleted file mode 100644 index 90b66c714..000000000 --- a/aclocal.m4.orig +++ /dev/null @@ -1,3952 +0,0 @@ -dnl -dnl Bash specific tests -dnl -dnl Some derived from PDKSH 5.1.3 autoconf tests -dnl - -AC_DEFUN(BASH_C_LONG_LONG, -[AC_CACHE_CHECK(for long long, ac_cv_c_long_long, -[if test "$GCC" = yes; then - ac_cv_c_long_long=yes -else -AC_TRY_RUN([ -int -main() -{ -long long foo = 0; -exit(sizeof(long long) < sizeof(long)); -} -], ac_cv_c_long_long=yes, ac_cv_c_long_long=no) -fi]) -if test $ac_cv_c_long_long = yes; then - AC_DEFINE(HAVE_LONG_LONG, 1, [Define if the `long long' type works.]) -fi -]) - -dnl -dnl This is very similar to AC_C_LONG_DOUBLE, with the fix for IRIX -dnl (< changed to <=) added. -dnl -AC_DEFUN(BASH_C_LONG_DOUBLE, -[AC_CACHE_CHECK(for long double, ac_cv_c_long_double, -[if test "$GCC" = yes; then - ac_cv_c_long_double=yes -else -AC_TRY_RUN([ -int -main() -{ - /* The Stardent Vistra knows sizeof(long double), but does not - support it. */ - long double foo = 0.0; - /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ - /* On IRIX 5.3, the compiler converts long double to double with a warning, - but compiles this successfully. */ - exit(sizeof(long double) <= sizeof(double)); -} -], ac_cv_c_long_double=yes, ac_cv_c_long_double=no) -fi]) -if test $ac_cv_c_long_double = yes; then - AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if the `long double' type works.]) -fi -]) - -dnl -dnl Check for . This is separated out so that it can be -dnl AC_REQUIREd. -dnl -dnl BASH_HEADER_INTTYPES -AC_DEFUN(BASH_HEADER_INTTYPES, -[ - AC_CHECK_HEADERS(inttypes.h) -]) - -dnl -dnl check for typedef'd symbols in header files, but allow the caller to -dnl specify the include files to be checked in addition to the default -dnl -dnl BASH_CHECK_TYPE(TYPE, HEADERS, DEFAULT[, VALUE-IF-FOUND]) -AC_DEFUN(BASH_CHECK_TYPE, -[ -AC_REQUIRE([AC_HEADER_STDC])dnl -AC_REQUIRE([BASH_HEADER_INTTYPES]) -AC_MSG_CHECKING(for $1) -AC_CACHE_VAL(bash_cv_type_$1, -[AC_EGREP_CPP($1, [#include -#if STDC_HEADERS -#include -#include -#endif -#if HAVE_INTTYPES_H -#include -#endif -$2 -], bash_cv_type_$1=yes, bash_cv_type_$1=no)]) -AC_MSG_RESULT($bash_cv_type_$1) -ifelse($#, 4, [if test $bash_cv_type_$1 = yes; then - AC_DEFINE($4) - fi]) -if test $bash_cv_type_$1 = no; then - AC_DEFINE_UNQUOTED($1, $3) -fi -]) - -dnl -dnl BASH_CHECK_DECL(FUNC) -dnl -dnl Check for a declaration of FUNC in stdlib.h and inttypes.h like -dnl AC_CHECK_DECL -dnl -AC_DEFUN(BASH_CHECK_DECL, -[ -AC_REQUIRE([AC_HEADER_STDC]) -AC_REQUIRE([BASH_HEADER_INTTYPES]) -AC_CACHE_CHECK([for declaration of $1], bash_cv_decl_$1, -[AC_TRY_LINK( -[ -#if STDC_HEADERS -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif -], -[return !$1;], -bash_cv_decl_$1=yes, bash_cv_decl_$1=no)]) -bash_tr_func=HAVE_DECL_`echo $1 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` -if test $bash_cv_decl_$1 = yes; then - AC_DEFINE_UNQUOTED($bash_tr_func, 1) -else - AC_DEFINE_UNQUOTED($bash_tr_func, 0) -fi -]) - -AC_DEFUN(BASH_DECL_PRINTF, -[AC_MSG_CHECKING(for declaration of printf in ) -AC_CACHE_VAL(bash_cv_printf_declared, -[AC_TRY_RUN([ -#include -#ifdef __STDC__ -typedef int (*_bashfunc)(const char *, ...); -#else -typedef int (*_bashfunc)(); -#endif -main() -{ -_bashfunc pf; -pf = (_bashfunc) printf; -exit(pf == 0); -} -], bash_cv_printf_declared=yes, bash_cv_printf_declared=no, - [AC_MSG_WARN(cannot check printf declaration if cross compiling -- defaulting to yes) - bash_cv_printf_declared=yes] -)]) -AC_MSG_RESULT($bash_cv_printf_declared) -if test $bash_cv_printf_declared = yes; then -AC_DEFINE(PRINTF_DECLARED) -fi -]) - -AC_DEFUN(BASH_DECL_SBRK, -[AC_MSG_CHECKING(for declaration of sbrk in ) -AC_CACHE_VAL(bash_cv_sbrk_declared, -[AC_EGREP_HEADER(sbrk, unistd.h, - bash_cv_sbrk_declared=yes, bash_cv_sbrk_declared=no)]) -AC_MSG_RESULT($bash_cv_sbrk_declared) -if test $bash_cv_sbrk_declared = yes; then -AC_DEFINE(SBRK_DECLARED) -fi -]) - -dnl -dnl Check for sys_siglist[] or _sys_siglist[] -dnl -AC_DEFUN(BASH_DECL_UNDER_SYS_SIGLIST, -[AC_MSG_CHECKING([for _sys_siglist in signal.h or unistd.h]) -AC_CACHE_VAL(bash_cv_decl_under_sys_siglist, -[AC_TRY_COMPILE([ -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif], [ char *msg = _sys_siglist[2]; ], - bash_cv_decl_under_sys_siglist=yes, bash_cv_decl_under_sys_siglist=no, - [AC_MSG_WARN(cannot check for _sys_siglist[] if cross compiling -- defaulting to no)])])dnl -AC_MSG_RESULT($bash_cv_decl_under_sys_siglist) -if test $bash_cv_decl_under_sys_siglist = yes; then -AC_DEFINE(UNDER_SYS_SIGLIST_DECLARED) -fi -]) - -AC_DEFUN(BASH_UNDER_SYS_SIGLIST, -[AC_REQUIRE([BASH_DECL_UNDER_SYS_SIGLIST]) -AC_MSG_CHECKING([for _sys_siglist in system C library]) -AC_CACHE_VAL(bash_cv_under_sys_siglist, -[AC_TRY_RUN([ -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifndef UNDER_SYS_SIGLIST_DECLARED -extern char *_sys_siglist[]; -#endif -main() -{ -char *msg = (char *)_sys_siglist[2]; -exit(msg == 0); -}], - bash_cv_under_sys_siglist=yes, bash_cv_under_sys_siglist=no, - [AC_MSG_WARN(cannot check for _sys_siglist[] if cross compiling -- defaulting to no) - bash_cv_under_sys_siglist=no])]) -AC_MSG_RESULT($bash_cv_under_sys_siglist) -if test $bash_cv_under_sys_siglist = yes; then -AC_DEFINE(HAVE_UNDER_SYS_SIGLIST) -fi -]) - -AC_DEFUN(BASH_SYS_SIGLIST, -[AC_REQUIRE([AC_DECL_SYS_SIGLIST]) -AC_MSG_CHECKING([for sys_siglist in system C library]) -AC_CACHE_VAL(bash_cv_sys_siglist, -[AC_TRY_RUN([ -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifndef SYS_SIGLIST_DECLARED -extern char *sys_siglist[]; -#endif -main() -{ -char *msg = sys_siglist[2]; -exit(msg == 0); -}], - bash_cv_sys_siglist=yes, bash_cv_sys_siglist=no, - [AC_MSG_WARN(cannot check for sys_siglist if cross compiling -- defaulting to no) - bash_cv_sys_siglist=no])]) -AC_MSG_RESULT($bash_cv_sys_siglist) -if test $bash_cv_sys_siglist = yes; then -AC_DEFINE(HAVE_SYS_SIGLIST) -fi -]) - -dnl Check for the various permutations of sys_siglist and make sure we -dnl compile in siglist.o if they're not defined -AC_DEFUN(BASH_CHECK_SYS_SIGLIST, [ -AC_REQUIRE([BASH_SYS_SIGLIST]) -AC_REQUIRE([BASH_DECL_UNDER_SYS_SIGLIST]) -AC_REQUIRE([BASH_FUNC_STRSIGNAL]) -if test "$bash_cv_sys_siglist" = no && test "$bash_cv_under_sys_siglist" = no && test "$bash_cv_have_strsignal" = no; then - SIGLIST_O=siglist.o -else - SIGLIST_O= -fi -AC_SUBST([SIGLIST_O]) -]) - -dnl Check for sys_errlist[] and sys_nerr, check for declaration -AC_DEFUN(BASH_SYS_ERRLIST, -[AC_MSG_CHECKING([for sys_errlist and sys_nerr]) -AC_CACHE_VAL(bash_cv_sys_errlist, -[AC_TRY_LINK([#include ], -[extern char *sys_errlist[]; - extern int sys_nerr; - char *msg = sys_errlist[sys_nerr - 1];], - bash_cv_sys_errlist=yes, bash_cv_sys_errlist=no)])dnl -AC_MSG_RESULT($bash_cv_sys_errlist) -if test $bash_cv_sys_errlist = yes; then -AC_DEFINE(HAVE_SYS_ERRLIST) -fi -]) - -dnl -dnl Check if dup2() does not clear the close on exec flag -dnl -AC_DEFUN(BASH_FUNC_DUP2_CLOEXEC_CHECK, -[AC_MSG_CHECKING(if dup2 fails to clear the close-on-exec flag) -AC_CACHE_VAL(bash_cv_dup2_broken, -[AC_TRY_RUN([ -#include -#include -main() -{ - int fd1, fd2, fl; - fd1 = open("/dev/null", 2); - if (fcntl(fd1, 2, 1) < 0) - exit(1); - fd2 = dup2(fd1, 1); - if (fd2 < 0) - exit(2); - fl = fcntl(fd2, 1, 0); - /* fl will be 1 if dup2 did not reset the close-on-exec flag. */ - exit(fl != 1); -} -], bash_cv_dup2_broken=yes, bash_cv_dup2_broken=no, - [AC_MSG_WARN(cannot check dup2 if cross compiling -- defaulting to no) - bash_cv_dup2_broken=no]) -]) -AC_MSG_RESULT($bash_cv_dup2_broken) -if test $bash_cv_dup2_broken = yes; then -AC_DEFINE(DUP2_BROKEN) -fi -]) - -AC_DEFUN(BASH_FUNC_STRSIGNAL, -[AC_MSG_CHECKING([for the existence of strsignal]) -AC_CACHE_VAL(bash_cv_have_strsignal, -[AC_TRY_LINK([#include -#include ], -[char *s = (char *)strsignal(2);], - bash_cv_have_strsignal=yes, bash_cv_have_strsignal=no)]) -AC_MSG_RESULT($bash_cv_have_strsignal) -if test $bash_cv_have_strsignal = yes; then -AC_DEFINE(HAVE_STRSIGNAL) -fi -]) - -dnl Check to see if opendir will open non-directories (not a nice thing) -AC_DEFUN(BASH_FUNC_OPENDIR_CHECK, -[AC_REQUIRE([AC_HEADER_DIRENT])dnl -AC_MSG_CHECKING(if opendir() opens non-directories) -AC_CACHE_VAL(bash_cv_opendir_not_robust, -[AC_TRY_RUN([ -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ -main() -{ -DIR *dir; -int fd, err; -err = mkdir("/tmp/bash-aclocal", 0700); -if (err < 0) { - perror("mkdir"); - exit(1); -} -unlink("/tmp/bash-aclocal/not_a_directory"); -fd = open("/tmp/bash-aclocal/not_a_directory", O_WRONLY|O_CREAT|O_EXCL, 0666); -write(fd, "\n", 1); -close(fd); -dir = opendir("/tmp/bash-aclocal/not_a_directory"); -unlink("/tmp/bash-aclocal/not_a_directory"); -rmdir("/tmp/bash-aclocal"); -exit (dir == 0); -}], bash_cv_opendir_not_robust=yes,bash_cv_opendir_not_robust=no, - [AC_MSG_WARN(cannot check opendir if cross compiling -- defaulting to no) - bash_cv_opendir_not_robust=no] -)]) -AC_MSG_RESULT($bash_cv_opendir_not_robust) -if test $bash_cv_opendir_not_robust = yes; then -AC_DEFINE(OPENDIR_NOT_ROBUST) -fi -]) - -dnl -AC_DEFUN(BASH_TYPE_SIGHANDLER, -[AC_MSG_CHECKING([whether signal handlers are of type void]) -AC_CACHE_VAL(bash_cv_void_sighandler, -[AC_TRY_COMPILE([#include -#include -#ifdef signal -#undef signal -#endif -#ifdef __cplusplus -extern "C" -#endif -void (*signal ()) ();], -[int i;], bash_cv_void_sighandler=yes, bash_cv_void_sighandler=no)])dnl -AC_MSG_RESULT($bash_cv_void_sighandler) -if test $bash_cv_void_sighandler = yes; then -AC_DEFINE(VOID_SIGHANDLER) -fi -]) - -dnl -dnl A signed 16-bit integer quantity -dnl -AC_DEFUN(BASH_TYPE_BITS16_T, -[ -if test "$ac_cv_sizeof_short" = 2; then - AC_CHECK_TYPE(bits16_t, short) -elif test "$ac_cv_sizeof_char" = 2; then - AC_CHECK_TYPE(bits16_t, char) -else - AC_CHECK_TYPE(bits16_t, short) -fi -]) - -dnl -dnl An unsigned 16-bit integer quantity -dnl -AC_DEFUN(BASH_TYPE_U_BITS16_T, -[ -if test "$ac_cv_sizeof_short" = 2; then - AC_CHECK_TYPE(u_bits16_t, unsigned short) -elif test "$ac_cv_sizeof_char" = 2; then - AC_CHECK_TYPE(u_bits16_t, unsigned char) -else - AC_CHECK_TYPE(u_bits16_t, unsigned short) -fi -]) - -dnl -dnl A signed 32-bit integer quantity -dnl -AC_DEFUN(BASH_TYPE_BITS32_T, -[ -if test "$ac_cv_sizeof_int" = 4; then - AC_CHECK_TYPE(bits32_t, int) -elif test "$ac_cv_sizeof_long" = 4; then - AC_CHECK_TYPE(bits32_t, long) -else - AC_CHECK_TYPE(bits32_t, int) -fi -]) - -dnl -dnl An unsigned 32-bit integer quantity -dnl -AC_DEFUN(BASH_TYPE_U_BITS32_T, -[ -if test "$ac_cv_sizeof_int" = 4; then - AC_CHECK_TYPE(u_bits32_t, unsigned int) -elif test "$ac_cv_sizeof_long" = 4; then - AC_CHECK_TYPE(u_bits32_t, unsigned long) -else - AC_CHECK_TYPE(u_bits32_t, unsigned int) -fi -]) - -AC_DEFUN(BASH_TYPE_PTRDIFF_T, -[ -if test "$ac_cv_sizeof_int" = "$ac_cv_sizeof_char_p"; then - AC_CHECK_TYPE(ptrdiff_t, int) -elif test "$ac_cv_sizeof_long" = "$ac_cv_sizeof_char_p"; then - AC_CHECK_TYPE(ptrdiff_t, long) -elif test "$ac_cv_type_long_long" = yes && test "$ac_cv_sizeof_long_long" = "$ac_cv_sizeof_char_p"; then - AC_CHECK_TYPE(ptrdiff_t, [long long]) -else - AC_CHECK_TYPE(ptrdiff_t, int) -fi -]) - -dnl -dnl A signed 64-bit quantity -dnl -AC_DEFUN(BASH_TYPE_BITS64_T, -[ -if test "$ac_cv_sizeof_char_p" = 8; then - AC_CHECK_TYPE(bits64_t, char *) -elif test "$ac_cv_sizeof_double" = 8; then - AC_CHECK_TYPE(bits64_t, double) -elif test -n "$ac_cv_type_long_long" && test "$ac_cv_sizeof_long_long" = 8; then - AC_CHECK_TYPE(bits64_t, [long long]) -elif test "$ac_cv_sizeof_long" = 8; then - AC_CHECK_TYPE(bits64_t, long) -else - AC_CHECK_TYPE(bits64_t, double) -fi -]) - -AC_DEFUN(BASH_TYPE_LONG_LONG, -[ -AC_CACHE_CHECK([for long long], bash_cv_type_long_long, -[AC_TRY_LINK([ -long long ll = 1; int i = 63;], -[ -long long llm = (long long) -1; -return ll << i | ll >> i | llm / ll | llm % ll; -], bash_cv_type_long_long='long long', bash_cv_type_long_long='long')]) -if test "$bash_cv_type_long_long" = 'long long'; then - AC_DEFINE(HAVE_LONG_LONG, 1) -fi -]) - -AC_DEFUN(BASH_TYPE_UNSIGNED_LONG_LONG, -[ -AC_CACHE_CHECK([for unsigned long long], bash_cv_type_unsigned_long_long, -[AC_TRY_LINK([ -unsigned long long ull = 1; int i = 63;], -[ -unsigned long long ullmax = (unsigned long long) -1; -return ull << i | ull >> i | ullmax / ull | ullmax % ull; -], bash_cv_type_unsigned_long_long='unsigned long long', - bash_cv_type_unsigned_long_long='unsigned long')]) -if test "$bash_cv_type_unsigned_long_long" = 'unsigned long long'; then - AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1) -fi -]) - -dnl -dnl Type of struct rlimit fields: some systems (OSF/1, NetBSD, RISC/os 5.0) -dnl have a rlim_t, others (4.4BSD based systems) use quad_t, others use -dnl long and still others use int (HP-UX 9.01, SunOS 4.1.3). To simplify -dnl matters, this just checks for rlim_t, quad_t, or long. -dnl -AC_DEFUN(BASH_TYPE_RLIMIT, -[AC_MSG_CHECKING(for size and type of struct rlimit fields) -AC_CACHE_VAL(bash_cv_type_rlimit, -[AC_TRY_COMPILE([#include -#include ], -[rlim_t xxx;], bash_cv_type_rlimit=rlim_t,[ -AC_TRY_RUN([ -#include -#include -#include -main() -{ -#ifdef HAVE_QUAD_T - struct rlimit rl; - if (sizeof(rl.rlim_cur) == sizeof(quad_t)) - exit(0); -#endif - exit(1); -}], bash_cv_type_rlimit=quad_t, bash_cv_type_rlimit=long, - [AC_MSG_WARN(cannot check quad_t if cross compiling -- defaulting to long) - bash_cv_type_rlimit=long])]) -]) -AC_MSG_RESULT($bash_cv_type_rlimit) -if test $bash_cv_type_rlimit = quad_t; then -AC_DEFINE(RLIMTYPE, quad_t) -elif test $bash_cv_type_rlimit = rlim_t; then -AC_DEFINE(RLIMTYPE, rlim_t) -fi -]) - -AC_DEFUN(BASH_FUNC_LSTAT, -[dnl Cannot use AC_CHECK_FUNCS(lstat) because Linux defines lstat() as an -dnl inline function in . -AC_CACHE_CHECK([for lstat], bash_cv_func_lstat, -[AC_TRY_LINK([ -#include -#include -],[ lstat(".",(struct stat *)0); ], -bash_cv_func_lstat=yes, bash_cv_func_lstat=no)]) -if test $bash_cv_func_lstat = yes; then - AC_DEFINE(HAVE_LSTAT) -fi -]) - -AC_DEFUN(BASH_FUNC_INET_ATON, -[ -AC_CACHE_CHECK([for inet_aton], bash_cv_func_inet_aton, -[AC_TRY_LINK([ -#include -#include -#include -struct in_addr ap;], [ inet_aton("127.0.0.1", &ap); ], -bash_cv_func_inet_aton=yes, bash_cv_func_inet_aton=no)]) -if test $bash_cv_func_inet_aton = yes; then - AC_DEFINE(HAVE_INET_ATON) -else - AC_LIBOBJ(inet_aton) -fi -]) - -AC_DEFUN(BASH_FUNC_GETENV, -[AC_MSG_CHECKING(to see if getenv can be redefined) -AC_CACHE_VAL(bash_cv_getenv_redef, -[AC_TRY_RUN([ -#ifdef HAVE_UNISTD_H -# include -#endif -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -char * -getenv (name) -#if defined (__linux__) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !__linux__ && !__bsdi__ && !convex */ -{ -return "42"; -} -main() -{ -char *s; -/* The next allows this program to run, but does not allow bash to link - when it redefines getenv. I'm not really interested in figuring out - why not. */ -#if defined (NeXT) -exit(1); -#endif -s = getenv("ABCDE"); -exit(s == 0); /* force optimizer to leave getenv in */ -} -], bash_cv_getenv_redef=yes, bash_cv_getenv_redef=no, - [AC_MSG_WARN(cannot check getenv redefinition if cross compiling -- defaulting to yes) - bash_cv_getenv_redef=yes] -)]) -AC_MSG_RESULT($bash_cv_getenv_redef) -if test $bash_cv_getenv_redef = yes; then -AC_DEFINE(CAN_REDEFINE_GETENV) -fi -]) - -# We should check for putenv before calling this -AC_DEFUN(BASH_FUNC_STD_PUTENV, -[ -AC_REQUIRE([AC_HEADER_STDC]) -AC_REQUIRE([AC_C_PROTOTYPES]) -AC_CACHE_CHECK([for standard-conformant putenv declaration], bash_cv_std_putenv, -[AC_TRY_LINK([ -#if STDC_HEADERS -#include -#include -#endif -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -#ifdef PROTOTYPES -extern int putenv (char *); -#else -extern int putenv (); -#endif -], -[return (putenv == 0);], -bash_cv_std_putenv=yes, bash_cv_std_putenv=no -)]) -if test $bash_cv_std_putenv = yes; then -AC_DEFINE(HAVE_STD_PUTENV) -fi -]) - -# We should check for unsetenv before calling this -AC_DEFUN(BASH_FUNC_STD_UNSETENV, -[ -AC_REQUIRE([AC_HEADER_STDC]) -AC_REQUIRE([AC_C_PROTOTYPES]) -AC_CACHE_CHECK([for standard-conformant unsetenv declaration], bash_cv_std_unsetenv, -[AC_TRY_LINK([ -#if STDC_HEADERS -#include -#include -#endif -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif -#ifdef PROTOTYPES -extern int unsetenv (const char *); -#else -extern int unsetenv (); -#endif -], -[return (unsetenv == 0);], -bash_cv_std_unsetenv=yes, bash_cv_std_unsetenv=no -)]) -if test $bash_cv_std_unsetenv = yes; then -AC_DEFINE(HAVE_STD_UNSETENV) -fi -]) - -AC_DEFUN(BASH_FUNC_ULIMIT_MAXFDS, -[AC_MSG_CHECKING(whether ulimit can substitute for getdtablesize) -AC_CACHE_VAL(bash_cv_ulimit_maxfds, -[AC_TRY_RUN([ -main() -{ -long maxfds = ulimit(4, 0L); -exit (maxfds == -1L); -} -], bash_cv_ulimit_maxfds=yes, bash_cv_ulimit_maxfds=no, - [AC_MSG_WARN(cannot check ulimit if cross compiling -- defaulting to no) - bash_cv_ulimit_maxfds=no] -)]) -AC_MSG_RESULT($bash_cv_ulimit_maxfds) -if test $bash_cv_ulimit_maxfds = yes; then -AC_DEFINE(ULIMIT_MAXFDS) -fi -]) - -AC_DEFUN(BASH_FUNC_GETCWD, -[AC_MSG_CHECKING([if getcwd() calls popen()]) -AC_CACHE_VAL(bash_cv_getcwd_calls_popen, -[AC_TRY_RUN([ -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifndef __STDC__ -#ifndef const -#define const -#endif -#endif - -int popen_called; - -FILE * -popen(command, type) - const char *command; - const char *type; -{ - popen_called = 1; - return (FILE *)NULL; -} - -FILE *_popen(command, type) - const char *command; - const char *type; -{ - return (popen (command, type)); -} - -int -pclose(stream) -FILE *stream; -{ - return 0; -} - -int -_pclose(stream) -FILE *stream; -{ - return 0; -} - -main() -{ - char lbuf[32]; - popen_called = 0; - getcwd(lbuf, 32); - exit (popen_called); -} -], bash_cv_getcwd_calls_popen=no, bash_cv_getcwd_calls_popen=yes, - [AC_MSG_WARN(cannot check whether getcwd calls popen if cross compiling -- defaulting to no) - bash_cv_getcwd_calls_popen=no] -)]) -AC_MSG_RESULT($bash_cv_getcwd_calls_popen) -if test $bash_cv_getcwd_calls_popen = yes; then -AC_DEFINE(GETCWD_BROKEN) -AC_LIBOBJ(getcwd) -fi -]) - -dnl -dnl This needs BASH_CHECK_SOCKLIB, but since that's not called on every -dnl system, we can't use AC_PREREQ -dnl -AC_DEFUN(BASH_FUNC_GETHOSTBYNAME, -[if test "X$bash_cv_have_gethostbyname" = "X"; then -_bash_needmsg=yes -else -AC_MSG_CHECKING(for gethostbyname in socket library) -_bash_needmsg= -fi -AC_CACHE_VAL(bash_cv_have_gethostbyname, -[AC_TRY_LINK([#include ], -[ struct hostent *hp; - hp = gethostbyname("localhost"); -], bash_cv_have_gethostbyname=yes, bash_cv_have_gethostbyname=no)] -) -if test "X$_bash_needmsg" = Xyes; then - AC_MSG_CHECKING(for gethostbyname in socket library) -fi -AC_MSG_RESULT($bash_cv_have_gethostbyname) -if test "$bash_cv_have_gethostbyname" = yes; then -AC_DEFINE(HAVE_GETHOSTBYNAME) -fi -]) - -AC_DEFUN(BASH_FUNC_FNMATCH_EXTMATCH, -[AC_MSG_CHECKING(if fnmatch does extended pattern matching with FNM_EXTMATCH) -AC_CACHE_VAL(bash_cv_fnm_extmatch, -[AC_TRY_RUN([ -#include - -main() -{ -#ifdef FNM_EXTMATCH - exit (0); -#else - exit (1); -#endif -} -], bash_cv_fnm_extmatch=yes, bash_cv_fnm_extmatch=no, - [AC_MSG_WARN(cannot check FNM_EXTMATCH if cross compiling -- defaulting to no) - bash_cv_fnm_extmatch=no]) -]) -AC_MSG_RESULT($bash_cv_fnm_extmatch) -if test $bash_cv_fnm_extmatch = yes; then -AC_DEFINE(HAVE_LIBC_FNM_EXTMATCH) -fi -]) - -AC_DEFUN(BASH_FUNC_POSIX_SETJMP, -[AC_REQUIRE([BASH_SYS_SIGNAL_VINTAGE]) -AC_MSG_CHECKING(for presence of POSIX-style sigsetjmp/siglongjmp) -AC_CACHE_VAL(bash_cv_func_sigsetjmp, -[AC_TRY_RUN([ -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#include - -main() -{ -#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) -exit (1); -#else - -int code; -sigset_t set, oset; -sigjmp_buf xx; - -/* get the mask */ -sigemptyset(&set); -sigemptyset(&oset); -sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &set); -sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset); - -/* save it */ -code = sigsetjmp(xx, 1); -if (code) - exit(0); /* could get sigmask and compare to oset here. */ - -/* change it */ -sigaddset(&set, SIGINT); -sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); - -/* and siglongjmp */ -siglongjmp(xx, 10); -exit(1); -#endif -}], bash_cv_func_sigsetjmp=present, bash_cv_func_sigsetjmp=missing, - [AC_MSG_WARN(cannot check for sigsetjmp/siglongjmp if cross-compiling -- defaulting to missing) - bash_cv_func_sigsetjmp=missing] -)]) -AC_MSG_RESULT($bash_cv_func_sigsetjmp) -if test $bash_cv_func_sigsetjmp = present; then -AC_DEFINE(HAVE_POSIX_SIGSETJMP) -fi -]) - -AC_DEFUN(BASH_FUNC_STRCOLL, -[ -AC_MSG_CHECKING(whether or not strcoll and strcmp differ) -AC_CACHE_VAL(bash_cv_func_strcoll_broken, -[AC_TRY_RUN([ -#include -#if defined (HAVE_LOCALE_H) -#include -#endif - -main(c, v) -int c; -char *v[]; -{ - int r1, r2; - char *deflocale, *defcoll; - -#ifdef HAVE_SETLOCALE - deflocale = setlocale(LC_ALL, ""); - defcoll = setlocale(LC_COLLATE, ""); -#endif - -#ifdef HAVE_STRCOLL - /* These two values are taken from tests/glob-test. */ - r1 = strcoll("abd", "aXd"); -#else - r1 = 0; -#endif - r2 = strcmp("abd", "aXd"); - - /* These two should both be greater than 0. It is permissible for - a system to return different values, as long as the sign is the - same. */ - - /* Exit with 1 (failure) if these two values are both > 0, since - this tests whether strcoll(3) is broken with respect to strcmp(3) - in the default locale. */ - exit (r1 > 0 && r2 > 0); -} -], bash_cv_func_strcoll_broken=yes, bash_cv_func_strcoll_broken=no, - [AC_MSG_WARN(cannot check strcoll if cross compiling -- defaulting to no) - bash_cv_func_strcoll_broken=no] -)]) -AC_MSG_RESULT($bash_cv_func_strcoll_broken) -if test $bash_cv_func_strcoll_broken = yes; then -AC_DEFINE(STRCOLL_BROKEN) -fi -]) - -AC_DEFUN(BASH_FUNC_PRINTF_A_FORMAT, -[AC_MSG_CHECKING([for printf floating point output in hex notation]) -AC_CACHE_VAL(bash_cv_printf_a_format, -[AC_TRY_RUN([ -#include -#include - -int -main() -{ - double y = 0.0; - char abuf[1024]; - - sprintf(abuf, "%A", y); - exit(strchr(abuf, 'P') == (char *)0); -} -], bash_cv_printf_a_format=yes, bash_cv_printf_a_format=no, - [AC_MSG_WARN(cannot check printf if cross compiling -- defaulting to no) - bash_cv_printf_a_format=no] -)]) -AC_MSG_RESULT($bash_cv_printf_a_format) -if test $bash_cv_printf_a_format = yes; then -AC_DEFINE(HAVE_PRINTF_A_FORMAT) -fi -]) - -AC_DEFUN(BASH_STRUCT_TERMIOS_LDISC, -[ -AC_CHECK_MEMBER(struct termios.c_line, AC_DEFINE(TERMIOS_LDISC), ,[ -#include -#include -]) -]) - -AC_DEFUN(BASH_STRUCT_TERMIO_LDISC, -[ -AC_CHECK_MEMBER(struct termio.c_line, AC_DEFINE(TERMIO_LDISC), ,[ -#include -#include -]) -]) - -dnl -dnl Like AC_STRUCT_ST_BLOCKS, but doesn't muck with LIBOBJS -dnl -dnl sets bash_cv_struct_stat_st_blocks -dnl -dnl unused for now; we'll see how AC_CHECK_MEMBERS works -dnl -AC_DEFUN(BASH_STRUCT_ST_BLOCKS, -[ -AC_MSG_CHECKING([for struct stat.st_blocks]) -AC_CACHE_VAL(bash_cv_struct_stat_st_blocks, -[AC_TRY_COMPILE( -[ -#include -#include -], -[ -main() -{ -static struct stat a; -if (a.st_blocks) return 0; -return 0; -} -], bash_cv_struct_stat_st_blocks=yes, bash_cv_struct_stat_st_blocks=no) -]) -AC_MSG_RESULT($bash_cv_struct_stat_st_blocks) -if test "$bash_cv_struct_stat_st_blocks" = "yes"; then -AC_DEFINE(HAVE_STRUCT_STAT_ST_BLOCKS) -fi -]) - -AC_DEFUN(BASH_CHECK_LIB_TERMCAP, -[ -if test "X$bash_cv_termcap_lib" = "X"; then -_bash_needmsg=yes -else -AC_MSG_CHECKING(which library has the termcap functions) -_bash_needmsg= -fi -AC_CACHE_VAL(bash_cv_termcap_lib, -[AC_CHECK_FUNC(tgetent, bash_cv_termcap_lib=libc, - [AC_CHECK_LIB(termcap, tgetent, bash_cv_termcap_lib=libtermcap, - [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo, - [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses, - [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, - bash_cv_termcap_lib=gnutermcap)])])])])]) -if test "X$_bash_needmsg" = "Xyes"; then -AC_MSG_CHECKING(which library has the termcap functions) -fi -AC_MSG_RESULT(using $bash_cv_termcap_lib) -if test $bash_cv_termcap_lib = gnutermcap && test -z "$prefer_curses"; then -LDFLAGS="$LDFLAGS -L./lib/termcap" -TERMCAP_LIB="./lib/termcap/libtermcap.a" -TERMCAP_DEP="./lib/termcap/libtermcap.a" -elif test $bash_cv_termcap_lib = libtermcap && test -z "$prefer_curses"; then -TERMCAP_LIB=-ltermcap -TERMCAP_DEP= -elif test $bash_cv_termcap_lib = libtinfo; then -TERMCAP_LIB=-ltinfo -TERMCAP_DEP= -elif test $bash_cv_termcap_lib = libncurses; then -TERMCAP_LIB=-lncurses -TERMCAP_DEP= -elif test $bash_cv_termcap_lib = libc; then -TERMCAP_LIB= -TERMCAP_DEP= -else -TERMCAP_LIB=-lcurses -TERMCAP_DEP= -fi -]) - -dnl -dnl Check for the presence of getpeername in libsocket. -dnl If libsocket is present, check for libnsl and add it to LIBS if -dnl it's there, since most systems with libsocket require linking -dnl with libnsl as well. This should only be called if getpeername -dnl was not found in libc. -dnl -dnl NOTE: IF WE FIND GETPEERNAME, WE ASSUME THAT WE HAVE BIND/CONNECT -dnl AS WELL -dnl -AC_DEFUN(BASH_CHECK_LIB_SOCKET, -[ -if test "X$bash_cv_have_socklib" = "X"; then -_bash_needmsg= -else -AC_MSG_CHECKING(for socket library) -_bash_needmsg=yes -fi -AC_CACHE_VAL(bash_cv_have_socklib, -[AC_CHECK_LIB(socket, getpeername, - bash_cv_have_socklib=yes, bash_cv_have_socklib=no, -lnsl)]) -if test "X$_bash_needmsg" = Xyes; then - AC_MSG_RESULT($bash_cv_have_socklib) - _bash_needmsg= -fi -if test $bash_cv_have_socklib = yes; then - # check for libnsl, add it to LIBS if present - if test "X$bash_cv_have_libnsl" = "X"; then - _bash_needmsg= - else - AC_MSG_CHECKING(for libnsl) - _bash_needmsg=yes - fi - AC_CACHE_VAL(bash_cv_have_libnsl, - [AC_CHECK_LIB(nsl, t_open, - bash_cv_have_libnsl=yes, bash_cv_have_libnsl=no)]) - if test "X$_bash_needmsg" = Xyes; then - AC_MSG_RESULT($bash_cv_have_libnsl) - _bash_needmsg= - fi - if test $bash_cv_have_libnsl = yes; then - LIBS="-lsocket -lnsl $LIBS" - else - LIBS="-lsocket $LIBS" - fi - AC_DEFINE(HAVE_LIBSOCKET) - AC_DEFINE(HAVE_GETPEERNAME) -fi -]) - -AC_DEFUN(BASH_STRUCT_DIRENT_D_INO, -[AC_REQUIRE([AC_HEADER_DIRENT]) -AC_MSG_CHECKING(for struct dirent.d_ino) -AC_CACHE_VAL(bash_cv_dirent_has_dino, -[AC_TRY_COMPILE([ -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ -],[ -struct dirent d; int z; z = d.d_ino; -], bash_cv_dirent_has_dino=yes, bash_cv_dirent_has_dino=no)]) -AC_MSG_RESULT($bash_cv_dirent_has_dino) -if test $bash_cv_dirent_has_dino = yes; then -AC_DEFINE(HAVE_STRUCT_DIRENT_D_INO) -fi -]) - -AC_DEFUN(BASH_STRUCT_DIRENT_D_FILENO, -[AC_REQUIRE([AC_HEADER_DIRENT]) -AC_MSG_CHECKING(for struct dirent.d_fileno) -AC_CACHE_VAL(bash_cv_dirent_has_d_fileno, -[AC_TRY_COMPILE([ -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ -],[ -struct dirent d; int z; z = d.d_fileno; -], bash_cv_dirent_has_d_fileno=yes, bash_cv_dirent_has_d_fileno=no)]) -AC_MSG_RESULT($bash_cv_dirent_has_d_fileno) -if test $bash_cv_dirent_has_d_fileno = yes; then -AC_DEFINE(HAVE_STRUCT_DIRENT_D_FILENO) -fi -]) - -AC_DEFUN(BASH_STRUCT_DIRENT_D_NAMLEN, -[AC_REQUIRE([AC_HEADER_DIRENT]) -AC_MSG_CHECKING(for struct dirent.d_namlen) -AC_CACHE_VAL(bash_cv_dirent_has_d_namlen, -[AC_TRY_COMPILE([ -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if defined(HAVE_DIRENT_H) -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif /* SYSNDIR */ -# ifdef HAVE_SYS_DIR_H -# include -# endif /* SYSDIR */ -# ifdef HAVE_NDIR_H -# include -# endif -#endif /* HAVE_DIRENT_H */ -],[ -struct dirent d; int z; z = d.d_namlen; -], bash_cv_dirent_has_d_namlen=yes, bash_cv_dirent_has_d_namlen=no)]) -AC_MSG_RESULT($bash_cv_dirent_has_d_namlen) -if test $bash_cv_dirent_has_d_namlen = yes; then -AC_DEFINE(HAVE_STRUCT_DIRENT_D_NAMLEN) -fi -]) - -AC_DEFUN(BASH_STRUCT_TIMEVAL, -[AC_MSG_CHECKING(for struct timeval in sys/time.h and time.h) -AC_CACHE_VAL(bash_cv_struct_timeval, -[ -AC_EGREP_HEADER(struct timeval, sys/time.h, - bash_cv_struct_timeval=yes, - AC_EGREP_HEADER(struct timeval, time.h, - bash_cv_struct_timeval=yes, - bash_cv_struct_timeval=no)) -]) -AC_MSG_RESULT($bash_cv_struct_timeval) -if test $bash_cv_struct_timeval = yes; then - AC_DEFINE(HAVE_TIMEVAL) -fi -]) - -AC_DEFUN(BASH_STRUCT_TIMEZONE, -[AC_MSG_CHECKING(for struct timezone in sys/time.h and time.h) -AC_CACHE_VAL(bash_cv_struct_timezone, -[ -AC_EGREP_HEADER(struct timezone, sys/time.h, - bash_cv_struct_timezone=yes, - AC_EGREP_HEADER(struct timezone, time.h, - bash_cv_struct_timezone=yes, - bash_cv_struct_timezone=no)) -]) -AC_MSG_RESULT($bash_cv_struct_timezone) -if test $bash_cv_struct_timezone = yes; then - AC_DEFINE(HAVE_STRUCT_TIMEZONE) -fi -]) - -AC_DEFUN(BASH_STRUCT_WINSIZE, -[AC_MSG_CHECKING(for struct winsize in sys/ioctl.h and termios.h) -AC_CACHE_VAL(bash_cv_struct_winsize_header, -[AC_TRY_COMPILE([#include -#include ], [struct winsize x;], - bash_cv_struct_winsize_header=ioctl_h, - [AC_TRY_COMPILE([#include -#include ], [struct winsize x;], - bash_cv_struct_winsize_header=termios_h, bash_cv_struct_winsize_header=other) -])]) -if test $bash_cv_struct_winsize_header = ioctl_h; then - AC_MSG_RESULT(sys/ioctl.h) - AC_DEFINE(STRUCT_WINSIZE_IN_SYS_IOCTL) -elif test $bash_cv_struct_winsize_header = termios_h; then - AC_MSG_RESULT(termios.h) - AC_DEFINE(STRUCT_WINSIZE_IN_TERMIOS) -else - AC_MSG_RESULT(not found) -fi -]) - -dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7) -AC_DEFUN(BASH_SYS_SIGNAL_VINTAGE, -[AC_REQUIRE([AC_TYPE_SIGNAL]) -AC_MSG_CHECKING(for type of signal functions) -AC_CACHE_VAL(bash_cv_signal_vintage, -[ - AC_TRY_LINK([#include ],[ - sigset_t ss; - struct sigaction sa; - sigemptyset(&ss); sigsuspend(&ss); - sigaction(SIGINT, &sa, (struct sigaction *) 0); - sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0); - ], bash_cv_signal_vintage=posix, - [ - AC_TRY_LINK([#include ], [ - int mask = sigmask(SIGINT); - sigsetmask(mask); sigblock(mask); sigpause(mask); - ], bash_cv_signal_vintage=4.2bsd, - [ - AC_TRY_LINK([ - #include - RETSIGTYPE foo() { }], [ - int mask = sigmask(SIGINT); - sigset(SIGINT, foo); sigrelse(SIGINT); - sighold(SIGINT); sigpause(SIGINT); - ], bash_cv_signal_vintage=svr3, bash_cv_signal_vintage=v7 - )] - )] -) -]) -AC_MSG_RESULT($bash_cv_signal_vintage) -if test "$bash_cv_signal_vintage" = posix; then -AC_DEFINE(HAVE_POSIX_SIGNALS) -elif test "$bash_cv_signal_vintage" = "4.2bsd"; then -AC_DEFINE(HAVE_BSD_SIGNALS) -elif test "$bash_cv_signal_vintage" = svr3; then -AC_DEFINE(HAVE_USG_SIGHOLD) -fi -]) - -dnl Check if the pgrp of setpgrp() can't be the pid of a zombie process. -AC_DEFUN(BASH_SYS_PGRP_SYNC, -[AC_REQUIRE([AC_FUNC_GETPGRP]) -AC_MSG_CHECKING(whether pgrps need synchronization) -AC_CACHE_VAL(bash_cv_pgrp_pipe, -[AC_TRY_RUN([ -#ifdef HAVE_UNISTD_H -# include -#endif -main() -{ -# ifdef GETPGRP_VOID -# define getpgID() getpgrp() -# else -# define getpgID() getpgrp(0) -# define setpgid(x,y) setpgrp(x,y) -# endif - int pid1, pid2, fds[2]; - int status; - char ok; - - switch (pid1 = fork()) { - case -1: - exit(1); - case 0: - setpgid(0, getpid()); - exit(0); - } - setpgid(pid1, pid1); - - sleep(2); /* let first child die */ - - if (pipe(fds) < 0) - exit(2); - - switch (pid2 = fork()) { - case -1: - exit(3); - case 0: - setpgid(0, pid1); - ok = getpgID() == pid1; - write(fds[1], &ok, 1); - exit(0); - } - setpgid(pid2, pid1); - - close(fds[1]); - if (read(fds[0], &ok, 1) != 1) - exit(4); - wait(&status); - wait(&status); - exit(ok ? 0 : 5); -} -], bash_cv_pgrp_pipe=no,bash_cv_pgrp_pipe=yes, - [AC_MSG_WARN(cannot check pgrp synchronization if cross compiling -- defaulting to no) - bash_cv_pgrp_pipe=no]) -]) -AC_MSG_RESULT($bash_cv_pgrp_pipe) -if test $bash_cv_pgrp_pipe = yes; then -AC_DEFINE(PGRP_PIPE) -fi -]) - -AC_DEFUN(BASH_SYS_REINSTALL_SIGHANDLERS, -[AC_REQUIRE([AC_TYPE_SIGNAL]) -AC_REQUIRE([BASH_SYS_SIGNAL_VINTAGE]) -AC_MSG_CHECKING([if signal handlers must be reinstalled when invoked]) -AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers, -[AC_TRY_RUN([ -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -typedef RETSIGTYPE sigfunc(); - -int nsigint; - -#ifdef HAVE_POSIX_SIGNALS -sigfunc * -set_signal_handler(sig, handler) - int sig; - sigfunc *handler; -{ - struct sigaction act, oact; - act.sa_handler = handler; - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); -} -#else -#define set_signal_handler(s, h) signal(s, h) -#endif - -RETSIGTYPE -sigint(s) -int s; -{ - nsigint++; -} - -main() -{ - nsigint = 0; - set_signal_handler(SIGINT, sigint); - kill((int)getpid(), SIGINT); - kill((int)getpid(), SIGINT); - exit(nsigint != 2); -} -], bash_cv_must_reinstall_sighandlers=no, bash_cv_must_reinstall_sighandlers=yes, - [AC_MSG_WARN(cannot check signal handling if cross compiling -- defaulting to no) - bash_cv_must_reinstall_sighandlers=no] -)]) -AC_MSG_RESULT($bash_cv_must_reinstall_sighandlers) -if test $bash_cv_must_reinstall_sighandlers = yes; then -AC_DEFINE(MUST_REINSTALL_SIGHANDLERS) -fi -]) - -dnl check that some necessary job control definitions are present -AC_DEFUN(BASH_SYS_JOB_CONTROL_MISSING, -[AC_REQUIRE([BASH_SYS_SIGNAL_VINTAGE]) -AC_MSG_CHECKING(for presence of necessary job control definitions) -AC_CACHE_VAL(bash_cv_job_control_missing, -[AC_TRY_RUN([ -#include -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -/* Add more tests in here as appropriate. */ -main() -{ -/* signal type */ -#if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) -exit(1); -#endif - -/* signals and tty control. */ -#if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) -exit (1); -#endif - -/* process control */ -#if !defined (WNOHANG) || !defined (WUNTRACED) -exit(1); -#endif - -/* Posix systems have tcgetpgrp and waitpid. */ -#if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) -exit(1); -#endif - -#if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) -exit(1); -#endif - -/* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ -#if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) -exit(1); -#endif - -exit(0); -}], bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing, - [AC_MSG_WARN(cannot check job control if cross-compiling -- defaulting to missing) - bash_cv_job_control_missing=missing] -)]) -AC_MSG_RESULT($bash_cv_job_control_missing) -if test $bash_cv_job_control_missing = missing; then -AC_DEFINE(JOB_CONTROL_MISSING) -fi -]) - -dnl check whether named pipes are present -dnl this requires a previous check for mkfifo, but that is awkward to specify -AC_DEFUN(BASH_SYS_NAMED_PIPES, -[AC_MSG_CHECKING(for presence of named pipes) -AC_CACHE_VAL(bash_cv_sys_named_pipes, -[AC_TRY_RUN([ -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -/* Add more tests in here as appropriate. */ -main() -{ -int fd, err; - -#if defined (HAVE_MKFIFO) -exit (0); -#endif - -#if !defined (S_IFIFO) && (defined (_POSIX_VERSION) && !defined (S_ISFIFO)) -exit (1); -#endif - -#if defined (NeXT) -exit (1); -#endif -err = mkdir("/tmp/bash-aclocal", 0700); -if (err < 0) { - perror ("mkdir"); - exit(1); -} -fd = mknod ("/tmp/bash-aclocal/sh-np-autoconf", 0666 | S_IFIFO, 0); -if (fd == -1) { - rmdir ("/tmp/bash-aclocal"); - exit (1); -} -close(fd); -unlink ("/tmp/bash-aclocal/sh-np-autoconf"); -rmdir ("/tmp/bash-aclocal"); -exit(0); -}], bash_cv_sys_named_pipes=present, bash_cv_sys_named_pipes=missing, - [AC_MSG_WARN(cannot check for named pipes if cross-compiling -- defaulting to missing) - bash_cv_sys_named_pipes=missing] -)]) -AC_MSG_RESULT($bash_cv_sys_named_pipes) -if test $bash_cv_sys_named_pipes = missing; then -AC_DEFINE(NAMED_PIPES_MISSING) -fi -]) - -AC_DEFUN(BASH_SYS_DEFAULT_MAIL_DIR, -[AC_MSG_CHECKING(for default mail directory) -AC_CACHE_VAL(bash_cv_mail_dir, -[if test -d /var/mail; then - bash_cv_mail_dir=/var/mail - elif test -d /var/spool/mail; then - bash_cv_mail_dir=/var/spool/mail - elif test -d /usr/mail; then - bash_cv_mail_dir=/usr/mail - elif test -d /usr/spool/mail; then - bash_cv_mail_dir=/usr/spool/mail - else - bash_cv_mail_dir=unknown - fi -]) -AC_MSG_RESULT($bash_cv_mail_dir) -AC_DEFINE_UNQUOTED(DEFAULT_MAIL_DIRECTORY, "$bash_cv_mail_dir") -]) - -AC_DEFUN(BASH_HAVE_TIOCGWINSZ, -[AC_MSG_CHECKING(for TIOCGWINSZ in sys/ioctl.h) -AC_CACHE_VAL(bash_cv_tiocgwinsz_in_ioctl, -[AC_TRY_COMPILE([#include -#include ], [int x = TIOCGWINSZ;], - bash_cv_tiocgwinsz_in_ioctl=yes,bash_cv_tiocgwinsz_in_ioctl=no)]) -AC_MSG_RESULT($bash_cv_tiocgwinsz_in_ioctl) -if test $bash_cv_tiocgwinsz_in_ioctl = yes; then -AC_DEFINE(GWINSZ_IN_SYS_IOCTL) -fi -]) - -AC_DEFUN(BASH_HAVE_TIOCSTAT, -[AC_MSG_CHECKING(for TIOCSTAT in sys/ioctl.h) -AC_CACHE_VAL(bash_cv_tiocstat_in_ioctl, -[AC_TRY_COMPILE([#include -#include ], [int x = TIOCSTAT;], - bash_cv_tiocstat_in_ioctl=yes,bash_cv_tiocstat_in_ioctl=no)]) -AC_MSG_RESULT($bash_cv_tiocstat_in_ioctl) -if test $bash_cv_tiocstat_in_ioctl = yes; then -AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL) -fi -]) - -AC_DEFUN(BASH_HAVE_FIONREAD, -[AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h) -AC_CACHE_VAL(bash_cv_fionread_in_ioctl, -[AC_TRY_COMPILE([#include -#include ], [int x = FIONREAD;], - bash_cv_fionread_in_ioctl=yes,bash_cv_fionread_in_ioctl=no)]) -AC_MSG_RESULT($bash_cv_fionread_in_ioctl) -if test $bash_cv_fionread_in_ioctl = yes; then -AC_DEFINE(FIONREAD_IN_SYS_IOCTL) -fi -]) - -dnl -dnl See if speed_t is declared in . Some versions of linux -dnl require a definition of speed_t each time is included, -dnl but you can only get speed_t if you include (on some -dnl versions) or (on others). -dnl -AC_DEFUN(BASH_CHECK_SPEED_T, -[AC_MSG_CHECKING(for speed_t in sys/types.h) -AC_CACHE_VAL(bash_cv_speed_t_in_sys_types, -[AC_TRY_COMPILE([#include ], [speed_t x;], - bash_cv_speed_t_in_sys_types=yes,bash_cv_speed_t_in_sys_types=no)]) -AC_MSG_RESULT($bash_cv_speed_t_in_sys_types) -if test $bash_cv_speed_t_in_sys_types = yes; then -AC_DEFINE(SPEED_T_IN_SYS_TYPES) -fi -]) - -AC_DEFUN(BASH_CHECK_GETPW_FUNCS, -[AC_MSG_CHECKING(whether getpw functions are declared in pwd.h) -AC_CACHE_VAL(bash_cv_getpw_declared, -[AC_EGREP_CPP(getpwuid, -[ -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -], -bash_cv_getpw_declared=yes,bash_cv_getpw_declared=no)]) -AC_MSG_RESULT($bash_cv_getpw_declared) -if test $bash_cv_getpw_declared = yes; then -AC_DEFINE(HAVE_GETPW_DECLS) -fi -]) - -AC_DEFUN(BASH_CHECK_DEV_FD, -[AC_MSG_CHECKING(whether /dev/fd is available) -AC_CACHE_VAL(bash_cv_dev_fd, -[if test -d /dev/fd && test -r /dev/fd/0 < /dev/null; then - bash_cv_dev_fd=standard - elif test -d /proc/self/fd && test -r /proc/self/fd/0 < /dev/null; then - bash_cv_dev_fd=whacky - else - bash_cv_dev_fd=absent - fi -]) -AC_MSG_RESULT($bash_cv_dev_fd) -if test $bash_cv_dev_fd = "standard"; then - AC_DEFINE(HAVE_DEV_FD) - AC_DEFINE(DEV_FD_PREFIX, "/dev/fd/") -elif test $bash_cv_dev_fd = "whacky"; then - AC_DEFINE(HAVE_DEV_FD) - AC_DEFINE(DEV_FD_PREFIX, "/proc/self/fd/") -fi -]) - -AC_DEFUN(BASH_CHECK_DEV_STDIN, -[AC_MSG_CHECKING(whether /dev/stdin stdout stderr are available) -AC_CACHE_VAL(bash_cv_dev_stdin, -[if test -d /dev/fd && test -r /dev/stdin < /dev/null; then - bash_cv_dev_stdin=present - elif test -d /proc/self/fd && test -r /dev/stdin < /dev/null; then - bash_cv_dev_stdin=present - else - bash_cv_dev_stdin=absent - fi -]) -AC_MSG_RESULT($bash_cv_dev_stdin) -if test $bash_cv_dev_stdin = "present"; then - AC_DEFINE(HAVE_DEV_STDIN) -fi -]) - -dnl -dnl Check if HPUX needs _KERNEL defined for RLIMIT_* definitions -dnl -AC_DEFUN(BASH_CHECK_KERNEL_RLIMIT, -[AC_MSG_CHECKING([whether $host_os needs _KERNEL for RLIMIT defines]) -AC_CACHE_VAL(bash_cv_kernel_rlimit, -[AC_TRY_COMPILE([ -#include -#include -], -[ - int f; - f = RLIMIT_DATA; -], bash_cv_kernel_rlimit=no, -[AC_TRY_COMPILE([ -#include -#define _KERNEL -#include -#undef _KERNEL -], -[ - int f; - f = RLIMIT_DATA; -], bash_cv_kernel_rlimit=yes, bash_cv_kernel_rlimit=no)] -)]) -AC_MSG_RESULT($bash_cv_kernel_rlimit) -if test $bash_cv_kernel_rlimit = yes; then -AC_DEFINE(RLIMIT_NEEDS_KERNEL) -fi -]) - -dnl -dnl Check for 64-bit off_t -- used for malloc alignment -dnl -dnl C does not allow duplicate case labels, so the compile will fail if -dnl sizeof(off_t) is > 4. -dnl -AC_DEFUN(BASH_CHECK_OFF_T_64, -[AC_CACHE_CHECK(for 64-bit off_t, bash_cv_off_t_64, -AC_TRY_COMPILE([ -#ifdef HAVE_UNISTD_H -#include -#endif -#include -],[ -switch (0) case 0: case (sizeof (off_t) <= 4):; -], bash_cv_off_t_64=no, bash_cv_off_t_64=yes)) -if test $bash_cv_off_t_64 = yes; then - AC_DEFINE(HAVE_OFF_T_64) -fi]) - -AC_DEFUN(BASH_CHECK_RTSIGS, -[AC_MSG_CHECKING(for unusable real-time signals due to large values) -AC_CACHE_VAL(bash_cv_unusable_rtsigs, -[AC_TRY_RUN([ -#include -#include - -#ifndef NSIG -# define NSIG 64 -#endif - -main () -{ - int n_sigs = 2 * NSIG; -#ifdef SIGRTMIN - int rtmin = SIGRTMIN; -#else - int rtmin = 0; -#endif - - exit(rtmin < n_sigs); -}], bash_cv_unusable_rtsigs=yes, bash_cv_unusable_rtsigs=no, - [AC_MSG_WARN(cannot check real-time signals if cross compiling -- defaulting to yes) - bash_cv_unusable_rtsigs=yes] -)]) -AC_MSG_RESULT($bash_cv_unusable_rtsigs) -if test $bash_cv_unusable_rtsigs = yes; then -AC_DEFINE(UNUSABLE_RT_SIGNALS) -fi -]) - -dnl -dnl check for availability of multibyte characters and functions -dnl -AC_DEFUN(BASH_CHECK_MULTIBYTE, -[ -AC_CHECK_HEADERS(wctype.h) -AC_CHECK_HEADERS(wchar.h) -AC_CHECK_HEADERS(langinfo.h) - -AC_CHECK_FUNC(mbsrtowcs, AC_DEFINE(HAVE_MBSRTOWCS)) -AC_CHECK_FUNC(mbrtowc, AC_DEFINE(HAVE_MBRTOWC)) -AC_CHECK_FUNC(mbrlen, AC_DEFINE(HAVE_MBRLEN)) -AC_CHECK_FUNC(wctomb, AC_DEFINE(HAVE_WCTOMB)) -AC_CHECK_FUNC(wcwidth, AC_DEFINE(HAVE_WCWIDTH)) -AC_CHECK_FUNC(wcsdup, AC_DEFINE(HAVE_WCSDUP)) - -AC_CACHE_CHECK([for mbstate_t], bash_cv_have_mbstate_t, -[AC_TRY_COMPILE([ -#include ], [ - mbstate_t ps; - mbstate_t *psp; - psp = (mbstate_t *)0; -], bash_cv_have_mbstate_t=yes, bash_cv_have_mbstate_t=no)]) -if test $bash_cv_have_mbstate_t = yes; then - AC_DEFINE(HAVE_MBSTATE_T) -fi - -AC_CACHE_CHECK([for nl_langinfo and CODESET], bash_cv_langinfo_codeset, -[AC_TRY_LINK( -[#include ], -[char* cs = nl_langinfo(CODESET);], -bash_cv_langinfo_codeset=yes, bash_cv_langinfo_codeset=no)]) -if test $bash_cv_langinfo_codeset = yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET) -fi - -]) - -dnl need: prefix exec_prefix libdir includedir CC TERMCAP_LIB -dnl require: -dnl AC_PROG_CC -dnl BASH_CHECK_LIB_TERMCAP - -AC_DEFUN(RL_LIB_READLINE_VERSION, -[ -AC_REQUIRE([BASH_CHECK_LIB_TERMCAP]) - -AC_MSG_CHECKING([version of installed readline library]) - -# What a pain in the ass this is. - -# save cpp and ld options -_save_CFLAGS="$CFLAGS" -_save_LDFLAGS="$LDFLAGS" -_save_LIBS="$LIBS" - -# Don't set ac_cv_rl_prefix if the caller has already assigned a value. This -# allows the caller to do something like $_rl_prefix=$withval if the user -# specifies --with-installed-readline=PREFIX as an argument to configure - -if test -z "$ac_cv_rl_prefix"; then -test "x$prefix" = xNONE && ac_cv_rl_prefix=$ac_default_prefix || ac_cv_rl_prefix=${prefix} -fi - -eval ac_cv_rl_includedir=${ac_cv_rl_prefix}/include -eval ac_cv_rl_libdir=${ac_cv_rl_prefix}/lib - -LIBS="$LIBS -lreadline ${TERMCAP_LIB}" -CFLAGS="$CFLAGS -I${ac_cv_rl_includedir}" -LDFLAGS="$LDFLAGS -L${ac_cv_rl_libdir}" - -AC_CACHE_VAL(ac_cv_rl_version, -[AC_TRY_RUN([ -#include -#include - -main() -{ - FILE *fp; - fp = fopen("conftest.rlv", "w"); - if (fp == 0) exit(1); - fprintf(fp, "%s\n", rl_library_version ? rl_library_version : "0.0"); - fclose(fp); - exit(0); -} -], -ac_cv_rl_version=`cat conftest.rlv`, -ac_cv_rl_version='0.0', -ac_cv_rl_version='4.2')]) - -CFLAGS="$_save_CFLAGS" -LDFLAGS="$_save_LDFLAGS" -LIBS="$_save_LIBS" - -RL_MAJOR=0 -RL_MINOR=0 - -# ( -case "$ac_cv_rl_version" in -2*|3*|4*|5*|6*|7*|8*|9*) - RL_MAJOR=`echo $ac_cv_rl_version | sed 's:\..*$::'` - RL_MINOR=`echo $ac_cv_rl_version | sed -e 's:^.*\.::' -e 's:[[a-zA-Z]]*$::'` - ;; -esac - -# ((( -case $RL_MAJOR in -[[0-9][0-9]]) _RL_MAJOR=$RL_MAJOR ;; -[[0-9]]) _RL_MAJOR=0$RL_MAJOR ;; -*) _RL_MAJOR=00 ;; -esac - -# ((( -case $RL_MINOR in -[[0-9][0-9]]) _RL_MINOR=$RL_MINOR ;; -[[0-9]]) _RL_MINOR=0$RL_MINOR ;; -*) _RL_MINOR=00 ;; -esac - -RL_VERSION="0x${_RL_MAJOR}${_RL_MINOR}" - -# Readline versions greater than 4.2 have these defines in readline.h - -if test $ac_cv_rl_version = '0.0' ; then - AC_MSG_WARN([Could not test version of installed readline library.]) -elif test $RL_MAJOR -gt 4 || { test $RL_MAJOR = 4 && test $RL_MINOR -gt 2 ; } ; then - # set these for use by the caller - RL_PREFIX=$ac_cv_rl_prefix - RL_LIBDIR=$ac_cv_rl_libdir - RL_INCLUDEDIR=$ac_cv_rl_includedir - AC_MSG_RESULT($ac_cv_rl_version) -else - -AC_DEFINE_UNQUOTED(RL_READLINE_VERSION, $RL_VERSION, [encoded version of the installed readline library]) -AC_DEFINE_UNQUOTED(RL_VERSION_MAJOR, $RL_MAJOR, [major version of installed readline library]) -AC_DEFINE_UNQUOTED(RL_VERSION_MINOR, $RL_MINOR, [minor version of installed readline library]) - -AC_SUBST(RL_VERSION) -AC_SUBST(RL_MAJOR) -AC_SUBST(RL_MINOR) - -# set these for use by the caller -RL_PREFIX=$ac_cv_rl_prefix -RL_LIBDIR=$ac_cv_rl_libdir -RL_INCLUDEDIR=$ac_cv_rl_includedir - -AC_MSG_RESULT($ac_cv_rl_version) - -fi -]) - -AC_DEFUN(BASH_FUNC_CTYPE_NONASCII, -[ -AC_MSG_CHECKING(whether the ctype macros accept non-ascii characters) -AC_CACHE_VAL(bash_cv_func_ctype_nonascii, -[AC_TRY_RUN([ -#ifdef HAVE_LOCALE_H -#include -#endif -#include -#include - -main(c, v) -int c; -char *v[]; -{ - char *deflocale; - unsigned char x; - int r1, r2; - -#ifdef HAVE_SETLOCALE - /* We take a shot here. If that locale is not known, try the - system default. We try this one because '\342' (226) is - known to be a printable character in that locale. */ - deflocale = setlocale(LC_ALL, "en_US.ISO8859-1"); - if (deflocale == 0) - deflocale = setlocale(LC_ALL, ""); -#endif - - x = '\342'; - r1 = isprint(x); - x -= 128; - r2 = isprint(x); - exit (r1 == 0 || r2 == 0); -} -], bash_cv_func_ctype_nonascii=yes, bash_cv_func_ctype_nonascii=no, - [AC_MSG_WARN(cannot check ctype macros if cross compiling -- defaulting to no) - bash_cv_func_ctype_nonascii=no] -)]) -AC_MSG_RESULT($bash_cv_func_ctype_nonascii) -if test $bash_cv_func_ctype_nonascii = yes; then -AC_DEFINE(CTYPE_NON_ASCII) -fi -]) - -dnl -dnl tests added for bashdb -dnl - - -AC_DEFUN([AM_PATH_LISPDIR], - [AC_ARG_WITH(lispdir, AC_HELP_STRING([--with-lispdir], [override the default lisp directory]), - [ lispdir="$withval" - AC_MSG_CHECKING([where .elc files should go]) - AC_MSG_RESULT([$lispdir])], - [ - # If set to t, that means we are running in a shell under Emacs. - # If you have an Emacs named "t", then use the full path. - test x"$EMACS" = xt && EMACS= - AC_CHECK_PROGS(EMACS, emacs xemacs, no) - if test $EMACS != "no"; then - if test x${lispdir+set} != xset; then - AC_CACHE_CHECK([where .elc files should go], [am_cv_lispdir], [dnl - am_cv_lispdir=`$EMACS -batch -q -eval '(while load-path (princ (concat (car load-path) "\n")) (setq load-path (cdr load-path)))' | sed -n -e 's,/$,,' -e '/.*\/lib\/\(x\?emacs\/site-lisp\)$/{s,,${libdir}/\1,;p;q;}' -e '/.*\/share\/\(x\?emacs\/site-lisp\)$/{s,,${datadir}/\1,;p;q;}'` - if test -z "$am_cv_lispdir"; then - am_cv_lispdir='${datadir}/emacs/site-lisp' - fi - ]) - lispdir="$am_cv_lispdir" - fi - fi - ]) - AC_SUBST(lispdir) -]) - -dnl -dnl tests added for gettext -dnl -# codeset.m4 serial AM1 (gettext-0.10.40) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -AC_DEFUN([AM_LANGINFO_CODESET], -[ - AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, - [AC_TRY_LINK([#include ], - [char* cs = nl_langinfo(CODESET);], - am_cv_langinfo_codeset=yes, - am_cv_langinfo_codeset=no) - ]) - if test $am_cv_langinfo_codeset = yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET, 1, - [Define if you have and nl_langinfo(CODESET).]) - fi -]) -# gettext.m4 serial 20 (gettext-0.12) -dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1995-2000. -dnl Bruno Haible , 2000-2003. - -dnl Macro to add for using GNU gettext. - -dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). -dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The -dnl default (if it is not specified or empty) is 'no-libtool'. -dnl INTLSYMBOL should be 'external' for packages with no intl directory, -dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. -dnl If INTLSYMBOL is 'use-libtool', then a libtool library -dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, -dnl depending on --{enable,disable}-{shared,static} and on the presence of -dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library -dnl $(top_builddir)/intl/libintl.a will be created. -dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext -dnl implementations (in libc or libintl) without the ngettext() function -dnl will be ignored. If NEEDSYMBOL is specified and is -dnl 'need-formatstring-macros', then GNU gettext implementations that don't -dnl support the ISO C 99 formatstring macros will be ignored. -dnl INTLDIR is used to find the intl libraries. If empty, -dnl the value `$(top_builddir)/intl/' is used. -dnl -dnl The result of the configuration is one of three cases: -dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled -dnl and used. -dnl Catalog format: GNU --> install in $(datadir) -dnl Catalog extension: .mo after installation, .gmo in source tree -dnl 2) GNU gettext has been found in the system's C library. -dnl Catalog format: GNU --> install in $(datadir) -dnl Catalog extension: .mo after installation, .gmo in source tree -dnl 3) No internationalization, always use English msgid. -dnl Catalog format: none -dnl Catalog extension: none -dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. -dnl The use of .gmo is historical (it was needed to avoid overwriting the -dnl GNU format catalogs when building on a platform with an X/Open gettext), -dnl but we keep it in order not to force irrelevant filename changes on the -dnl maintainers. -dnl -AC_DEFUN([AM_GNU_GETTEXT], -[ - dnl Argument checking. - ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , - [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT -])])])])]) - ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , - [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT -])])])]) - define(gt_included_intl, ifelse([$1], [external], [no], [yes])) - define(gt_libtool_suffix_prefix, ifelse([$1], [use-libtool], [l], [])) - - AC_REQUIRE([AM_PO_SUBDIRS])dnl - ifelse(gt_included_intl, yes, [ - AC_REQUIRE([AM_INTL_SUBDIR])dnl - ]) - - dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - - dnl Sometimes libintl requires libiconv, so first search for libiconv. - dnl Ideally we would do this search only after the - dnl if test "$USE_NLS" = "yes"; then - dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then - dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT - dnl the configure script would need to contain the same shell code - dnl again, outside any 'if'. There are two solutions: - dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. - dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. - dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not - dnl documented, we avoid it. - ifelse(gt_included_intl, yes, , [ - AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) - ]) - - dnl Set USE_NLS. - AM_NLS - - ifelse(gt_included_intl, yes, [ - BUILD_INCLUDED_LIBINTL=no - USE_INCLUDED_LIBINTL=no - ]) - LIBINTL= - LTLIBINTL= - POSUB= - - dnl If we use NLS figure out what method - if test "$USE_NLS" = "yes"; then - gt_use_preinstalled_gnugettext=no - ifelse(gt_included_intl, yes, [ - AC_MSG_CHECKING([whether included gettext is requested]) - AC_ARG_WITH(included-gettext, - [ --with-included-gettext use the GNU gettext library included here], - nls_cv_force_use_gnu_gettext=$withval, - nls_cv_force_use_gnu_gettext=no) - AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) - - nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" - if test "$nls_cv_force_use_gnu_gettext" != "yes"; then - ]) - dnl User does not insist on using GNU NLS library. Figure out what - dnl to use. If GNU gettext is available we use this. Else we have - dnl to fall back to GNU NLS library. - - dnl Add a version number to the cache macros. - define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1))) - define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc]) - define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl]) - - AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc, - [AC_TRY_LINK([#include -]ifelse([$2], [need-formatstring-macros], -[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) -#endif -changequote(,)dnl -typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; -changequote([,])dnl -], [])[extern int _nl_msg_cat_cntr; -extern int *_nl_domain_bindings;], - [bindtextdomain ("", ""); -return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings], - gt_cv_func_gnugettext_libc=yes, - gt_cv_func_gnugettext_libc=no)]) - - if test "$gt_cv_func_gnugettext_libc" != "yes"; then - dnl Sometimes libintl requires libiconv, so first search for libiconv. - ifelse(gt_included_intl, yes, , [ - AM_ICONV_LINK - ]) - dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL - dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) - dnl because that would add "-liconv" to LIBINTL and LTLIBINTL - dnl even if libiconv doesn't exist. - AC_LIB_LINKFLAGS_BODY([intl]) - AC_CACHE_CHECK([for GNU gettext in libintl], - gt_cv_func_gnugettext_libintl, - [gt_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $INCINTL" - gt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBINTL" - dnl Now see whether libintl exists and does not depend on libiconv. - AC_TRY_LINK([#include -]ifelse([$2], [need-formatstring-macros], -[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) -#endif -changequote(,)dnl -typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; -changequote([,])dnl -], [])[extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias ();], - [bindtextdomain ("", ""); -return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], - gt_cv_func_gnugettext_libintl=yes, - gt_cv_func_gnugettext_libintl=no) - dnl Now see whether libintl exists and depends on libiconv. - if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then - LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include -]ifelse([$2], [need-formatstring-macros], -[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION -#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) -#endif -changequote(,)dnl -typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; -changequote([,])dnl -], [])[extern int _nl_msg_cat_cntr; -extern -#ifdef __cplusplus -"C" -#endif -const char *_nl_expand_alias ();], - [bindtextdomain ("", ""); -return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], - [LIBINTL="$LIBINTL $LIBICONV" - LTLIBINTL="$LTLIBINTL $LTLIBICONV" - gt_cv_func_gnugettext_libintl=yes - ]) - fi - CPPFLAGS="$gt_save_CPPFLAGS" - LIBS="$gt_save_LIBS"]) - fi - - dnl If an already present or preinstalled GNU gettext() is found, - dnl use it. But if this macro is used in GNU gettext, and GNU - dnl gettext is already preinstalled in libintl, we update this - dnl libintl. (Cf. the install rule in intl/Makefile.in.) - if test "$gt_cv_func_gnugettext_libc" = "yes" \ - || { test "$gt_cv_func_gnugettext_libintl" = "yes" \ - && test "$PACKAGE" != gettext-runtime \ - && test "$PACKAGE" != gettext-tools; }; then - gt_use_preinstalled_gnugettext=yes - else - dnl Reset the values set by searching for libintl. - LIBINTL= - LTLIBINTL= - INCINTL= - fi - - ifelse(gt_included_intl, yes, [ - if test "$gt_use_preinstalled_gnugettext" != "yes"; then - dnl GNU gettext is not found in the C library. - dnl Fall back on included GNU gettext library. - nls_cv_use_gnu_gettext=yes - fi - fi - - if test "$nls_cv_use_gnu_gettext" = "yes"; then - dnl Mark actions used to generate GNU NLS library. - BUILD_INCLUDED_LIBINTL=yes - USE_INCLUDED_LIBINTL=yes - LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV" - LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV" - LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` - fi - - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - dnl Mark actions to use GNU gettext tools. - CATOBJEXT=.gmo - fi - ]) - - if test "$gt_use_preinstalled_gnugettext" = "yes" \ - || test "$nls_cv_use_gnu_gettext" = "yes"; then - AC_DEFINE(ENABLE_NLS, 1, - [Define to 1 if translation of program messages to the user's native language - is requested.]) - else - USE_NLS=no - fi - fi - - AC_MSG_CHECKING([whether to use NLS]) - AC_MSG_RESULT([$USE_NLS]) - if test "$USE_NLS" = "yes"; then - AC_MSG_CHECKING([where the gettext function comes from]) - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if test "$gt_cv_func_gnugettext_libintl" = "yes"; then - gt_source="external libintl" - else - gt_source="libc" - fi - else - gt_source="included intl directory" - fi - AC_MSG_RESULT([$gt_source]) - fi - - if test "$USE_NLS" = "yes"; then - - if test "$gt_use_preinstalled_gnugettext" = "yes"; then - if test "$gt_cv_func_gnugettext_libintl" = "yes"; then - AC_MSG_CHECKING([how to link with libintl]) - AC_MSG_RESULT([$LIBINTL]) - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) - fi - - dnl For backward compatibility. Some packages may be using this. - AC_DEFINE(HAVE_GETTEXT, 1, - [Define if the GNU gettext() function is already present or preinstalled.]) - AC_DEFINE(HAVE_DCGETTEXT, 1, - [Define if the GNU dcgettext() function is already present or preinstalled.]) - fi - - dnl We need to process the po/ directory. - POSUB=po - fi - - ifelse(gt_included_intl, yes, [ - dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL - dnl to 'yes' because some of the testsuite requires it. - if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then - BUILD_INCLUDED_LIBINTL=yes - fi - - dnl Make all variables we use known to autoconf. - AC_SUBST(BUILD_INCLUDED_LIBINTL) - AC_SUBST(USE_INCLUDED_LIBINTL) - AC_SUBST(CATOBJEXT) - - dnl For backward compatibility. Some configure.ins may be using this. - nls_cv_header_intl= - nls_cv_header_libgt= - - dnl For backward compatibility. Some Makefiles may be using this. - DATADIRNAME=share - AC_SUBST(DATADIRNAME) - - dnl For backward compatibility. Some Makefiles may be using this. - INSTOBJEXT=.mo - AC_SUBST(INSTOBJEXT) - - dnl For backward compatibility. Some Makefiles may be using this. - GENCAT=gencat - AC_SUBST(GENCAT) - - dnl For backward compatibility. Some Makefiles may be using this. - if test "$USE_INCLUDED_LIBINTL" = yes; then - INTLOBJS="\$(GETTOBJS)" - fi - AC_SUBST(INTLOBJS) - - dnl Enable libtool support if the surrounding package wishes it. - INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix - AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) - ]) - - dnl For backward compatibility. Some Makefiles may be using this. - INTLLIBS="$LIBINTL" - AC_SUBST(INTLLIBS) - - dnl Make all documented variables known to autoconf. - AC_SUBST(LIBINTL) - AC_SUBST(LTLIBINTL) - AC_SUBST(POSUB) -]) - - -dnl Checks for all prerequisites of the intl subdirectory, -dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, -dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. -AC_DEFUN([AM_INTL_SUBDIR], -[ - AC_REQUIRE([AC_PROG_INSTALL])dnl - AC_REQUIRE([AM_MKINSTALLDIRS])dnl - AC_REQUIRE([AC_PROG_CC])dnl - AC_REQUIRE([AC_CANONICAL_HOST])dnl - AC_REQUIRE([AC_PROG_RANLIB])dnl - AC_REQUIRE([AC_ISC_POSIX])dnl - AC_REQUIRE([AC_HEADER_STDC])dnl - AC_REQUIRE([AC_C_CONST])dnl - AC_REQUIRE([AC_C_INLINE])dnl - AC_REQUIRE([AC_TYPE_OFF_T])dnl - AC_REQUIRE([AC_TYPE_SIZE_T])dnl - AC_REQUIRE([AC_FUNC_ALLOCA])dnl - AC_REQUIRE([AC_FUNC_MMAP])dnl - AC_REQUIRE([jm_GLIBC21])dnl - AC_REQUIRE([gt_INTDIV0])dnl - AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])dnl - AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl - AC_REQUIRE([gt_INTTYPES_PRI])dnl - - AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ -stdlib.h string.h unistd.h sys/param.h]) - AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ -geteuid getgid getuid mempcpy munmap putenv setenv setlocale stpcpy \ -strcasecmp strdup strtoul tsearch __argz_count __argz_stringify __argz_next \ -__fsetlocking]) - - AM_ICONV - AM_LANGINFO_CODESET - if test $ac_cv_header_locale_h = yes; then - AM_LC_MESSAGES - fi - - dnl intl/plural.c is generated from intl/plural.y. It requires bison, - dnl because plural.y uses bison specific features. It requires at least - dnl bison-1.26 because earlier versions generate a plural.c that doesn't - dnl compile. - dnl bison is only needed for the maintainer (who touches plural.y). But in - dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put - dnl the rule in general Makefile. Now, some people carelessly touch the - dnl files or have a broken "make" program, hence the plural.c rule will - dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not - dnl present or too old. - AC_CHECK_PROGS([INTLBISON], [bison]) - if test -z "$INTLBISON"; then - ac_verc_fail=yes - else - dnl Found it, now check the version. - AC_MSG_CHECKING([version of bison]) -changequote(<<,>>)dnl - ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` - case $ac_prog_version in - '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; - 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) -changequote([,])dnl - ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; - *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; - esac - AC_MSG_RESULT([$ac_prog_version]) - fi - if test $ac_verc_fail = yes; then - INTLBISON=: - fi -]) - - -dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) -AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) -# glibc21.m4 serial 2 (fileutils-4.1.3, gettext-0.10.40) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -# Test for the GNU C Library, version 2.1 or newer. -# From Bruno Haible. - -AC_DEFUN([jm_GLIBC21], - [ - AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, - ac_cv_gnu_library_2_1, - [AC_EGREP_CPP([Lucky GNU user], - [ -#include -#ifdef __GNU_LIBRARY__ - #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) - Lucky GNU user - #endif -#endif - ], - ac_cv_gnu_library_2_1=yes, - ac_cv_gnu_library_2_1=no) - ] - ) - AC_SUBST(GLIBC21) - GLIBC21="$ac_cv_gnu_library_2_1" - ] -) -# iconv.m4 serial AM4 (gettext-0.11.3) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], -[ - dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([iconv]) -]) - -AC_DEFUN([AM_ICONV_LINK], -[ - dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and - dnl those with the standalone portable GNU libiconv installed). - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) - - dnl Add $INCICONV to CPPFLAGS before performing the following checks, - dnl because if the user has installed libiconv and not disabled its use - dnl via --without-libiconv-prefix, he wants to use it. The first - dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. - am_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) - - AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_func_iconv=yes) - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_lib_iconv=yes - am_cv_func_iconv=yes) - LIBS="$am_save_LIBS" - fi - ]) - if test "$am_cv_func_iconv" = yes; then - AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) - fi - if test "$am_cv_lib_iconv" = yes; then - AC_MSG_CHECKING([how to link with libiconv]) - AC_MSG_RESULT([$LIBICONV]) - else - dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV - dnl either. - CPPFLAGS="$am_save_CPPFLAGS" - LIBICONV= - LTLIBICONV= - fi - AC_SUBST(LIBICONV) - AC_SUBST(LTLIBICONV) -]) - -AC_DEFUN([AM_ICONV], -[ - AM_ICONV_LINK - if test "$am_cv_func_iconv" = yes; then - AC_MSG_CHECKING([for iconv declaration]) - AC_CACHE_VAL(am_cv_proto_iconv, [ - AC_TRY_COMPILE([ -#include -#include -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif -], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) - am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - AC_MSG_RESULT([$]{ac_t:- - }[$]am_cv_proto_iconv) - AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, - [Define as const if the declaration of iconv() needs const.]) - fi -]) -# intdiv0.m4 serial 1 (gettext-0.11.3) -dnl Copyright (C) 2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -AC_DEFUN([gt_INTDIV0], -[ - AC_REQUIRE([AC_PROG_CC])dnl - AC_REQUIRE([AC_CANONICAL_HOST])dnl - - AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], - gt_cv_int_divbyzero_sigfpe, - [ - AC_TRY_RUN([ -#include -#include - -static void -#ifdef __cplusplus -sigfpe_handler (int sig) -#else -sigfpe_handler (sig) int sig; -#endif -{ - /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ - exit (sig != SIGFPE); -} - -int x = 1; -int y = 0; -int z; -int nan; - -int main () -{ - signal (SIGFPE, sigfpe_handler); -/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ -#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) - signal (SIGTRAP, sigfpe_handler); -#endif -/* Linux/SPARC yields signal SIGILL. */ -#if defined (__sparc__) && defined (__linux__) - signal (SIGILL, sigfpe_handler); -#endif - - z = x / y; - nan = y / y; - exit (1); -} -], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, - [ - # Guess based on the CPU. - case "$host_cpu" in - alpha* | i[34567]86 | m68k | s390*) - gt_cv_int_divbyzero_sigfpe="guessing yes";; - *) - gt_cv_int_divbyzero_sigfpe="guessing no";; - esac - ]) - ]) - case "$gt_cv_int_divbyzero_sigfpe" in - *yes) value=1;; - *) value=0;; - esac - AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, - [Define if integer division by zero raises signal SIGFPE.]) -]) -# inttypes.m4 serial 1 (gettext-0.11.4) -dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Paul Eggert. - -# Define HAVE_INTTYPES_H if exists and doesn't clash with -# . - -AC_DEFUN([gt_HEADER_INTTYPES_H], -[ - AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, - [ - AC_TRY_COMPILE( - [#include -#include ], - [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) - ]) - if test $gt_cv_header_inttypes_h = yes; then - AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, - [Define if exists and doesn't clash with .]) - fi -]) -# inttypes_h.m4 serial 5 (gettext-0.12) -dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Paul Eggert. - -# Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, -# doesn't clash with , and declares uintmax_t. - -AC_DEFUN([jm_AC_HEADER_INTTYPES_H], -[ - AC_CACHE_CHECK([for inttypes.h], jm_ac_cv_header_inttypes_h, - [AC_TRY_COMPILE( - [#include -#include ], - [uintmax_t i = (uintmax_t) -1;], - jm_ac_cv_header_inttypes_h=yes, - jm_ac_cv_header_inttypes_h=no)]) - if test $jm_ac_cv_header_inttypes_h = yes; then - AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, - [Define if exists, doesn't clash with , - and declares uintmax_t. ]) - fi -]) -# inttypes-pri.m4 serial 1 (gettext-0.11.4) -dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -# Define PRI_MACROS_BROKEN if exists and defines the PRI* -# macros to non-string values. This is the case on AIX 4.3.3. - -AC_DEFUN([gt_INTTYPES_PRI], -[ - AC_REQUIRE([gt_HEADER_INTTYPES_H]) - if test $gt_cv_header_inttypes_h = yes; then - AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], - gt_cv_inttypes_pri_broken, - [ - AC_TRY_COMPILE([#include -#ifdef PRId32 -char *p = PRId32; -#endif -], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) - ]) - fi - if test "$gt_cv_inttypes_pri_broken" = yes; then - AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, - [Define if exists and defines unusable PRI* macros.]) - fi -]) -# isc-posix.m4 serial 2 (gettext-0.11.2) -dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -# This file is not needed with autoconf-2.53 and newer. Remove it in 2005. - -# This test replaces the one in autoconf. -# Currently this macro should have the same name as the autoconf macro -# because gettext's gettext.m4 (distributed in the automake package) -# still uses it. Otherwise, the use in gettext.m4 makes autoheader -# give these diagnostics: -# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX -# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX - -undefine([AC_ISC_POSIX]) - -AC_DEFUN([AC_ISC_POSIX], - [ - dnl This test replaces the obsolescent AC_ISC_POSIX kludge. - AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) - ] -) -# lcmessage.m4 serial 3 (gettext-0.11.3) -dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1995. - -# Check whether LC_MESSAGES is available in . - -AC_DEFUN([AM_LC_MESSAGES], -[ - AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, - [AC_TRY_LINK([#include ], [return LC_MESSAGES], - am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) - if test $am_cv_val_LC_MESSAGES = yes; then - AC_DEFINE(HAVE_LC_MESSAGES, 1, - [Define if your file defines LC_MESSAGES.]) - fi -]) -# lib-ld.m4 serial 2 (gettext-0.12) -dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl Subroutines of libtool.m4, -dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision -dnl with libtool.m4. - -dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. -AC_DEFUN([AC_LIB_PROG_LD_GNU], -[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, -[# I'd rather use --version here, but apparently some GNU ld's only accept -v. -if $LD -v 2>&1 &5; then - acl_cv_prog_gnu_ld=yes -else - acl_cv_prog_gnu_ld=no -fi]) -with_gnu_ld=$acl_cv_prog_gnu_ld -]) - -dnl From libtool-1.4. Sets the variable LD. -AC_DEFUN([AC_LIB_PROG_LD], -[AC_ARG_WITH(gnu-ld, -[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], -test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by GCC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]* | [A-Za-z]:[\\/]*)] - [re_direlt='/[^/][^/]*/\.\./'] - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(acl_cv_path_LD, -[if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then - test "$with_gnu_ld" != no && break - else - test "$with_gnu_ld" != yes && break - fi - fi - done - IFS="$ac_save_ifs" -else - acl_cv_path_LD="$LD" # Let the user override the test with a path. -fi]) -LD="$acl_cv_path_LD" -if test -n "$LD"; then - AC_MSG_RESULT($LD) -else - AC_MSG_RESULT(no) -fi -test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) -AC_LIB_PROG_LD_GNU -]) -# lib-link.m4 serial 4 (gettext-0.12) -dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and -dnl augments the CPPFLAGS variable. -AC_DEFUN([AC_LIB_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - define([Name],[translit([$1],[./-], [___])]) - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - ac_cv_lib[]Name[]_libs="$LIB[]NAME" - ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" - ac_cv_lib[]Name[]_cppflags="$INC[]NAME" - ]) - LIB[]NAME="$ac_cv_lib[]Name[]_libs" - LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" - INC[]NAME="$ac_cv_lib[]Name[]_cppflags" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the - dnl results of this search when this library appears as a dependency. - HAVE_LIB[]NAME=yes - undefine([Name]) - undefine([NAME]) -]) - -dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) -dnl searches for libname and the libraries corresponding to explicit and -dnl implicit dependencies, together with the specified include files and -dnl the ability to compile and link the specified testcode. If found, it -dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and -dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and -dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs -dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. -AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - define([Name],[translit([$1],[./-], [___])]) - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - - dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - - dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, - dnl because if the user has installed lib[]Name and not disabled its use - dnl via --without-lib[]Name-prefix, he wants to use it. - ac_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - - AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ - ac_save_LIBS="$LIBS" - LIBS="$LIBS $LIB[]NAME" - AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) - LIBS="$ac_save_LIBS" - ]) - if test "$ac_cv_lib[]Name" = yes; then - HAVE_LIB[]NAME=yes - AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) - AC_MSG_CHECKING([how to link with lib[]$1]) - AC_MSG_RESULT([$LIB[]NAME]) - else - HAVE_LIB[]NAME=no - dnl If $LIB[]NAME didn't lead to a usable library, we don't need - dnl $INC[]NAME either. - CPPFLAGS="$ac_save_CPPFLAGS" - LIB[]NAME= - LTLIB[]NAME= - fi - AC_SUBST([HAVE_LIB]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - undefine([Name]) - undefine([NAME]) -]) - -dnl Determine the platform dependent parameters needed to use rpath: -dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, -dnl hardcode_direct, hardcode_minus_L. -AC_DEFUN([AC_LIB_RPATH], -[ - AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS - AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld - AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host - AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir - AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - ]) - wl="$acl_cv_wl" - libext="$acl_cv_libext" - shlibext="$acl_cv_shlibext" - hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - hardcode_direct="$acl_cv_hardcode_direct" - hardcode_minus_L="$acl_cv_hardcode_minus_L" - dnl Determine whether the user wants rpath handling at all. - AC_ARG_ENABLE(rpath, - [ --disable-rpath do not hardcode runtime library paths], - :, enable_rpath=yes) -]) - -dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. -AC_DEFUN([AC_LIB_LINKFLAGS_BODY], -[ - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_LIB_ARG_WITH([lib$1-prefix], -[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib - --without-lib$1-prefix don't search for lib$1 in includedir and libdir], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi -]) - dnl Search the library and its dependencies in $additional_libdir and - dnl $LDFLAGS. Using breadth-first-seach. - LIB[]NAME= - LTLIB[]NAME= - INC[]NAME= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='$1 $2' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - dnl See if it was already located by an earlier AC_LIB_LINKFLAGS - dnl or AC_LIB_HAVE_LINKFLAGS call. - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" - else - dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined - dnl that this library doesn't exist. So just drop it. - : - fi - else - dnl Search the library lib$name in $additional_libdir and $LDFLAGS - dnl and the already constructed $LIBNAME/$LTLIBNAME. - found_dir= - found_la= - found_so= - found_a= - if test $use_additional = yes; then - if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then - found_dir="$additional_libdir" - found_so="$additional_libdir/lib$name.$shlibext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - else - if test -f "$additional_libdir/lib$name.$libext"; then - found_dir="$additional_libdir" - found_a="$additional_libdir/lib$name.$libext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then - found_dir="$dir" - found_so="$dir/lib$name.$shlibext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - else - if test -f "$dir/lib$name.$libext"; then - found_dir="$dir" - found_a="$dir/lib$name.$libext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - dnl Found the library. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - dnl Linking with a shared library. We attempt to hardcode its - dnl directory into the executable's runpath, unless it's the - dnl standard /usr/lib. - if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then - dnl No hardcoding is needed. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - dnl The hardcoding into $LIBNAME is system dependent. - if test "$hardcode_direct" = yes; then - dnl Using DIR/libNAME.so during linking hardcodes DIR into the - dnl resulting binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - dnl Rely on "-L$found_dir". - dnl But don't add it if it's already contained in the LDFLAGS - dnl or the already constructed $LIBNAME - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" - fi - if test "$hardcode_minus_L" != no; then - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH - dnl here, because this doesn't fit in flags passed to the - dnl compiler. So give up. No hardcoding. This affects only - dnl very old systems. - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - dnl Linking with a static library. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" - else - dnl We shouldn't come here, but anyway it's good to have a - dnl fallback. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" - fi - fi - dnl Assume the include files are nearby. - additional_includedir= - case "$found_dir" in - */lib | */lib/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - dnl Potentially add $additional_includedir to $INCNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's /usr/local/include and we are using GCC on Linux, - dnl 3. if it's already present in $CPPFLAGS or the already - dnl constructed $INCNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INC[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $INCNAME. - INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - dnl Look for dependencies. - if test -n "$found_la"; then - dnl Read the .la file. It defines the variables - dnl dlname, library_names, old_library, dependency_libs, current, - dnl age, revision, installed, dlopen, dlpreopen, libdir. - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - dnl We use only dependency_libs. - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's /usr/local/lib and we are using GCC on Linux, - dnl 3. if it's already present in $LDFLAGS or the already - dnl constructed $LIBNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LIBNAME. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LTLIBNAME. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - dnl Handle this in the next round. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - dnl Handle this in the next round. Throw away the .la's - dnl directory; it is already contained in a preceding -L - dnl option. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - dnl Most likely an immediate library name. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" - ;; - esac - done - fi - else - dnl Didn't find the library; assume it is in the system directories - dnl known to the linker and runtime loader. (All the system - dnl directories known to the linker should also be known to the - dnl runtime loader, otherwise the system is severely misconfigured.) - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$hardcode_libdir_separator"; then - dnl Weird platform: only the last -rpath option counts, the user must - dnl pass all path elements in one option. We can arrange that for a - dnl single library, but not when more than one $LIBNAMEs are used. - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" - done - dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - else - dnl The -rpath options are cumulative. - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - dnl When using libtool, the option that works for both libraries and - dnl executables is -R. The -R options are cumulative. - for found_dir in $ltrpathdirs; do - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" - done - fi -]) - -dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, -dnl unless already present in VAR. -dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes -dnl contains two or three consecutive elements that belong together. -AC_DEFUN([AC_LIB_APPENDTOVAR], -[ - for element in [$2]; do - haveit= - for x in $[$1]; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - [$1]="${[$1]}${[$1]:+ }$element" - fi - done -]) -# lib-prefix.m4 serial 2 (gettext-0.12) -dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and -dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't -dnl require excessive bracketing. -ifdef([AC_HELP_STRING], -[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], -[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) - -dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed -dnl to access previously installed libraries. The basic assumption is that -dnl a user will want packages to use other packages he previously installed -dnl with the same --prefix option. -dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate -dnl libraries, but is otherwise very convenient. -AC_DEFUN([AC_LIB_PREFIX], -[ - AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AC_CANONICAL_HOST]) - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_LIB_ARG_WITH([lib-prefix], -[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib - --without-lib-prefix don't search for libraries in includedir and libdir], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi -]) - if test $use_additional = yes; then - dnl Potentially add $additional_includedir to $CPPFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's already present in $CPPFLAGS, - dnl 3. if it's /usr/local/include and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - for x in $CPPFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $CPPFLAGS. - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" - fi - fi - fi - fi - dnl Potentially add $additional_libdir to $LDFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's already present in $LDFLAGS, - dnl 3. if it's /usr/local/lib and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - for x in $LDFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LDFLAGS. - LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" - fi - fi - fi - fi - fi -]) - -dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, -dnl acl_final_exec_prefix, containing the values to which $prefix and -dnl $exec_prefix will expand at the end of the configure script. -AC_DEFUN([AC_LIB_PREPARE_PREFIX], -[ - dnl Unfortunately, prefix and exec_prefix get only finally determined - dnl at the end of configure. - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" -]) - -dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the -dnl variables prefix and exec_prefix bound to the values they will have -dnl at the end of the configure script. -AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], -[ - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - $1 - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" -]) -# nls.m4 serial 1 (gettext-0.12) -dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1995-2000. -dnl Bruno Haible , 2000-2003. - -AC_DEFUN([AM_NLS], -[ - AC_MSG_CHECKING([whether NLS is requested]) - dnl Default is enabled NLS - AC_ARG_ENABLE(nls, - [ --disable-nls do not use Native Language Support], - USE_NLS=$enableval, USE_NLS=yes) - AC_MSG_RESULT($USE_NLS) - AC_SUBST(USE_NLS) -]) - -AC_DEFUN([AM_MKINSTALLDIRS], -[ - dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly - dnl find the mkinstalldirs script in another subdir but $(top_srcdir). - dnl Try to locate it. - MKINSTALLDIRS= - if test -n "$ac_aux_dir"; then - case "$ac_aux_dir" in - /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;; - *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;; - esac - fi - if test -z "$MKINSTALLDIRS"; then - MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" - fi - AC_SUBST(MKINSTALLDIRS) -]) -# po.m4 serial 1 (gettext-0.12) -dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1995-2000. -dnl Bruno Haible , 2000-2003. - -dnl Checks for all prerequisites of the po subdirectory. -AC_DEFUN([AM_PO_SUBDIRS], -[ - AC_REQUIRE([AC_PROG_MAKE_SET])dnl - AC_REQUIRE([AC_PROG_INSTALL])dnl - AC_REQUIRE([AM_MKINSTALLDIRS])dnl - AC_REQUIRE([AM_NLS])dnl - - dnl Perform the following tests also if --disable-nls has been given, - dnl because they are needed for "make dist" to work. - - dnl Search for GNU msgfmt in the PATH. - dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. - dnl The second test excludes FreeBSD msgfmt. - AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, - [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 && - (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], - :) - AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) - - dnl Search for GNU xgettext 0.12 or newer in the PATH. - dnl The first test excludes Solaris xgettext and early GNU xgettext versions. - dnl The second test excludes FreeBSD xgettext. - AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, - [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && - (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], - :) - dnl Remove leftover from FreeBSD xgettext call. - rm -f messages.po - - dnl Search for GNU msgmerge 0.11 or newer in the PATH. - AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, - [$ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1], :) - - dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. - dnl Test whether we really found GNU msgfmt. - if test "$GMSGFMT" != ":"; then - dnl If it is no GNU msgfmt we define it as : so that the - dnl Makefiles still can work. - if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && - (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then - : ; - else - GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` - AC_MSG_RESULT( - [found $GMSGFMT program is not GNU msgfmt; ignore it]) - GMSGFMT=":" - fi - fi - - dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. - dnl Test whether we really found GNU xgettext. - if test "$XGETTEXT" != ":"; then - dnl If it is no GNU xgettext we define it as : so that the - dnl Makefiles still can work. - if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && - (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then - : ; - else - AC_MSG_RESULT( - [found xgettext program is not GNU xgettext; ignore it]) - XGETTEXT=":" - fi - dnl Remove leftover from FreeBSD xgettext call. - rm -f messages.po - fi - - AC_OUTPUT_COMMANDS([ - for ac_file in $CONFIG_FILES; do - # Support "outfile[:infile[:infile...]]" - case "$ac_file" in - *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - esac - # PO directories have a Makefile.in generated from Makefile.in.in. - case "$ac_file" in */Makefile.in) - # Adjust a relative srcdir. - ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` - ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" - ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" - case "$ac_given_srcdir" in - .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; - /*) top_srcdir="$ac_given_srcdir" ;; - *) top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then - rm -f "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" - cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" - POMAKEFILEDEPS="POTFILES.in" - # ALL_LINGUAS, POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES depend - # on $ac_dir but don't depend on user-specified configuration - # parameters. - if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then - # The LINGUAS file contains the set of available languages. - if test -n "$OBSOLETE_ALL_LINGUAS"; then - test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" - fi - ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"` - # Hide the ALL_LINGUAS assigment from automake. - eval 'ALL_LINGUAS''=$ALL_LINGUAS_' - POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" - else - # The set of available languages was given in configure.in. - eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' - fi - case "$ac_given_srcdir" in - .) srcdirpre= ;; - *) srcdirpre='$(srcdir)/' ;; - esac - POFILES= - GMOFILES= - UPDATEPOFILES= - DUMMYPOFILES= - for lang in $ALL_LINGUAS; do - POFILES="$POFILES $srcdirpre$lang.po" - GMOFILES="$GMOFILES $srcdirpre$lang.gmo" - UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" - DUMMYPOFILES="$DUMMYPOFILES $lang.nop" - done - # CATALOGS depends on both $ac_dir and the user's LINGUAS - # environment variable. - INST_LINGUAS= - if test -n "$ALL_LINGUAS"; then - for presentlang in $ALL_LINGUAS; do - useit=no - if test "%UNSET%" != "$LINGUAS"; then - desiredlanguages="$LINGUAS" - else - desiredlanguages="$ALL_LINGUAS" - fi - for desiredlang in $desiredlanguages; do - # Use the presentlang catalog if desiredlang is - # a. equal to presentlang, or - # b. a variant of presentlang (because in this case, - # presentlang can be used as a fallback for messages - # which are not translated in the desiredlang catalog). - case "$desiredlang" in - "$presentlang"*) useit=yes;; - esac - done - if test $useit = yes; then - INST_LINGUAS="$INST_LINGUAS $presentlang" - fi - done - fi - CATALOGS= - if test -n "$INST_LINGUAS"; then - for lang in $INST_LINGUAS; do - CATALOGS="$CATALOGS $lang.gmo" - done - fi - test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" - sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" - for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do - if test -f "$f"; then - case "$f" in - *.orig | *.bak | *~) ;; - *) cat "$f" >> "$ac_dir/Makefile" ;; - esac - fi - done - fi - ;; - esac - done], - [# Capture the value of obsolete ALL_LINGUAS because we need it to compute - # POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES, CATALOGS. But hide it - # from automake. - eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' - # Capture the value of LINGUAS because we need it to compute CATALOGS. - LINGUAS="${LINGUAS-%UNSET%}" - ]) -]) -# progtest.m4 serial 3 (gettext-0.12) -dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1996. - -# Search path for a program which passes the given test. - -dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, -dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) -AC_DEFUN([AM_PATH_PROG_WITH_TEST], -[ -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "$2", so it can be a program name with args. -set dummy $2; ac_word=[$]2 -AC_MSG_CHECKING([for $ac_word]) -AC_CACHE_VAL(ac_cv_path_$1, -[case "[$]$1" in - [[\\/]]* | ?:[[\\/]]*) - ac_cv_path_$1="[$]$1" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in ifelse([$5], , $PATH, [$5]); do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - if [$3]; then - ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" -dnl If no 4th arg is given, leave the cache variable unset, -dnl so AC_PATH_PROGS will keep looking. -ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" -])dnl - ;; -esac])dnl -$1="$ac_cv_path_$1" -if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then - AC_MSG_RESULT([$]$1) -else - AC_MSG_RESULT(no) -fi -AC_SUBST($1)dnl -]) -# stdint_h.m4 serial 3 (gettext-0.12) -dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Paul Eggert. - -# Define HAVE_STDINT_H_WITH_UINTMAX if exists, -# doesn't clash with , and declares uintmax_t. - -AC_DEFUN([jm_AC_HEADER_STDINT_H], -[ - AC_CACHE_CHECK([for stdint.h], jm_ac_cv_header_stdint_h, - [AC_TRY_COMPILE( - [#include -#include ], - [uintmax_t i = (uintmax_t) -1;], - jm_ac_cv_header_stdint_h=yes, - jm_ac_cv_header_stdint_h=no)]) - if test $jm_ac_cv_header_stdint_h = yes; then - AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, - [Define if exists, doesn't clash with , - and declares uintmax_t. ]) - fi -]) -# uintmax_t.m4 serial 7 (gettext-0.12) -dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Paul Eggert. - -AC_PREREQ(2.13) - -# Define uintmax_t to 'unsigned long' or 'unsigned long long' -# if it is not already defined in or . - -AC_DEFUN([jm_AC_TYPE_UINTMAX_T], -[ - AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) - AC_REQUIRE([jm_AC_HEADER_STDINT_H]) - if test $jm_ac_cv_header_inttypes_h = no && test $jm_ac_cv_header_stdint_h = no; then - AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG]) - test $ac_cv_type_unsigned_long_long = yes \ - && ac_type='unsigned long long' \ - || ac_type='unsigned long' - AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, - [Define to unsigned long or unsigned long long - if and don't define.]) - else - AC_DEFINE(HAVE_UINTMAX_T, 1, - [Define if you have the 'uintmax_t' type in or .]) - fi -]) -# ulonglong.m4 serial 2 (fileutils-4.0.32, gettext-0.10.40) -dnl Copyright (C) 1999-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Paul Eggert. - -AC_DEFUN([jm_AC_TYPE_UNSIGNED_LONG_LONG], -[ - AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, - [AC_TRY_LINK([unsigned long long ull = 1; int i = 63;], - [unsigned long long ullmax = (unsigned long long) -1; - return ull << i | ull >> i | ullmax / ull | ullmax % ull;], - ac_cv_type_unsigned_long_long=yes, - ac_cv_type_unsigned_long_long=no)]) - if test $ac_cv_type_unsigned_long_long = yes; then - AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, - [Define if you have the unsigned long long type.]) - fi -]) diff --git a/bashhist.c~ b/bashhist.c~ deleted file mode 100644 index fed0e0626..000000000 --- a/bashhist.c~ +++ /dev/null @@ -1,813 +0,0 @@ -/* 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#if defined (HISTORY) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bashtypes.h" -#include -#include -#include "bashansi.h" -#include "posixstat.h" -#include "filecntl.h" - -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "input.h" -#include "parser.h" /* for the struct dstack stuff. */ -#include "pathexp.h" /* for the struct ignorevar stuff */ -#include "bashhist.h" /* matching prototypes and declarations */ -#include "builtins/common.h" - -#include -#include -#include - -#if defined (READLINE) -# include "bashline.h" -extern int rl_done, rl_dispatching; /* should really include readline.h */ -#endif - -#if !defined (errno) -extern int errno; -#endif - -static int histignore_item_func __P((struct ign *)); -static int check_history_control __P((char *)); -static void hc_erasedups __P((char *)); -static void really_add_history __P((char *)); - -static struct ignorevar histignore = -{ - "HISTIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *)histignore_item_func, -}; - -#define HIGN_EXPAND 0x01 - -/* Declarations of bash history variables. */ -/* Non-zero means to remember lines typed to the shell on the history - 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. The - difference between the number of the top element in the history list - (offset from history_base) and the number of lines in the history file. - Appending this session's history to the history file resets this to 0. */ -int history_lines_this_session; - -/* The number of lines that Bash has read from the history file. */ -int history_lines_in_file; - -#if defined (BANG_HISTORY) -/* Non-zero means do no history expansion on this line, regardless - of what history_expansion says. */ -int history_expansion_inhibited; -#endif - -/* With the old default, every line was 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. - - This is now enabled by default. - */ -int command_oriented_history = 1; - -/* Set to 1 if the first line of a possibly-multi-line command was saved - in the history list. Managed by maybe_add_history(), but global so - the history-manipluating builtins can see it. */ -int current_command_first_line_saved = 0; - -/* Non-zero means to store newlines in the history list when using - command_oriented_history rather than trying to use semicolons. */ -int literal_history; - -/* Non-zero means to append the history to the history file at shell - exit, even if the history has been stifled. */ -int force_append_history; - -/* A nit for picking at history saving. Flags have the following values: - - Value == 0 means save all lines parsed by the shell on the history. - Value & HC_IGNSPACE means save all lines that do not start with a space. - Value & HC_IGNDUPS means save all lines that do not match the last - line saved. - Value & HC_ERASEDUPS means to remove all other matching lines from the - history list before saving the latest line. */ -int history_control; - -/* Set to 1 if the last command was added to the history list successfully - as a separate history entry; set to 0 if the line was ignored or added - to a previous entry as part of command-oriented-history processing. */ -int hist_last_line_added; - -#if defined (READLINE) -/* If non-zero, and readline is being used, the user is offered the - chance to re-edit a failed history expansion. */ -int history_reediting; - -/* If non-zero, and readline is being used, don't directly execute a - line with history substitution. Reload it into the editing buffer - instead and let the user further edit and confirm with a newline. */ -int hist_verify; - -#endif /* READLINE */ - -/* Non-zero means to not save function definitions in the history list. */ -int dont_save_function_defs; - -/* Variables declared in other files used here. */ -extern int current_command_line_count; - -extern struct dstack dstack; - -static int bash_history_inhibit_expansion __P((char *, int)); -#if defined (READLINE) -static void re_edit __P((char *)); -#endif -static int history_expansion_p __P((char *)); -static int shell_comment __P((char *)); -static int should_expand __P((char *)); -static HIST_ENTRY *last_history_entry __P((void)); -static char *expand_histignore_pattern __P((char *)); -static int history_should_ignore __P((char *)); - -/* Is the history expansion starting at string[i] one that should not - be expanded? */ -static int -bash_history_inhibit_expansion (string, i) - char *string; - int i; -{ - /* The shell uses ! as a pattern negation character in globbing [...] - expressions, so let those pass without expansion. */ - if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1)) - return (1); - /* The shell uses ! as the indirect expansion character, so let those - expansions pass as well. */ - else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' && - member ('}', string + i + 1)) - return (1); -#if defined (EXTENDED_GLOB) - else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2)) - return (1); -#endif - else - return (0); -} - -void -bash_initialize_history () -{ - history_quotes_inhibit_expansion = 1; - history_search_delimiter_chars = ";&()|<>"; - history_inhibit_expansion_function = bash_history_inhibit_expansion; - sv_histchars ("histchars"); -} - -void -bash_history_reinit (interact) - int interact; -{ -#if defined (BANG_HISTORY) - history_expansion = interact != 0; - history_expansion_inhibited = 1; -#endif - remember_on_history = interact != 0; - history_inhibit_expansion_function = bash_history_inhibit_expansion; -} - -void -bash_history_disable () -{ - remember_on_history = 0; -#if defined (BANG_HISTORY) - history_expansion_inhibited = 1; -#endif -} - -void -bash_history_enable () -{ - remember_on_history = 1; -#if defined (BANG_HISTORY) - history_expansion_inhibited = 0; -#endif - history_inhibit_expansion_function = bash_history_inhibit_expansion; - sv_history_control ("HISTCONTROL"); - sv_histignore ("HISTIGNORE"); -} - -/* Load the history list from the history file. */ -void -load_history () -{ - char *hf; - struct stat buf; - - /* Truncate history file for interactive shells which desire it. - Note that the history file is automatically truncated to the - size of HISTSIZE if the user does not explicitly set the size - differently. */ - set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE")); - sv_histsize ("HISTFILESIZE"); - - /* Read the history in HISTFILE into the history list. */ - hf = get_string_value ("HISTFILE"); - - if (hf && *hf && stat (hf, &buf) == 0) - { - read_history (hf); - using_history (); - history_lines_in_file = where_history (); - } -} - -#ifdef INCLUDE_UNUSED -/* Write the existing history out to the history file. */ -void -save_history () -{ - char *hf; - struct stat buf; - - hf = get_string_value ("HISTFILE"); - if (hf && *hf && stat (hf, &buf) == 0) - { - /* Append only the lines that occurred this session to - the history file. */ - using_history (); - - if (history_lines_this_session < where_history () || force_append_history) - append_history (history_lines_this_session, hf); - else - write_history (hf); - - sv_histsize ("HISTFILESIZE"); - } -} -#endif - -int -maybe_append_history (filename) - char *filename; -{ - int fd, result; - struct stat buf; - - result = EXECUTION_SUCCESS; - if (history_lines_this_session && (history_lines_this_session < where_history ())) - { - /* If the filename was supplied, then create it if necessary. */ - if (stat (filename, &buf) == -1 && errno == ENOENT) - { - fd = open (filename, O_WRONLY|O_CREAT, 0600); - if (fd < 0) - { - builtin_error (_("%s: cannot create: %s"), filename, strerror (errno)); - return (EXECUTION_FAILURE); - } - close (fd); - } - result = append_history (history_lines_this_session, filename); - history_lines_in_file += history_lines_this_session; - history_lines_this_session = 0; - } - return (result); -} - -/* If this is an interactive shell, then append the lines executed - this session to the history file. */ -int -maybe_save_shell_history () -{ - int result; - char *hf; - struct stat buf; - - result = 0; - if (history_lines_this_session) - { - hf = get_string_value ("HISTFILE"); - - if (hf && *hf) - { - /* If the file doesn't exist, then create it. */ - if (stat (hf, &buf) == -1) - { - int file; - file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600); - 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 () || force_append_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; - - sv_histsize ("HISTFILESIZE"); - } - } - return (result); -} - -#if defined (READLINE) -/* Tell readline () that we have some text for it to edit. */ -static void -re_edit (text) - char *text; -{ - if (bash_input.type == st_stdin) - bash_re_edit (text); -} -#endif /* READLINE */ - -/* Return 1 if this line needs history expansion. */ -static int -history_expansion_p (line) - char *line; -{ - register char *s; - - for (s = line; *s; s++) - if (*s == history_expansion_char || *s == history_subst_char) - return 1; - return 0; -} - -/* 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; - - return_value = line; - expanded = 0; - -# if defined (BANG_HISTORY) - /* History expand the line. If this results in no errors, then - add that line to the history if ADDIT is non-zero. */ - if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) - { - expanded = history_expand (line, &history_value); - - if (expanded) - { - if (print_changes) - { - if (expanded < 0) - internal_error ("%s", history_value); -#if defined (READLINE) - else if (hist_verify == 0 || expanded == 2) -#else - else -#endif - fprintf (stderr, "%s\n", history_value); - } - - /* If there was an error, return NULL. */ - if (expanded < 0 || expanded == 2) /* 2 == print only */ - { -# if defined (READLINE) - if (expanded == 2 && rl_dispatching == 0 && *history_value) -# else - if (expanded == 2 && *history_value) -# endif /* !READLINE */ - maybe_add_history (history_value); - - free (history_value); - -# if defined (READLINE) - /* New hack. We can allow the user to edit the - failed history expansion. */ - if (history_reediting && expanded < 0 && rl_done) - re_edit (line); -# endif /* READLINE */ - return ((char *)NULL); - } - -# if defined (READLINE) - if (hist_verify && expanded == 1) - { - re_edit (history_value); - return ((char *)NULL); - } -# endif - } - - /* Let other expansions know that return_value can be free'ed, - 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 0 - if (expanded == 0) - return_value = savestring (line); -#endif - - return (return_value); -} - -/* Return 1 if the first non-whitespace character in LINE is a `#', indicating - * that the line is a shell comment. */ -static int -shell_comment (line) - char *line; -{ - char *p; - - for (p = line; p && *p && whitespace (*p); p++) - ; - return (p && *p == '#'); -} - -#ifdef INCLUDE_UNUSED -/* Remove shell comments from LINE. A `#' and anything after it is a comment. - This isn't really useful yet, since it doesn't handle quoting. */ -static char * -filter_comments (line) - char *line; -{ - char *p; - - for (p = line; p && *p && *p != '#'; p++) - ; - if (p && *p == '#') - *p = '\0'; - return (line); -} -#endif - -/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line - should be saved; 0 if it should be discarded. */ -static int -check_history_control (line) - char *line; -{ - HIST_ENTRY *temp; - int r; - - if (history_control == 0) - return 1; - - /* ignorespace or ignoreboth */ - if ((history_control & HC_IGNSPACE) && *line == ' ') - return 0; - - /* ignoredups or ignoreboth */ - if (history_control & HC_IGNDUPS) - { - using_history (); - temp = previous_history (); - - r = (temp == 0 || STREQ (temp->line, line) == 0); - - using_history (); - - if (r == 0) - return r; - } - - return 1; -} - -/* Remove all entries matching LINE from the history list. Triggered when - HISTCONTROL includes `erasedups'. */ -static void -hc_erasedups (line) - char *line; -{ - HIST_ENTRY *temp; - int r; - - using_history (); - while (temp = previous_history ()) - { - if (STREQ (temp->line, line)) - { - r = where_history (); - remove_history (r); - } - } - using_history (); -} - -/* Add LINE to the history list, handling possibly multi-line compound - commands. We note whether or not we save the first line of each command - (which is usually the entire command and history entry), and don't add - the second and subsequent lines of a multi-line compound command if we - didn't save the first line. We don't usually save shell comment lines in - compound commands in the history, because they could have the effect of - commenting out the rest of the command when the entire command is saved as - a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If - LITERAL_HISTORY is set, we're saving lines in the history with embedded - newlines, so it's OK to save comment lines. We also make sure to save - multiple-line quoted strings or other constructs. */ -void -maybe_add_history (line) - char *line; -{ - hist_last_line_added = 0; - - /* Don't use the value of history_control to affect the second - and subsequent lines of a multi-line command (old code did - this only when command_oriented_history is enabled). */ - if (current_command_line_count > 1) - { - if (current_command_first_line_saved && - (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0)) - bash_add_history (line); - return; - } - - /* This is the first line of a (possible multi-line) command. Note whether - or not we should save the first line and remember it. */ - current_command_first_line_saved = check_add_history (line, 0); -} - -/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the - history if it's OK. Used by `history -s' as well as maybe_add_history(). - Returns 1 if the line was saved in the history, 0 otherwise. */ -int -check_add_history (line, force) - char *line; - int force; -{ - if (check_history_control (line) && history_should_ignore (line) == 0) - { - /* We're committed to saving the line. If the user has requested it, - remove other matching lines from the history. */ - if (history_control & HC_ERASEDUPS) - hc_erasedups (line); - - if (force) - { - really_add_history (line); - using_history (); - } - else - bash_add_history (line); - return 1; - } - return 0; -} - -/* 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. */ -void -bash_add_history (line) - char *line; -{ - int add_it, offset, curlen; - HIST_ENTRY *current, *old; - char *chars_to_add, *new_line; - - add_it = 1; - if (command_oriented_history && current_command_line_count > 1) - { - chars_to_add = literal_history ? "\n" : 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. */ - curlen = strlen (current->line); - - if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' && - current->line[curlen - 2] != '\\') - { - current->line[curlen - 1] = '\0'; - curlen--; - chars_to_add = ""; - } - - new_line = (char *)xmalloc (1 - + curlen - + strlen (line) - + strlen (chars_to_add)); - sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); - offset = where_history (); - old = replace_history_entry (offset, new_line, current->data); - free (new_line); - - if (old) - free_history_entry (old); - - add_it = 0; - } - } - - if (add_it) - really_add_history (line); - - using_history (); -} - -static void -really_add_history (line) - char *line; -{ - hist_last_line_added = 1; - add_history (line); - history_lines_this_session++; -} - -int -history_number () -{ - using_history (); - return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1); -} - -static int -should_expand (s) - char *s; -{ - char *p; - - for (p = s; p && *p; p++) - { - if (*p == '\\') - p++; - else if (*p == '&') - return 1; - } - return 0; -} - -static int -histignore_item_func (ign) - struct ign *ign; -{ - if (should_expand (ign->val)) - ign->flags |= HIGN_EXPAND; - return (0); -} - -void -setup_history_ignore (varname) - char *varname; -{ - setup_ignore_patterns (&histignore); -} - -static HIST_ENTRY * -last_history_entry () -{ - HIST_ENTRY *he; - - using_history (); - he = previous_history (); - using_history (); - return he; -} - -char * -last_history_line () -{ - HIST_ENTRY *he; - - he = last_history_entry (); - if (he == 0) - return ((char *)NULL); - return he->line; -} - -static char * -expand_histignore_pattern (pat) - char *pat; -{ - HIST_ENTRY *phe; - char *ret; - - phe = last_history_entry (); - - if (phe == (HIST_ENTRY *)0) - return (savestring (pat)); - - ret = strcreplace (pat, '&', phe->line, 1); - - return ret; -} - -/* Return 1 if we should not put LINE into the history according to the - patterns in HISTIGNORE. */ -static int -history_should_ignore (line) - char *line; -{ - register int i, match; - char *npat; - - if (histignore.num_ignores == 0) - return 0; - - for (i = match = 0; i < histignore.num_ignores; i++) - { - if (histignore.ignores[i].flags & HIGN_EXPAND) - npat = expand_histignore_pattern (histignore.ignores[i].val); - else - npat = histignore.ignores[i].val; - - match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH; - - if (histignore.ignores[i].flags & HIGN_EXPAND) - free (npat); - - if (match) - break; - } - - return match; -} -#endif /* HISTORY */ diff --git a/bashline.c~ b/bashline.c~ deleted file mode 100644 index 0db80683e..000000000 --- a/bashline.c~ +++ /dev/null @@ -1,3049 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#if defined (READLINE) - -#include "bashtypes.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_GRP_H) -# include -#endif - -#if defined (HAVE_NETDB_H) -# include -#endif - -#include -#include "chartypes.h" -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "input.h" -#include "builtins.h" -#include "bashhist.h" -#include "bashline.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "pathexp.h" -#include "builtins/common.h" -#include -#include -#include - -#include - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -/* These should agree with the defines for emacs_mode and vi_mode in - rldefs.h, even though that's not a public readline header file. */ -#ifndef EMACS_EDITING_MODE -# define NO_EDITING_MODE -1 -# define EMACS_EDITING_MODE 1 -# define VI_EDITING_MODE 0 -#endif - -#if defined (BRACE_COMPLETION) -extern int bash_brace_completion __P((int, int)); -#endif /* BRACE_COMPLETION */ - -/* Forward declarations */ - -/* Functions bound to keys in Readline for Bash users. */ -static int shell_expand_line __P((int, int)); -static int display_shell_version __P((int, int)); -static int operate_and_get_next __P((int, int)); - -static int bash_ignore_filenames __P((char **)); -static int bash_ignore_everything __P((char **)); - -#if defined (BANG_HISTORY) -static char *history_expand_line_internal __P((char *)); -static int history_expand_line __P((int, int)); -static int tcsh_magic_space __P((int, int)); -#endif /* BANG_HISTORY */ -#ifdef ALIAS -static int alias_expand_line __P((int, int)); -#endif -#if defined (BANG_HISTORY) && defined (ALIAS) -static int history_and_alias_expand_line __P((int, int)); -#endif - -/* Helper functions for Readline. */ -static int bash_directory_completion_hook __P((char **)); -static int filename_completion_ignore __P((char **)); -static int bash_push_line __P((void)); - -static void cleanup_expansion_error __P((void)); -static void maybe_make_readline_line __P((char *)); -static void set_up_new_line __P((char *)); - -static int check_redir __P((int)); -static char **attempt_shell_completion __P((const char *, int, int)); -static char *variable_completion_function __P((const char *, int)); -static char *hostname_completion_function __P((const char *, int)); -static char *command_subst_completion_function __P((const char *, int)); - -static void build_history_completion_array __P((void)); -static char *history_completion_generator __P((const char *, int)); -static int dynamic_complete_history __P((int, int)); - -static void initialize_hostname_list __P((void)); -static void add_host_name __P((char *)); -static void snarf_hosts_from_file __P((char *)); -static char **hostnames_matching __P((char *)); - -static void _ignore_completion_names __P((char **, sh_ignore_func_t *)); -static int name_is_acceptable __P((const char *)); -static int test_for_directory __P((const char *)); -static int return_zero __P((const char *)); - -static char *bash_dequote_filename __P((char *, int)); -static char *quote_word_break_chars __P((char *)); -static char *bash_quote_filename __P((char *, int, char *)); - -static int bash_execute_unix_command __P((int, int)); -static void init_unix_command_map __P((void)); -static int isolate_sequence __P((char *, int, int, int *)); - -static int set_saved_history __P((void)); - -#if defined (ALIAS) -static int posix_edit_macros __P((int, int)); -#endif - -#if defined (PROGRAMMABLE_COMPLETION) -static int find_cmd_start __P((int)); -static int find_cmd_end __P((int)); -static char *find_cmd_name __P((int)); -static char *prog_complete_return __P((const char *, int)); - -static char **prog_complete_matches; -#endif - -/* Variables used here but defined in other files. */ -#if defined (BANG_HISTORY) -extern int hist_verify; -#endif - -extern int current_command_line_count, last_command_exit_value; -extern int posixly_correct, no_symbolic_links; -extern char *current_prompt_string, *ps1_prompt; -extern STRING_INT_ALIST word_token_alist[]; -extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; - -/* 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 int bash_specific_completion __P((int, rl_compentry_func_t *)); - -static int bash_complete_filename_internal __P((int)); -static int bash_complete_username_internal __P((int)); -static int bash_complete_hostname_internal __P((int)); -static int bash_complete_variable_internal __P((int)); -static int bash_complete_command_internal __P((int)); - -static int bash_complete_filename __P((int, int)); -static int bash_possible_filename_completions __P((int, int)); -static int bash_complete_username __P((int, int)); -static int bash_possible_username_completions __P((int, int)); -static int bash_complete_hostname __P((int, int)); -static int bash_possible_hostname_completions __P((int, int)); -static int bash_complete_variable __P((int, int)); -static int bash_possible_variable_completions __P((int, int)); -static int bash_complete_command __P((int, int)); -static int bash_possible_command_completions __P((int, int)); - -static char *glob_complete_word __P((const char *, int)); -static int bash_glob_completion_internal __P((int)); -static int bash_glob_complete_word __P((int, int)); -static int bash_glob_expand_word __P((int, int)); -static int bash_glob_list_expansions __P((int, int)); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -static int edit_and_execute_command __P((int, int, int, char *)); -#if defined (VI_MODE) -static int vi_edit_and_execute_command __P((int, int)); -static int bash_vi_complete __P((int, int)); -#endif -static int emacs_edit_and_execute_command __P((int, int)); - -/* Non-zero once initalize_readline () has been called. */ -int bash_readline_initialized = 0; - -/* If non-zero, we do hostname completion, breaking words at `@' and - trying to complete the stuff after the `@' from our own internal - host list. */ -int perform_hostname_completion = 1; - -/* If non-zero, we don't do command completion on an empty line. */ -int no_empty_command_completion; - -/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the - only possible matches. Set to 0 if you want to match filenames if they - are the only possible matches, even if FIGNORE says to. */ -int force_fignore = 1; - -static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; -static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; -/* )) */ - -static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; - -/* What kind of quoting is performed by bash_quote_filename: - COMPLETE_DQUOTE = double-quoting the filename - COMPLETE_SQUOTE = single_quoting the filename - COMPLETE_BSQUOTE = backslash-quoting special chars in the filename -*/ -#define COMPLETE_DQUOTE 1 -#define COMPLETE_SQUOTE 2 -#define COMPLETE_BSQUOTE 3 -static int completion_quoting_style = COMPLETE_BSQUOTE; - -/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. - Called when the shell is put into or out of `posix' mode. */ -void -posix_readline_initialize (on_or_off) - int on_or_off; -{ - if (on_or_off) - rl_variable_bind ("comment-begin", "#"); -#if defined (VI_MODE) - rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); -#endif -} - -/* When this function returns, rl_completer_word_break_characters points to - dynamically allocated memory. */ -int -enable_hostname_completion (on_or_off) - int on_or_off; -{ - int old_value; - char *at, *nv, *nval; - - old_value = perform_hostname_completion; - - if (on_or_off) - { - perform_hostname_completion = 1; - rl_special_prefixes = "$@"; - } - else - { - perform_hostname_completion = 0; - rl_special_prefixes = "$"; - } - - /* Now we need to figure out how to appropriately modify and assign - rl_completer_word_break_characters depending on whether we want - hostname completion on or off. */ - - /* If this is the first time this has been called - (bash_readline_initialized == 0), use the sames values as before, but - allocate new memory for rl_completer_word_break_characters. */ - - if (bash_readline_initialized == 0 && - (rl_completer_word_break_characters == 0 || - rl_completer_word_break_characters == rl_basic_word_break_characters)) - { - if (on_or_off) - rl_completer_word_break_characters = savestring (bash_completer_word_break_characters); - else - rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters); - } - else - { - /* See if we have anything to do. */ - at = strchr (rl_completer_word_break_characters, '@'); - if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) - return; - - /* We have something to do. Do it. */ - nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); - - if (on_or_off == 0) - { - /* Turn it off -- just remove `@' from word break chars. We want - to remove all occurrences of `@' from the char list, so we loop - rather than just copy the rest of the list over AT. */ - for (nv = nval, at = rl_completer_word_break_characters; *at; ) - if (*at != '@') - *nv++ = *at++; - else - at++; - *nv = '\0'; - } - else - { - nval[0] = '@'; - strcpy (nval + 1, rl_completer_word_break_characters); - } - - free (rl_completer_word_break_characters); - rl_completer_word_break_characters = nval; - } - - return (old_value); -} - -/* Called once from parse.y if we are going to use readline. */ -void -initialize_readline () -{ - rl_command_func_t *func; - char kseq[2]; - - if (bash_readline_initialized) - return; - - rl_terminal_name = get_string_value ("TERM"); - rl_instream = stdin; - rl_outstream = stderr; - - /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "Bash"; - - /* Add bindable names before calling rl_initialize so they may be - referenced in the various inputrc files. */ - rl_add_defun ("shell-expand-line", shell_expand_line, -1); -#ifdef BANG_HISTORY - rl_add_defun ("history-expand-line", history_expand_line, -1); - rl_add_defun ("magic-space", tcsh_magic_space, -1); -#endif - -#ifdef ALIAS - rl_add_defun ("alias-expand-line", alias_expand_line, -1); -# ifdef BANG_HISTORY - rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); -# endif -#endif - - /* Backwards compatibility. */ - rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); - - rl_add_defun ("operate-and-get-next", operate_and_get_next, -1); - rl_add_defun ("display-shell-version", display_shell_version, -1); - rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); - -#if defined (BRACE_COMPLETION) - rl_add_defun ("complete-into-braces", bash_brace_completion, -1); -#endif - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_add_defun ("complete-filename", bash_complete_filename, -1); - rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); - rl_add_defun ("complete-username", bash_complete_username, -1); - rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); - rl_add_defun ("complete-hostname", bash_complete_hostname, -1); - rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); - rl_add_defun ("complete-variable", bash_complete_variable, -1); - rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); - rl_add_defun ("complete-command", bash_complete_command, -1); - rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); - rl_add_defun ("glob-complete-word", bash_glob_complete_word, -1); - rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); - rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); -#endif - - rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); - - /* Bind defaults before binding our custom shell keybindings. */ - if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) - rl_initialize (); - - /* Bind up our special shell functions. */ - rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); - -#ifdef BANG_HISTORY - rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); -#endif - - rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap); - rl_bind_key_if_unbound_in_map (CTRL ('V'), 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. */ - kseq[0] = CTRL('J'); - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); - kseq[0] = CTRL('M'); - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - 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_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/ -#endif /* BRACE_COMPLETION */ - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); - - /* Have to jump through hoops here because there is a default binding for - M-~ (rl_tilde_expand) */ - kseq[0] = '~'; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tilde_expand) - rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); - - rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); - rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - - rl_bind_key_if_unbound_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); - - /* Tell the completer that we want a crack first. */ - rl_attempted_completion_function = 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 = filename_completion_ignore; - - /* Bind C-xC-e to invoke emacs and run result as commands. */ - rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); -#if defined (VI_MODE) - rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); -# if defined (ALIAS) - rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); -# endif - - rl_bind_key_in_map ('\\', bash_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('*', bash_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('=', bash_vi_complete, vi_movement_keymap); -#endif - - rl_completer_quote_characters = "'\""; - - /* This sets rl_completer_word_break_characters and rl_special_prefixes - to the appropriate values, depending on whether or not hostname - completion is enabled. */ - enable_hostname_completion (perform_hostname_completion); - - /* characters that need to be quoted when appearing in filenames. */ - rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{"; /*}*/ - rl_filename_quoting_function = bash_quote_filename; - rl_filename_dequoting_function = bash_dequote_filename; - rl_char_is_quoted_p = char_is_quoted; - -#if 0 - /* This is superfluous and makes it impossible to use tab completion in - vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() - should already have called posix_readline_initialize() when - posixly_correct was set. */ - if (posixly_correct) - posix_readline_initialize (1); -#endif - - 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 = NULL; - rl_directory_completion_hook = bash_directory_completion_hook; - rl_ignore_some_completions_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 int -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; - } - return 0; -} - -/* Call this to set the initial text for the next line to read - from readline. */ -int -bash_re_edit (line) - char *line; -{ - FREE (push_to_readline); - - push_to_readline = savestring (line); - old_rl_startup_hook = rl_startup_hook; - rl_startup_hook = bash_push_line; - - return (0); -} - -static int -display_shell_version (count, c) - int count, c; -{ - rl_crlf (); - show_shell_version (0); - putc ('\r', rl_outstream); - fflush (rl_outstream); - rl_on_new_line (); - rl_redisplay (); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Readline Stuff */ -/* */ -/* **************************************************************** */ - -/* If the user requests hostname completion, then simply build a list - of hosts, and complete from that forever more, or at least until - HOSTFILE is unset. */ - -/* THIS SHOULD BE A STRINGLIST. */ -/* The kept list of hostnames. */ -static char **hostname_list = (char **)NULL; - -/* The physical size of the above list. */ -static int hostname_list_size; - -/* The number of hostnames in the above list. */ -static int hostname_list_length; - -/* Whether or not HOSTNAME_LIST has been initialized. */ -int hostname_list_initialized = 0; - -/* Initialize the hostname completion table. */ -static void -initialize_hostname_list () -{ - char *temp; - - temp = get_string_value ("HOSTFILE"); - if (temp == 0) - temp = get_string_value ("hostname_completion_file"); - if (temp == 0) - temp = DEFAULT_HOSTS_FILE; - - snarf_hosts_from_file (temp); - - 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_size = (hostname_list_size + 32) - (hostname_list_size % 32); - hostname_list = strvec_resize (hostname_list, hostname_list_size); - } - - hostname_list[hostname_list_length++] = savestring (name); - hostname_list[hostname_list_length] = (char *)NULL; -} - -#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) - -static void -snarf_hosts_from_file (filename) - char *filename; -{ - FILE *file; - char *temp, buffer[256], name[256]; - register int i, start; - - file = fopen (filename, "r"); - if (file == 0) - return; - - while (temp = fgets (buffer, 255, file)) - { - /* Skip to first character. */ - for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) - ; - - /* If comment or blank line, ignore. */ - if (buffer[i] == '\0' || buffer[i] == '#') - continue; - - /* If `preprocessor' directive, do the include. */ - if (strncmp (buffer + i, "$include ", 9) == 0) - { - char *incfile, *t; - - /* Find start of filename. */ - for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) - ; - - /* Find end of filename. */ - for (t = incfile; *t && cr_whitespace (*t) == 0; t++) - ; - - *t = '\0'; - - snarf_hosts_from_file (incfile); - continue; - } - - /* Skip internet address if present. */ - if (DIGIT (buffer[i])) - for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); - - /* Gobble up names. Each name is separated with whitespace. */ - while (buffer[i]) - { - for (; cr_whitespace (buffer[i]); i++) - ; - if (buffer[i] == '\0' || buffer[i] == '#') - break; - - /* Isolate the current word. */ - for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) - ; - if (i == start) - continue; - strncpy (name, buffer + start, i - start); - name[i - start] = '\0'; - add_host_name (name); - } - } - fclose (file); -} - -/* Return the hostname list. */ -char ** -get_hostname_list () -{ - if (hostname_list_initialized == 0) - initialize_hostname_list (); - return (hostname_list); -} - -void -clear_hostname_list () -{ - register int i; - - if (hostname_list_initialized == 0) - return; - for (i = 0; i < hostname_list_length; i++) - free (hostname_list[i]); - hostname_list_length = 0; -} - -/* 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, nmatch, rsize; - char **result; - - if (hostname_list_initialized == 0) - initialize_hostname_list (); - - if (hostname_list_initialized == 0) - return ((char **)NULL); - - /* Special case. If TEXT consists of nothing, then the whole list is - what is desired. */ - if (*text == '\0') - { - result = strvec_create (1 + hostname_list_length); - for (i = 0; i < hostname_list_length; i++) - result[i] = hostname_list[i]; - result[i] = (char *)NULL; - return (result); - } - - /* Scan until found, or failure. */ - len = strlen (text); - result = (char **)NULL; - for (i = nmatch = rsize = 0; i < hostname_list_length; i++) - { - if (STREQN (text, hostname_list[i], len) == 0) - continue; - - /* OK, it matches. Add it to the list. */ - if (nmatch >= (rsize - 1)) - { - rsize = (rsize + 16) - (rsize % 16); - result = strvec_resize (result, rsize); - } - - result[nmatch++] = hostname_list[i]; - } - if (nmatch) - result[nmatch] = (char *)NULL; - return (result); -} - -/* The equivalent of the Korn shell C-o operate-and-get-next-history-line - editing command. */ -static int saved_history_line_to_use = -1; - -static int -set_saved_history () -{ - if (saved_history_line_to_use >= 0) - rl_get_previous_history (history_length - saved_history_line_to_use, 0); - saved_history_line_to_use = -1; - rl_startup_hook = old_rl_startup_hook; - return (0); -} - -static int -operate_and_get_next (count, c) - int count, c; -{ - int where; - - /* Accept the current line. */ - rl_newline (1, c); - - /* Find the current line, and find the next line to use. */ - where = where_history (); - - if ((history_is_stifled () && (history_length >= history_max_entries)) || - (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 = set_saved_history; - - return 0; -} - -/* 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}}\"" -#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" - -static int -edit_and_execute_command (count, c, editing_mode, edit_command) - int count, c, editing_mode; - char *edit_command; -{ - char *command; - int r, cclc, rrs; - - rrs = rl_readline_state; - cclc = current_command_line_count; - - /* Accept the current line. */ - rl_newline (1, c); - - if (rl_explicit_arg) - { - command = (char *)xmalloc (strlen (edit_command) + 8); - sprintf (command, "%s %d", 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 (); - bash_add_history (rl_line_buffer); - bash_add_history (""); - history_lines_this_session++; - using_history (); - command = savestring (edit_command); - } - - /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the - temporary file should be placed into the history. We don't do that - yet. */ - r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); - - current_command_line_count = cclc; - - /* Now erase the contents of the current line and undo the effects of the - rl_accept_line() above. We don't even want to make the text we just - executed available for undoing. */ - rl_line_buffer[0] = '\0'; /* XXX */ - rl_point = rl_end = 0; - rl_done = 0; - rl_readline_state = rrs; - - rl_forced_update_display (); - - return r; -} - -#if defined (VI_MODE) -static int -vi_edit_and_execute_command (count, c) - int count, c; -{ - return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); -} -#endif /* VI_MODE */ - -static int -emacs_edit_and_execute_command (count, c) - int count, c; -{ - return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); -} - -#if defined (ALIAS) -static int -posix_edit_macros (count, key) - int count, key; -{ - int c; - char alias_name[3], *alias_value, *macro; - - c = rl_read_key (); - alias_name[0] = '_'; - alias_name[1] = c; - alias_name[2] = '\0'; - - alias_value = get_alias_value (alias_name); - if (alias_value && *alias_value) - { - macro = savestring (alias_value); - rl_push_macro_input (macro); - } - return 0; -} -#endif - -/* **************************************************************** */ -/* */ -/* How To Do Shell Completion */ -/* */ -/* **************************************************************** */ - -#define COMMAND_SEPARATORS ";|&{(`" -/* )} */ - -static int -check_redir (ti) - int ti; -{ - register int this_char, prev_char; - - /* 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 == '>')) - return (1); - else if ((this_char == '{' && prev_char == '$') || /* } */ - (char_is_quoted (rl_line_buffer, ti))) - return (1); - return (0); -} - -#if defined (PROGRAMMABLE_COMPLETION) -/* - * XXX - because of the <= start test, and setting os = s+1, this can - * potentially return os > start. This is probably not what we want to - * happen, but fix later after 2.05a-release. - */ -static int -find_cmd_start (start) - int start; -{ - register int s, os; - - os = 0; - while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS)) <= start) && - rl_line_buffer[s]) - os = s+1; - return os; -} - -static int -find_cmd_end (end) - int end; -{ - register int e; - - e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS); - return e; -} - -static char * -find_cmd_name (start) - int start; -{ - char *name; - register int s, e; - - for (s = start; whitespace (rl_line_buffer[s]); s++) - ; - - /* skip until a shell break character */ - e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n"); - - name = substring (rl_line_buffer, s, e); - - return (name); -} - -static char * -prog_complete_return (text, matchnum) - const char *text; - int matchnum; -{ - static int ind; - - if (matchnum == 0) - ind = 0; - - if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) - return (char *)NULL; - return (prog_complete_matches[ind++]); -} - -#endif /* PROGRAMMABLE_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) - const char *text; - int start, end; -{ - int in_command_position, ti, saveti, qc; - char **matches, *command_separator_chars; - - command_separator_chars = COMMAND_SEPARATORS; - matches = (char **)NULL; - rl_ignore_some_completions_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; - saveti = qc = -1; - - while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) - ti--; - -#if 1 - /* If this is an open quote, maybe we're trying to complete a quoted - command name. */ - if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) - { - qc = rl_line_buffer[ti]; - saveti = ti--; - while (ti > -1 && (whitespace (rl_line_buffer[ti]))) - ti--; - } -#endif - - 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)) - { - in_command_position++; - - if (check_redir (ti) == 1) - 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. */ - } - - /* Check that we haven't incorrectly flagged a closed command substitution - as indicating we're in a command position. */ - if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && - *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) - in_command_position = 0; - - /* Special handling for command substitution. If *TEXT is a backquote, - it can be the start or end of an old-style command substitution, or - unmatched. If it's unmatched, both calls to unclosed_pair will - succeed. */ - if (*text == '`' && - (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && - unclosed_pair (rl_line_buffer, end, "`")))) - matches = rl_completion_matches (text, command_subst_completion_function); - -#if defined (PROGRAMMABLE_COMPLETION) - /* Attempt programmable completion. */ - if (!matches && in_command_position == 0 && prog_completion_enabled && - (progcomp_size () > 0) && current_prompt_string == ps1_prompt) - { - int s, e, foundcs; - char *n; - - /* XXX - don't free the members */ - if (prog_complete_matches) - free (prog_complete_matches); - prog_complete_matches = (char **)NULL; - - s = find_cmd_start (start); - e = find_cmd_end (end); - n = find_cmd_name (s); - if (e > s) - prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); - else - foundcs = 0; - FREE (n); - /* XXX - if we found a COMPSPEC for the command, just return whatever - the programmable completion code returns, and disable the default - filename completion that readline will do unless the COPT_DEFAULT - option has been set with the `-o default' option to complete. */ - if (foundcs) - { - /* If the user specified that the compspec returns filenames, make - sure that readline knows it. */ - if (foundcs & COPT_FILENAMES) - rl_filename_completion_desired = 1; - /* If the user doesn't want a space appended, tell readline. */ - if (foundcs & COPT_NOSPACE) - rl_completion_suppress_append = 1; - /* Turn what the programmable completion code returns into what - readline wants. I should have made compute_lcd_of_matches - external... */ - matches = rl_completion_matches (text, prog_complete_return); - if ((foundcs & COPT_DEFAULT) == 0) - rl_attempted_completion_over = 1; /* no default */ - if (matches || ((foundcs & COPT_BASHDEFAULT) == 0)) - return (matches); - } - } -#endif - - if (matches == 0) - matches = bash_default_completion (text, start, end, qc, in_command_position); - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, in_command_position) - const char *text; - int start, end, qc, in_command_position; -{ - char **matches; - - matches = (char **)NULL; - - /* New posix-style command substitution or variable name? */ - if (!matches && *text == '$') - { - if (qc != '\'' && text[1] == '(') /* ) */ - matches = rl_completion_matches (text, command_subst_completion_function); - else - matches = rl_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 == '~' && !xstrchr (text, '/')) - matches = rl_completion_matches (text, rl_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 && perform_hostname_completion && *text == '@') - matches = rl_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) - { - if (start == 0 && end == 0 && text[0] == '\0' && no_empty_command_completion) - { - matches = (char **)NULL; - rl_ignore_some_completions_function = bash_ignore_everything; - } - else - { -#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) - - matches = rl_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 == (char **)NULL) - rl_ignore_some_completions_function = bash_ignore_filenames; -#if 0 - else if (matches[1] == 0 && CMD_IS_DIR(matches[0])) - /* Turn off rl_filename_completion_desired so readline doesn't - append a slash if there is a directory with the same name - in the current directory, or other filename-specific things. - If the name begins with a slash, we're either completing a - full pathname or a directory pathname, and readline won't be - looking in the current directory anyway, so there's no - conflict. */ - rl_filename_completion_desired = 0; - else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) - /* There are multiple instances of the same match (duplicate - completions haven't yet been removed). In this case, all of - the matches will be the same, and the duplicate removal code - will distill them all down to one. We turn off - rl_filename_completion_desired for the same reason as above. - Remember: we only care if there's eventually a single unique - completion. If there are multiple completions this won't - make a difference and the problem won't occur. */ - rl_filename_completion_desired = 0; -#endif - } - } - - /* This could be a globbing pattern, so try to expand it using pathname - expansion. */ - if (!matches && glob_pattern_p (text)) - { - matches = rl_completion_matches (text, glob_complete_word); - /* A glob expression that matches more than one filename is problematic. - If we match more than one filename, punt. */ - if (matches && matches[1] && rl_completion_type == TAB) - { - strvec_dispose (matches); - matches = (char **)0; - } - } - - 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. */ -char * -command_word_completion_function (hint_text, state) - const 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 alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (!state) - { - if (hint) - 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 = bash_tilde_expand (hint_text, 0); - 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_function while we have - members of PATH left. Question: should we stat each file? - Answer: we call executable_file () on each file. */ - outer: - - istate = (val != (char *)NULL); - - if (!istate) - { - char *current_path; - - /* Get the next directory from the path. If there is none, then we - are all done. */ - if (!path || !path[path_index] || - (current_path = extract_colon_unit (path, &path_index)) == 0) - return ((char *)NULL); - - if (*current_path == 0) - { - free (current_path); - current_path = savestring ("."); - } - - if (*current_path == '~') - { - char *t; - - t = bash_tilde_expand (current_path, 0); - free (current_path); - current_path = t; - } - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - - free (current_path); - } - - inner: - val = rl_filename_completion_function (filename_hint, istate); - istate = 1; - - if (val == 0) - { - /* If the hint text is an absolute program, then don't bother - searching through PATH. */ - if (absolute_program (hint)) - return ((char *)NULL); - - goto outer; - } - else - { - int match, freetemp; - char *temp; - - if (absolute_program (hint)) - { - match = strncmp (val, hint, hint_len) == 0; - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, tl, vl; - vl = strlen (val); - tl = strlen (hint_text); - l = vl - hint_len; /* # of chars added */ - temp = (char *)xmalloc (l + 2 + tl); - strcpy (temp, hint_text); - strcpy (temp + tl, val + vl - l); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - freetemp = match = strncmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - - /* If we have found a match, and it is an executable file or a - directory name, return it. */ - if (match && executable_or_directory (val)) - { - free (val); - val = ""; /* So it won't be NULL. */ - return (temp); - } - else - { - if (freetemp) - free (temp); - free (val); - goto inner; - } - } -} - -/* Completion inside an unterminated command substitution. */ -static char * -command_subst_completion_function (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static const char *orig_start; - static char *filename_text = (char *)NULL; - static int cmd_index, start_len; - char *value; - - if (state == 0) - { - if (filename_text) - free (filename_text); - orig_start = text; - if (*text == '`') - text++; - else if (*text == '$' && text[1] == '(') /* ) */ - text += 2; - /* If the text was quoted, suppress any quote character that the - readline completion code would insert. */ - rl_completion_suppress_quote = 1; - start_len = text - orig_start; - filename_text = savestring (text); - if (matches) - free (matches); - - /* - * At this point we can entertain the idea of re-parsing - * `filename_text' into a (possibly incomplete) command name and - * arguments, and doing completion based on that. This is - * currently very rudimentary, but it is a small improvement. - */ - for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) - if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) - break; - if (value <= filename_text) - matches = rl_completion_matches (filename_text, command_word_completion_function); - else - { - value++; - start_len += value - filename_text; - if (whitespace (value[-1])) - matches = rl_completion_matches (value, rl_filename_completion_function); - else - matches = rl_completion_matches (value, command_word_completion_function); - } - - /* If there is more than one match, rl_completion_matches has already - put the lcd in matches[0]. Skip over it. */ - cmd_index = matches && matches[0] && matches[1]; - } - - if (!matches || !matches[cmd_index]) - { - rl_filename_quoting_desired = 0; /* disable quoting */ - return ((char *)NULL); - } - else - { - value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); - - if (start_len == 1) - value[0] = *orig_start; - else - strncpy (value, orig_start, start_len); - - strcpy (value + start_len, matches[cmd_index]); - - cmd_index++; - return (value); - } -} - -/* Okay, now we write the entry_function for variable completion. */ -static char * -variable_completion_function (text, state) - const char *text; - int state; -{ - static char **varlist = (char **)NULL; - static int varlist_index; - static char *varname = (char *)NULL; - static int namelen; - static int first_char, first_char_loc; - - if (!state) - { - if (varname) - free (varname); - - first_char_loc = 0; - first_char = text[0]; - - if (first_char == '$') - first_char_loc++; - - if (text[first_char_loc] == '{') - first_char_loc++; - - varname = savestring (text + first_char_loc); - - namelen = strlen (varname); - if (varlist) - strvec_dispose (varlist); - - varlist = all_variables_matching_prefix (varname); - varlist_index = 0; - } - - if (!varlist || !varlist[varlist_index]) - { - return ((char *)NULL); - } - else - { - char *value; - - value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); - - if (first_char_loc) - { - value[0] = first_char; - if (first_char_loc == 2) - value[1] = '{'; - } - - strcpy (value + first_char_loc, varlist[varlist_index]); - if (first_char_loc == 2) - strcat (value, "}"); - - varlist_index++; - return (value); - } -} - -/* How about a completion function for hostnames? */ -static char * -hostname_completion_function (text, state) - const char *text; - int state; -{ - 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 == 0) - { - FREE (list); - - list = (char **)NULL; - - first_char_loc = 0; - first_char = *text; - - if (first_char == '@') - first_char_loc++; - - list = hostnames_matching ((char *)text+first_char_loc); - list_index = 0; - } - - if (list && list[list_index]) - { - char *t; - - t = (char *)xmalloc (2 + strlen (list[list_index])); - *t = first_char; - strcpy (t + first_char_loc, list[list_index]); - list_index++; - return (t); - } - - return ((char *)NULL); -} - -/* - * A completion function for service names from /etc/services (or wherever). - */ -char * -bash_servicename_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) - return ((char *)NULL); -#else - static char *sname = (char *)NULL; - static struct servent *srvent; - static int snamelen, firstc; - char *value; - char **alist, *aentry; - int afound; - - if (state == 0) - { - FREE (sname); - firstc = *text; - - sname = savestring (text); - snamelen = strlen (sname); - setservent (0); - } - - while (srvent = getservent ()) - { - afound = 0; - if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) - break; - /* Not primary, check aliases */ - for (alist = srvent->s_aliases; aentry = *alist; alist++) - { - if (STREQN (sname, aentry, snamelen)) - { - afound = 1; - break; - } - } - - if (afound) - break; - } - - if (srvent == 0) - { - endservent (); - return ((char *)NULL); - } - - value = afound ? savestring (aentry) : savestring (srvent->s_name); - return value; -#endif -} - -/* - * A completion function for group names from /etc/group (or wherever). - */ -char * -bash_groupname_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) - return ((char *)NULL); -#else - static char *gname = (char *)NULL; - static struct group *grent; - static int gnamelen; - char *value; - - if (state == 0) - { - FREE (gname); - gname = savestring (text); - gnamelen = strlen (gname); - - setgrent (); - } - - while (grent = getgrent ()) - { - if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) - break; - } - - if (grent == 0) - { - endgrent (); - return ((char *)NULL); - } - - value = savestring (grent->gr_name); - return (value); -#endif -} - -/* Functions to perform history and alias expansions on the current line. */ - -#if defined (BANG_HISTORY) -/* Perform history expansion on the current line. If no history expansion - is done, pre_process_line() returns what it was passed, so we need to - allocate a new line here. */ -static char * -history_expand_line_internal (line) - char *line; -{ - char *new_line; - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; - new_line = pre_process_line (line, 0, 0); - hist_verify = old_verify; - - return (new_line == line) ? savestring (line) : new_line; -} -#endif - -/* There was an error in expansion. Let the preprocessor print - the error here. */ -static void -cleanup_expansion_error () -{ - char *to_free; -#if defined (BANG_HISTORY) - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; -#endif - - fprintf (rl_outstream, "\r\n"); - to_free = pre_process_line (rl_line_buffer, 1, 0); -#if defined (BANG_HISTORY) - hist_verify = old_verify; -#endif - if (to_free != rl_line_buffer) - 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 = rl_mark = 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, at_end; - - old_point = rl_point; - 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, 0); - } -} - -#if defined (ALIAS) -/* Expand aliases in the current readline line. */ -static int -alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = alias_expand (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} -#endif - -#if defined (BANG_HISTORY) -/* History expand the line. */ -static int -history_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = history_expand_line_internal (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* Expand history substitutions in the current line and then insert a - space (hopefully close to where we were before). */ -static int -tcsh_magic_space (count, ignore) - int count, ignore; -{ - int dist_from_end, old_point; - - old_point = rl_point; - dist_from_end = rl_end - rl_point; - if (history_expand_line (count, ignore) == 0) - { - /* Try a simple heuristic from Stephen Gildea . - This works if all expansions were before rl_point or if no expansions - were performed. */ - rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; - rl_insert (1, ' '); - return (0); - } - else - return (1); -} -#endif - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = history_expand_line_internal (rl_line_buffer); - -#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); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* History and alias expand the line, then perform the shell word - expansions by calling expand_string. This can't use set_up_new_line() - because we want the variable expansions as a separate undo'able - set of operations. */ -static int -shell_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - WORD_LIST *expanded_string; - - new_line = history_expand_line_internal (rl_line_buffer); - -#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. */ - new_line = savestring (rl_line_buffer); - expanded_string = expand_string (new_line, 0); - FREE (new_line); - if (expanded_string == 0) - { - new_line = (char *)xmalloc (1); - new_line[0] = '\0'; - } - else - { - new_line = string_list (expanded_string); - dispose_words (expanded_string); - } - - maybe_make_readline_line (new_line); - free (new_line); - - /* 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, 0); - } - return 0; - } - else - { - cleanup_expansion_error (); - return 1; - } -} - -/* If FIGNORE is set, then don't match files with the given suffixes when - completing filenames. If only one of the possibilities has an acceptable - suffix, delete the others, else just return and let the completer - signal an error. It is called by the completer when real - completions are done on filenames by the completer's internal - function, not for completion lists (M-?) and not on "other" - completion types, such as hostnames or commands. */ - -static struct ignorevar fignore = -{ - "FIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *) 0, -}; - -static void -_ignore_completion_names (names, name_func) - char **names; - sh_ignore_func_t *name_func; -{ - char **newnames; - int idx, nidx; - char **oldnames; - int oidx; - - /* 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 (force_fignore) - 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 = strvec_create (nidx + 1); - - if (force_fignore == 0) - { - oldnames = strvec_create (nidx - 1); - oidx = 0; - } - - newnames[0] = names[0]; - for (idx = nidx = 1; names[idx]; idx++) - { - if ((*name_func) (names[idx])) - newnames[nidx++] = names[idx]; - else if (force_fignore == 0) - oldnames[oidx++] = names[idx]; - else - free (names[idx]); - } - - newnames[nidx] = (char *)NULL; - - /* If none are acceptable then let the completer handle it. */ - if (nidx == 1) - { - if (force_fignore) - { - free (names[0]); - names[0] = (char *)NULL; - } - else - free (oldnames); - - free (newnames); - return; - } - - if (force_fignore == 0) - { - while (oidx) - free (oldnames[--oidx]); - free (oldnames); - } - - /* 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; - free (newnames); -} - -static int -name_is_acceptable (name) - const char *name; -{ - struct ign *p; - int nlen; - - for (nlen = strlen (name), p = fignore.ignores; p->val; p++) - { - if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) - return (0); - } - - return (1); -} - -#if 0 -static int -ignore_dot_names (name) - char *name; -{ - return (name[0] != '.'); -} -#endif - -static int -filename_completion_ignore (names) - char **names; -{ -#if 0 - if (glob_dot_filenames == 0) - _ignore_completion_names (names, ignore_dot_names); -#endif - - setup_ignore_patterns (&fignore); - - if (fignore.num_ignores == 0) - return 0; - - _ignore_completion_names (names, name_is_acceptable); - - return 0; -} - -/* Return 1 if NAME is a directory. */ -static int -test_for_directory (name) - const char *name; -{ - struct stat finfo; - char *fn; - - fn = bash_tilde_expand (name, 0); - if (stat (fn, &finfo) != 0) - { - free (fn); - return 0; - } - free (fn); - return (S_ISDIR (finfo.st_mode)); -} - -/* Remove files from NAMES, leaving directories. */ -static int -bash_ignore_filenames (names) - char **names; -{ - _ignore_completion_names (names, test_for_directory); - return 0; -} - -static int -return_zero (name) - const char *name; -{ - return 0; -} - -static int -bash_ignore_everything (names) - char **names; -{ - _ignore_completion_names (names, return_zero); - return 0; -} - -/* Handle symbolic link references and other directory name - expansions while hacking completion. */ -static int -bash_directory_completion_hook (dirname) - char **dirname; -{ - char *local_dirname, *new_dirname, *t; - int return_value, should_expand_dirname; - WORD_LIST *wl; - struct stat sb; - - return_value = should_expand_dirname = 0; - local_dirname = *dirname; - -#if 0 - should_expand_dirname = xstrchr (local_dirname, '$') || xstrchr (local_dirname, '`'); -#else - if (xstrchr (local_dirname, '$')) - should_expand_dirname = 1; - else - { - t = xstrchr (local_dirname, '`'); - if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) - should_expand_dirname = 1; - } -#endif - - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0); /* does the right thing */ - 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); - free (new_dirname); - dispose_words (wl); - local_dirname = *dirname; - } - else - { - free (new_dirname); - free (local_dirname); - *dirname = (char *)xmalloc (1); - **dirname = '\0'; - 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 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return 1; - } - len1 = strlen (temp1); - if (temp1[len1 - 1] == '/') - { - len2 = strlen (temp2); - temp2 = (char *)xrealloc (temp2, len2 + 2); - temp2[len2] = '/'; - temp2[len2 + 1] = '\0'; - } - free (local_dirname); - *dirname = temp2; - free (temp1); - } - return (return_value); -} - -static char **history_completion_array = (char **)NULL; -static int harry_size; -static int harry_len; - -static void -build_history_completion_array () -{ - register int i, j; - HIST_ENTRY **hlist; - char **tokens; - - /* First, clear out the current dynamic history completion list. */ - if (harry_size) - { - strvec_dispose (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. */ - hlist = history_list (); - - if (hlist) - { - for (i = 0; hlist[i]; i++) - { - /* Separate each token, and place into an array. */ - tokens = history_tokenize (hlist[i]->line); - - for (j = 0; tokens && tokens[j]; j++) - { - if (harry_len + 2 > harry_size) - history_completion_array = strvec_resize (history_completion_array, harry_size += 10); - - 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 *), (QSFUNC *)strvec_strcmp); - } -} - -static char * -history_completion_generator (hint_text, state) - const char *hint_text; - int state; -{ - static int local_index, len; - static const char *text; - - /* If this is the first call to the generator, then initialize the - list of strings to complete over. */ - if (state == 0) - { - 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 int -dynamic_complete_history (count, key) - int count, key; -{ - int r; - - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - rl_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - - /* XXX - use rl_completion_mode here? */ - if (rl_last_func == dynamic_complete_history) - r = rl_complete_internal ('?'); - else - r = rl_complete_internal (TAB); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - return r; -} - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static int -bash_complete_username (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_username_internal (rl_completion_mode (bash_complete_username)); -} - -static int -bash_possible_username_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_username_internal ('?'); -} - -static int -bash_complete_username_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, rl_username_completion_function); -} - -static int -bash_complete_filename (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_filename_internal (rl_completion_mode (bash_complete_filename)); -} - -static int -bash_possible_filename_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_filename_internal ('?'); -} - -static int -bash_complete_filename_internal (what_to_do) - int what_to_do; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_icppfunc_t *orig_dir_func; - /*const*/ char *orig_rl_completer_word_break_characters; - int r; - - 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 = rl_filename_completion_function; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_directory_completion_hook = (rl_icppfunc_t *)NULL; - rl_completer_word_break_characters = " \t\n\"\'"; - - r = 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; - - return r; -} - -static int -bash_complete_hostname (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_hostname_internal (rl_completion_mode (bash_complete_hostname)); -} - -static int -bash_possible_hostname_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_hostname_internal ('?'); -} - -static int -bash_complete_variable (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_variable_internal (rl_completion_mode (bash_complete_variable)); -} - -static int -bash_possible_variable_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_variable_internal ('?'); -} - -static int -bash_complete_command (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_command_internal (rl_completion_mode (bash_complete_command)); -} - -static int -bash_possible_command_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_command_internal ('?'); -} - -static int -bash_complete_hostname_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, hostname_completion_function); -} - -static int -bash_complete_variable_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, variable_completion_function); -} - -static int -bash_complete_command_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, command_word_completion_function); -} - -static char *globtext; -static char *globorig; - -static char * -glob_complete_word (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static int ind; - int glen; - char *ret; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - if (rl_explicit_arg) - { - globorig = savestring (text); - glen = strlen (text); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, text); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (text); - - matches = shell_glob_filename (globtext); - if (GLOB_FAILED (matches)) - matches = (char **)NULL; - ind = 0; - } - - ret = matches ? matches[ind] : (char *)NULL; - ind++; - return ret; -} - -static int -bash_glob_completion_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, glob_complete_word); -} - -/* A special quoting function so we don't end up quoting globbing characters - in the word if there are no matches or multiple matches. */ -static char * -bash_glob_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) - return (savestring (s)); - else - return (bash_quote_filename (s, rtype, qcp)); -} - -static int -bash_glob_complete_word (count, key) - int count, key; -{ - int r; - rl_quote_func_t *orig_quoting_function; - - if (rl_editing_mode == EMACS_EDITING_MODE) - rl_explicit_arg = 1; /* force `*' append */ - orig_quoting_function = rl_filename_quoting_function; - rl_filename_quoting_function = bash_glob_quote_filename; - - r = bash_glob_completion_internal (rl_completion_mode (bash_glob_complete_word)); - - rl_filename_quoting_function = orig_quoting_function; - return r; -} - -static int -bash_glob_expand_word (count, key) - int count, key; -{ - return bash_glob_completion_internal ('*'); -} - -static int -bash_glob_list_expansions (count, key) - int count, key; -{ - return bash_glob_completion_internal ('?'); -} - -static int -bash_specific_completion (what_to_do, generator) - int what_to_do; - rl_compentry_func_t *generator; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - int r; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - rl_completion_entry_function = generator; - rl_attempted_completion_function = NULL; - - r = rl_complete_internal (what_to_do); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - - return r; -} - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -#if defined (VI_MODE) -/* Completion, from vi mode's point of view. This is a modified version of - rl_vi_complete which uses the bash globbing code to implement what POSIX - specifies, which is to append a `*' and attempt filename generation (which - has the side effect of expanding any globbing characters in the word). */ -static int -bash_vi_complete (count, key) - int count, key; -{ -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - int p, r; - char *t; - - 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++; - } - - /* Find boundaries of current word, according to vi definition of a - `bigword'. */ - t = 0; - if (rl_point > 0) - { - p = rl_point; - rl_vi_bWord (1, 'B'); - r = rl_point; - rl_point = p; - p = r; - - t = substring (rl_line_buffer, p, rl_point); - } - - if (t && glob_pattern_p (t) == 0) - rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ - FREE (t); - - if (key == '*') /* Expansion and replacement. */ - r = bash_glob_expand_word (count, key); - else if (key == '=') /* List possible completions. */ - r = bash_glob_list_expansions (count, key); - else if (key == '\\') /* Standard completion */ - r = bash_glob_complete_word (count, key); - else - r = rl_complete (0, key); - - if (key == '*' || key == '\\') - rl_vi_start_inserting (key, 1, 1); - - return (r); -#else - return rl_vi_complete (count, key); -#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ -} -#endif /* VI_MODE */ - -/* Filename quoting for completion. */ -/* A function to strip unquoted quote characters (single quotes, double - quotes, and backslashes). It allows single quotes to appear - within double quotes, and vice versa. It should be smarter. */ -static char * -bash_dequote_filename (text, quote_char) - char *text; - int quote_char; -{ - char *ret, *p, *r; - int l, quoted; - - l = strlen (text); - ret = (char *)xmalloc (l + 1); - for (quoted = quote_char, p = text, r = ret; p && *p; p++) - { - /* Allow backslash-quoted characters to pass through unscathed. */ - if (*p == '\\') - { - *r++ = *++p; - if (*p == '\0') - break; - continue; - } - /* Close quote. */ - if (quoted && *p == quoted) - { - quoted = 0; - continue; - } - /* Open quote. */ - if (quoted == 0 && (*p == '\'' || *p == '"')) - { - quoted = *p; - continue; - } - *r++ = *p; - } - *r = '\0'; - return ret; -} - -/* Quote characters that the readline completion code would treat as - word break characters with backslashes. Pass backslash-quoted - characters through without examination. */ -static char * -quote_word_break_chars (text) - char *text; -{ - char *ret, *r, *s; - int l; - - l = strlen (text); - ret = (char *)xmalloc ((2 * l) + 1); - for (s = text, r = ret; *s; s++) - { - /* Pass backslash-quoted characters through, including the backslash. */ - if (*s == '\\') - { - *r++ = '\\'; - *r++ = *++s; - if (*s == '\0') - break; - continue; - } - /* OK, we have an unquoted character. Check its presence in - rl_completer_word_break_characters. */ - if (xstrchr (rl_completer_word_break_characters, *s)) - *r++ = '\\'; - *r++ = *s; - } - *r = '\0'; - return ret; -} - -/* Quote a filename using double quotes, single quotes, or backslashes - depending on the value of completion_quoting_style. If we're - completing using backslashes, we need to quote some additional - characters (those that readline treats as word breaks), so we call - quote_word_break_chars on the result. This returns newly-allocated - memory. */ -static char * -bash_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - char *rtext, *mtext, *ret; - int rlen, cs; - - rtext = (char *)NULL; - - /* If RTYPE == MULT_MATCH, it means that there is - more than one match. In this case, we do not add - the closing quote or attempt to perform tilde - expansion. If RTYPE == SINGLE_MATCH, we try - to perform tilde expansion, because single and double - quotes inhibit tilde expansion by the shell. */ - - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH) - mtext = bash_tilde_expand (s, 0); - - cs = completion_quoting_style; - /* Might need to modify the default completion style based on *qcp, - since it's set to any user-provided opening quote. We also change - to single-quoting if there is no user-provided opening quote and - the word being completed contains newlines, since those are not - quoted correctly using backslashes (a backslash-newline pair is - special to the shell parser). */ - if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && xstrchr (mtext, '\n')) - cs = COMPLETE_SQUOTE; - else if (*qcp == '"') - cs = COMPLETE_DQUOTE; - else if (*qcp == '\'') - cs = COMPLETE_SQUOTE; -#if defined (BANG_HISTORY) - else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (mtext, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (mtext, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - switch (cs) - { - case COMPLETE_DQUOTE: - rtext = sh_double_quote (mtext); - break; - case COMPLETE_SQUOTE: - rtext = sh_single_quote (mtext); - break; - case COMPLETE_BSQUOTE: - rtext = sh_backslash_quote (mtext); - break; - } - - if (mtext != s) - free (mtext); - - /* We may need to quote additional characters: those that readline treats - as word breaks that are not quoted by backslash_quote. */ - if (rtext && cs == COMPLETE_BSQUOTE) - { - mtext = quote_word_break_chars (rtext); - free (rtext); - rtext = mtext; - } - - /* Leave the opening quote intact. The readline completion code takes - care of avoiding doubled opening quotes. */ - rlen = strlen (rtext); - ret = (char *)xmalloc (rlen + 1); - strcpy (ret, rtext); - - /* If there are multiple matches, cut off the closing quote. */ - if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) - ret[rlen - 1] = '\0'; - free (rtext); - return ret; -} - -/* Support for binding readline key sequences to Unix commands. */ -static Keymap cmd_xmap; - -static int -bash_execute_unix_command (count, key) - int count; /* ignored */ - int key; -{ - Keymap ckmap; /* current keymap */ - Keymap xkmap; /* unix command executing keymap */ - register int i; - char *cmd; - sh_parser_state_t ps; - - /* First, we need to find the right command to execute. This is tricky, - because we might have already indirected into another keymap. */ - ckmap = rl_get_keymap (); - if (ckmap != rl_executing_keymap) - { - /* bogus. we have to search. only handle one level of indirection. */ - for (i = 0; i < KEYMAP_SIZE; i++) - { - if (ckmap[i].type == ISKMAP && (Keymap)ckmap[i].function == rl_executing_keymap) - break; - } - if (i < KEYMAP_SIZE) - xkmap = (Keymap)cmd_xmap[i].function; - else - { - rl_crlf (); - internal_error (_("bash_execute_unix_command: cannot find keymap for command")); - rl_forced_update_display (); - return 1; - } - } - else - xkmap = cmd_xmap; - - cmd = (char *)xkmap[key].function; - - if (cmd == 0) - { - rl_ding (); - return 1; - } - - rl_crlf (); /* move to a new line */ - - save_parser_state (&ps); - - cmd = savestring (cmd); - parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST); - - restore_parser_state (&ps); - - /* and restore the readline buffer and display after command execution. */ - rl_forced_update_display (); - return 0; -} - -static void -init_unix_command_map () -{ - cmd_xmap = rl_make_bare_keymap (); -} - -static int -isolate_sequence (string, ind, need_dquote, startp) - char *string; - int ind, need_dquote, *startp; -{ - register int i; - int c, passc, delim; - - for (i = ind; string[i] && whitespace (string[i]); i++) - ; - /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ - if (need_dquote && string[i] != '"') - { - builtin_error (_("%s: first non-whitespace character is not `\"'"), string); - return -1; - } - - /* We can have delimited strings even if NEED_DQUOTE == 0, like the command - string to bind the key sequence to. */ - delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; - - if (startp) - *startp = delim ? ++i : i; - - for (passc = 0; c = string[i]; i++) - { - if (passc) - { - passc = 0; - continue; - } - if (c == '\\') - { - passc++; - continue; - } - if (c == delim) - break; - } - - if (delim && string[i] != delim) - { - builtin_error (_("no closing `%c' in %s"), delim, string); - return -1; - } - - return i; -} - -int -bind_keyseq_to_unix_command (line) - char *line; -{ - Keymap kmap; - char *kseq, *value; - int i, kstart; - - if (cmd_xmap == 0) - init_unix_command_map (); - - kmap = rl_get_keymap (); - - /* We duplicate some of the work done by rl_parse_and_bind here, but - this code only has to handle `"keyseq": ["]command["]' and can - generate an error for anything else. */ - i = isolate_sequence (line, 0, 1, &kstart); - if (i < 0) - return -1; - - /* Create the key sequence string to pass to rl_generic_bind */ - kseq = substring (line, kstart, i); - - for ( ; line[i] && line[i] != ':'; i++) - ; - if (line[i] != ':') - { - builtin_error (_("%s: missing colon separator"), line); - return -1; - } - - i = isolate_sequence (line, i + 1, 0, &kstart); - if (i < 0) - return -1; - - /* Create the value string containing the command to execute. */ - value = substring (line, kstart, i); - - /* Save the command to execute and the key sequence in the CMD_XMAP */ - rl_generic_bind (ISMACR, kseq, value, cmd_xmap); - - /* and bind the key sequence in the current keymap to a function that - understands how to execute from CMD_XMAP */ - rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap); - - return 0; -} - -/* Used by the programmable completion code. Complete TEXT as a filename, - but return only directories as matches. Dequotes the filename before - attempting to find matches. */ -char ** -bash_directory_completion_matches (text) - const char *text; -{ - char **m1; - char *dfn; - int qc; - -#if 0 - qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; -#else - qc = rl_dispatching ? rl_completion_quote_character : 0; -#endif - dfn = bash_dequote_filename ((char *)text, qc); - m1 = rl_completion_matches (dfn, rl_filename_completion_function); - free (dfn); - - if (m1 == 0 || m1[0] == 0) - return m1; - /* We don't bother recomputing the lcd of the matches, because it will just - get thrown away by the programmable completion code and recomputed - later. */ - (void)bash_ignore_filenames (m1); - return m1; -} - -char * -bash_dequote_text (text) - const char *text; -{ - char *dtxt; - int qc; - - qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; - dtxt = bash_dequote_filename ((char *)text, qc); - return (dtxt); -} -#endif /* READLINE */ diff --git a/builtins/alias.def~ b/builtins/alias.def~ deleted file mode 100644 index 2ffae2862..000000000 --- a/builtins/alias.def~ +++ /dev/null @@ -1,229 +0,0 @@ -This file is alias.def, from which is created alias.c -It implements the builtins "alias" and "unalias" in Bash. - -Copyright (C) 1987-2002 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$BUILTIN alias -$FUNCTION alias_builtin -$DEPENDS_ON ALIAS -$PRODUCES alias.c -$SHORT_DOC alias [-p] [name[=value] ... ] -`alias' with no arguments or with the -p option prints the list -of aliases in the form alias NAME=VALUE on standard output. -Otherwise, an alias is defined for each NAME whose VALUE is given. -A trailing space in VALUE causes the next word to be checked for -alias substitution when the alias is expanded. Alias returns -true unless a NAME is given for which no alias has been defined. -$END - -#include - -#if defined (ALIAS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -# include "../bashansi.h" - -# include -# include "../shell.h" -# include "../alias.h" -# include "common.h" -# include "bashgetopt.h" - -/* Flags for print_alias */ -#define AL_REUSABLE 0x01 - -static void print_alias __P((alias_t *, int)); - -extern int posixly_correct; - -/* Hack the alias command in a Korn shell way. */ -int -alias_builtin (list) - WORD_LIST *list; -{ - int any_failed, offset, pflag, dflags; - alias_t **alias_list, *t; - char *name, *value; - - dflags = posixly_correct ? 0 : AL_REUSABLE; - pflag = 0; - reset_internal_getopt (); - while ((offset = internal_getopt (list, "p")) != -1) - { - switch (offset) - { - case 'p': - pflag = 1; - dflags |= AL_REUSABLE; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (list == 0 || pflag) - { - if (aliases == 0) - return (EXECUTION_SUCCESS); - - alias_list = all_aliases (); - - if (alias_list == 0) - return (EXECUTION_SUCCESS); - - for (offset = 0; alias_list[offset]; offset++) - print_alias (alias_list[offset], dflags); - - free (alias_list); /* XXX - Do not free the strings. */ - - if (list == 0) - return (EXECUTION_SUCCESS); - } - - any_failed = 0; - while (list) - { - name = list->word->word; - - for (offset = 0; name[offset] && name[offset] != '='; offset++) - ; - - if (offset && name[offset] == '=') - { - name[offset] = '\0'; - value = name + offset + 1; - - if (legal_alias_name (name, 0) == 0) - { - builtin_error ("%s: invalid alias name", name); - any_failed++; - continue; - } - - add_alias (name, value); - } - else - { - t = find_alias (name); - if (t) - print_alias (t, dflags); - else - { - sh_notfound (name); - any_failed++; - } - } - list = list->next; - } - - return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif /* ALIAS */ - -$BUILTIN unalias -$FUNCTION unalias_builtin -$DEPENDS_ON ALIAS -$SHORT_DOC unalias [-a] name [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. */ -int -unalias_builtin (list) - register WORD_LIST *list; -{ - register alias_t *alias; - int opt, aflag; - - aflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "a")) != -1) - { - switch (opt) - { - case 'a': - aflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (aflag) - { - delete_all_aliases (); - return (EXECUTION_SUCCESS); - } - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - aflag = 0; - while (list) - { - alias = find_alias (list->word->word); - - if (alias) - remove_alias (alias->name); - else - { - sh_notfound (list->word->word); - aflag++; - } - - list = list->next; - } - - return (aflag ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} - -/* Output ALIAS in such a way as to allow it to be read back in. */ -static void -print_alias (alias, flags) - alias_t *alias; - int flags; -{ - char *value; - - value = sh_single_quote (alias->value); - if (flags & AL_REUSABLE) - printf ("alias "); - printf ("%s=%s\n", alias->name, value); - free (value); - - fflush (stdout); -} -#endif /* ALIAS */ diff --git a/builtins/cd.def.orig b/builtins/cd.def.orig deleted file mode 100644 index a9024769b..000000000 --- a/builtins/cd.def.orig +++ /dev/null @@ -1,484 +0,0 @@ -This file is cd.def, from which is created cd.c. It implements the -builtins "cd" and "pwd" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES cd.c -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashtypes.h" -#include "posixdir.h" -#include "posixstat.h" -#ifndef _MINIX -#include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include -#include - -#include "../shell.h" -#include "../flags.h" -#include "maxpath.h" -#include "common.h" -#include "bashgetopt.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; -extern int array_needs_making; -extern char *bash_getcwd_errstr; - -static int bindpwd __P((int)); -static int change_to_directory __P((char *, int)); - -static char *cdspell __P((char *)); - -/* Change this to 1 to get cd spelling correction by default. */ -int cdspelling = 0; - -int cdable_vars; - -$BUILTIN cd -$FUNCTION cd_builtin -$SHORT_DOC cd [-L|-P] [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 in CDPATH -are separated by a colon (:). A null directory name is the same as -the current directory, i.e. `.'. If DIR begins with a slash (/), -then CDPATH is not used. If the directory is not found, and the -shell option `cdable_vars' is set, then try the word as a variable -name. If that variable has a value, then cd to the value of that -variable. The -P option says to use the physical directory structure -instead of following symbolic links; the -L option forces symbolic links -to be followed. -$END - -static int -bindpwd (no_symlinks) - int no_symlinks; -{ - char *dirname, *pwdvar; - int old_anm; - SHELL_VAR *tvar; - -#define tcwd the_current_working_directory - dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("cd"); -#undef tcwd - - old_anm = array_needs_making; - pwdvar = get_string_value ("PWD"); - - tvar = bind_variable ("OLDPWD", pwdvar); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("OLDPWD=", 7, pwdvar); - array_needs_making = 0; - } - - tvar = bind_variable ("PWD", dirname); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("PWD=", 4, dirname); - array_needs_making = 0; - } - - if (dirname && dirname != the_current_working_directory) - free (dirname); - return (EXECUTION_SUCCESS); -} - -/* Call get_working_directory to reset the value of - the_current_working_directory () */ -static char * -resetpwd (caller) - char *caller; -{ - char *tdir; - - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - tdir = get_working_directory (caller); - return (tdir); -} - -#define LCD_DOVARS 0x001 -#define LCD_DOSPELL 0x002 -#define LCD_PRINTPATH 0x004 -#define LCD_FREEDIRNAME 0x010 - -/* 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, *cdpath, *path, *temp; - int path_index, no_symlinks, opt, lflag; - -#if defined (RESTRICTED_SHELL) - if (restricted) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif /* RESTRICTED_SHELL */ - - no_symlinks = no_symbolic_links; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - no_symlinks = 1; - break; - case 'L': - no_symlinks = 0; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - - lflag = (cdable_vars ? LCD_DOVARS : 0) | - ((interactive && cdspelling) ? LCD_DOSPELL : 0); - - if (list == 0) - { - /* `cd' without arguments is equivalent to `cd $HOME' */ - dirname = get_string_value ("HOME"); - - if (dirname == 0) - { - builtin_error (_("HOME not set")); - return (EXECUTION_FAILURE); - } - lflag = 0; - } - else if (list->word->word[0] == '-' && list->word->word[1] == '\0') - { - /* This is `cd -', equivalent to `cd $OLDPWD' */ - dirname = get_string_value ("OLDPWD"); - - if (dirname == 0) - { - builtin_error (_("OLDPWD not set")); - return (EXECUTION_FAILURE); - } -#if 0 - lflag = interactive ? LCD_PRINTPATH : 0; -#else - lflag = LCD_PRINTPATH; /* According to SUSv3 */ -#endif - } - else if (absolute_pathname (list->word->word)) - dirname = list->word->word; - else if (cdpath = get_string_value ("CDPATH")) - { - dirname = list->word->word; - - /* Find directory in $CDPATH. */ - path_index = 0; - while (path = extract_colon_unit (cdpath, &path_index)) - { - /* OPT is 1 if the path element is non-empty */ - opt = path[0] != '\0'; - temp = sh_makepath (path, dirname, MP_DOTILDE); - free (path); - - if (change_to_directory (temp, no_symlinks)) - { - /* POSIX.2 says that if a nonempty directory from CDPATH - is used to find the directory to change to, the new - directory name is echoed to stdout, whether or not - the shell is interactive. */ - if (opt && (path = no_symlinks ? temp : the_current_working_directory)) - printf ("%s\n", path); - - free (temp); - /* Posix.2 says that after using CDPATH, the resultant - value of $PWD will not contain `.' or `..'. */ - return (bindpwd (posixly_correct || no_symlinks)); - } - else - free (temp); - } - - /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't - try the current directory, so we just punt now with an error - message if POSIXLY_CORRECT is non-zero. The check for cdpath[0] - is so we don't mistakenly treat a CDPATH value of "" as not - specifying the current directory. */ - if (posixly_correct && cdpath[0]) - { - builtin_error ("%s: %s", dirname, strerror (ENOENT)); - return (EXECUTION_FAILURE); - } - } - else - dirname = list->word->word; - - /* When we get here, DIRNAME is the directory to change to. If we - chdir successfully, just return. */ - if (change_to_directory (dirname, no_symlinks)) - { - if (lflag & LCD_PRINTPATH) - printf ("%s\n", dirname); - return (bindpwd (no_symlinks)); - } - - /* If the user requests it, then perhaps this is the name of - a shell variable, whose value contains the directory to - change to. */ - if (lflag & LCD_DOVARS) - { - temp = get_string_value (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - return (bindpwd (no_symlinks)); - } - } - - /* If the user requests it, try to find a directory name similar in - spelling to the one requested, in case the user made a simple - typo. This is similar to the UNIX 8th and 9th Edition shells. */ - if (lflag & LCD_DOSPELL) - { - temp = cdspell (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - return (bindpwd (no_symlinks)); - } - else - FREE (temp); - } - - builtin_error ("%s: %s", dirname, strerror (errno)); - return (EXECUTION_FAILURE); -} - -$BUILTIN pwd -$FUNCTION pwd_builtin -$SHORT_DOC pwd [-PL] -Print the current working directory. With the -P option, pwd prints -the physical directory, without any symbolic links; the -L option -makes pwd follow symbolic links. -$END - -/* Non-zero means that pwd always prints the physical directory, without - symbolic links. */ -static int verbatim_pwd; - -/* Print the name of the current working directory. */ -int -pwd_builtin (list) - WORD_LIST *list; -{ - char *directory; - int opt; - - verbatim_pwd = no_symbolic_links; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - verbatim_pwd = 1; - break; - case 'L': - verbatim_pwd = 0; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - -#define tcwd the_current_working_directory - - directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("pwd"); - - /* Try again using getcwd() if canonicalization fails (for instance, if - the file system has changed state underneath bash). */ - if (tcwd && directory == 0) - directory = resetpwd ("pwd"); - -#undef tcwd - - if (directory) - { - printf ("%s\n", directory); - if (directory != the_current_working_directory) - free (directory); - fflush (stdout); - if (ferror (stdout)) - { - builtin_error (_("write error: %s"), strerror (errno)); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); - } - else - return (EXECUTION_FAILURE); -} - -/* Do the work of changing to the directory NEWDIR. Handle symbolic - link following, etc. This function *must* return with - the_current_working_directory either set to NULL (in which case - getcwd() will eventually be called), or set to a string corresponding - to the working directory. Return 1 on success, 0 on failure. */ - -static int -change_to_directory (newdir, nolinks) - char *newdir; - int nolinks; -{ - char *t, *tdir; - int err, canon_failed; - - tdir = (char *)NULL; - - if (the_current_working_directory == 0) - { - t = get_working_directory ("chdir"); - FREE (t); - } - - t = make_absolute (newdir, the_current_working_directory); - - /* TDIR is either the canonicalized absolute pathname of NEWDIR - (nolinks == 0) or the absolute physical pathname of NEWDIR - (nolinks != 0). */ - tdir = nolinks ? sh_physpath (t, 0) - : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* Use the canonicalized version of NEWDIR, or, if canonicalization - failed, use the non-canonical form. */ - canon_failed = 0; - if (tdir && *tdir) - free (t); - else - { - FREE (tdir); - tdir = t; - canon_failed = 1; - } - - /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath - returns NULL (because it checks the path, it will return NULL if the - resolved path doesn't exist), fail immediately. */ - if (posixly_correct && nolinks == 0 && canon_failed) - { - if (errno != ENOENT) - errno = ENOTDIR; - return (0); - } - - /* If the chdir succeeds, update the_current_working_directory. */ - if (chdir (nolinks ? newdir : tdir) == 0) - { - /* If canonicalization failed, but the chdir succeeded, reset the - shell's idea of the_current_working_directory. */ - if (canon_failed) - resetpwd ("cd"); - else - { - FREE (the_current_working_directory); - the_current_working_directory = tdir; - } - - return (1); - } - - /* We failed to change to the appropriate directory name. If we tried - what the user passed (nolinks != 0), punt now. */ - if (nolinks) - return (0); - - err = errno; - free (tdir); - - /* We're not in physical mode (nolinks == 0), but we failed to change to - the canonicalized directory name (TDIR). Try what the user passed - verbatim. If we succeed, reinitialize the_current_working_directory. */ - if (chdir (newdir) == 0) - { - tdir = resetpwd ("cd"); - FREE (tdir); - - return (1); - } - else - { - errno = err; - return (0); - } -} - -/* Code for cd spelling correction. Original patch submitted by - Neil Russel (caret@c-side.com). */ - -static char * -cdspell (dirname) - char *dirname; -{ - int n; - char *guess; - - n = (strlen (dirname) * 3 + 1) / 2 + 1; - guess = (char *)xmalloc (n); - - switch (spname (dirname, guess)) - { - case -1: - default: - free (guess); - return (char *)NULL; - case 0: - case 1: - return guess; - } -} diff --git a/builtins/cd.def~ b/builtins/cd.def~ deleted file mode 100644 index d63e93c51..000000000 --- a/builtins/cd.def~ +++ /dev/null @@ -1,494 +0,0 @@ -This file is cd.def, from which is created cd.c. It implements the -builtins "cd" and "pwd" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES cd.c -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashtypes.h" -#include "posixdir.h" -#include "posixstat.h" -#ifndef _MINIX -#include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include -#include - -#include "../shell.h" -#include "../flags.h" -#include "maxpath.h" -#include "common.h" -#include "bashgetopt.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; -extern int array_needs_making; -extern char *bash_getcwd_errstr; - -static int bindpwd __P((int)); -static int change_to_directory __P((char *, int)); - -static char *cdspell __P((char *)); - -/* Change this to 1 to get cd spelling correction by default. */ -int cdspelling = 0; - -int cdable_vars; - -$BUILTIN cd -$FUNCTION cd_builtin -$SHORT_DOC cd [-L|-P] [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 in CDPATH -are separated by a colon (:). A null directory name is the same as -the current directory, i.e. `.'. If DIR begins with a slash (/), -then CDPATH is not used. If the directory is not found, and the -shell option `cdable_vars' is set, then try the word as a variable -name. If that variable has a value, then cd to the value of that -variable. The -P option says to use the physical directory structure -instead of following symbolic links; the -L option forces symbolic links -to be followed. -$END - -static int -bindpwd (no_symlinks) - int no_symlinks; -{ - char *dirname, *pwdvar; - int old_anm; - SHELL_VAR *tvar; - -#define tcwd the_current_working_directory - dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("cd"); -#undef tcwd - - old_anm = array_needs_making; - pwdvar = get_string_value ("PWD"); - - tvar = bind_variable ("OLDPWD", pwdvar); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("OLDPWD=", 7, pwdvar); - array_needs_making = 0; - } - - tvar = bind_variable ("PWD", dirname); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("PWD=", 4, dirname); - array_needs_making = 0; - } - - if (dirname && dirname != the_current_working_directory) - free (dirname); - return (EXECUTION_SUCCESS); -} - -/* Call get_working_directory to reset the value of - the_current_working_directory () */ -static char * -resetpwd (caller) - char *caller; -{ - char *tdir; - - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - tdir = get_working_directory (caller); - return (tdir); -} - -#define LCD_DOVARS 0x001 -#define LCD_DOSPELL 0x002 -#define LCD_PRINTPATH 0x004 -#define LCD_FREEDIRNAME 0x010 - -/* 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, *cdpath, *path, *temp; - int path_index, no_symlinks, opt, lflag; - -#if defined (RESTRICTED_SHELL) - if (restricted) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif /* RESTRICTED_SHELL */ - - no_symlinks = no_symbolic_links; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - no_symlinks = 1; - break; - case 'L': - no_symlinks = 0; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - - lflag = (cdable_vars ? LCD_DOVARS : 0) | - ((interactive && cdspelling) ? LCD_DOSPELL : 0); - - if (list == 0) - { - /* `cd' without arguments is equivalent to `cd $HOME' */ - dirname = get_string_value ("HOME"); - - if (dirname == 0) - { - builtin_error (_("HOME not set")); - return (EXECUTION_FAILURE); - } - lflag = 0; - } - else if (list->word->word[0] == '-' && list->word->word[1] == '\0') - { - /* This is `cd -', equivalent to `cd $OLDPWD' */ - dirname = get_string_value ("OLDPWD"); - - if (dirname == 0) - { - builtin_error (_("OLDPWD not set")); - return (EXECUTION_FAILURE); - } -#if 0 - lflag = interactive ? LCD_PRINTPATH : 0; -#else - lflag = LCD_PRINTPATH; /* According to SUSv3 */ -#endif - } - else if (absolute_pathname (list->word->word)) - dirname = list->word->word; - else if (cdpath = get_string_value ("CDPATH")) - { - dirname = list->word->word; - - /* Find directory in $CDPATH. */ - path_index = 0; - while (path = extract_colon_unit (cdpath, &path_index)) - { - /* OPT is 1 if the path element is non-empty */ - opt = path[0] != '\0'; - temp = sh_makepath (path, dirname, MP_DOTILDE); - free (path); - - if (change_to_directory (temp, no_symlinks)) - { - /* POSIX.2 says that if a nonempty directory from CDPATH - is used to find the directory to change to, the new - directory name is echoed to stdout, whether or not - the shell is interactive. */ - if (opt && (path = no_symlinks ? temp : the_current_working_directory)) - printf ("%s\n", path); - - free (temp); - /* Posix.2 says that after using CDPATH, the resultant - value of $PWD will not contain `.' or `..'. */ - return (bindpwd (posixly_correct || no_symlinks)); - } - else - free (temp); - } - - /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't - try the current directory, so we just punt now with an error - message if POSIXLY_CORRECT is non-zero. The check for cdpath[0] - is so we don't mistakenly treat a CDPATH value of "" as not - specifying the current directory. */ - if (posixly_correct && cdpath[0]) - { - builtin_error ("%s: %s", dirname, strerror (ENOENT)); - return (EXECUTION_FAILURE); - } - } - else - dirname = list->word->word; - - /* When we get here, DIRNAME is the directory to change to. If we - chdir successfully, just return. */ - if (change_to_directory (dirname, no_symlinks)) - { - if (lflag & LCD_PRINTPATH) - printf ("%s\n", dirname); - return (bindpwd (no_symlinks)); - } - - /* If the user requests it, then perhaps this is the name of - a shell variable, whose value contains the directory to - change to. */ - if (lflag & LCD_DOVARS) - { - temp = get_string_value (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - return (bindpwd (no_symlinks)); - } - } - - /* If the user requests it, try to find a directory name similar in - spelling to the one requested, in case the user made a simple - typo. This is similar to the UNIX 8th and 9th Edition shells. */ - if (lflag & LCD_DOSPELL) - { - temp = cdspell (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - return (bindpwd (no_symlinks)); - } - else - FREE (temp); - } - - builtin_error ("%s: %s", dirname, strerror (errno)); - return (EXECUTION_FAILURE); -} - -$BUILTIN pwd -$FUNCTION pwd_builtin -$SHORT_DOC pwd [-PL] -Print the current working directory. With the -P option, pwd prints -the physical directory, without any symbolic links; the -L option -makes pwd follow symbolic links. -$END - -/* Non-zero means that pwd always prints the physical directory, without - symbolic links. */ -static int verbatim_pwd; - -/* Print the name of the current working directory. */ -int -pwd_builtin (list) - WORD_LIST *list; -{ - char *directory; - int opt; - - verbatim_pwd = no_symbolic_links; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - verbatim_pwd = 1; - break; - case 'L': - verbatim_pwd = 0; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - -#define tcwd the_current_working_directory - - directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("pwd"); - - /* Try again using getcwd() if canonicalization fails (for instance, if - the file system has changed state underneath bash). */ - if (tcwd && directory == 0) - directory = resetpwd ("pwd"); - -#undef tcwd - - if (directory) - { - printf ("%s\n", directory); - if (directory != the_current_working_directory) - free (directory); - fflush (stdout); - if (ferror (stdout)) - { - builtin_error (_("write error: %s"), strerror (errno)); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); - } - else - return (EXECUTION_FAILURE); -} - -/* Do the work of changing to the directory NEWDIR. Handle symbolic - link following, etc. This function *must* return with - the_current_working_directory either set to NULL (in which case - getcwd() will eventually be called), or set to a string corresponding - to the working directory. Return 1 on success, 0 on failure. */ - -static int -change_to_directory (newdir, nolinks) - char *newdir; - int nolinks; -{ - char *t, *tdir; - int err, canon_failed, r; - - tdir = (char *)NULL; - - if (the_current_working_directory == 0) - { - t = get_working_directory ("chdir"); - FREE (t); - } - - t = make_absolute (newdir, the_current_working_directory); - - /* TDIR is either the canonicalized absolute pathname of NEWDIR - (nolinks == 0) or the absolute physical pathname of NEWDIR - (nolinks != 0). */ - tdir = nolinks ? sh_physpath (t, 0) - : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* Use the canonicalized version of NEWDIR, or, if canonicalization - failed, use the non-canonical form. */ - canon_failed = 0; - if (tdir && *tdir) - free (t); - else - { - FREE (tdir); - tdir = t; - canon_failed = 1; - } - - /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath - returns NULL (because it checks the path, it will return NULL if the - resolved path doesn't exist), fail immediately. */ - if (posixly_correct && nolinks == 0 && canon_failed) - { -#if defined ENAMETOOLONG - if (errno != ENOENT && errno != ENAMETOOLONG) -#else - if (errno != ENOENT) -#endif - errno = ENOTDIR; - return (0); - } - - /* If the chdir succeeds, update the_current_working_directory. */ - if (chdir (nolinks ? newdir : tdir) == 0) - { - /* If canonicalization failed, but the chdir succeeded, reset the - shell's idea of the_current_working_directory. */ - if (canon_failed) - { - t = resetpwd ("cd"); - if (t == 0) - set_working_directory (tdir); - } - else - set_working_directory (tdir); - - return (1); - } - - /* We failed to change to the appropriate directory name. If we tried - what the user passed (nolinks != 0), punt now. */ - if (nolinks) - return (0); - - err = errno; - - /* We're not in physical mode (nolinks == 0), but we failed to change to - the canonicalized directory name (TDIR). Try what the user passed - verbatim. If we succeed, reinitialize the_current_working_directory. */ - if (chdir (newdir) == 0) - { - t = resetpwd ("cd"); - if (t == 0) - set_working_directory (tdir); - else - free (t); - - r = 1; - } - else - { - errno = err; - r = 0; - } - - free (tdir); - return r; -} - -/* Code for cd spelling correction. Original patch submitted by - Neil Russel (caret@c-side.com). */ - -static char * -cdspell (dirname) - char *dirname; -{ - int n; - char *guess; - - n = (strlen (dirname) * 3 + 1) / 2 + 1; - guess = (char *)xmalloc (n); - - switch (spname (dirname, guess)) - { - case -1: - default: - free (guess); - return (char *)NULL; - case 0: - case 1: - return guess; - } -} diff --git a/builtins/common.c.orig b/builtins/common.c.orig deleted file mode 100644 index 2715f28c4..000000000 --- a/builtins/common.c.orig +++ /dev/null @@ -1,815 +0,0 @@ -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include -#include "../bashtypes.h" -#include "posixstat.h" -#include - -#include - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "maxpath.h" -#include "../flags.h" -#include "../jobs.h" -#include "../builtins.h" -#include "../input.h" -#include "../execute_cmd.h" -#include "../trap.h" -#include "bashgetopt.h" -#include "common.h" -#include "builtext.h" -#include - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int indirection_level, subshell_environment; -extern int line_number; -extern int last_command_exit_value; -extern int running_trap; -extern int posixly_correct; -extern char *this_command_name, *shell_name; -extern char *bash_getcwd_errstr; - -/* Used by some builtins and the mainline code. */ -sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL; -sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL; - -/* **************************************************************** */ -/* */ -/* Error reporting, usage, and option processing */ -/* */ -/* **************************************************************** */ - -/* This is a lot like report_error (), but it is for shell builtins - instead of shell control structures, and it won't ever exit the - shell. */ -void -#if defined (PREFER_STDARG) -builtin_error (const char *format, ...) -#else -builtin_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - char *name; - - name = get_name_for_error (); - fprintf (stderr, "%s: ", name); - - if (interactive_shell == 0) - fprintf (stderr, "line %d: ", executing_line_number ()); - - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} - -/* Print a usage summary for the currently-executing builtin command. */ -void -builtin_usage () -{ - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: usage: ", this_command_name); - fprintf (stderr, "%s\n", current_builtin->short_doc); - fflush (stderr); -} - -/* Return if LIST is NULL else barf and jump to top_level. Used by some - builtins that do not accept arguments. */ -void -no_args (list) - WORD_LIST *list; -{ - if (list) - { - builtin_error (_("too many arguments")); - jump_to_top_level (DISCARD); - } -} - -/* Check that no options were given to the currently-executing builtin, - and return 0 if there were options. */ -int -no_options (list) - WORD_LIST *list; -{ - reset_internal_getopt (); - if (internal_getopt (list, "") != -1) - { - builtin_usage (); - return (1); - } - return (0); -} - -void -sh_needarg (s) - char *s; -{ - builtin_error (_("%s: option requires an argument"), s); -} - -void -sh_neednumarg (s) - char *s; -{ - builtin_error (_("%s: numeric argument required"), s); -} - -void -sh_notfound (s) - char *s; -{ - builtin_error (_("%s: not found"), s); -} - -/* Function called when one of the builtin commands detects an invalid - option. */ -void -sh_invalidopt (s) - char *s; -{ - builtin_error (_("%s: invalid option"), s); -} - -void -sh_invalidoptname (s) - char *s; -{ - builtin_error (_("%s: invalid option name"), s); -} - -void -sh_invalidid (s) - char *s; -{ - builtin_error (_("`%s': not a valid identifier"), s); -} - -void -sh_invalidnum (s) - char *s; -{ - builtin_error (_("%s: invalid number"), s); -} - -void -sh_invalidsig (s) - char *s; -{ - builtin_error (_("%s: invalid signal specification"), s); -} - -void -sh_badpid (s) - char *s; -{ - builtin_error (_("`%s': not a pid or valid job spec"), s); -} - -void -sh_readonly (s) - const char *s; -{ - builtin_error (_("%s: readonly variable"), s); -} - -void -sh_erange (s, desc) - char *s, *desc; -{ - if (s) - builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument")); - else - builtin_error (_("%s out of range"), desc ? desc : _("argument")); -} - -#if defined (JOB_CONTROL) -void -sh_badjob (s) - char *s; -{ - builtin_error (_("%s: no such job"), s); -} - -void -sh_nojobs (s) - char *s; -{ - if (s) - builtin_error (_("%s: no job control"), s); - else - builtin_error (_("no job control")); -} -#endif - -#if defined (RESTRICTED_SHELL) -void -sh_restricted (s) - char *s; -{ - if (s) - builtin_error (_("%s: restricted"), s); - else - builtin_error (_("restricted")); -} -#endif - -void -sh_notbuiltin (s) - char *s; -{ - builtin_error (_("%s: not a shell builtin"), s); -} - -/* **************************************************************** */ -/* */ -/* Shell positional parameter manipulation */ -/* */ -/* **************************************************************** */ - -/* Convert a WORD_LIST into a C-style argv. Return the number of elements - in the list in *IP, if IP is non-null. A convenience function for - loadable builtins; also used by `test'. */ -char ** -make_builtin_argv (list, ip) - WORD_LIST *list; - int *ip; -{ - char **argv; - - argv = strvec_from_word_list (list, 0, 1, ip); - argv[0] = this_command_name; - return argv; -} - -/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is - non-zero, then discard whatever the existing arguments are, else - 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 || list) && dollar_vars[i]) - { - free (dollar_vars[i]); - dollar_vars[i] = (char *)NULL; - } - - if (list) - { - 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 (); -} - -static int changed_dollar_vars; - -/* Have the dollar variables been reset to new values since we last - checked? */ -int -dollar_vars_changed () -{ - return (changed_dollar_vars); -} - -void -set_dollar_vars_unchanged () -{ - changed_dollar_vars = 0; -} - -void -set_dollar_vars_changed () -{ - if (variable_context) - changed_dollar_vars |= ARGS_FUNC; - else if (this_shell_builtin == set_builtin) - changed_dollar_vars |= ARGS_SETBLTIN; - else - changed_dollar_vars |= ARGS_INVOC; -} - -/* **************************************************************** */ -/* */ -/* Validating numeric input and arguments */ -/* */ -/* **************************************************************** */ - -/* Read a numeric arg for this_command_name, the name of the shell builtin - that wants it. LIST is the word list that the arg is to come from. - Accept only the numeric argument; report an error if other arguments - follow. If FATAL is true, call throw_to_top_level, which exits the - shell; if not, call jump_to_top_level (DISCARD), which aborts the - current command. */ -intmax_t -get_numeric_arg (list, fatal) - WORD_LIST *list; - int fatal; -{ - intmax_t count = 1; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list) - { - register char *arg; - - arg = list->word->word; - if (arg == 0 || (legal_number (arg, &count) == 0)) - { - sh_neednumarg (list->word->word); - if (fatal) - throw_to_top_level (); - else - jump_to_top_level (DISCARD); - } - no_args (list->next); - } - - return (count); -} - -/* Get an eight-bit status value from LIST */ -int -get_exitstat (list) - WORD_LIST *list; -{ - int status; - intmax_t sval; - char *arg; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list == 0) - return (last_command_exit_value); - - arg = list->word->word; - if (arg == 0 || legal_number (arg, &sval) == 0) - { - sh_neednumarg (list->word->word ? list->word->word : "`'"); - return 255; - } - no_args (list->next); - - status = sval & 255; - return status; -} - -/* Return the octal number parsed from STRING, or -1 to indicate - that the string contained a bad number. */ -int -read_octal (string) - char *string; -{ - int result, digits; - - result = digits = 0; - while (*string && ISOCTAL (*string)) - { - digits++; - result = (result * 8) + (*string++ - '0'); - if (result > 0777) - return -1; - } - - if (digits == 0 || *string) - result = -1; - - return (result); -} - -/* **************************************************************** */ -/* */ -/* Manipulating the current working directory */ -/* */ -/* **************************************************************** */ - -/* Return a consed string which is the current working directory. - FOR_WHOM is the name of the caller for error printing. */ -char *the_current_working_directory = (char *)NULL; - -char * -get_working_directory (for_whom) - char *for_whom; -{ - char *directory; - size_t dsize; - - if (no_symbolic_links) - { - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - } - - if (the_current_working_directory == 0) - { -#if defined (HAVE_PATHCONF) - dsize = pathconf (".", _PC_PATH_MAX); -#else - dsize = PATH_MAX; -#endif - - the_current_working_directory = (char *)xmalloc (dsize+1); - the_current_working_directory[0] = '\0'; - directory = getcwd (the_current_working_directory, dsize); - if (directory == 0) - { - fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"), - (for_whom && *for_whom) ? for_whom : get_name_for_error (), - _(bash_getcwd_errstr), strerror (errno)); - - 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; -{ - FREE (the_current_working_directory); - the_current_working_directory = savestring (name); -} - -/* **************************************************************** */ -/* */ -/* Job control support functions */ -/* */ -/* **************************************************************** */ - -#if defined (JOB_CONTROL) -int -get_job_by_name (name, flags) - const char *name; - int flags; -{ - register int i, wl, cl, match, job; - register PROCESS *p; - - job = NO_JOB; - wl = strlen (name); - for (i = job_slots - 1; i >= 0; i--) - { - if (jobs[i] == 0 || ((flags & JM_STOPPED) && JOBSTATE(i) != JSTOPPED)) - continue; - - p = jobs[i]->pipe; - do - { - if (flags & JM_EXACT) - { - cl = strlen (p->command); - match = STREQN (p->command, name, cl); - } - else if (flags & JM_SUBSTRING) - match = strindex (p->command, name) != (char *)0; - else - match = STREQN (p->command, name, wl); - - if (match == 0) - { - p = p->next; - continue; - } - else if (flags & JM_FIRSTMATCH) - return i; /* return first match */ - else if (job != NO_JOB) - { - if (this_shell_builtin) - builtin_error (_("%s: ambiguous job spec"), name); - else - report_error (_("%s: ambiguous job spec"), name); - return (DUP_JOB); - } - else - job = i; - } - while (p != jobs[i]->pipe); - } - - return (job); -} - -/* Return the job spec found in LIST. */ -int -get_job_spec (list) - WORD_LIST *list; -{ - register char *word; - int job, jflags; - - if (list == 0) - return (current_job); - - word = list->word->word; - - if (*word == '\0') - return (NO_JOB); - - if (*word == '%') - word++; - - if (DIGIT (*word) && all_digits (word)) - { - job = atoi (word); - return (job > job_slots ? NO_JOB : job - 1); - } - - jflags = 0; - switch (*word) - { - case 0: - return NO_JOB; - case '%': - case '+': - return (current_job); - - case '-': - return (previous_job); - - case '?': /* Substring search requested. */ - jflags |= JM_SUBSTRING; - word++; - /* FALLTHROUGH */ - - default: - return get_job_by_name (word, jflags); - } -} -#endif /* JOB_CONTROL */ - -/* - * NOTE: `kill' calls this function with forcecols == 0 - */ -int -display_signal_list (list, forcecols) - WORD_LIST *list; - int forcecols; -{ - register int i, column; - char *name; - int result, signum, dflags; - intmax_t lsignum; - - result = EXECUTION_SUCCESS; - if (!list) - { - for (i = 1, column = 0; i < NSIG; i++) - { - name = signal_name (i); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - continue; - - if (posixly_correct && !forcecols) - { - /* This is for the kill builtin. POSIX.2 says the signal names - are displayed without the `SIG' prefix. */ - if (STREQN (name, "SIG", 3)) - name += 3; - 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 && !forcecols) || column != 0) - printf ("\n"); - return result; - } - - /* List individual signal names or numbers. */ - while (list) - { - if (legal_number (list->word->word, &lsignum)) - { - /* This is specified by Posix.2 so that exit statuses can be - mapped into signal numbers. */ - if (lsignum > 128) - lsignum -= 128; - if (lsignum < 0 || lsignum >= NSIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - - signum = lsignum; - name = signal_name (signum); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - { - list = list->next; - continue; - } -#if defined (JOB_CONTROL) - /* POSIX.2 says that `kill -l signum' prints the signal name without - the `SIG' prefix. */ - printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name); -#else - printf ("%s\n", name); -#endif - } - else - { - dflags = DSIG_NOCASE; - if (posixly_correct == 0 || this_shell_builtin != kill_builtin) - dflags |= DSIG_SIGPREFIX; - signum = decode_signal (list->word->word, dflags); - if (signum == NO_SIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - printf ("%d\n", signum); - } - list = list->next; - } - return (result); -} - -/* **************************************************************** */ -/* */ -/* Finding builtin commands and their functions */ -/* */ -/* **************************************************************** */ - -/* Perform a binary search and return the address of the builtin function - whose name is NAME. If the function couldn't be found, or the builtin - is disabled or has no function associated with it, return NULL. - Return the address of the builtin. - DISABLED_OKAY means find it even if the builtin is disabled. */ -struct builtin * -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, - and it must not have been deleted. */ - if (shell_builtins[mid].function && - ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) && - ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay)) - return (&shell_builtins[mid]); - else - return ((struct builtin *)NULL); - } - if (j > 0) - hi = mid - 1; - else - lo = mid + 1; - } - return ((struct builtin *)NULL); -} - -/* Return the pointer to the function implementing builtin command NAME. */ -sh_builtin_func_t * -find_shell_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the address of builtin with NAME, whether it is enabled or not. */ -sh_builtin_func_t * -builtin_address (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 1); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the function implementing the builtin NAME, but only if it is a - POSIX.2 special builtin. */ -sh_builtin_func_t * -find_special_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ? - current_builtin->function : - (sh_builtin_func_t *)NULL); -} - -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), - (QSFUNC *)shell_builtin_compare); -} diff --git a/builtins/common.c~ b/builtins/common.c~ deleted file mode 100644 index 2715f28c4..000000000 --- a/builtins/common.c~ +++ /dev/null @@ -1,815 +0,0 @@ -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include -#include "../bashtypes.h" -#include "posixstat.h" -#include - -#include - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "maxpath.h" -#include "../flags.h" -#include "../jobs.h" -#include "../builtins.h" -#include "../input.h" -#include "../execute_cmd.h" -#include "../trap.h" -#include "bashgetopt.h" -#include "common.h" -#include "builtext.h" -#include - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int indirection_level, subshell_environment; -extern int line_number; -extern int last_command_exit_value; -extern int running_trap; -extern int posixly_correct; -extern char *this_command_name, *shell_name; -extern char *bash_getcwd_errstr; - -/* Used by some builtins and the mainline code. */ -sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL; -sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL; - -/* **************************************************************** */ -/* */ -/* Error reporting, usage, and option processing */ -/* */ -/* **************************************************************** */ - -/* This is a lot like report_error (), but it is for shell builtins - instead of shell control structures, and it won't ever exit the - shell. */ -void -#if defined (PREFER_STDARG) -builtin_error (const char *format, ...) -#else -builtin_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - char *name; - - name = get_name_for_error (); - fprintf (stderr, "%s: ", name); - - if (interactive_shell == 0) - fprintf (stderr, "line %d: ", executing_line_number ()); - - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} - -/* Print a usage summary for the currently-executing builtin command. */ -void -builtin_usage () -{ - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: usage: ", this_command_name); - fprintf (stderr, "%s\n", current_builtin->short_doc); - fflush (stderr); -} - -/* Return if LIST is NULL else barf and jump to top_level. Used by some - builtins that do not accept arguments. */ -void -no_args (list) - WORD_LIST *list; -{ - if (list) - { - builtin_error (_("too many arguments")); - jump_to_top_level (DISCARD); - } -} - -/* Check that no options were given to the currently-executing builtin, - and return 0 if there were options. */ -int -no_options (list) - WORD_LIST *list; -{ - reset_internal_getopt (); - if (internal_getopt (list, "") != -1) - { - builtin_usage (); - return (1); - } - return (0); -} - -void -sh_needarg (s) - char *s; -{ - builtin_error (_("%s: option requires an argument"), s); -} - -void -sh_neednumarg (s) - char *s; -{ - builtin_error (_("%s: numeric argument required"), s); -} - -void -sh_notfound (s) - char *s; -{ - builtin_error (_("%s: not found"), s); -} - -/* Function called when one of the builtin commands detects an invalid - option. */ -void -sh_invalidopt (s) - char *s; -{ - builtin_error (_("%s: invalid option"), s); -} - -void -sh_invalidoptname (s) - char *s; -{ - builtin_error (_("%s: invalid option name"), s); -} - -void -sh_invalidid (s) - char *s; -{ - builtin_error (_("`%s': not a valid identifier"), s); -} - -void -sh_invalidnum (s) - char *s; -{ - builtin_error (_("%s: invalid number"), s); -} - -void -sh_invalidsig (s) - char *s; -{ - builtin_error (_("%s: invalid signal specification"), s); -} - -void -sh_badpid (s) - char *s; -{ - builtin_error (_("`%s': not a pid or valid job spec"), s); -} - -void -sh_readonly (s) - const char *s; -{ - builtin_error (_("%s: readonly variable"), s); -} - -void -sh_erange (s, desc) - char *s, *desc; -{ - if (s) - builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument")); - else - builtin_error (_("%s out of range"), desc ? desc : _("argument")); -} - -#if defined (JOB_CONTROL) -void -sh_badjob (s) - char *s; -{ - builtin_error (_("%s: no such job"), s); -} - -void -sh_nojobs (s) - char *s; -{ - if (s) - builtin_error (_("%s: no job control"), s); - else - builtin_error (_("no job control")); -} -#endif - -#if defined (RESTRICTED_SHELL) -void -sh_restricted (s) - char *s; -{ - if (s) - builtin_error (_("%s: restricted"), s); - else - builtin_error (_("restricted")); -} -#endif - -void -sh_notbuiltin (s) - char *s; -{ - builtin_error (_("%s: not a shell builtin"), s); -} - -/* **************************************************************** */ -/* */ -/* Shell positional parameter manipulation */ -/* */ -/* **************************************************************** */ - -/* Convert a WORD_LIST into a C-style argv. Return the number of elements - in the list in *IP, if IP is non-null. A convenience function for - loadable builtins; also used by `test'. */ -char ** -make_builtin_argv (list, ip) - WORD_LIST *list; - int *ip; -{ - char **argv; - - argv = strvec_from_word_list (list, 0, 1, ip); - argv[0] = this_command_name; - return argv; -} - -/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is - non-zero, then discard whatever the existing arguments are, else - 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 || list) && dollar_vars[i]) - { - free (dollar_vars[i]); - dollar_vars[i] = (char *)NULL; - } - - if (list) - { - 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 (); -} - -static int changed_dollar_vars; - -/* Have the dollar variables been reset to new values since we last - checked? */ -int -dollar_vars_changed () -{ - return (changed_dollar_vars); -} - -void -set_dollar_vars_unchanged () -{ - changed_dollar_vars = 0; -} - -void -set_dollar_vars_changed () -{ - if (variable_context) - changed_dollar_vars |= ARGS_FUNC; - else if (this_shell_builtin == set_builtin) - changed_dollar_vars |= ARGS_SETBLTIN; - else - changed_dollar_vars |= ARGS_INVOC; -} - -/* **************************************************************** */ -/* */ -/* Validating numeric input and arguments */ -/* */ -/* **************************************************************** */ - -/* Read a numeric arg for this_command_name, the name of the shell builtin - that wants it. LIST is the word list that the arg is to come from. - Accept only the numeric argument; report an error if other arguments - follow. If FATAL is true, call throw_to_top_level, which exits the - shell; if not, call jump_to_top_level (DISCARD), which aborts the - current command. */ -intmax_t -get_numeric_arg (list, fatal) - WORD_LIST *list; - int fatal; -{ - intmax_t count = 1; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list) - { - register char *arg; - - arg = list->word->word; - if (arg == 0 || (legal_number (arg, &count) == 0)) - { - sh_neednumarg (list->word->word); - if (fatal) - throw_to_top_level (); - else - jump_to_top_level (DISCARD); - } - no_args (list->next); - } - - return (count); -} - -/* Get an eight-bit status value from LIST */ -int -get_exitstat (list) - WORD_LIST *list; -{ - int status; - intmax_t sval; - char *arg; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list == 0) - return (last_command_exit_value); - - arg = list->word->word; - if (arg == 0 || legal_number (arg, &sval) == 0) - { - sh_neednumarg (list->word->word ? list->word->word : "`'"); - return 255; - } - no_args (list->next); - - status = sval & 255; - return status; -} - -/* Return the octal number parsed from STRING, or -1 to indicate - that the string contained a bad number. */ -int -read_octal (string) - char *string; -{ - int result, digits; - - result = digits = 0; - while (*string && ISOCTAL (*string)) - { - digits++; - result = (result * 8) + (*string++ - '0'); - if (result > 0777) - return -1; - } - - if (digits == 0 || *string) - result = -1; - - return (result); -} - -/* **************************************************************** */ -/* */ -/* Manipulating the current working directory */ -/* */ -/* **************************************************************** */ - -/* Return a consed string which is the current working directory. - FOR_WHOM is the name of the caller for error printing. */ -char *the_current_working_directory = (char *)NULL; - -char * -get_working_directory (for_whom) - char *for_whom; -{ - char *directory; - size_t dsize; - - if (no_symbolic_links) - { - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - } - - if (the_current_working_directory == 0) - { -#if defined (HAVE_PATHCONF) - dsize = pathconf (".", _PC_PATH_MAX); -#else - dsize = PATH_MAX; -#endif - - the_current_working_directory = (char *)xmalloc (dsize+1); - the_current_working_directory[0] = '\0'; - directory = getcwd (the_current_working_directory, dsize); - if (directory == 0) - { - fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"), - (for_whom && *for_whom) ? for_whom : get_name_for_error (), - _(bash_getcwd_errstr), strerror (errno)); - - 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; -{ - FREE (the_current_working_directory); - the_current_working_directory = savestring (name); -} - -/* **************************************************************** */ -/* */ -/* Job control support functions */ -/* */ -/* **************************************************************** */ - -#if defined (JOB_CONTROL) -int -get_job_by_name (name, flags) - const char *name; - int flags; -{ - register int i, wl, cl, match, job; - register PROCESS *p; - - job = NO_JOB; - wl = strlen (name); - for (i = job_slots - 1; i >= 0; i--) - { - if (jobs[i] == 0 || ((flags & JM_STOPPED) && JOBSTATE(i) != JSTOPPED)) - continue; - - p = jobs[i]->pipe; - do - { - if (flags & JM_EXACT) - { - cl = strlen (p->command); - match = STREQN (p->command, name, cl); - } - else if (flags & JM_SUBSTRING) - match = strindex (p->command, name) != (char *)0; - else - match = STREQN (p->command, name, wl); - - if (match == 0) - { - p = p->next; - continue; - } - else if (flags & JM_FIRSTMATCH) - return i; /* return first match */ - else if (job != NO_JOB) - { - if (this_shell_builtin) - builtin_error (_("%s: ambiguous job spec"), name); - else - report_error (_("%s: ambiguous job spec"), name); - return (DUP_JOB); - } - else - job = i; - } - while (p != jobs[i]->pipe); - } - - return (job); -} - -/* Return the job spec found in LIST. */ -int -get_job_spec (list) - WORD_LIST *list; -{ - register char *word; - int job, jflags; - - if (list == 0) - return (current_job); - - word = list->word->word; - - if (*word == '\0') - return (NO_JOB); - - if (*word == '%') - word++; - - if (DIGIT (*word) && all_digits (word)) - { - job = atoi (word); - return (job > job_slots ? NO_JOB : job - 1); - } - - jflags = 0; - switch (*word) - { - case 0: - return NO_JOB; - case '%': - case '+': - return (current_job); - - case '-': - return (previous_job); - - case '?': /* Substring search requested. */ - jflags |= JM_SUBSTRING; - word++; - /* FALLTHROUGH */ - - default: - return get_job_by_name (word, jflags); - } -} -#endif /* JOB_CONTROL */ - -/* - * NOTE: `kill' calls this function with forcecols == 0 - */ -int -display_signal_list (list, forcecols) - WORD_LIST *list; - int forcecols; -{ - register int i, column; - char *name; - int result, signum, dflags; - intmax_t lsignum; - - result = EXECUTION_SUCCESS; - if (!list) - { - for (i = 1, column = 0; i < NSIG; i++) - { - name = signal_name (i); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - continue; - - if (posixly_correct && !forcecols) - { - /* This is for the kill builtin. POSIX.2 says the signal names - are displayed without the `SIG' prefix. */ - if (STREQN (name, "SIG", 3)) - name += 3; - 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 && !forcecols) || column != 0) - printf ("\n"); - return result; - } - - /* List individual signal names or numbers. */ - while (list) - { - if (legal_number (list->word->word, &lsignum)) - { - /* This is specified by Posix.2 so that exit statuses can be - mapped into signal numbers. */ - if (lsignum > 128) - lsignum -= 128; - if (lsignum < 0 || lsignum >= NSIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - - signum = lsignum; - name = signal_name (signum); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - { - list = list->next; - continue; - } -#if defined (JOB_CONTROL) - /* POSIX.2 says that `kill -l signum' prints the signal name without - the `SIG' prefix. */ - printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name); -#else - printf ("%s\n", name); -#endif - } - else - { - dflags = DSIG_NOCASE; - if (posixly_correct == 0 || this_shell_builtin != kill_builtin) - dflags |= DSIG_SIGPREFIX; - signum = decode_signal (list->word->word, dflags); - if (signum == NO_SIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - printf ("%d\n", signum); - } - list = list->next; - } - return (result); -} - -/* **************************************************************** */ -/* */ -/* Finding builtin commands and their functions */ -/* */ -/* **************************************************************** */ - -/* Perform a binary search and return the address of the builtin function - whose name is NAME. If the function couldn't be found, or the builtin - is disabled or has no function associated with it, return NULL. - Return the address of the builtin. - DISABLED_OKAY means find it even if the builtin is disabled. */ -struct builtin * -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, - and it must not have been deleted. */ - if (shell_builtins[mid].function && - ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) && - ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay)) - return (&shell_builtins[mid]); - else - return ((struct builtin *)NULL); - } - if (j > 0) - hi = mid - 1; - else - lo = mid + 1; - } - return ((struct builtin *)NULL); -} - -/* Return the pointer to the function implementing builtin command NAME. */ -sh_builtin_func_t * -find_shell_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the address of builtin with NAME, whether it is enabled or not. */ -sh_builtin_func_t * -builtin_address (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 1); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the function implementing the builtin NAME, but only if it is a - POSIX.2 special builtin. */ -sh_builtin_func_t * -find_special_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ? - current_builtin->function : - (sh_builtin_func_t *)NULL); -} - -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), - (QSFUNC *)shell_builtin_compare); -} diff --git a/builtins/common.h~ b/builtins/common.h~ deleted file mode 100644 index 309bb6d86..000000000 --- a/builtins/common.h~ +++ /dev/null @@ -1,161 +0,0 @@ -/* common.h -- extern declarations for functions defined in common.c. */ - -/* Copyright (C) 1993-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (__COMMON_H) -# define __COMMON_H - -#include "stdc.h" - -#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c) - -/* Flag values for parse_and_execute () */ -#define SEVAL_NONINT 0x001 -#define SEVAL_INTERACT 0x002 -#define SEVAL_NOHIST 0x004 -#define SEVAL_NOFREE 0x008 -#define SEVAL_RESETLINE 0x010 - -/* Flags for describe_command, shared between type.def and command.def */ -#define CDESC_ALL 0x001 /* type -a */ -#define CDESC_SHORTDESC 0x002 /* command -V */ -#define CDESC_REUSABLE 0x004 /* command -v */ -#define CDESC_TYPE 0x008 /* type -t */ -#define CDESC_PATH_ONLY 0x010 /* type -p */ -#define CDESC_FORCE_PATH 0x020 /* type -ap or type -P */ -#define CDESC_NOFUNCS 0x040 /* type -f */ - -/* Flags for get_job_by_name */ -#define JM_PREFIX 0x01 /* prefix of job name */ -#define JM_SUBSTRING 0x02 /* substring of job name */ -#define JM_EXACT 0x04 /* match job name exactly */ -#define JM_STOPPED 0x08 /* match stopped jobs only */ -#define JM_FIRSTMATCH 0x10 /* return first matching job */ - -/* Flags for remember_args and value of changed_dollar_vars */ -#define ARGS_NONE 0x0 -#define ARGS_INVOC 0x01 -#define ARGS_FUNC 0x02 -#define ARGS_SETBLTIN 0x04 - -/* Functions from common.c */ -extern void builtin_error __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -extern void builtin_usage __P((void)); -extern void no_args __P((WORD_LIST *)); -extern int no_options __P((WORD_LIST *)); - -/* common error message functions */ -extern void sh_needarg __P((char *)); -extern void sh_neednumarg __P((char *)); -extern void sh_notfound __P((char *)); -extern void sh_invalidopt __P((char *)); -extern void sh_invalidoptname __P((char *)); -extern void sh_invalidid __P((char *)); -extern void sh_invalidnum __P((char *)); -extern void sh_invalidsig __P((char *)); -extern void sh_erange __P((char *, char *)); -extern void sh_badpid __P((char *)); -extern void sh_badjob __P((char *)); -extern void sh_readonly __P((const char *)); -extern void sh_nojobs __P((char *)); -extern void sh_restricted __P((char *)); -extern void sh_notbuiltin __P((char *)); - -extern char **make_builtin_argv __P((WORD_LIST *, int *)); -extern void remember_args __P((WORD_LIST *, int)); - -extern int dollar_vars_changed __P((void)); -extern void set_dollar_vars_unchanged __P((void)); -extern void set_dollar_vars_changed __P((void)); - -extern intmax_t get_numeric_arg __P((WORD_LIST *, int)); -extern int get_exitstat __P((WORD_LIST *)); -extern int read_octal __P((char *)); - -/* Keeps track of the current working directory. */ -extern char *the_current_working_directory; -extern char *get_working_directory __P((char *)); -extern void set_working_directory __P((char *)); - -#if defined (JOB_CONTROL) -extern int get_job_by_name __P((const char *, int)); -extern int get_job_spec __P((WORD_LIST *)); -#endif -extern int display_signal_list __P((WORD_LIST *, int)); - -/* It's OK to declare a function as returning a Function * without - providing a definition of what a `Function' is. */ -extern struct builtin *builtin_address_internal __P((char *, int)); -extern sh_builtin_func_t *find_shell_builtin __P((char *)); -extern sh_builtin_func_t *builtin_address __P((char *)); -extern sh_builtin_func_t *find_special_builtin __P((char *)); -extern void initialize_shell_builtins __P((void)); - -/* Functions from exit.def */ -extern void bash_logout __P((void)); - -/* Functions from getopts.def */ -extern void getopts_reset __P((int)); - -/* Functions from set.def */ -extern int minus_o_option_value __P((char *)); -extern void list_minus_o_opts __P((int, int)); -extern char **get_minus_o_opts __P((void)); -extern int set_minus_o_option __P((int, char *)); - -extern void set_shellopts __P((void)); -extern void parse_shellopts __P((char *)); -extern void initialize_shell_options __P((int)); - -extern void reset_shell_options __P((void)); - -/* Functions from shopt.def */ -extern void reset_shopt_options __P((void)); -extern char **get_shopt_options __P((void)); - -extern int shopt_setopt __P((char *, int)); -extern int shopt_listopt __P((char *, int)); - -extern int set_login_shell __P((int)); - -/* Functions from type.def */ -extern int describe_command __P((char *, int)); - -/* Functions from setattr.def */ -extern int set_or_show_attributes __P((WORD_LIST *, int, int)); -extern int show_var_attributes __P((SHELL_VAR *, int, int)); -extern int show_name_attributes __P((char *, int)); -extern void set_var_attribute __P((char *, int, int)); - -/* Functions from pushd.def */ -extern char *get_dirstack_from_string __P((char *)); -extern char *get_dirstack_element __P((intmax_t, int)); -extern void set_dirstack_element __P((intmax_t, int, char *)); -extern WORD_LIST *get_directory_stack __P((void)); - -/* Functions from evalstring.c */ -extern int parse_and_execute __P((char *, const char *, int)); -extern void parse_and_execute_cleanup __P((void)); - -/* Functions from evalfile.c */ -extern int maybe_execute_file __P((const char *, int)); -extern int source_file __P((const char *, int)); -extern int fc_execute_file __P((const char *)); - -#endif /* !__COMMON_H */ diff --git a/builtins/getopts.def~ b/builtins/getopts.def~ deleted file mode 100644 index 6cd40d322..000000000 --- a/builtins/getopts.def~ +++ /dev/null @@ -1,322 +0,0 @@ -This file is getopts.def, from which is created getopts.c. -It implements the builtin "getopts" in Bash. - -Copyright (C) 1987-2002 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES getopts.c - -$BUILTIN getopts -$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 invalid 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 invalid option is seen, getopts places '?' into -NAME and unsets OPTARG. If a required argument 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 - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" -#include "getopt.h" - -#define G_EOF -1 -#define G_INVALID_OPT -2 -#define G_ARG_MISSING -3 - -extern char *this_command_name; - -static int getopts_bind_variable __P((char *, char *)); -static int dogetopts __P((int, char **)); - -/* 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; - sh_badopt = 0; -} - -static int -getopts_bind_variable (name, value) - char *name, *value; -{ - SHELL_VAR *v; - - if (legal_identifier (name)) - { - v = bind_variable (name, value); - return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; - } - else - { - sh_invalidid (name); - return (EXECUTION_FAILURE); - } -} - -/* 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 invalid option characters. The handling is as follows. - - INVALID 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, 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_usage (); - 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) - { - for (i = 0; i < 10 && dollar_vars[i]; i++) - ; - - sh_getopt_restore_state (dollar_vars); - ret = sh_getopt (i, dollar_vars, optstr); - } - else - { - 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 = strvec_create (i + 1); - 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; - sh_getopt_restore_state (v); - 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. It's - highly unlikely that 14 digits will be too few. */ - 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 OPTOPT. If an invalid option was encountered, OPTARG is - NULL. If a required option argument was missing, OPTARG points - to a NULL string (that is, sh_optarg[0] == 0). */ - if (ret == '?') - { - if (sh_optarg == NULL) - ret = G_INVALID_OPT; - else if (sh_optarg[0] == '\0') - ret = G_ARG_MISSING; - } - - if (ret == G_EOF) - { - getopts_bind_variable (name, "?"); - return (EXECUTION_FAILURE); - } - - if (ret == G_INVALID_OPT) - { - /* Invalid option encountered. */ - ret = getopts_bind_variable (name, "?"); - - if (special_error) - { - strval[0] = (char)sh_optopt; - strval[1] = '\0'; - bind_variable ("OPTARG", strval); - } - else - unbind_variable ("OPTARG"); - - return (ret); - } - - if (ret == G_ARG_MISSING) - { - /* Required argument missing. */ - if (special_error) - { - ret = getopts_bind_variable (name, ":"); - - strval[0] = (char)sh_optopt; - strval[1] = '\0'; - bind_variable ("OPTARG", strval); - } - else - { - ret = getopts_bind_variable (name, "?"); - unbind_variable ("OPTARG"); - } - return (ret); - } - - bind_variable ("OPTARG", sh_optarg); - - strval[0] = (char) ret; - strval[1] = '\0'; - return (getopts_bind_variable (name, strval)); -} - -/* The getopts builtin. Build an argv, and call dogetopts with it. */ -int -getopts_builtin (list) - WORD_LIST *list; -{ - char **av; - int ac, ret; - - if (list == 0) - { - builtin_usage (); - return EX_USAGE; - } - - reset_internal_getopt (); - if (internal_getopt (list, "") != -1) - { - builtin_usage (); - return (EX_USAGE); - } - list = loptend; - - av = make_builtin_argv (list, &ac); - ret = dogetopts (ac, av); - free ((char *)av); - - return (ret); -} diff --git a/builtins/jobs.def.save1 b/builtins/jobs.def.save1 deleted file mode 100644 index a1f75ae29..000000000 --- a/builtins/jobs.def.save1 +++ /dev/null @@ -1,281 +0,0 @@ -This file is jobs.def, from which is created jobs.c. -It implements the builtins "jobs" and "disown" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES jobs.c - -$BUILTIN jobs -$FUNCTION jobs_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args] -Lists the active jobs. The -l option lists process id's in addition -to the normal information; the -p option lists process id's only. -If -n is given, only processes that have changed status since the last -notification are printed. JOBSPEC restricts output to that job. The --r and -s options restrict output to running and stopped jobs only, -respectively. Without options, the status of all active jobs is -printed. If -x is given, COMMAND is run after all job specifications -that appear in ARGS have been replaced with the process ID of that job's -process group leader. -$END - -#include - -#if defined (JOB_CONTROL) -#include "../bashtypes.h" -#include -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../jobs.h" -#include "../execute_cmd.h" -#include "bashgetopt.h" -#include "common.h" - -#define JSTATE_ANY 0x0 -#define JSTATE_RUNNING 0x1 -#define JSTATE_STOPPED 0x2 - -static int execute_list_with_replacements __P((WORD_LIST *)); - -/* 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. The -r and -s options mean - to print info about running and stopped jobs only, respectively. */ -int -jobs_builtin (list) - WORD_LIST *list; -{ - int form, execute, state, opt, any_failed, job; - sigset_t set, oset; - - if (job_control == 0 && interactive_shell == 0) - return (EXECUTION_SUCCESS); - - execute = any_failed = 0; - form = JLIST_STANDARD; - state = JSTATE_ANY; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "lpnxrs")) != -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 (_("no other options allowed with `-x'")); - return (EXECUTION_FAILURE); - } - execute++; - break; - case 'r': - state = JSTATE_RUNNING; - break; - case 's': - state = JSTATE_STOPPED; - break; - - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (execute) - return (execute_list_with_replacements (list)); - - if (!list) - { - switch (state) - { - case JSTATE_ANY: - list_all_jobs (form); - break; - case JSTATE_RUNNING: - list_running_jobs (form); - break; - case JSTATE_STOPPED: - list_stopped_jobs (form); - break; - } - return (EXECUTION_SUCCESS); - } - - while (list) - { - BLOCK_CHILD (set, oset); - job = get_job_spec (list); - - if ((job == NO_JOB) || !jobs || !jobs[job]) - { - sh_badjob (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; - COMMAND *command; - - /* 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 = 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; - - add_unwind_protect (dispose_command, command); - result = execute_command (command); - dispose_command (command); - - discard_unwind_frame ("jobs_builtin"); - return (result); -} -#endif /* JOB_CONTROL */ - -$BUILTIN disown -$FUNCTION disown_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC disown [-h] [-ar] [jobspec ...] -By default, removes each JOBSPEC argument from the table of active jobs. -If the -h option is given, the job is not removed from the table, but is -marked so that SIGHUP is not sent to the job if the shell receives a -SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all -jobs from the job table; the -r option means to remove only running jobs. -$END - -#if defined (JOB_CONTROL) -int -disown_builtin (list) - WORD_LIST *list; -{ - int opt, job, retval, nohup_only, running_jobs, all_jobs; - sigset_t set, oset; - intmax_t pid_value; - - nohup_only = running_jobs = all_jobs = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "ahr")) != -1) - { - switch (opt) - { - case 'a': - all_jobs = 1; - break; - case 'h': - nohup_only = 1; - break; - case 'r': - running_jobs = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - retval = EXECUTION_SUCCESS; - - /* `disown -a' or `disown -r' */ - if (list == 0 && (all_jobs || running_jobs)) - { - if (nohup_only) - nohup_all_jobs (running_jobs); - else - delete_all_jobs (running_jobs); - return (EXECUTION_SUCCESS); - } - - do - { - BLOCK_CHILD (set, oset); - job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value) - ? get_job_by_pid ((pid_t) pid_value, 0) - : get_job_spec (list); - - if (job == NO_JOB || jobs == 0 || job < 0 || job >= job_slots || jobs[job] == 0) - { - sh_badjob (list ? list->word->word : "current"); - retval = EXECUTION_FAILURE; - } - else if (nohup_only) - nohup_job (job); - else - delete_job (job, 1); - UNBLOCK_CHILD (oset); - - if (list) - list = list->next; - } - while (list); - - return (retval); -} -#endif /* JOB_CONTROL */ diff --git a/builtins/jobs.def~ b/builtins/jobs.def~ deleted file mode 100644 index 38e2232c7..000000000 --- a/builtins/jobs.def~ +++ /dev/null @@ -1,283 +0,0 @@ -This file is jobs.def, from which is created jobs.c. -It implements the builtins "jobs" and "disown" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES jobs.c - -$BUILTIN jobs -$FUNCTION jobs_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args] -Lists the active jobs. The -l option lists process id's in addition -to the normal information; the -p option lists process id's only. -If -n is given, only processes that have changed status since the last -notification are printed. JOBSPEC restricts output to that job. The --r and -s options restrict output to running and stopped jobs only, -respectively. Without options, the status of all active jobs is -printed. If -x is given, COMMAND is run after all job specifications -that appear in ARGS have been replaced with the process ID of that job's -process group leader. -$END - -#include - -#if defined (JOB_CONTROL) -#include "../bashtypes.h" -#include -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../jobs.h" -#include "../execute_cmd.h" -#include "bashgetopt.h" -#include "common.h" - -#define JSTATE_ANY 0x0 -#define JSTATE_RUNNING 0x1 -#define JSTATE_STOPPED 0x2 - -static int execute_list_with_replacements __P((WORD_LIST *)); - -/* 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. The -r and -s options mean - to print info about running and stopped jobs only, respectively. */ -int -jobs_builtin (list) - WORD_LIST *list; -{ - int form, execute, state, opt, any_failed, job; - sigset_t set, oset; - -#if 0 - if (job_control == 0 && interactive_shell == 0) - return (EXECUTION_SUCCESS); -#endif - - execute = any_failed = 0; - form = JLIST_STANDARD; - state = JSTATE_ANY; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "lpnxrs")) != -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 (_("no other options allowed with `-x'")); - return (EXECUTION_FAILURE); - } - execute++; - break; - case 'r': - state = JSTATE_RUNNING; - break; - case 's': - state = JSTATE_STOPPED; - break; - - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (execute) - return (execute_list_with_replacements (list)); - - if (!list) - { - switch (state) - { - case JSTATE_ANY: - list_all_jobs (form); - break; - case JSTATE_RUNNING: - list_running_jobs (form); - break; - case JSTATE_STOPPED: - list_stopped_jobs (form); - break; - } - return (EXECUTION_SUCCESS); - } - - while (list) - { - BLOCK_CHILD (set, oset); - job = get_job_spec (list); - - if ((job == NO_JOB) || !jobs || !jobs[job]) - { - sh_badjob (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; - COMMAND *command; - - /* 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 = 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; - - add_unwind_protect (dispose_command, command); - result = execute_command (command); - dispose_command (command); - - discard_unwind_frame ("jobs_builtin"); - return (result); -} -#endif /* JOB_CONTROL */ - -$BUILTIN disown -$FUNCTION disown_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC disown [-h] [-ar] [jobspec ...] -By default, removes each JOBSPEC argument from the table of active jobs. -If the -h option is given, the job is not removed from the table, but is -marked so that SIGHUP is not sent to the job if the shell receives a -SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all -jobs from the job table; the -r option means to remove only running jobs. -$END - -#if defined (JOB_CONTROL) -int -disown_builtin (list) - WORD_LIST *list; -{ - int opt, job, retval, nohup_only, running_jobs, all_jobs; - sigset_t set, oset; - intmax_t pid_value; - - nohup_only = running_jobs = all_jobs = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "ahr")) != -1) - { - switch (opt) - { - case 'a': - all_jobs = 1; - break; - case 'h': - nohup_only = 1; - break; - case 'r': - running_jobs = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - retval = EXECUTION_SUCCESS; - - /* `disown -a' or `disown -r' */ - if (list == 0 && (all_jobs || running_jobs)) - { - if (nohup_only) - nohup_all_jobs (running_jobs); - else - delete_all_jobs (running_jobs); - return (EXECUTION_SUCCESS); - } - - do - { - BLOCK_CHILD (set, oset); - job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value) - ? get_job_by_pid ((pid_t) pid_value, 0) - : get_job_spec (list); - - if (job == NO_JOB || jobs == 0 || job < 0 || job >= job_slots || jobs[job] == 0) - { - sh_badjob (list ? list->word->word : "current"); - retval = EXECUTION_FAILURE; - } - else if (nohup_only) - nohup_job (job); - else - delete_job (job, 1); - UNBLOCK_CHILD (oset); - - if (list) - list = list->next; - } - while (list); - - return (retval); -} -#endif /* JOB_CONTROL */ diff --git a/builtins/kill.def.save1 b/builtins/kill.def.save1 deleted file mode 100644 index fcd5f4685..000000000 --- a/builtins/kill.def.save1 +++ /dev/null @@ -1,250 +0,0 @@ -This file is kill.def, from which is created kill.c. -It implements the builtin "kill" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES kill.c - -$BUILTIN kill -$FUNCTION kill_builtin -$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] [pid | job]... or kill -l [sigspec] -Send the processes named by PID (or JOB) the signal SIGSPEC. If -SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l' -lists the signal names; if arguments follow `-l' they are assumed to -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 - -#include - -#include -#include -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../trap.h" -#include "../jobs.h" -#include "common.h" - -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; - -static void kill_error __P((pid_t, int)); - -#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 sig, any_succeeded, listing, saw_signal, dflags; - char *sigspec, *word; - pid_t pid; - intmax_t pid_value; - - if (list == 0) - { - builtin_usage (); - return (EXECUTION_FAILURE); - } - - any_succeeded = listing = saw_signal = 0; - sig = SIGTERM; - sigspec = "TERM"; - - dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0); - /* Process options. */ - while (list) - { - word = list->word->word; - - if (ISOPTION (word, 'l')) - { - listing++; - list = list->next; - } - else if (ISOPTION (word, 's') || ISOPTION (word, 'n')) - { - list = list->next; - if (list) - { - sigspec = list->word->word; - if (sigspec[0] == '0' && sigspec[1] == '\0') - sig = 0; - else - sig = decode_signal (sigspec, dflags); - list = list->next; - } - else - { - sh_needarg (word); - return (EXECUTION_FAILURE); - } - } - else if (ISOPTION (word, '-')) - { - list = list->next; - break; - } - else if (ISOPTION (word, '?')) - { - builtin_usage (); - return (EXECUTION_SUCCESS); - } - /* If this is a signal specification then process it. We only process - the first one seen; other arguments may signify process groups (e.g, - -num == process group num). */ - else if ((*word == '-') && !saw_signal) - { - sigspec = word + 1; - sig = decode_signal (sigspec, dflags); - saw_signal++; - list = list->next; - } - else - break; - } - - if (listing) - return (display_signal_list (list, 0)); - - /* OK, we are killing processes. */ - if (sig == NO_SIG) - { - sh_invalidsig (sigspec); - return (EXECUTION_FAILURE); - } - - if (list == 0) - { - builtin_usage (); - return (EXECUTION_FAILURE); - } - - while (list) - { - word = list->word->word; - - if (*word == '-') - word++; - - /* Use the entire argument in case of minus sign presence. */ - if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value)) - { - pid = (pid_t) pid_value; - - if ((pid < -1 ? kill_pid (-pid, sig, 1) : kill_pid (pid, sig, 0)) < 0) - { - if (errno == EINVAL) - sh_invalidsig (sigspec); - else - kill_error (pid, errno); - CONTINUE_OR_FAIL; - } - else - any_succeeded++; - } -#if defined (JOB_CONTROL) - else if (*list->word->word && *list->word->word != '%') - { - builtin_error (_("%s: arguments must be process or job IDs"), list->word->word); - CONTINUE_OR_FAIL; - } - else if (*word && (interactive || job_control)) - /* Posix.2 says you can kill without job control active (4.32.4) */ - { /* 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) - sh_badjob (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. */ - pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid; - - UNBLOCK_CHILD (oset); - - if (kill_pid (pid, sig, 1) < 0) - { - if (errno == EINVAL) - sh_invalidsig (sigspec); - else - kill_error (pid, errno); - CONTINUE_OR_FAIL; - } - else - any_succeeded++; - } -#endif /* !JOB_CONTROL */ - else - { - sh_badpid (list->word->word); - CONTINUE_OR_FAIL; - } - continue_killing: - list = list->next; - } - - return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -static void -kill_error (pid, e) - pid_t pid; - int e; -{ - char *x; - - x = strerror (e); - if (x == 0) - x = _("Unknown error"); - builtin_error ("(%ld) - %s", (long)pid, x); -} diff --git a/builtins/kill.def~ b/builtins/kill.def~ deleted file mode 100644 index 77f52afcb..000000000 --- a/builtins/kill.def~ +++ /dev/null @@ -1,250 +0,0 @@ -This file is kill.def, from which is created kill.c. -It implements the builtin "kill" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES kill.c - -$BUILTIN kill -$FUNCTION kill_builtin -$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] [pid | job]... or kill -l [sigspec] -Send the processes named by PID (or JOB) the signal SIGSPEC. If -SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l' -lists the signal names; if arguments follow `-l' they are assumed to -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 - -#include - -#include -#include -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../trap.h" -#include "../jobs.h" -#include "common.h" - -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; - -static void kill_error __P((pid_t, int)); - -#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 sig, any_succeeded, listing, saw_signal, dflags; - char *sigspec, *word; - pid_t pid; - intmax_t pid_value; - - if (list == 0) - { - builtin_usage (); - return (EXECUTION_FAILURE); - } - - any_succeeded = listing = saw_signal = 0; - sig = SIGTERM; - sigspec = "TERM"; - - dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0); - /* Process options. */ - while (list) - { - word = list->word->word; - - if (ISOPTION (word, 'l')) - { - listing++; - list = list->next; - } - else if (ISOPTION (word, 's') || ISOPTION (word, 'n')) - { - list = list->next; - if (list) - { - sigspec = list->word->word; - if (sigspec[0] == '0' && sigspec[1] == '\0') - sig = 0; - else - sig = decode_signal (sigspec, dflags); - list = list->next; - } - else - { - sh_needarg (word); - return (EXECUTION_FAILURE); - } - } - else if (ISOPTION (word, '-')) - { - list = list->next; - break; - } - else if (ISOPTION (word, '?')) - { - builtin_usage (); - return (EXECUTION_SUCCESS); - } - /* If this is a signal specification then process it. We only process - the first one seen; other arguments may signify process groups (e.g, - -num == process group num). */ - else if ((*word == '-') && !saw_signal) - { - sigspec = word + 1; - sig = decode_signal (sigspec, dflags); - saw_signal++; - list = list->next; - } - else - break; - } - - if (listing) - return (display_signal_list (list, 0)); - - /* OK, we are killing processes. */ - if (sig == NO_SIG) - { - sh_invalidsig (sigspec); - return (EXECUTION_FAILURE); - } - - if (list == 0) - { - builtin_usage (); - return (EXECUTION_FAILURE); - } - - while (list) - { - word = list->word->word; - - if (*word == '-') - word++; - - /* Use the entire argument in case of minus sign presence. */ - if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value)) - { - pid = (pid_t) pid_value; - - if ((pid < -1 ? kill_pid (-pid, sig, 1) : kill_pid (pid, sig, 0)) < 0) - { - if (errno == EINVAL) - sh_invalidsig (sigspec); - else - kill_error (pid, errno); - CONTINUE_OR_FAIL; - } - else - any_succeeded++; - } -#if defined (JOB_CONTROL) - else if (*list->word->word && *list->word->word != '%') - { - builtin_error (_("%s: arguments must be process or job IDs"), list->word->word); - CONTINUE_OR_FAIL; - } - else if (*word) - /* Posix.2 says you can kill without job control active (4.32.4) */ - { /* 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) - sh_badjob (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. */ - pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid; - - UNBLOCK_CHILD (oset); - - if (kill_pid (pid, sig, 1) < 0) - { - if (errno == EINVAL) - sh_invalidsig (sigspec); - else - kill_error (pid, errno); - CONTINUE_OR_FAIL; - } - else - any_succeeded++; - } -#endif /* !JOB_CONTROL */ - else - { - sh_badpid (list->word->word); - CONTINUE_OR_FAIL; - } - continue_killing: - list = list->next; - } - - return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -static void -kill_error (pid, e) - pid_t pid; - int e; -{ - char *x; - - x = strerror (e); - if (x == 0) - x = _("Unknown error"); - builtin_error ("(%ld) - %s", (long)pid, x); -} diff --git a/builtins/read.def~ b/builtins/read.def~ deleted file mode 100644 index 30c893aec..000000000 --- a/builtins/read.def~ +++ /dev/null @@ -1,736 +0,0 @@ -This file is read.def, from which is created read.c. -It implements the builtin "read" in Bash. - -Copyright (C) 1987-2003 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES read.c - -$BUILTIN read -$FUNCTION read_builtin -$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] -One line is read from the standard input, or from file descriptor FD if the --u option is supplied, and the first word is assigned to the first NAME, -the second word to the second NAME, and so on, with leftover words assigned -to the last NAME. Only the characters found in $IFS are recognized as word -delimiters. If no NAMEs are supplied, the line read is stored in the REPLY -variable. If the -r option is given, this signifies `raw' input, and -backslash escaping is disabled. The -d option causes read to continue -until the first character of DELIM is read, rather than newline. If the -p -option is supplied, the string PROMPT is output without a trailing newline -before attempting to read. If -a is supplied, the words read are assigned -to sequential indices of ARRAY, starting at zero. If -e is supplied and -the shell is interactive, readline is used to obtain the line. If -n is -supplied with a non-zero NCHARS argument, read returns after NCHARS -characters have been read. The -s option causes input coming from a -terminal to not be echoed. - -The -t option causes read to time out and return failure if a complete line -of input is not read within TIMEOUT seconds. If the TMOUT variable is set, -its value is the default timeout. The return code is zero, unless end-of-file -is encountered, read times out, or an invalid file descriptor is supplied as -the argument to -u. -$END - -#include - -#include "bashtypes.h" -#include "posixstat.h" - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#ifdef __CYGWIN__ -# include -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" - -#include - -#if defined (READLINE) -#include "../bashline.h" -#include -#endif - -#if !defined(errno) -extern int errno; -#endif - -extern int interrupt_immediately; - -#if defined (READLINE) -static char *edit_line __P((char *)); -static void set_eol_delim __P((int)); -static void reset_eol_delim __P((char *)); -#endif -static SHELL_VAR *bind_read_variable __P((char *, char *)); - -static sighandler sigalrm __P((int)); -static void reset_alarm __P((void)); - -static procenv_t alrmbuf; -static SigHandler *old_alrm; -static unsigned char delim; - -static sighandler -sigalrm (s) - int s; -{ - longjmp (alrmbuf, 1); -} - -static void -reset_alarm () -{ - set_signal_handler (SIGALRM, old_alrm); - alarm (0); -} - -/* 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. */ -int -read_builtin (list) - WORD_LIST *list; -{ - register char *varname; - int size, i, pass_next, saw_escape, eof, opt, retval, code; - int input_is_tty, input_is_pipe, unbuffered_read; - int raw, edit, nchars, silent, have_timeout, fd; - unsigned int tmout; - intmax_t intval; - char c; - char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; - char *e, *t, *t1; - struct stat tsb; - SHELL_VAR *var; -#if defined (ARRAY_VARS) - WORD_LIST *alist; -#endif -#if defined (READLINE) - char *rlbuf; - int rlind; -#endif - - USE_VAR(size); - USE_VAR(i); - USE_VAR(pass_next); - USE_VAR(saw_escape); - USE_VAR(input_is_pipe); -/* USE_VAR(raw); */ - USE_VAR(edit); - USE_VAR(tmout); - USE_VAR(nchars); - USE_VAR(silent); - USE_VAR(ifs_chars); - USE_VAR(prompt); - USE_VAR(arrayname); -#if defined (READLINE) - USE_VAR(rlbuf); - USE_VAR(rlind); -#endif - USE_VAR(list); - - i = 0; /* Index into the string that we are reading. */ - raw = edit = 0; /* Not reading raw input by default. */ - silent = 0; - arrayname = prompt = (char *)NULL; - fd = 0; /* file descriptor to read from */ - -#if defined (READLINE) - rlbuf = (char *)0; - rlind = 0; -#endif - - tmout = 0; /* no timeout */ - nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0; - delim = '\n'; /* read until newline */ - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1) - { - switch (opt) - { - case 'r': - raw = 1; - break; - case 'p': - prompt = list_optarg; - break; - case 's': - silent = 1; - break; - case 'e': -#if defined (READLINE) - edit = 1; -#endif - break; -#if defined (ARRAY_VARS) - case 'a': - arrayname = list_optarg; - break; -#endif - case 't': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (unsigned int)intval) - { - builtin_error (_("%s: invalid timeout specification"), list_optarg); - return (EXECUTION_FAILURE); - } - else - { - have_timeout = 1; - tmout = intval; - } - break; - case 'n': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (int)intval) - { - sh_invalidnum (list_optarg); - return (EXECUTION_FAILURE); - } - else - nchars = intval; - break; - case 'u': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (int)intval) - { - builtin_error (_("%s: invalid file descriptor specification"), list_optarg); - return (EXECUTION_FAILURE); - } - else - fd = intval; - if (sh_validfd (fd) == 0) - { - builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno)); - return (EXECUTION_FAILURE); - } - break; - case 'd': - delim = *list_optarg; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - /* `read -t 0 var' returns failure immediately. XXX - should it test - whether input is available with select/FIONREAD, and fail if those - are unavailable? */ - if (have_timeout && tmout == 0) - return (EXECUTION_FAILURE); - - /* IF IFS is unset, we use the default of " \t\n". */ - ifs_chars = getifs (); - if (ifs_chars == 0) /* XXX - shouldn't happen */ - ifs_chars = ""; - - input_string = (char *)xmalloc (size = 112); /* XXX was 128 */ - - /* $TMOUT, if set, is the default timeout for read. */ - if (have_timeout == 0 && (e = get_string_value ("TMOUT"))) - { - code = legal_number (e, &intval); - if (code == 0 || intval < 0 || intval != (unsigned int)intval) - tmout = 0; - else - tmout = intval; - } - - begin_unwind_frame ("read_builtin"); - - input_is_tty = isatty (fd); - if (input_is_tty == 0) -#ifndef __CYGWIN__ - input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE); -#else - input_is_pipe = 1; -#endif - - /* If the -p, -e or -s flags were given, but input is not coming from the - terminal, turn them off. */ - if ((prompt || edit || silent) && input_is_tty == 0) - { - prompt = (char *)NULL; - edit = silent = 0; - } - -#if defined (READLINE) - if (edit) - add_unwind_protect (xfree, rlbuf); -#endif - - if (prompt && edit == 0) - { - fprintf (stderr, "%s", prompt); - fflush (stderr); - } - - pass_next = 0; /* Non-zero signifies last char was backslash. */ - saw_escape = 0; /* Non-zero signifies that we saw an escape char */ - - if (tmout > 0) - { - /* Turn off the timeout if stdin is a regular file (e.g. from - input redirection). */ - if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode)) - tmout = 0; - } - - if (tmout > 0) - { - code = setjmp (alrmbuf); - if (code) - { - run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); - } - old_alrm = set_signal_handler (SIGALRM, sigalrm); - add_unwind_protect (reset_alarm, (char *)NULL); - alarm (tmout); - } - - /* If we've been asked to read only NCHARS chars, or we're using some - character other than newline to terminate the line, do the right - thing to readline or the tty. */ - if (nchars > 0 || delim != '\n') - { -#if defined (READLINE) - if (edit) - { - if (nchars > 0) - { - unwind_protect_int (rl_num_chars_to_read); - rl_num_chars_to_read = nchars; - } - if (delim != '\n') - { - set_eol_delim (delim); - add_unwind_protect (reset_eol_delim, (char *)NULL); - } - } - else -#endif - if (input_is_tty) - { - ttsave (); - if (silent) - ttcbreak (); - else - ttonechar (); - add_unwind_protect ((Function *)ttrestore, (char *)NULL); - } - } - else if (silent) /* turn off echo but leave term in canonical mode */ - { - ttsave (); - ttnoecho (); - add_unwind_protect ((Function *)ttrestore, (char *)NULL); - } - - /* This *must* be the top unwind-protect on the stack, so the manipulation - of the unwind-protect stack after the realloc() works right. */ - add_unwind_protect (xfree, input_string); - interrupt_immediately++; - - unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe; - -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (0, O_TEXT); -#endif - - for (eof = retval = 0;;) - { -#if defined (READLINE) - if (edit) - { - if (rlbuf && rlbuf[rlind] == '\0') - { - xfree (rlbuf); - rlbuf = (char *)0; - } - if (rlbuf == 0) - { - rlbuf = edit_line (prompt ? prompt : ""); - rlind = 0; - } - if (rlbuf == 0) - { - eof = 1; - break; - } - c = rlbuf[rlind++]; - } - else - { -#endif - - if (unbuffered_read) - retval = zread (fd, &c, 1); - else - retval = zreadc (fd, &c); - - if (retval <= 0) - { - eof = 1; - break; - } - -#if defined (READLINE) - } -#endif - - if (i + 2 >= size) - { - input_string = (char *)xrealloc (input_string, size += 128); - remove_unwind_protect (); - add_unwind_protect (xfree, input_string); - } - - /* 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 == 0) - { - pass_next++; - saw_escape++; - input_string[i++] = CTLESC; - continue; - } - - if ((unsigned char)c == delim) - break; - - if (c == CTLESC || c == CTLNUL) - { - saw_escape++; - input_string[i++] = CTLESC; - } - - input_string[i++] = c; - - if (nchars > 0 && i >= nchars) - break; - } - input_string[i] = '\0'; - -#if 1 - if (retval < 0) - { - builtin_error (_("read error: %d: %s"), fd, strerror (errno)); - return (EXECUTION_FAILURE); - } -#endif - - if (tmout > 0) - reset_alarm (); - - if (nchars > 0 || delim != '\n') - { -#if defined (READLINE) - if (edit) - { - if (nchars > 0) - rl_num_chars_to_read = 0; - if (delim != '\n') - reset_eol_delim ((char *)NULL); - } - else -#endif - if (input_is_tty) - ttrestore (); - } - else if (silent) - ttrestore (); - - if (unbuffered_read == 0) - zsyncfd (fd); - - interrupt_immediately--; - discard_unwind_frame ("read_builtin"); - - retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - -#if defined (ARRAY_VARS) - /* If -a was given, take the string read, break it into a list of words, - an assign them to `arrayname' in turn. */ - if (arrayname) - { - if (legal_identifier (arrayname) == 0) - { - sh_invalidid (arrayname); - xfree (input_string); - return (EXECUTION_FAILURE); - } - - var = find_or_make_array_variable (arrayname, 1); - if (var == 0) - return EXECUTION_FAILURE; /* readonly or noassign */ - array_flush (array_cell (var)); - - alist = list_string (input_string, ifs_chars, 0); - if (alist) - { - word_list_remove_quoted_nulls (alist); - assign_array_var_from_word_list (var, alist); - dispose_words (alist); - } - xfree (input_string); - return (retval); - } -#endif /* ARRAY_VARS */ - - /* If there are no variables, save the text of the line read to the - variable $REPLY. ksh93 strips leading and trailing IFS whitespace, - so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the - same way, but I believe that the difference in behaviors is useful - enough to not do it. Without the bash behavior, there is no way - to read a line completely without interpretation or modification - unless you mess with $IFS (e.g., setting it to the empty string). - If you disagree, change the occurrences of `#if 0' to `#if 1' below. */ - if (list == 0) - { -#if 0 - orig_input_string = input_string; - for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++) - ; - input_string = t; - input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape); -#endif - - if (saw_escape) - { - t = dequote_string (input_string); - var = bind_variable ("REPLY", t); - free (t); - } - else - var = bind_variable ("REPLY", input_string); - VUNSETATTR (var, att_invisible); - - free (input_string); - return (retval); - } - - /* This code implements the Posix.2 spec for splitting the words - read and assigning them to variables. */ - orig_input_string = input_string; - - /* Remove IFS white space at the beginning of the input string. If - $IFS is null, no field splitting is performed. */ - for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++) - ; - input_string = t; - - for (; list->next; list = list->next) - { - varname = list->word->word; -#if defined (ARRAY_VARS) - if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0) -#else - if (legal_identifier (varname) == 0) -#endif - { - sh_invalidid (varname); - xfree (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_read_variable (varname, t1); - xfree (t1); - } - else - var = bind_read_variable (varname, t); - } - else - { - t = (char *)0; - var = bind_read_variable (varname, ""); - } - - FREE (t); - if (var == 0) - { - xfree (orig_input_string); - return (EXECUTION_FAILURE); - } - - stupidly_hack_special_variables (varname); - VUNSETATTR (var, att_invisible); - } - - /* Now assign the rest of the line to the last variable argument. */ -#if defined (ARRAY_VARS) - if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0) -#else - if (legal_identifier (list->word->word) == 0) -#endif - { - sh_invalidid (list->word->word); - xfree (orig_input_string); - return (EXECUTION_FAILURE); - } - - /* This has to be done this way rather than using string_list - and list_string because Posix.2 says that the last variable gets the - remaining words and their intervening separators. */ - input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape); - - if (saw_escape) - { - t = dequote_string (input_string); - var = bind_read_variable (list->word->word, t); - xfree (t); - } - else - var = bind_read_variable (list->word->word, input_string); - stupidly_hack_special_variables (list->word->word); - if (var) - VUNSETATTR (var, att_invisible); - xfree (orig_input_string); - - return (retval); -} - -static SHELL_VAR * -bind_read_variable (name, value) - char *name, *value; -{ -#if defined (ARRAY_VARS) - if (valid_array_reference (name) == 0) - return (bind_variable (name, value)); - else - return (assign_array_element (name, value)); -#else /* !ARRAY_VARS */ - return bind_variable (name, value); -#endif /* !ARRAY_VARS */ -} - -#if defined (READLINE) -static rl_completion_func_t *old_attempted_completion_function; - -static char * -edit_line (p) - char *p; -{ - char *ret; - int len; - - if (!bash_readline_initialized) - initialize_readline (); - old_attempted_completion_function = rl_attempted_completion_function; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - ret = readline (p); - rl_attempted_completion_function = old_attempted_completion_function; - if (ret == 0) - return ret; - len = strlen (ret); - ret = (char *)xrealloc (ret, len + 2); - ret[len++] = delim; - ret[len] = '\0'; - return ret; -} - -static int old_delim_ctype; -static rl_command_func_t *old_delim_func; -static int old_newline_ctype; -static rl_command_func_t *old_newline_func; - -static unsigned char delim_char; - -static void -set_eol_delim (c) - int c; -{ - Keymap cmap; - - if (bash_readline_initialized == 0) - initialize_readline (); - cmap = rl_get_keymap (); - - /* Change newline to self-insert */ - old_newline_ctype = cmap[RETURN].type; - old_newline_func = cmap[RETURN].function; - cmap[RETURN].type = ISFUNC; - cmap[RETURN].function = rl_insert; - - /* Bind the delimiter character to accept-line. */ - old_delim_ctype = cmap[c].type; - old_delim_func = cmap[c].function; - cmap[c].type = ISFUNC; - cmap[c].function = rl_newline; - - delim_char = c; -} - -static void -reset_eol_delim (cp) - char *cp; -{ - Keymap cmap; - - cmap = rl_get_keymap (); - - cmap[RETURN].type = old_newline_ctype; - cmap[RETURN].function = old_newline_func; - - cmap[delim_char].type = old_delim_ctype; - cmap[delim_char].function = old_delim_func; -} -#endif diff --git a/builtins/trap.def~ b/builtins/trap.def~ deleted file mode 100644 index e80f0d38c..000000000 --- a/builtins/trap.def~ +++ /dev/null @@ -1,261 +0,0 @@ -This file is trap.def, from which is created trap.c. -It implements the builtin "trap" in Bash. - -Copyright (C) 1987-2004 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES trap.c - -$BUILTIN trap -$FUNCTION trap_builtin -$SHORT_DOC trap [-lp] [[arg] signal_spec ] -The command ARG is to be read and executed when the shell receives -signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC -is supplied) or `-', each specified signal is reset to its original -value. If ARG is the null string each SIGNAL_SPEC is ignored by the -shell and by the commands it invokes. If a SIGNAL_SPEC is EXIT (0) -the command ARG is executed on exit from the shell. If a SIGNAL_SPEC -is DEBUG, ARG is executed after every simple command. If the`-p' option -is supplied then the trap commands associated with each SIGNAL_SPEC are -displayed. If no arguments are supplied or if only `-p' is given, trap -prints the list of commands associated with each signal. Each SIGNAL_SPEC -is either a signal name in or a signal number. Signal names -are case insensitive and the SIG prefix is optional. `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 - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashtypes.h" -#include -#include -#include "../bashansi.h" - -#include "../shell.h" -#include "../trap.h" -#include "common.h" -#include "bashgetopt.h" - -static void showtrap __P((int)); -static int display_traps __P((WORD_LIST *)); - -/* The trap command: - - trap - trap - trap -l - trap -p [sigspec ...] - trap [--] - - Set things up so that ARG is executed when SIGNAL(s) N is recieved. - 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 posixly_correct; - -int -trap_builtin (list) - WORD_LIST *list; -{ - int list_signal_names, display, result, opt; - - list_signal_names = display = 0; - result = EXECUTION_SUCCESS; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "lp")) != -1) - { - switch (opt) - { - case 'l': - list_signal_names++; - break; - case 'p': - display++; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */ - - if (list_signal_names) - return (display_signal_list ((WORD_LIST *)NULL, 1)); - else if (display || list == 0) - return (display_traps (list)); - else - { - char *first_arg; - int operation, sig; - - operation = SET; - first_arg = list->word->word; - /* When in posix mode, the historical behavior of looking for a - missing first argument is disabled. To revert to the original - signal handling disposition, use `-' as the first argument. */ - if (posixly_correct == 0 && first_arg && *first_arg && - (*first_arg != '-' || first_arg[1]) && - signal_object_p (first_arg, opt) && list->next == 0) - operation = REVERT; - else - { - list = list->next; - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - else if (*first_arg == '\0') - operation = IGNORE; - else if (first_arg[0] == '-' && !first_arg[1]) - operation = REVERT; - } - - while (list) - { - sig = decode_signal (list->word->word, opt); - - if (sig == NO_SIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - } - 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 (result); -} - -static void -showtrap (i) - int i; -{ - char *t, *p, *sn; - - p = trap_list[i]; - - if (p == (char *)DEFAULT_SIG) - return; - - t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p); - sn = signal_name (i); - /* Make sure that signals whose names are unknown (for whatever reason) - are printed as signal numbers. */ - if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7)) - printf ("trap -- %s %d\n", t ? t : "''", i); - else if (posixly_correct) - { - if (STREQN (sn, "SIG", 3)) - printf ("trap -- %s %s\n", t ? t : "''", sn+3); - else - printf ("trap -- %s %s\n", t ? t : "''", sn); - } - else - printf ("trap -- %s %s\n", t ? t : "''", sn); - - FREE (t); -} - -static int -display_traps (list) - WORD_LIST *list; -{ - int result, i; - - if (list == 0) - { - for (i = 0; i < BASH_NSIG; i++) - showtrap (i); - return (EXECUTION_SUCCESS); - } - - for (result = EXECUTION_SUCCESS; list; list = list->next) - { - i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX); - if (i == NO_SIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - } - else - showtrap (i); - } - - return (result); -} diff --git a/builtins/umask.def~ b/builtins/umask.def~ deleted file mode 100644 index 72d292a99..000000000 --- a/builtins/umask.def~ +++ /dev/null @@ -1,309 +0,0 @@ -This file is umask.def, from which is created umask.c. -It implements the builtin "umask" in Bash. - -Copyright (C) 1987-2004 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$PRODUCES umask.c - -$BUILTIN umask -$FUNCTION umask_builtin -$SHORT_DOC umask [-p] [-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 `-p' is supplied, and MODE is omitted, the output is in a form -that may be used as input. 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 "../bashtypes.h" -#include "filecntl.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -#include -#endif - -#include -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "posixstat.h" -#include "common.h" -#include "bashgetopt.h" - -#ifdef __LCC__ -#define mode_t int -#endif - -/* **************************************************************** */ -/* */ -/* UMASK Builtin and Helpers */ -/* */ -/* **************************************************************** */ - -static void print_symbolic_umask __P((mode_t)); -static int symbolic_umask __P((WORD_LIST *)); - -/* Set or display the mask used by the system when creating files. Flag - of -S means display the umask in a symbolic mode. */ -int -umask_builtin (list) - WORD_LIST *list; -{ - int print_symbolically, opt, umask_value, pflag; - mode_t umask_arg; - - print_symbolically = pflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "Sp")) != -1) - { - switch (opt) - { - case 'S': - print_symbolically++; - break; - case 'p': - pflag++; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (list) - { - if (DIGIT (*list->word->word)) - { - umask_value = read_octal (list->word->word); - - /* Note that other shells just let you set the umask to zero - by specifying a number out of range. This is a problem - with those shells. We don't change the umask if the input - is lousy. */ - if (umask_value == -1) - { - sh_erange (list->word->word, _("octal number")); - return (EXECUTION_FAILURE); - } - } - else - { - umask_value = symbolic_umask (list); - if (umask_value == -1) - return (EXECUTION_FAILURE); - } - umask_arg = (mode_t)umask_value; - umask (umask_arg); - if (print_symbolically) - print_symbolic_umask (umask_arg); - } - else /* Display the UMASK for this user. */ - { - umask_arg = umask (022); - umask (umask_arg); - - if (pflag) - printf ("umask%s ", (print_symbolically ? " -S" : "")); - if (print_symbolically) - print_symbolic_umask (umask_arg); - else - printf ("%04lo\n", (unsigned long)umask_arg); - } - - 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) - mode_t 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); -} - -int -parse_symbolic_mode (mode, initial_bits) - char *mode; - int initial_bits; -{ - int who, op, perm, bits, c; - char *s; - - for (s = mode, bits = initial_bits;;) - { - who = op = perm = 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 (_("`%c': invalid symbolic mode operator"), 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 '+': - bits |= perm; - break; - case '-': - bits &= ~perm; - break; - case '=': - bits &= ~who; - bits |= perm; - break; - - /* No other values are possible. */ - } - - if (*s == '\0') - break; - else - s++; /* skip past ',' */ - } - else - { - builtin_error (_("`%c': invalid symbolic mode character"), *s); - return (-1); - } - } - - return (bits); -} - -/* 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, bits; - - /* Get the initial umask. Don't change it yet. */ - um = umask (022); - umask (um); - - /* All work is done with the complement of the umask -- it's - more intuitive and easier to deal with. It is complemented - again before being returned. */ - bits = parse_symbolic_mode (list->word->word, ~um & 0777); - if (bits == -1) - return (-1); - - um = ~bits & 0777; - return (um); -} diff --git a/builtins/wait.def.save1 b/builtins/wait.def.save1 deleted file mode 100644 index 23c8b19f6..000000000 --- a/builtins/wait.def.save1 +++ /dev/null @@ -1,183 +0,0 @@ -This file is wait.def, from which is created wait.c. -It implements the builtin "wait" in Bash. - -Copyright (C) 1987-2002 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$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 "../bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#include "../bashansi.h" - -#include "../shell.h" -#include "../jobs.h" -#include "common.h" -#include "bashgetopt.h" - -extern int interrupt_immediately; -extern int wait_signal_received; - -procenv_t wait_intr_buf; - -/* 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. */ - -#define WAIT_RETURN(s) \ - do \ - { \ - interrupt_immediately = old_interrupt_immediately;\ - return (s);\ - } \ - while (0) - -int -wait_builtin (list) - WORD_LIST *list; -{ - int status, code; - volatile int old_interrupt_immediately; - - USE_VAR(list); - - if (no_options (list)) - return (EX_USAGE); - list = loptend; - - old_interrupt_immediately = interrupt_immediately; - interrupt_immediately++; - - /* POSIX.2 says: When the shell is waiting (by means of the wait utility) - for asynchronous commands to complete, the reception of a signal for - which a trap has been set shall cause the wait utility to return - immediately with an exit status greater than 128, after which the trap - associated with the signal shall be taken. - - We handle SIGINT here; it's the only one that needs to be treated - specially (I think), since it's handled specially in {no,}jobs.c. */ - code = setjmp (wait_intr_buf); - if (code) - { - status = 128 + wait_signal_received; - WAIT_RETURN (status); - } - - /* 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 == 0) - { - wait_for_background_pids (); - WAIT_RETURN (EXECUTION_SUCCESS); - } - - status = EXECUTION_SUCCESS; - while (list) - { - pid_t pid; - char *w; - intmax_t pid_value; - - w = list->word->word; - if (DIGIT (*w)) - { - if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value) - { - pid = (pid_t)pid_value; - status = wait_for_single_pid (pid); - } - else - { - sh_badpid (w); - WAIT_RETURN (EXECUTION_FAILURE); - } - } -#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) - sh_badjob (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); - } - else if (job_control == 0 && *w == '%') - { - /* can't use jobspecs as arguments if job control is not active. */ - sh_nojobs ((char *)NULL); - status = EXECUTION_FAILURE; - } -#endif /* JOB_CONTROL */ - else - { - sh_badpid (w); - status = EXECUTION_FAILURE; - } - list = list->next; - } - - WAIT_RETURN (status); -} diff --git a/builtins/wait.def~ b/builtins/wait.def~ deleted file mode 100644 index 53533bae5..000000000 --- a/builtins/wait.def~ +++ /dev/null @@ -1,177 +0,0 @@ -This file is wait.def, from which is created wait.c. -It implements the builtin "wait" in Bash. - -Copyright (C) 1987-2004 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -$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 "../bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#include "../bashansi.h" - -#include "../shell.h" -#include "../jobs.h" -#include "common.h" -#include "bashgetopt.h" - -extern int interrupt_immediately; -extern int wait_signal_received; - -procenv_t wait_intr_buf; - -/* 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. */ - -#define WAIT_RETURN(s) \ - do \ - { \ - interrupt_immediately = old_interrupt_immediately;\ - return (s);\ - } \ - while (0) - -int -wait_builtin (list) - WORD_LIST *list; -{ - int status, code; - volatile int old_interrupt_immediately; - - USE_VAR(list); - - if (no_options (list)) - return (EX_USAGE); - list = loptend; - - old_interrupt_immediately = interrupt_immediately; - interrupt_immediately++; - - /* POSIX.2 says: When the shell is waiting (by means of the wait utility) - for asynchronous commands to complete, the reception of a signal for - which a trap has been set shall cause the wait utility to return - immediately with an exit status greater than 128, after which the trap - associated with the signal shall be taken. - - We handle SIGINT here; it's the only one that needs to be treated - specially (I think), since it's handled specially in {no,}jobs.c. */ - code = setjmp (wait_intr_buf); - if (code) - { - status = 128 + wait_signal_received; - WAIT_RETURN (status); - } - - /* 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 == 0) - { - wait_for_background_pids (); - WAIT_RETURN (EXECUTION_SUCCESS); - } - - status = EXECUTION_SUCCESS; - while (list) - { - pid_t pid; - char *w; - intmax_t pid_value; - - w = list->word->word; - if (DIGIT (*w)) - { - if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value) - { - pid = (pid_t)pid_value; - status = wait_for_single_pid (pid); - } - else - { - sh_badpid (w); - WAIT_RETURN (EXECUTION_FAILURE); - } - } -#if defined (JOB_CONTROL) - else if (*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) - sh_badjob (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 - { - sh_badpid (w); - status = EXECUTION_FAILURE; - } - list = list->next; - } - - WAIT_RETURN (status); -} diff --git a/config-bot.h~ b/config-bot.h~ deleted file mode 100644 index 06e107c65..000000000 --- a/config-bot.h~ +++ /dev/null @@ -1,181 +0,0 @@ -/* config-bot.h */ -/* modify settings or make new ones based on what autoconf tells us. */ - -/* Copyright (C) 1989-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/*********************************************************/ -/* Modify or set defines based on the configure results. */ -/*********************************************************/ - -#if !defined (HAVE_VPRINTF) && defined (HAVE_DOPRNT) -# define USE_VFPRINTF_EMULATION -# define HAVE_VPRINTF -#endif - -#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_GETRLIMIT) -# define HAVE_RESOURCE -#endif - -#if !defined (GETPGRP_VOID) -# define HAVE_BSD_PGRP -#endif - -/* Try this without testing __STDC__ for the time being. */ -#if defined (HAVE_STDARG_H) -# define PREFER_STDARG -# define USE_VARARGS -#else -# if defined (HAVE_VARARGS_H) -# define PREFER_VARARGS -# define USE_VARARGS -# endif -#endif - -#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && defined (HAVE_NETINET_IN_H) -# define HAVE_NETWORK -#endif - -#if defined (HAVE_REGEX_H) && defined (HAVE_REGCOMP) && defined (HAVE_REGEXEC) -# define HAVE_POSIX_REGEXP -#endif - -/* backwards compatibility between different autoconf versions */ -#if defined (HAVE_DECL_SYS_SIGLIST) && !defined (SYS_SIGLIST_DECLARED) -# define SYS_SIGLIST_DECLARED -#endif - -/***********************************************************************/ -/* Unset defines based on what configure reports as missing or broken. */ -/***********************************************************************/ - -/* Ultrix botches type-ahead when switching from canonical to - non-canonical mode, at least through version 4.3 */ -#if !defined (HAVE_TERMIOS_H) || !defined (HAVE_TCGETATTR) || defined (ultrix) -# define TERMIOS_MISSING -#endif - -/* If we have a getcwd(3), but it calls popen(), #undef HAVE_GETCWD so - the replacement in getcwd.c will be built. */ -#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) -# undef HAVE_GETCWD -#endif - -#if !defined (HAVE_DEV_FD) && defined (NAMED_PIPES_MISSING) -# undef PROCESS_SUBSTITUTION -#endif - -#if defined (JOB_CONTROL_MISSING) -# undef JOB_CONTROL -#endif - -#if defined (STRCOLL_BROKEN) -# undef HAVE_STRCOLL -#endif - -#if !defined (HAVE_POSIX_REGEXP) -# undef COND_REGEXP -#endif - -/* If the shell is called by this name, it will become restricted. */ -#if defined (RESTRICTED_SHELL) -# define RESTRICTED_SHELL_NAME "rbash" -#endif - -/***********************************************************/ -/* Make sure feature defines have necessary prerequisites. */ -/***********************************************************/ - -/* BANG_HISTORY requires HISTORY. */ -#if defined (BANG_HISTORY) && !defined (HISTORY) -# define HISTORY -#endif /* BANG_HISTORY && !HISTORY */ - -#if defined (READLINE) && !defined (HISTORY) -# define HISTORY -#endif - -#if defined (PROGRAMMABLE_COMPLETION) && !defined (READLINE) -# undef PROGRAMMABLE_COMPLETION -#endif - -#if !defined (V9_ECHO) -# undef DEFAULT_ECHO_TO_XPG -#endif - -#if !defined (PROMPT_STRING_DECODE) -# undef PPROMPT -# define PPROMPT "$ " -#endif - -/************************************************/ -/* check multibyte capability for I18N code */ -/************************************************/ - -/* For platforms which support the ISO C amendement 1 functionality we - support user defined character classes. */ -/* Solaris 2.5 has a bug: must be included before . */ -#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) -# include -# include -# if defined (HAVE_MBSRTOWCS) && defined (HAVE_MBRTOWC) && defined (HAVE_MBRLEN) && defined (HAVE_WCWIDTH) - /* system is supposed to support XPG5 */ -# define HANDLE_MULTIBYTE 1 -# endif -#endif - -/* If we don't want multibyte chars even on a system that supports them, let - the configuring user turn multibyte support off. */ -#if defined (NO_MULTIBYTE_SUPPORT) -# undef HANDLE_MULTIBYTE -#endif - -/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) -# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) -# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) -# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) -# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) -# define mbstate_t int -#endif - -/* Make sure MB_LEN_MAX is at least 16 (some systems define - MB_LEN_MAX as 1) */ -#ifdef HANDLE_MULTIBYTE -# include -# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) -# undef MB_LEN_MAX -# endif -# if !defined (MB_LEN_MAX) -# define MB_LEN_MAX 16 -# endif -#endif - -/************************************************/ -/* end of multibyte capability checks for I18N */ -/************************************************/ - -/******************************************************************/ -/* Placeholder for builders to #undef any unwanted features from */ -/* config-top.h or created by configure (such as the default mail */ -/* file for mail checking). */ -/******************************************************************/ - -/* If you don't want bash to provide a default mail file to check. */ -/* #undef DEFAULT_MAIL_DIRECTORY */ diff --git a/config.h.in~ b/config.h.in~ deleted file mode 100644 index b23573aec..000000000 --- a/config.h.in~ +++ /dev/null @@ -1,974 +0,0 @@ -/* config.h -- Configuration file for bash. */ - -/* Copyright (C) 1987-2003 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -/* Configuration feature settings controllable by autoconf. */ - -/* Define JOB_CONTROL if your operating system supports - BSD-like job control. */ -#undef JOB_CONTROL - -/* Define ALIAS if you want the alias features. */ -#undef ALIAS - -/* Define PUSHD_AND_POPD if you want those commands to be compiled in. - (Also the `dirs' commands.) */ -#undef PUSHD_AND_POPD - -/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: - foo{a,b} -> fooa foob. Even if this is compiled in (the default) you - can turn it off at shell startup with `-nobraceexpansion', or during - shell execution with `set +o braceexpand'. */ -#undef BRACE_EXPANSION - -/* Define READLINE to get the nifty/glitzy editing features. - This is on by default. You can turn it off interactively - with the -nolineediting flag. */ -#undef READLINE - -/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. - This is unrelated to READLINE. */ -#undef BANG_HISTORY - -/* Define HISTORY if you want to have access to previously typed commands. - - If both HISTORY and READLINE are defined, you can get at the commands - with line editing commands, and you can directly manipulate the history - from the command line. - - If only HISTORY is defined, the `fc' and `history' builtins are - available. */ -#undef HISTORY - -/* Define this if you want completion that puts all alternatives into - a brace expansion shell expression. */ -#if defined (BRACE_EXPANSION) && defined (READLINE) -# define BRACE_COMPLETION -#endif /* BRACE_EXPANSION */ - -/* Define DEFAULT_ECHO_TO_XPG if you want the echo builtin to interpret - the backslash-escape characters by default, like the XPG Single Unix - Specification V2 for echo. - This requires that V9_ECHO be defined. */ -#undef DEFAULT_ECHO_TO_XPG - -/* Define HELP_BUILTIN if you want the `help' shell builtin and the long - documentation strings compiled into the shell. */ -#undef HELP_BUILTIN - -/* Define RESTRICTED_SHELL if you want the generated shell to have the - ability to be a restricted one. The shell thus generated can become - restricted by being run with the name "rbash", or by setting the -r - flag. */ -#undef RESTRICTED_SHELL - -/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the - shell builtin "foo", even if it has been disabled with "enable -n foo". */ -#undef DISABLED_BUILTINS - -/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process - substitution features "<(file)". */ -/* Right now, you cannot do this on machines without fully operational - FIFO support. This currently include NeXT and Alliant. */ -#undef PROCESS_SUBSTITUTION - -/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special - characters in PS1 and PS2 expanded. Variable expansion will still be - performed. */ -#undef PROMPT_STRING_DECODE - -/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: - select word in word_list; do command_list; done */ -#undef SELECT_COMMAND - -/* Define COMMAND_TIMING of you want the ksh-style `time' reserved word and - the ability to time pipelines, functions, and builtins. */ -#undef COMMAND_TIMING - -/* Define ARRAY_VARS if you want ksh-style one-dimensional array variables. */ -#undef ARRAY_VARS - -/* Define DPAREN_ARITHMETIC if you want the ksh-style ((...)) arithmetic - evaluation command. */ -#undef DPAREN_ARITHMETIC - -/* Define EXTENDED_GLOB if you want the ksh-style [*+@?!](patlist) extended - pattern matching. */ -#undef EXTENDED_GLOB - -/* Define COND_COMMAND if you want the ksh-style [[...]] conditional - command. */ -#undef COND_COMMAND - -/* Define COND_REGEXP if you want extended regular expression matching and the - =~ binary operator in the [[...]] conditional command. */ -#define COND_REGEXP - -/* Define ARITH_FOR_COMMAND if you want the ksh93-style - for (( init; test; step )) do list; done - arithmetic for command. */ -#undef ARITH_FOR_COMMAND - -/* Define NETWORK_REDIRECTIONS if you want /dev/(tcp|udp)/host/port to open - socket connections when used in redirections */ -#undef NETWORK_REDIRECTIONS - -/* Define PROGRAMMABLE_COMPLETION for the programmable completion features - and the complete builtin. */ -#undef PROGRAMMABLE_COMPLETION - -/* Define NO_MULTIBYTE_SUPPORT to not compile in support for multibyte - characters, even if the OS supports them. */ -#undef NO_MULTIBYTE_SUPPORT - -/* Define DEBUGGER if you want to compile in some features used only by the - bash debugger. */ -#undef DEBUGGER - -/* Define MEMSCRAMBLE if you want the bash malloc and free to scramble - memory contents on malloc() and free(). */ -#undef MEMSCRAMBLE - -/* Define AFS if you are using Transarc's AFS. */ -#undef AFS - -#undef ENABLE_NLS - -/* End of configuration settings controllable by autoconf. */ -/* Other settable options appear in config-top.h. */ - -#include "config-top.h" - -/* Beginning of autoconf additions. */ - -/* Characteristics of the C compiler */ -#undef const - -#undef inline - -/* Define if cpp supports the ANSI-C stringizing `#' operator */ -#undef HAVE_STRINGIZE - -/* Define if the compiler supports `long double' variables. */ -#undef HAVE_LONG_DOUBLE - -#undef PROTOTYPES - -#undef __CHAR_UNSIGNED__ - -/* Define if the compiler supports `long long' variables. */ -#undef HAVE_LONG_LONG - -#undef HAVE_UNSIGNED_LONG_LONG - -/* The number of bytes in a int. */ -#undef SIZEOF_INT - -/* The number of bytes in a long. */ -#undef SIZEOF_LONG - -/* The number of bytes in a pointer to char. */ -#undef SIZEOF_CHAR_P - -/* The number of bytes in a double (hopefully 8). */ -#undef SIZEOF_DOUBLE - -/* The number of bytes in a `long long', if we have one. */ -#undef SIZEOF_LONG_LONG - -/* System paths */ - -#define DEFAULT_MAIL_DIRECTORY "/usr/spool/mail" - -/* Characteristics of the system's header files and libraries that affect - the compilation environment. */ - -/* Define if the system does not provide POSIX.1 features except - with this defined. */ -#undef _POSIX_1_SOURCE - -/* Define if you need to in order for stat and other things to work. */ -#undef _POSIX_SOURCE - -/* Define to use GNU libc extensions */ -#undef _GNU_SOURCE - -/* Define if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Memory management functions. */ - -/* Define if using the bash version of malloc in lib/malloc/malloc.c */ -#undef USING_BASH_MALLOC - -#undef DISABLE_MALLOC_WRAPPERS - -/* Define if using alloca.c. */ -#undef C_ALLOCA - -/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. - This function is required for alloca.c support on those systems. */ -#undef CRAY_STACKSEG_END - -/* Define if you have alloca, as a function or macro. */ -#undef HAVE_ALLOCA - -/* Define if you have and it should be used (not on Ultrix). */ -#undef HAVE_ALLOCA_H - - -/* SYSTEM TYPES */ - -/* Define to `long' if doesn't define. */ -#undef off_t - -/* Define to `int' if doesn't define. */ -#undef mode_t - -/* Define to `int' if doesn't define. */ -#undef sigset_t - -/* Define to `int' if doesn't define. */ -#undef pid_t - -/* Define to `short' if doesn't define. */ -#undef bits16_t - -/* Define to `unsigned short' if doesn't define. */ -#undef u_bits16_t - -/* Define to `int' if doesn't define. */ -#undef bits32_t - -/* Define to `unsigned int' if doesn't define. */ -#undef u_bits32_t - -/* Define to `double' if doesn't define. */ -#undef bits64_t - -/* Define to `unsigned int' if doesn't define. */ -#undef u_int - -/* Define to `unsigned long' if doesn't define. */ -#undef u_long - -/* Define to `int' if doesn't define. */ -#undef ptrdiff_t - -/* Define to `unsigned' if doesn't define. */ -#undef size_t - -/* Define to `int' if doesn't define. */ -#undef ssize_t - -/* Define to `long' if doesn't define. */ -#undef intmax_t - -/* Define to `unsigned long' if doesn't define. */ -#undef uintmax_t - -/* Define to `int' if doesn't define. */ -#undef uid_t - -/* Define to `long' if doesn't define. */ -#undef clock_t - -/* Define to `long' if doesn't define. */ -#undef time_t - -/* Define to `int' if doesn't define. */ -#undef gid_t - -/* Define to `unsigned int' if doesn't define. */ -#undef socklen_t - -/* Define if you have quad_t in . */ -#undef HAVE_QUAD_T - -#undef RLIMTYPE - -/* Define to the type of elements in the array set by `getgroups'. - Usually this is either `int' or `gid_t'. */ -#undef GETGROUPS_T - -/* Characteristics of the machine archictecture. */ - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown - */ -#undef STACK_DIRECTION - -/* Define if the machine architecture is big-endian. */ -#undef WORDS_BIGENDIAN - -/* Check for the presence of certain non-function symbols in the system - libraries. */ - -/* Define if `sys_siglist' is declared by or . */ -#undef HAVE_DECL_SYS_SIGLIST -#undef SYS_SIGLIST_DECLARED - -/* Define if `_sys_siglist' is declared by or . */ -#undef UNDER_SYS_SIGLIST_DECLARED - -#undef HAVE_SYS_SIGLIST - -#undef HAVE_UNDER_SYS_SIGLIST - -#undef HAVE_SYS_ERRLIST - -#undef HAVE_TZNAME - - -/* Characteristics of some of the system structures. */ - -#undef STRUCT_DIRENT_HAS_D_INO - -#undef STRUCT_DIRENT_HAS_D_FILENO - -#undef TIOCSTAT_IN_SYS_IOCTL - -#undef FIONREAD_IN_SYS_IOCTL - -#undef GWINSZ_IN_SYS_IOCTL - -#undef STRUCT_WINSIZE_IN_SYS_IOCTL - -#undef TM_IN_SYS_TIME - -#undef STRUCT_WINSIZE_IN_TERMIOS - -#undef SPEED_T_IN_SYS_TYPES - -#undef TERMIOS_LDISC - -#undef TERMIO_LDISC - -#undef HAVE_STRUCT_STAT_ST_BLOCKS - -#undef HAVE_STRUCT_TM_TM_ZONE -#undef HAVE_TM_ZONE - -#undef HAVE_TIMEVAL - -#undef HAVE_STRUCT_TIMEZONE - -/* Characteristics of definitions in the system header files. */ - -#undef HAVE_GETPW_DECLS - -#undef HAVE_RESOURCE - -#undef HAVE_LIBC_FNM_EXTMATCH - - -#undef HAVE_DECL_CONFSTR - -#undef HAVE_DECL_PRINTF - -#undef HAVE_DECL_SBRK - -#undef HAVE_DECL_STRCPY - -#undef HAVE_DECL_STRSIGNAL - -#undef HAVE_DECL_STRTOLD - -#undef STRTOLD_BROKEN - -#undef HAVE_MBSTATE_T - -/* These are checked with BASH_CHECK_DECL */ - -#undef HAVE_DECL_STRTOIMAX -#undef HAVE_DECL_STRTOL -#undef HAVE_DECL_STRTOLL -#undef HAVE_DECL_STRTOUL -#undef HAVE_DECL_STRTOULL -#undef HAVE_DECL_STRTOUMAX - -/* Characteristics of system calls and C library functions. */ - -/* Define if the `getpgrp' function takes no argument. */ -#undef GETPGRP_VOID - -#undef NAMED_PIPES_MISSING - -#undef OPENDIR_NOT_ROBUST - -#undef PGRP_PIPE - -/* Define if the setvbuf function takes the buffering type as its second - argument and the buffer pointer as the third, as on System V - before release 3. */ -#undef SETVBUF_REVERSED - -#undef STAT_MACROS_BROKEN - -#undef ULIMIT_MAXFDS - -#undef CAN_REDEFINE_GETENV - -#undef HAVE_STD_PUTENV - -#undef HAVE_STD_UNSETENV - -#undef HAVE_PRINTF_A_FORMAT - -#undef CTYPE_NON_ASCII - -/* Define if you have and nl_langinfo(CODESET). */ -#undef HAVE_LANGINFO_CODESET - -/* Characteristics of properties exported by the kernel. */ - -/* Define if the kernel can exec files beginning with #! */ -#undef HAVE_HASH_BANG_EXEC - -/* Define if you have the /dev/fd devices to map open files into the file system. */ -#undef HAVE_DEV_FD - -/* Defined to /dev/fd or /proc/self/fd (linux). */ -#undef DEV_FD_PREFIX - -/* Define if you have the /dev/stdin device. */ -#undef HAVE_DEV_STDIN - - -/* Type and behavior of signal handling functions. */ - -/* Define as the return type of signal handlers (int or void). */ -#undef RETSIGTYPE - -/* Define if return type of signal handlers is void */ -#undef VOID_SIGHANDLER - -#undef MUST_REINSTALL_SIGHANDLERS - -#undef HAVE_BSD_SIGNALS - -#undef HAVE_POSIX_SIGNALS - -#undef HAVE_USG_SIGHOLD - -#undef UNUSABLE_RT_SIGNALS - - -/* Presence of system and C library functions. */ - -/* Define if you have the asprintf function. */ -#undef HAVE_ASPRINTF - -/* Define if you have the bcopy function. */ -#undef HAVE_BCOPY - -/* Define if you have the bzero function. */ -#undef HAVE_BZERO - -/* Define if you have the confstr function. */ -#undef HAVE_CONFSTR - -/* Define if you have the dlclose function. */ -#undef HAVE_DLCLOSE - -/* Define if you have the dlopen function. */ -#undef HAVE_DLOPEN - -/* Define if you have the dlsym function. */ -#undef HAVE_DLSYM - -/* Define if you don't have vprintf but do have _doprnt. */ -#undef HAVE_DOPRNT - -/* Define if you have the dup2 function. */ -#undef HAVE_DUP2 - -/* Define if you have the getaddrinfo function. */ -#undef HAVE_GETADDRINFO - -/* Define if you have the getcwd function. */ -#undef HAVE_GETCWD - -/* Define if you have the getdtablesize function. */ -#undef HAVE_GETDTABLESIZE - -/* Define if you have the getgroups function. */ -#undef HAVE_GETGROUPS - -/* Define if you have the gethostbyname function. */ -#undef HAVE_GETHOSTBYNAME - -/* Define if you have the gethostname function. */ -#undef HAVE_GETHOSTNAME - -/* Define if you have the getpagesize function. */ -#undef HAVE_GETPAGESIZE - -/* Define if you have the getpeername function. */ -#undef HAVE_GETPEERNAME - -/* Define if you have the getrlimit function. */ -#undef HAVE_GETRLIMIT - -/* Define if you have the getrusage function. */ -#undef HAVE_GETRUSAGE - -/* Define if you have the getservbyname function. */ -#undef HAVE_GETSERVBYNAME - -/* Define if you have the getservent function. */ -#undef HAVE_GETSERVENT - -/* Define if you have the gettimeofday function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define if you have the getwd function. */ -#undef HAVE_GETWD - -/* Define if you have the inet_aton function. */ -#undef HAVE_INET_ATON - -/* Define if you have the isascii function. */ -#undef HAVE_ISASCII - -/* Define if you have the isblank function. */ -#undef HAVE_ISBLANK - -/* Define if you have the isgraph function. */ -#undef HAVE_ISGRAPH - -/* Define if you have the isint function in libc */ -#undef HAVE_ISINF_IN_LIBC - -/* Define if you have the isprint function. */ -#undef HAVE_ISPRINT - -/* Define if you have the isspace function. */ -#undef HAVE_ISSPACE - -/* Define if you have the isxdigit function. */ -#undef HAVE_ISXDIGIT - -/* Define if you have the killpg function. */ -#undef HAVE_KILLPG - -/* Define if you have the lstat function. */ -#undef HAVE_LSTAT - -/* Define if you have the mbrlen function. */ -#undef HAVE_MBRLEN - -/* Define if you have the mbrtowc function. */ -#undef HAVE_MBRTOWC - -/* Define if you have the mbsrtowcs function. */ -#undef HAVE_MBSRTOWCS - -/* Define if you have the memmove function. */ -#undef HAVE_MEMMOVE - -/* Define if you have the memset function. */ -#undef HAVE_MEMSET - -/* Define if you have the mkfifo function. */ -#undef HAVE_MKFIFO - -/* Define if you have the pathconf function. */ -#undef HAVE_PATHCONF - -/* Define if you have the putenv function. */ -#undef HAVE_PUTENV - -/* Define if you have the readlink function. */ -#undef HAVE_READLINK - -/* Define if you have the regcomp function. */ -#undef HAVE_REGCOMP - -/* Define if you have the regexec function. */ -#undef HAVE_REGEXEC - -/* Define if you have the rename function. */ -#undef HAVE_RENAME - -/* Define if you have the sbrk function. */ -#undef HAVE_SBRK - -/* Define if you have the select function. */ -#undef HAVE_SELECT - -/* Define if you have the setdtablesize function. */ -#undef HAVE_SETDTABLESIZE - -/* Define if you have the setenv function. */ -#undef HAVE_SETENV - -/* Define if you have the setlinebuf function. */ -#undef HAVE_SETLINEBUF - -/* Define if you have the setlocale function. */ -#undef HAVE_SETLOCALE - -/* Define if you have the setostype function. */ -#undef HAVE_SETOSTYPE - -/* Define if you have the setvbuf function. */ -#undef HAVE_SETVBUF - -/* Define if you have the siginterrupt function. */ -#undef HAVE_SIGINTERRUPT - -/* Define if you have the POSIX.1-style sigsetjmp function. */ -#undef HAVE_POSIX_SIGSETJMP - -/* Define if you have the snprintf function. */ -#undef HAVE_SNPRINTF - -/* Define if you have the strcasecmp function. */ -#undef HAVE_STRCASECMP - -/* Define if you have the strchr function. */ -#undef HAVE_STRCHR - -/* Define if you have the strcoll function. */ -#undef HAVE_STRCOLL - -/* Define if you have the strerror function. */ -#undef HAVE_STRERROR - -/* Define if you have the strftime function. */ -#undef HAVE_STRFTIME - -/* Define if you have the strpbrk function. */ -#undef HAVE_STRPBRK - -/* Define if you have the strstr function. */ -#undef HAVE_STRSTR - -/* Define if you have the strtod function. */ -#undef HAVE_STRTOD - -/* Define if you have the strtoimax function. */ -#undef HAVE_STRTOIMAX - -/* Define if you have the strtol function. */ -#undef HAVE_STRTOL - -/* Define if you have the strtoll function. */ -#undef HAVE_STRTOLL - -/* Define if you have the strtoul function. */ -#undef HAVE_STRTOUL - -/* Define if you have the strtoull function. */ -#undef HAVE_STRTOULL - -/* Define if you have the strtoumax function. */ -#undef HAVE_STRTOUMAX - -/* Define if you have the strsignal function or macro. */ -#undef HAVE_STRSIGNAL - -/* Define if you have the sysconf function. */ -#undef HAVE_SYSCONF - -/* Define if you have the tcgetattr function. */ -#undef HAVE_TCGETATTR - -/* Define if you have the tcgetpgrp function. */ -#undef HAVE_TCGETPGRP - -/* Define if you have the times function. */ -#undef HAVE_TIMES - -/* Define if you have the ttyname function. */ -#undef HAVE_TTYNAME - -/* Define if you have the tzset function. */ -#undef HAVE_TZSET - -/* Define if you have the ulimit function. */ -#undef HAVE_ULIMIT - -/* Define if you have the uname function. */ -#undef HAVE_UNAME - -/* Define if you have the unsetenv function. */ -#undef HAVE_UNSETENV - -/* Define if you have the vasprintf function. */ -#undef HAVE_VASPRINTF - -/* Define if you have the vprintf function. */ -#undef HAVE_VPRINTF - -/* Define if you have the vsnprintf function. */ -#undef HAVE_VSNPRINTF - -/* Define if you have the waitpid function. */ -#undef HAVE_WAITPID - -/* Define if you have the wait3 function. */ -#undef HAVE_WAIT3 - -/* Define if you have the wcsdup function. */ -#undef HAVE_WCSDUP - -/* Define if you have the wctomb function. */ -#undef HAVE_WCTOMB - -/* Define if you have the wcwidth function. */ -#undef HAVE_WCWIDTH - -/* Presence of certain system include files. */ - -/* Define if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define if you have the header file. */ -#undef HAVE_DIRENT_H - -/* Define if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define if you have the header file. */ -#undef HAVE_GRP_H - -/* Define if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define if you have the header file. */ -#undef HAVE_LANGINFO_H - -/* Define if you have the header file. */ -#undef HAVE_LIBINTL_H - -/* Define if you have the header file. */ -#undef HAVE_LIMITS_H - -/* Define if you have the header file. */ -#undef HAVE_LOCALE_H - -/* Define if you have the header file. */ -#undef HAVE_NDIR_H - -/* Define if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define if you have the header file. */ -#undef HAVE_REGEX_H - -/* Define if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define if you have the header file. */ -#undef HAVE_STDARG_H - -/* Define if you have the header file. */ -#undef HAVE_STRING_H - -/* Define if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define if you have the header file. */ -#undef HAVE_STDDEF_H - -/* Define if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_DIR_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_FILE_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_NDIR_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_PTE_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_PTEM_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_STREAM_H - -/* Define if you have */ -#undef HAVE_SYS_TIME_H - -#undef TIME_WITH_SYS_TIME - -/* Define if you have */ -#undef HAVE_SYS_TIMES_H - -/* Define if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define if you have that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H - -/* Define if you have the header file. */ -#undef HAVE_TERMCAP_H - -/* Define if you have the header file. */ -#undef HAVE_TERMIO_H - -/* Define if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define if you have the header file. */ -#undef HAVE_VARARGS_H - -/* Define if you have the header file. */ -#undef HAVE_WCHAR_H - -/* Define if you have the header file. */ -#undef HAVE_WCTYPE_H - -/* Presence of certain system libraries. */ - -#undef HAVE_LIBDL - -#undef HAVE_LIBSUN - -#undef HAVE_LIBSOCKET - - -/* Define if on MINIX. */ -#undef _MINIX - -/* Are we running SVR5 (UnixWare 7)? */ -#undef SVR5 - -/* Are we running SVR4.2? */ -#undef SVR4_2 - -/* Are we running some version of SVR4? */ -#undef SVR4 - -/* Define if job control is unusable or unsupported. */ -#undef JOB_CONTROL_MISSING - -/* Do we need to define _KERNEL to get the RLIMIT_* defines from - ? */ -#undef RLIMIT_NEEDS_KERNEL - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Do strcoll(3) and strcmp(3) give different results in the default locale? */ -#undef STRCOLL_BROKEN - -#undef DUP2_BROKEN - -#undef GETCWD_BROKEN - -/* Additional defines for configuring lib/intl, maintained by autoscan/autoheader */ - -/* Define if you have the header file. */ -#undef HAVE_ARGZ_H - -/* Define if you have the header file. */ -#undef HAVE_ERRNO_H - -/* Define if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define if you have the header file. */ -#undef HAVE_MALLOC_H - -/* Define if you have the header file. */ -#undef HAVE_STDIO_EXT_H - -/* Define if you have the `dcgettext' function. */ -#undef HAVE_DCGETTEXT - -/* Define if your system has a working `malloc' function. */ -#undef HAVE_MALLOC - -/* Define if you have the `mempcpy' function. */ -#undef HAVE_MEMPCPY - -/* Define if you have a working `mmap' system call. */ -#undef HAVE_MMAP - -/* Define if you have the `munmap' function. */ -#undef HAVE_MUNMAP - -/* Define if you have the `nl_langinfo' function. */ -#undef HAVE_NL_LANGINFO - -/* Define if you have the `stpcpy' function. */ -#undef HAVE_STPCPY - -/* Define if you have the `strcspn' function. */ -#undef HAVE_STRCSPN - -/* Define if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define if you have the `__argz_count' function. */ -#undef HAVE___ARGZ_COUNT - -/* Define if you have the `__argz_next' function. */ -#undef HAVE___ARGZ_NEXT - -/* Define if you have the `__argz_stringify' function. */ -#undef HAVE___ARGZ_STRINGIFY - -/* End additions for lib/intl */ - -#include "config-bot.h" - -#endif /* _CONFIG_H_ */ diff --git a/configure.in~ b/configure.in~ deleted file mode 100644 index ade5b8db8..000000000 --- a/configure.in~ +++ /dev/null @@ -1,1019 +0,0 @@ -dnl -dnl Configure script for bash-3.0 -dnl -dnl report bugs to chet@po.cwru.edu -dnl -dnl Process this file with autoconf to produce a configure script. - -# Copyright (C) 1987-2004 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., 59 Temple Place - Suite 330, Boston, MA -# 02111-1307, USA. - -AC_REVISION([for Bash 3.0, version 3.163, from autoconf version] AC_ACVERSION)dnl - -define(bashvers, 3.0) -define(relstatus, rc1) - -AC_INIT(bash, bashvers-relstatus, bug-bash@gnu.org) - -dnl make sure we are using a recent autoconf version -AC_PREREQ(2.50) - -AC_CONFIG_SRCDIR(shell.h) -dnl where to find install.sh, config.sub, and config.guess -AC_CONFIG_AUX_DIR(./support) -AC_CONFIG_HEADERS(config.h) - -dnl checks for version info -BASHVERS=bashvers -RELSTATUS=relstatus - -dnl defaults for debug settings -case "$RELSTATUS" in -alp*|bet*|dev*|rc*) DEBUG='-DDEBUG' MALLOC_DEBUG='-DMALLOC_DEBUG' ;; -*) DEBUG= MALLOC_DEBUG= ;; -esac - -dnl canonicalize the host and os so we can do some tricky things before -dnl parsing options -AC_CANONICAL_HOST - -dnl configure defaults -opt_bash_malloc=yes -opt_purify=no -opt_purecov=no -opt_afs=no -opt_curses=no -opt_with_installed_readline=no - -#htmldir= - -dnl some systems should be configured without the bash malloc by default -dnl and some need a special compiler or loader -dnl look in the NOTES file for more -case "${host_cpu}-${host_os}" in -alpha*-*) opt_bash_malloc=no ;; # alpha running osf/1 or linux -*[[Cc]]ray*-*) opt_bash_malloc=no ;; # Crays -*-osf1*) opt_bash_malloc=no ;; # other osf/1 machines -sparc-svr4*) opt_bash_malloc=no ;; # sparc SVR4, SVR4.2 -sparc-netbsd*) opt_bash_malloc=no ;; # needs 8-byte alignment -mips-irix6*) opt_bash_malloc=no ;; # needs 8-byte alignment -m68k-sysv) opt_bash_malloc=no ;; # fixes file descriptor leak in closedir -sparc-linux*) opt_bash_malloc=no ;; # sparc running linux; requires ELF -*-freebsd*-gnu) opt_bash_malloc=no ;; # there's some undetermined problem here -#*-freebsd*) opt_bash_malloc=no ;; # they claim it's better; I disagree -*-openbsd*) opt_bash_malloc=no ;; # they claim it needs eight-bit alignment -*-aix*) opt_bash_malloc=no ;; # AIX machines -*-nextstep*) opt_bash_malloc=no ;; # NeXT machines running NeXTstep -*-macos*) opt_bash_malloc=no ;; # Apple MacOS X -*-rhapsody*) opt_bash_malloc=no ;; # Apple Rhapsody (MacOS X) -*-darwin*) opt_bash_malloc=no ;; # Apple Darwin (MacOS X) -*-dgux*) opt_bash_malloc=no ;; # DG/UX machines -*-qnx*) opt_bash_malloc=no ;; # QNX 4.2 -*-machten4) opt_bash_malloc=no ;; # MachTen 4.x -*-bsdi2.1|*-bsdi3.?) opt_bash_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins -*-beos*) opt_bash_malloc=no ;; # they say it's suitable -*-cygwin*) opt_bash_malloc=no ;; # Cygnus's CYGWIN environment -*-opennt*|*-interix*) opt_bash_malloc=no ;; # Interix, now owned by Microsoft -esac - -# memory scrambling on free() -case "${host_os}" in -sco3.2v5*|sco3.2v4*) opt_memscramble=no ;; -*) opt_memscramble=yes ;; -esac - -dnl -dnl macros for the bash debugger -dnl -AM_PATH_LISPDIR -AC_ARG_VAR(DEBUGGER_START_FILE, [location of bash debugger initialization file]) - -dnl arguments to configure -dnl packages -AC_ARG_WITH(afs, AC_HELP_STRING([--with-afs], [if you are running AFS]), opt_afs=$withval) -AC_ARG_WITH(bash-malloc, AC_HELP_STRING([--with-bash-malloc], [use the Bash version of malloc]), opt_bash_malloc=$withval) -AC_ARG_WITH(curses, AC_HELP_STRING([--with-curses], [use the curses library instead of the termcap library]), opt_curses=$withval) -AC_ARG_WITH(gnu-malloc, AC_HELP_STRING([--with-gnu-malloc], [synonym for --with-bash-malloc]), opt_bash_malloc=$withval) -AC_ARG_WITH(installed-readline, AC_HELP_STRING([--with-installed-readline], [use a version of the readline library that is already installed]), opt_with_installed_readline=$withval) -AC_ARG_WITH(purecov, AC_HELP_STRING([--with-purecov], [configure to postprocess with pure coverage]), opt_purecov=$withval) -AC_ARG_WITH(purify, AC_HELP_STRING([--with-purify], [configure to postprocess with purify]), opt_purify=$withval) - -if test "$opt_bash_malloc" = yes; then - MALLOC_TARGET=malloc - MALLOC_SRC=malloc.c - - MALLOC_LIB='-lmalloc' - MALLOC_LIBRARY='$(ALLOC_LIBDIR)/libmalloc.a' - MALLOC_LDFLAGS='-L$(ALLOC_LIBDIR)' - MALLOC_DEP='$(MALLOC_LIBRARY)' - - AC_DEFINE(USING_BASH_MALLOC) -else - MALLOC_LIB= - MALLOC_LIBRARY= - MALLOC_LDFLAGS= - MALLOC_DEP= -fi - -if test "$opt_purify" = yes; then - PURIFY="purify " - AC_DEFINE(DISABLE_MALLOC_WRAPPERS) -else - PURIFY= -fi - -if test "$opt_purecov" = yes; then - PURIFY="${PURIFY}purecov" -fi - -if test "$opt_afs" = yes; then - AC_DEFINE(AFS) -fi - -if test "$opt_curses" = yes; then - prefer_curses=yes -fi - -if test -z "${DEBUGGER_START_FILE}"; then - DEBUGGER_START_FILE=${ac_default_prefix}/lib/bashdb/bashdb-main.inc -fi - -dnl optional shell features in config.h.in -opt_minimal_config=no - -opt_job_control=yes -opt_alias=yes -opt_readline=yes -opt_history=yes -opt_bang_history=yes -opt_dirstack=yes -opt_restricted=yes -opt_process_subst=yes -opt_prompt_decoding=yes -opt_select=yes -opt_help=yes -opt_array_variables=yes -opt_dparen_arith=yes -opt_extended_glob=yes -opt_brace_expansion=yes -opt_disabled_builtins=no -opt_command_timing=yes -opt_xpg_echo=no -opt_cond_command=yes -opt_cond_regexp=yes -opt_arith_for_command=yes -opt_net_redirs=yes -opt_progcomp=yes -opt_separate_help=no -opt_multibyte=yes -opt_debugger=yes - -dnl options that affect how bash is compiled and linked -opt_static_link=no -opt_profiling=no - -dnl argument parsing for optional features -AC_ARG_ENABLE(minimal-config, AC_HELP_STRING([--enable-minimal-config], [a minimal sh-like configuration]), opt_minimal_config=$enableval) - -dnl a minimal configuration turns everything off, but features can be -dnl added individually -if test $opt_minimal_config = yes; then - opt_job_control=no opt_alias=no opt_readline=no - opt_history=no opt_bang_history=no opt_dirstack=no - opt_restricted=no opt_process_subst=no opt_prompt_decoding=no - opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no - opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no - opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no - opt_net_redirs=no opt_progcomp=no opt_separate_help=no - opt_multibyte=yes opt_cond_regexp=no -fi - -AC_ARG_ENABLE(alias, AC_HELP_STRING([--enable-alias], [enable shell aliases]), opt_alias=$enableval) -AC_ARG_ENABLE(arith-for-command, AC_HELP_STRING([--enable-arith-for-command], [enable arithmetic for command]), opt_arith_for_command=$enableval) -AC_ARG_ENABLE(array-variables, AC_HELP_STRING([--enable-array-variables], [include shell array variables]), opt_array_variables=$enableval) -AC_ARG_ENABLE(bang-history, AC_HELP_STRING([--enable-bang-history], [turn on csh-style history substitution]), opt_bang_history=$enableval) -AC_ARG_ENABLE(brace-expansion, AC_HELP_STRING([--enable-brace-expansion], [include brace expansion]), opt_brace_expansion=$enableval) -AC_ARG_ENABLE(command-timing, AC_HELP_STRING([--enable-command-timing], [enable the time reserved word and command timing]), opt_command_timing=$enableval) -AC_ARG_ENABLE(cond-command, AC_HELP_STRING([--enable-cond-command], [enable the conditional command]), opt_cond_command=$enableval) -AC_ARG_ENABLE(cond-regexp, AC_HELP_STRING([--enable-cond-regexp], [enable extgended regular expression matching in conditional commands]), opt_cond_regexp=$enableval) -AC_ARG_ENABLE(debugger, AC_HELP_STRING([--enable-debugger], [enable support for bash debugger]), opt_debugger=$enableval) -AC_ARG_ENABLE(directory-stack, AC_HELP_STRING([--enable-directory-stack], [enable builtins pushd/popd/dirs]), opt_dirstack=$enableval) -AC_ARG_ENABLE(disabled-builtins, AC_HELP_STRING([--enable-disabled-builtins], [allow disabled builtins to still be invoked]), opt_disabled_builtins=$enableval) -AC_ARG_ENABLE(dparen-arithmetic, AC_HELP_STRING([--enable-dparen-arithmetic], [include ((...)) command]), opt_dparen_arith=$enableval) -AC_ARG_ENABLE(extended-glob, AC_HELP_STRING([--enable-extended-glob], [include ksh-style extended pattern matching]), opt_extended_glob=$enableval) -AC_ARG_ENABLE(help-builtin, AC_HELP_STRING([--enable-help-builtin], [include the help builtin]), opt_help=$enableval) -AC_ARG_ENABLE(history, AC_HELP_STRING([--enable-history], [turn on command history]), opt_history=$enableval) -AC_ARG_ENABLE(job-control, AC_HELP_STRING([--enable-job-control], [enable job control features]), opt_job_control=$enableval) -AC_ARG_ENABLE(multibyte, AC_HELP_STRING([--enable-multibyte], [enable multibyte characters if OS supports them]), opt_multibyte=$enableval) -AC_ARG_ENABLE(net-redirections, AC_HELP_STRING([--enable-net-redirections], [enable /dev/tcp/host/port redirection]), opt_net_redirs=$enableval) -AC_ARG_ENABLE(process-substitution, AC_HELP_STRING([--enable-process-substitution], [enable process substitution]), opt_process_subst=$enableval) -AC_ARG_ENABLE(progcomp, AC_HELP_STRING([--enable-progcomp], [enable programmable completion and the complete builtin]), opt_progcomp=$enableval) -AC_ARG_ENABLE(prompt-string-decoding, AC_HELP_STRING([--enable-prompt-string-decoding], [turn on escape character decoding in prompts]), opt_prompt_decoding=$enableval) -AC_ARG_ENABLE(readline, AC_HELP_STRING([--enable-readline], [turn on command line editing]), opt_readline=$enableval) -AC_ARG_ENABLE(restricted, AC_HELP_STRING([--enable-restricted], [enable a restricted shell]), opt_restricted=$enableval) -AC_ARG_ENABLE(select, AC_HELP_STRING([--enable-select], [include select command]), opt_select=$enableval) -AC_ARG_ENABLE(separate-helpfiles, AC_HELP_STRING([--enable-separate-helpfiles], [use external files for help builtin documentation]), opt_separate_help=$enableval) -AC_ARG_ENABLE(usg-echo-default, AC_HELP_STRING([--enable-usg-echo-default], [a synonym for --enable-xpg-echo-default]), opt_xpg_echo=$enableval) -AC_ARG_ENABLE(xpg-echo-default, AC_HELP_STRING([--enable-xpg-echo-default], [make the echo builtin expand escape sequences by default]), opt_xpg_echo=$enableval) - -dnl options that alter how bash is compiled and linked -AC_ARG_ENABLE(mem-scramble, AC_HELP_STRING([--enable-mem-scramble], [scramble memory on calls to malloc and free]), opt_memscramble=$enableval) -AC_ARG_ENABLE(profiling, AC_HELP_STRING([--enable-profiling], [allow profiling with gprof]), opt_profiling=$enableval) -AC_ARG_ENABLE(static-link, AC_HELP_STRING([--enable-static-link], [link bash statically, for use as a root shell]), opt_static_link=$enableval) - -dnl opt_job_control is handled later, after BASH_JOB_CONTROL_MISSING runs - -dnl opt_readline and opt_history are handled later, because AC_PROG_CC needs -dnl to be run before we can check the version of an already-installed readline -dnl library - -if test $opt_alias = yes; then -AC_DEFINE(ALIAS) -fi -if test $opt_dirstack = yes; then -AC_DEFINE(PUSHD_AND_POPD) -fi -if test $opt_restricted = yes; then -AC_DEFINE(RESTRICTED_SHELL) -fi -if test $opt_process_subst = yes; then -AC_DEFINE(PROCESS_SUBSTITUTION) -fi -if test $opt_prompt_decoding = yes; then -AC_DEFINE(PROMPT_STRING_DECODE) -fi -if test $opt_select = yes; then -AC_DEFINE(SELECT_COMMAND) -fi -if test $opt_help = yes; then -AC_DEFINE(HELP_BUILTIN) -fi -if test $opt_array_variables = yes; then -AC_DEFINE(ARRAY_VARS) -fi -if test $opt_dparen_arith = yes; then -AC_DEFINE(DPAREN_ARITHMETIC) -fi -if test $opt_brace_expansion = yes; then -AC_DEFINE(BRACE_EXPANSION) -fi -if test $opt_disabled_builtins = yes; then -AC_DEFINE(DISABLED_BUILTINS) -fi -if test $opt_command_timing = yes; then -AC_DEFINE(COMMAND_TIMING) -fi -if test $opt_xpg_echo = yes ; then -AC_DEFINE(DEFAULT_ECHO_TO_XPG) -fi -if test $opt_extended_glob = yes ; then -AC_DEFINE(EXTENDED_GLOB) -fi -if test $opt_cond_command = yes ; then -AC_DEFINE(COND_COMMAND) -fi -if test $opt_cond_regexp = yes ; then -AC_DEFINE(COND_REGEXP) -fi -if test $opt_arith_for_command = yes; then -AC_DEFINE(ARITH_FOR_COMMAND) -fi -if test $opt_net_redirs = yes; then -AC_DEFINE(NETWORK_REDIRECTIONS) -fi -if test $opt_progcomp = yes; then -AC_DEFINE(PROGRAMMABLE_COMPLETION) -fi -if test $opt_multibyte = no; then -AC_DEFINE(NO_MULTIBYTE_SUPPORT) -fi -if test $opt_debugger = yes; then -AC_DEFINE(DEBUGGER) -fi - -if test $opt_memscramble = yes; then -AC_DEFINE(MEMSCRAMBLE) -fi - -if test "$opt_minimal_config" = yes; then - TESTSCRIPT=run-minimal -else - TESTSCRIPT=run-all -fi - -HELPDIR= HELPDIRDEFINE= HELPINSTALL= -if test "$opt_separate_help" != no; then - if test "$opt_separate_help" = "yes" ; then - HELPDIR='${datadir}/bash' - else - HELPDIR=$opt_separate_help - fi - HELPDIRDEFINE='-H ${HELPDIR}' - HELPINSTALL='install-help' -fi - -dnl now substitute in the values generated by arguments -AC_SUBST(TESTSCRIPT) -AC_SUBST(PURIFY) -AC_SUBST(MALLOC_TARGET) -AC_SUBST(MALLOC_SRC) - -AC_SUBST(MALLOC_LIB) -AC_SUBST(MALLOC_LIBRARY) -AC_SUBST(MALLOC_LDFLAGS) -AC_SUBST(MALLOC_DEP) - -AC_SUBST(htmldir) - -AC_SUBST(HELPDIR) -AC_SUBST(HELPDIRDEFINE) -AC_SUBST(HELPINSTALL) - -echo "" -echo "Beginning configuration for bash-$BASHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}" -echo "" - -dnl compilation checks -dnl AC_PROG_CC sets $cross_compiling to `yes' if cross-compiling for a -dnl different environment -AC_PROG_CC - -dnl test for Unix variants -AC_ISC_POSIX -AC_MINIX - -dnl test for non-Unix variants -AC_CYGWIN -AC_MINGW32 - -AC_SYS_LARGEFILE - -dnl BEGIN changes for cross-building for cygwin and BeOS - -SIGNAMES_H=lsignames.h - -dnl load up the cross-building cache file -- add more cases and cache -dnl files as necessary - -dnl Note that host and target machine are the same, and different than the -dnl build machine. -dnl Set SIGNAMES_H based on whether or not we're cross-compiling. - -if test "x$cross_compiling" = "xyes"; then - case "${host}" in - *-cygwin*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - SIGNAMES_H='$(srcdir)/cross-build/win32sig.h' - ;; - i[[3456]]86-*-beos*) - cross_cache=${srcdir}/cross-build/x86-beos.cache - SIGNAMES_H='${srcdir}/cross-build/beos-sig.h' - ;; - *) echo "configure: cross-compiling for $host is not supported" >&2 - ;; - esac - if test -n "${cross_cache}" && test -r "${cross_cache}"; then - echo "loading cross-build cache file ${cross_cache}" - . ${cross_cache} - fi - unset cross_cache -fi -AC_SUBST(SIGNAMES_H) - -if test -z "$CC_FOR_BUILD"; then - if test "x$cross_compiling" = "xno"; then - CC_FOR_BUILD='$(CC)' - else - CC_FOR_BUILD=gcc - fi -fi -AC_SUBST(CC_FOR_BUILD) - -dnl END changes for cross-building - -dnl We want these before the checks, so the checks can modify their values. -test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 - -dnl If we're using gcc and the user hasn't specified CFLAGS, add -O2 to CFLAGS. -test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O2" - -dnl handle options that alter how bash is compiled and linked -dnl these must come after the test for cc/gcc -if test "$opt_profiling" = "yes"; then - PROFILE_FLAGS=-pg - case "$host_os" in - solaris2*) ;; - *) opt_static_link=yes ;; - esac - DEBUG= MALLOC_DEBUG= -fi - -if test "$opt_static_link" = yes; then - # if we're using gcc, add `-static' to LDFLAGS, except on Solaris >= 2 - if test -n "$GCC" || test "$ac_cv_prog_gcc" = "yes"; then - STATIC_LD="-static" - case "$host_os" in - solaris2*) ;; - *) LDFLAGS="$LDFLAGS -static" ;; # XXX experimental - esac - fi -fi - -test -z "$CPPFLAGS_FOR_BUILD" && CPPFLAGS_FOR_BUILD="$CPPFLAGS" -test -z "$CFLAGS_FOR_BUILD" && CFLAGS_FOR_BUILD="-g" - -AC_SUBST(CFLAGS) -AC_SUBST(CPPFLAGS) -AC_SUBST(LDFLAGS) -AC_SUBST(STATIC_LD) - -AC_SUBST(CFLAGS_FOR_BUILD) -AC_SUBST(CPPFLAGS_FOR_BUILD) -AC_SUBST(LDFLAGS_FOR_BUILD) - -AC_PROG_GCC_TRADITIONAL - -dnl BEGIN READLINE and HISTORY LIBRARY SECTION -dnl prepare to allow bash to be linked against an already-installed readline - -dnl first test that the readline version is new enough to link bash against -if test "$opt_readline" = yes && test "$opt_with_installed_readline" != "no" -then - # If the user specified --with-installed-readline=PREFIX and PREFIX - # is not `yes', set ac_cv_rl_prefix to PREFIX - test $opt_with_installed_readline != "yes" && ac_cv_rl_prefix=$opt_with_installed_readline - - RL_LIB_READLINE_VERSION - - case "$ac_cv_rl_version" in - 5*|6*|7*|8*|9*) ;; - *) opt_with_installed_readline=no - AC_MSG_WARN(installed readline library is too old to be linked with bash) - AC_MSG_WARN(using private bash version) - ;; - esac -fi - -if test $opt_readline = yes; then - AC_DEFINE(READLINE) - READLINE_LIB=-lreadline - if test "$opt_with_installed_readline" != "no" ; then - case "$opt_with_installed_readline" in - yes) RL_INCLUDE= ;; - *) case "$RL_INCLUDEDIR" in - /usr/include) ;; - *) RL_INCLUDE='-I${RL_INCLUDEDIR}' ;; - esac - ;; - esac - READLINE_DEP= - else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_DEP='$(READLINE_LIBRARY)' - fi -else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_LIB= READLINE_DEP= -fi -if test $opt_history = yes || test $opt_bang_history = yes; then - if test $opt_history = yes; then - AC_DEFINE(HISTORY) - fi - if test $opt_bang_history = yes; then - AC_DEFINE(BANG_HISTORY) - fi - HISTORY_LIB=-lhistory - if test "$opt_with_installed_readline" != "no"; then - HIST_LIBDIR=$RL_LIBDIR - HISTORY_DEP= - case "$opt_with_installed_readline" in - yes) RL_INCLUDE= ;; - *) case "$RL_INCLUDEDIR" in - /usr/include) ;; - *) RL_INCLUDE='-I${RL_INCLUDEDIR}' ;; - esac - ;; - esac - else - HIST_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - HISTORY_DEP='$(HISTORY_LIBRARY)' - fi -else - HIST_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - HISTORY_LIB= HISTORY_DEP= -fi -AC_SUBST(READLINE_LIB) -AC_SUBST(READLINE_DEP) -AC_SUBST(RL_LIBDIR) -AC_SUBST(RL_INCLUDEDIR) -AC_SUBST(RL_INCLUDE) -AC_SUBST(HISTORY_LIB) -AC_SUBST(HISTORY_DEP) -AC_SUBST(HIST_LIBDIR) - -dnl END READLINE and HISTORY LIBRARY SECTION - -dnl programs needed by the build and install process -AC_PROG_INSTALL -AC_CHECK_PROG(AR, ar, , ar) -dnl Set default for ARFLAGS, since autoconf does not have a macro for it. -dnl This allows people to set it when running configure or make -test -n "$ARFLAGS" || ARFLAGS="cr" -AC_PROG_RANLIB -AC_PROG_YACC -AC_PROG_MAKE_SET - -case "$host_os" in -opennt*|interix*) MAKE_SHELL="$INTERIX_ROOT/bin/sh" ;; -*) MAKE_SHELL=/bin/sh ;; -esac -AC_SUBST(MAKE_SHELL) - -dnl Turn on any extensions available in the GNU C library. -AC_DEFINE(_GNU_SOURCE, 1) - -dnl C compiler characteristics -AC_C_CONST -AC_C_INLINE -AC_C_BIGENDIAN -AC_C_STRINGIZE -AC_C_LONG_DOUBLE -AC_C_PROTOTYPES -AC_C_CHAR_UNSIGNED - -dnl initialize GNU gettext -AM_GNU_GETTEXT([no-libtool], [need-ngettext], [lib/intl]) - -dnl header files -AC_HEADER_DIRENT -AC_HEADER_TIME - -BASH_HEADER_INTTYPES - -AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ - memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ - stddef.h stdint.h netdb.h grp.h strings.h regex.h) -AC_CHECK_HEADERS(sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ - sys/resource.h sys/param.h sys/socket.h sys/stat.h \ - sys/time.h sys/times.h sys/types.h sys/wait.h) -AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) - -dnl special checks for libc functions -AC_FUNC_ALLOCA -AC_FUNC_GETPGRP -AC_FUNC_SETVBUF_REVERSED -AC_FUNC_VPRINTF -AC_FUNC_STRCOLL - -dnl if we're not using the bash malloc but require the C alloca, set things -dnl up to build a libmalloc.a containing only alloca.o - -if test "$ac_cv_func_alloca_works" = "no" && test "$opt_bash_malloc" = "no"; then - MALLOC_TARGET=alloca - MALLOC_SRC=alloca.c - - MALLOC_LIB='-lmalloc' - MALLOC_LIBRARY='$(ALLOC_LIBDIR)/libmalloc.a' - MALLOC_LDFLAGS='-L$(ALLOC_LIBDIR)' - MALLOC_DEP='$(MALLOC_LIBRARY)' -fi - -dnl if vprintf is not in libc, see if it's defined in stdio.h -if test "$ac_cv_func_vprintf" = no; then - AC_MSG_CHECKING(for declaration of vprintf in stdio.h) - AC_EGREP_HEADER([[int[ ]*vprintf[^a-zA-Z0-9]]],stdio.h,ac_cv_func_vprintf=yes) - AC_MSG_RESULT($ac_cv_func_vprintf) - if test $ac_cv_func_vprintf = yes; then - AC_DEFINE(HAVE_VPRINTF) - fi -fi - -if test "$ac_cv_func_vprintf" = no && test "$ac_cv_func__doprnt" = "yes"; then - AC_LIBOBJ(vprint) -fi - -dnl signal stuff -AC_TYPE_SIGNAL - -dnl checks for certain version-specific system calls and libc functions -AC_CHECK_FUNC(__setostype, AC_DEFINE(HAVE_SETOSTYPE)) -AC_CHECK_FUNC(wait3, AC_DEFINE(HAVE_WAIT3)) -AC_CHECK_FUNC(isinf, AC_DEFINE(HAVE_ISINF_IN_LIBC)) - -dnl checks for missing libc functions -AC_CHECK_FUNC(mkfifo,AC_DEFINE(HAVE_MKFIFO),AC_DEFINE(MKFIFO_MISSING)) - -dnl checks for system calls -AC_CHECK_FUNCS(dup2 select getdtablesize getgroups gethostname \ - setdtablesize getpagesize killpg lstat getpeername sbrk \ - getrlimit getrusage gettimeofday waitpid tcgetpgrp \ - readlink) -AC_REPLACE_FUNCS(rename) - -dnl checks for c library functions -AC_CHECK_FUNCS(bcopy bzero confstr sysconf pathconf setenv putenv unsetenv \ - setlinebuf setvbuf setlocale strchr tcgetattr uname \ - ulimit tzset siginterrupt memmove ttyname times \ - getaddrinfo gethostbyname getservbyname getservent inet_aton \ - vsnprintf snprintf vasprintf asprintf fnmatch regcomp regexec) -AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit) -AC_REPLACE_FUNCS(getcwd strcasecmp strerror strftime strpbrk memset strstr) -AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax) - -AC_CHECK_DECLS([confstr]) -AC_CHECK_DECLS([printf]) -AC_CHECK_DECLS([sbrk]) -AC_CHECK_DECLS([strcpy]) -AC_CHECK_DECLS([strsignal]) - -dnl Extra test to detect the horribly broken HP/UX 11.00 strtold(3) -AC_CHECK_DECLS([strtold], [ - AC_MSG_CHECKING([for broken strtold]) - AC_CACHE_VAL(bash_cv_strtold_broken, - [AC_TRY_COMPILE( - [#include ], - [int main() { long double r; char *foo, bar; r = strtold(foo, &bar);}], - bash_cv_strtold_broken=no, bash_cv_strtold_broken=yes, - [AC_MSG_WARN(cannot check for broken strtold if cross-compiling, defaulting to no)]) - ] - ) - AC_MSG_RESULT($bash_cv_strtold_broken) - if test "$bash_cv_strtold_broken" = "yes" ; then - AC_DEFINE(STRTOLD_BROKEN) - fi -]) - - -BASH_CHECK_DECL(strtoimax) -BASH_CHECK_DECL(strtol) -BASH_CHECK_DECL(strtoll) -BASH_CHECK_DECL(strtoul) -BASH_CHECK_DECL(strtoull) -BASH_CHECK_DECL(strtoumax) - -AC_FUNC_MKTIME - -dnl -dnl Checks for lib/intl and related code (uses some of the output from -dnl AM_GNU_GETTEXT) -dnl - -AC_CHECK_HEADERS([argz.h errno.h fcntl.h malloc.h stdio_ext.h]) - -AC_FUNC_MALLOC -AC_FUNC_MMAP -AC_CHECK_FUNCS([__argz_count __argz_next __argz_stringify dcgettext mempcpy \ - munmap stpcpy strcspn strdup]) - -INTL_DEP= INTL_INC= LIBINTL_H= -if test "x$USE_INCLUDED_LIBINTL" = "xyes"; then - INTL_DEP='${INTL_LIBDIR}/libintl.a' - INTL_INC='-I${INTL_LIBSRC} -I${INTL_BUILDDIR}' - LIBINTL_H='${INTL_BUILDDIR}/libintl.h' -fi -AC_SUBST(INTL_DEP) -AC_SUBST(INTL_INC) -AC_SUBST(LIBINTL_H) - -dnl -dnl End of checks needed by files in lib/intl -dnl - -BASH_CHECK_MULTIBYTE - -dnl checks for the dynamic loading library functions in libc and libdl -if test "$opt_static_link" != yes; then -AC_CHECK_LIB(dl, dlopen) -AC_CHECK_FUNCS(dlopen dlclose dlsym) -fi - -dnl this defines SYS_SIGLIST_DECLARED -AC_DECL_SYS_SIGLIST - -dnl network functions -- check for inet_aton again -if test "$ac_cv_func_inet_aton" != 'yes'; then -BASH_FUNC_INET_ATON -fi - -dnl libraries -dnl this is reportedly no longer necessary for irix[56].? -case "$host_os" in -irix4*) AC_CHECK_LIB(sun, getpwent) ;; -esac - -dnl check for getpeername in the socket library only if it's not in libc -if test "$ac_cv_func_getpeername" = no; then - BASH_CHECK_LIB_SOCKET -fi -dnl check for gethostbyname in socket libraries if it's not in libc -if test "$ac_cv_func_gethostbyname" = no; then - BASH_FUNC_GETHOSTBYNAME -fi - -dnl system types -AC_TYPE_GETGROUPS -AC_TYPE_OFF_T -AC_TYPE_MODE_T -AC_TYPE_UID_T -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_CHECK_TYPE(ssize_t, int) -AC_CHECK_TYPE(time_t, long) - -BASH_TYPE_LONG_LONG -BASH_TYPE_UNSIGNED_LONG_LONG - -AC_TYPE_SIGNAL - -AC_CHECK_SIZEOF(char, 1) -AC_CHECK_SIZEOF(short, 2) -AC_CHECK_SIZEOF(int, 4) -AC_CHECK_SIZEOF(long, 4) -AC_CHECK_SIZEOF(char *, 4) -AC_CHECK_SIZEOF(double, 8) -AC_CHECK_SIZEOF([long long], 8) - -AC_CHECK_TYPE(u_int, [unsigned int]) -AC_CHECK_TYPE(u_long, [unsigned long]) - -BASH_TYPE_BITS16_T -BASH_TYPE_U_BITS16_T -BASH_TYPE_BITS32_T -BASH_TYPE_U_BITS32_T -BASH_TYPE_BITS64_T - -BASH_TYPE_PTRDIFF_T - -dnl structures -AC_HEADER_STAT - -dnl system services -AC_SYS_INTERPRETER -if test $ac_cv_sys_interpreter = yes; then -AC_DEFINE(HAVE_HASH_BANG_EXEC) -fi - -dnl Miscellaneous Bash tests -if test "$ac_cv_func_lstat" = "no"; then -BASH_FUNC_LSTAT -fi - -dnl behavior of system calls and library functions -BASH_FUNC_CTYPE_NONASCII -BASH_FUNC_DUP2_CLOEXEC_CHECK -BASH_SYS_PGRP_SYNC -BASH_SYS_SIGNAL_VINTAGE - -dnl checking for the presence of certain library symbols -BASH_SYS_ERRLIST -BASH_SYS_SIGLIST -BASH_UNDER_SYS_SIGLIST - -dnl various system types -BASH_TYPE_SIGHANDLER -BASH_CHECK_TYPE(clock_t, [#include ], long) -BASH_CHECK_TYPE(sigset_t, [#include ], int) -BASH_CHECK_TYPE(quad_t, , long, HAVE_QUAD_T) -BASH_CHECK_TYPE(intmax_t, , $bash_cv_type_long_long) -BASH_CHECK_TYPE(uintmax_t, , $bash_cv_type_unsigned_long_long) -if test "$ac_cv_header_sys_socket_h" = "yes"; then -BASH_CHECK_TYPE(socklen_t, [#include ], int, HAVE_SOCKLEN_T) -fi -BASH_TYPE_RLIMIT - -dnl presence and contents of structures used by system calls -BASH_STRUCT_TERMIOS_LDISC -BASH_STRUCT_TERMIO_LDISC -BASH_STRUCT_DIRENT_D_INO -BASH_STRUCT_DIRENT_D_FILENO -BASH_STRUCT_DIRENT_D_NAMLEN -BASH_STRUCT_WINSIZE -BASH_STRUCT_TIMEVAL -AC_CHECK_MEMBERS([struct stat.st_blocks]) -AC_STRUCT_TM -AC_STRUCT_TIMEZONE -BASH_STRUCT_TIMEZONE - -dnl presence and behavior of C library functions -BASH_FUNC_STRSIGNAL -BASH_FUNC_OPENDIR_CHECK -BASH_FUNC_ULIMIT_MAXFDS -BASH_FUNC_GETENV -if test "$ac_cv_func_getcwd" = "yes"; then -BASH_FUNC_GETCWD -fi -BASH_FUNC_POSIX_SETJMP -BASH_FUNC_STRCOLL - -dnl If putenv or unsetenv is not present, set the right define so the -dnl prototype and declaration in lib/sh/getenv.c will be standard-conformant - -if test "$ac_cv_func_putenv" = "yes"; then -BASH_FUNC_STD_PUTENV -else -AC_DEFINE(HAVE_STD_PUTENV) -fi -if test "$ac_cv_func_unsetenv" = "yes"; then -BASH_FUNC_STD_UNSETENV -else -AC_DEFINE(HAVE_STD_UNSETENV) -fi - -BASH_FUNC_PRINTF_A_FORMAT - -dnl presence and behavior of OS functions -BASH_SYS_REINSTALL_SIGHANDLERS -BASH_SYS_JOB_CONTROL_MISSING -BASH_SYS_NAMED_PIPES - -dnl presence of certain CPP defines -AC_HEADER_TIOCGWINSZ -BASH_HAVE_TIOCSTAT -BASH_HAVE_FIONREAD - -dnl miscellaneous -BASH_CHECK_SPEED_T -BASH_CHECK_GETPW_FUNCS -BASH_CHECK_RTSIGS -BASH_CHECK_SYS_SIGLIST - -dnl special checks -case "$host_os" in -hpux*) BASH_CHECK_KERNEL_RLIMIT ;; -esac - -if test "$opt_readline" = yes; then -dnl yuck -case "$host_os" in -aix*) prefer_curses=yes ;; -esac -BASH_CHECK_LIB_TERMCAP -fi -AC_SUBST(TERMCAP_LIB) -AC_SUBST(TERMCAP_DEP) - -BASH_CHECK_DEV_FD -BASH_CHECK_DEV_STDIN -BASH_SYS_DEFAULT_MAIL_DIR - -if test "$bash_cv_job_control_missing" = missing; then - opt_job_control=no -fi - -if test "$opt_job_control" = yes; then -AC_DEFINE(JOB_CONTROL) -JOBS_O=jobs.o -else -JOBS_O=nojobs.o -fi - -AC_SUBST(JOBS_O) - -dnl Defines that we want to propagate to the Makefiles in subdirectories, -dnl like glob and readline - -LOCAL_DEFS=-DSHELL - -dnl use this section to possibly define more cpp variables, specify local -dnl libraries, and specify any additional local cc flags -dnl -dnl this should really go away someday - -case "${host_os}" in -sysv4.2*) AC_DEFINE(SVR4_2) - AC_DEFINE(SVR4) ;; -sysv4*) AC_DEFINE(SVR4) ;; -sysv5*) AC_DEFINE(SVR5) ;; -hpux9*) LOCAL_CFLAGS="-DHPUX9 -DHPUX" ;; -hpux*) LOCAL_CFLAGS=-DHPUX ;; -dgux*) LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;; -isc*) LOCAL_CFLAGS=-Disc386 ;; -rhapsody*) LOCAL_CFLAGS=-DRHAPSODY ;; -darwin*) LOCAL_CFLAGS=-DMACOSX ;; -sco3.2v5*) LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;; -sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;; -sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; -sunos4*) LOCAL_CFLAGS=-DSunOS4 ;; -solaris2.5*) LOCAL_CFLAGS=-DSunOS5 ;; -lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; -linux*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading -*qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s" LOCAL_LIBS="-lunix -lncurses" ;; -powerux*) LOCAL_LIBS="-lgen" ;; -cygwin*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; -opennt*|interix*) LOCAL_CFLAGS="-DNO_MAIN_ENV_ARG -DBROKEN_DIRENT_D_INO" ;; -esac - -dnl Stanza for OS/compiler pair-specific flags -case "${host_os}-${CC}" in -aix4.2*-*gcc*) LOCAL_LDFLAGS="-Xlinker -bexpall -Xlinker -brtl" ;; -aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl" ;; -bsdi4*-*gcc*) LOCAL_LDFLAGS="-rdynamic" ;; # allow dynamic loading, like Linux -esac - -dnl FreeBSD-3.x can have either a.out or ELF -case "${host_os}" in -freebsd[[3-9]]*) - if test -x /usr/bin/objformat && test "`/usr/bin/objformat`" = "elf" ; then - LOCAL_LDFLAGS=-rdynamic # allow dynamic loading - fi ;; -freebsdelf*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading -esac - -case "$host_cpu" in -*cray*) LOCAL_CFLAGS="-DCRAY" ;; # shell var so config.h can use it -esac - -case "$host_cpu-$host_os" in -ibmrt-*bsd4*) LOCAL_CFLAGS="-ma -U__STDC__" ;; -esac - -case "$host_cpu-$host_vendor-$host_os" in -m88k-motorola-sysv3) LOCAL_CFLAGS=-DWAITPID_BROKEN ;; -mips-pyramid-sysv4) LOCAL_CFLAGS=-Xa ;; -esac - -# -# Shared object configuration section. These values are generated by -# ${srcdir}/support/shobj-conf -# -if test "$ac_cv_func_dlopen" = "yes" && test -f ${srcdir}/support/shobj-conf -then - AC_MSG_CHECKING(shared object configuration for loadable builtins) - eval `${CONFIG_SHELL-/bin/sh} ${srcdir}/support/shobj-conf -C "${CC}" -c "${host_cpu}" -o "${host_os}" -v "${host_vendor}"` - AC_SUBST(SHOBJ_CC) - AC_SUBST(SHOBJ_CFLAGS) - AC_SUBST(SHOBJ_LD) - AC_SUBST(SHOBJ_LDFLAGS) - AC_SUBST(SHOBJ_XLDFLAGS) - AC_SUBST(SHOBJ_LIBS) - AC_SUBST(SHOBJ_STATUS) - AC_MSG_RESULT($SHOBJ_STATUS) -fi - -# try to create a directory tree if the source is elsewhere -# this should be packaged into a script accessible via ${srcdir}/support -case "$srcdir" in -.) ;; -*) for d in doc tests support lib examples; do # dirs - test -d $d || mkdir $d - done - for ld in readline glob tilde malloc sh termcap; do # libdirs - test -d lib/$ld || mkdir lib/$ld - done - test -d examples/loadables || mkdir examples/loadables # loadable builtins - test -d examples/loadables/perl || mkdir examples/loadables/perl - ;; -esac - -BUILD_DIR=`pwd` - -AC_SUBST(PROFILE_FLAGS) - -AC_SUBST(incdir) -AC_SUBST(BUILD_DIR) - -AC_SUBST(YACC) -AC_SUBST(AR) -AC_SUBST(ARFLAGS) - -AC_SUBST(BASHVERS) -AC_SUBST(RELSTATUS) -AC_SUBST(DEBUG) -AC_SUBST(MALLOC_DEBUG) - -AC_SUBST(host_cpu) -AC_SUBST(host_vendor) -AC_SUBST(host_os) - -AC_SUBST(LOCAL_LIBS) -AC_SUBST(LOCAL_CFLAGS) -AC_SUBST(LOCAL_LDFLAGS) -AC_SUBST(LOCAL_DEFS) - -#AC_SUBST(ALLOCA_SOURCE) -#AC_SUBST(ALLOCA_OBJECT) - -AC_OUTPUT([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ - lib/intl/Makefile \ - lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ - lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \ - examples/loadables/Makefile examples/loadables/perl/Makefile \ - pathnames.h], -[ -# Makefile uses this timestamp file to record whether config.h is up to date. -echo timestamp > stamp-h -]) diff --git a/doc/FAQ-3.0~ b/doc/FAQ-3.0~ deleted file mode 100644 index f0f3d1b6b..000000000 --- a/doc/FAQ-3.0~ +++ /dev/null @@ -1,1771 +0,0 @@ -This is the Bash FAQ, version 3.26, for Bash version 2.05b. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet@po.cwru.edu. - -This document is available for anonymous FTP with the URL - -ftp://ftp.cwru.edu/pub/bash/FAQ - -The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html - ----------- -Contents: - -Section A: The Basics - -A1) What is it? -A2) What's the latest version? -A3) Where can I get it? -A4) On what machines will bash run? -A5) Will bash run on operating systems other than Unix? -A6) How can I build bash with gcc? -A7) How can I make bash my login shell? -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? -A9) What's the `POSIX Shell and Utilities standard'? -A10) What is the bash `posix mode'? - -Section B: The latest version - -B1) What's new in version 2.05b? -B2) Are there any user-visible incompatibilities between bash-2.05b and - bash-1.14.7? - -Section C: Differences from other Unix shells - -C1) How does bash differ from sh, the Bourne shell? -C2) How does bash differ from the Korn shell, version ksh88? -C3) Which new features in ksh-93 are not in bash, and which are? - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? -D2) Why doesn't bash treat brace expansions exactly like csh? -D3) Why doesn't bash have csh variable modifiers? -D4) How can I make my csh aliases work when I convert to bash? -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -Section E: Why does bash do certain things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? -E2) Why does bash sometimes say `Broken pipe'? -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -E4) 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? -E5) 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? -E6) Why doesn't a while or for loop get suspended when I type ^Z? -E7) What about empty for loops in Makefiles? -E8) Why does the arithmetic evaluation code complain about `08'? -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? -E10) Why does `cd //' leave $PWD as `//'? -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? -E12) Why don't negative offsets in substring expansion work like I expect? - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? -G5) How do I get the current directory into my prompt? -G6) How can I rename "*.foo" to "*.bar"? -G7) How can I translate a filename from uppercase to lowercase? -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? -H2) What kind of bash documentation is there? -H3) What's coming in future versions? -H4) What's on the bash `wish list'? -H5) When will the next release appear? - ----------- -Section A: The Basics - -A1) 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. - -A2) What's the latest version? - -The latest version is 2.05b, first made available on Wednesday, 17 -July, 2002. - -A3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, ftp.gnu.org, and its mirrors. The -latest version is also available for FTP from ftp.cwru.edu. -The following URLs tell how to get version 2.05b: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz - -A4) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `configure' and then `make'. The build process -will attempt to discover the version of UNIX you have and tailor -itself accordingly, using a script created by GNU autoconf. - -More information appears in the file `INSTALL' in the distribution. - -The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) -explains how to obtain binary versions of bash for most of the major -commercial Unix systems. - -A5) Will bash run on operating systems other than Unix? - -Configuration specifics for Unix-like systems such as QNX and -LynxOS are included in the distribution. Bash-2.05 and later -versions should compile and run on Minix 2.0 (patches were -contributed), but I don't believe anyone has built bash-2.x on -earlier Minix versions yet. - -Bash has been ported to versions of Windows implementing the Win32 -programming interface. This includes Windows 95 and Windows NT. -The port was done by Cygnus Solutions as part of their CYGWIN -project. For more information about the project, look at the URLs - -http://www.cygwin.com/ -http://sourceware.cygnus.com/cygwin - -Cygnus originally ported bash-1.14.7, and that port was part of their -early GNU-Win32 (the original name) releases. Cygnus has also done a -port of bash-2.05 to the CYGWIN environment, and it is available as -part of their current release. - -Bash-2.05b should require no local Cygnus changes to build and run under -CYGWIN. - -The Cygnus port works only on Intel machines. There is a port of bash -(I don't know which version) to the alpha/NT environment available from - -ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz - -DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part -of the DJGPP project. For more information on the project, see - -http://www.delorie.com/djgpp/ - -I have been told that the original DJGPP port was done by Daisuke Aoyama. - -Mark Elbrecht has sent me notice that bash-2.04 -is available for DJGPP V2. The files are available as: - -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source - -Mark has begun to work with bash-2.05, but I don't know the status. - -Ports of bash-1.12 and bash-2.0 are available for OS/2 from - -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip - -I haven't looked at either, but the second appears to be a binary-only -distribution. Beware. - -I have received word that Bash (I'm not sure which version, but I -believe that it's at least bash-2.02.1) is the standard shell on -BeOS. - -A6) How can I build bash with gcc? - -Bash configures to use gcc by default if it is available. Read the -file INSTALL in the distribution for more information. - -A7) How can I make bash my login shell? - -Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s' or `passwd -e'. If one of these works for -you, that's all you need. Note that many systems require the full -pathname to a shell to appear in /etc/shells before you can make it -your login shell. For this, you may need the assistance of your -friendly local system administrator. - -If you cannot do this, you can still use bash as your login shell, but -you need to perform some tricks. The basic idea is to add a command -to your login shell's startup file to replace your login shell with -bash. - -For example, if your login shell is csh or tcsh, and you have installed -bash in /usr/gnu/bin/bash, add the following line to ~/.login: - - if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login - -(the `--login' tells bash that it is a login shell). - -It's not a good idea to put this command into ~/.cshrc, because every -csh you run without the `-f' option, even ones started to run csh scripts, -reads that file. If you must put the command in ~/.cshrc, use something -like - - if ( $?prompt ) exec /usr/gnu/bin/bash --login - -to ensure that bash is exec'd only when the csh is interactive. - -If your login shell is sh or ksh, you have to do two things. - -First, create an empty file in your home directory named `.bash_profile'. -The existence of this file will prevent the exec'd bash from trying to -read ~/.profile, and re-execing itself over and over again. ~/.bash_profile -is the first file bash tries to read initialization commands from when -it is invoked as a login shell. - -Next, add a line similar to the above to ~/.profile: - - [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ - exec /usr/gnu/bin/bash --login - -This will cause login shells to replace themselves with bash running as -a login shell. Once you have this working, you can copy your initialization -code from ~/.profile to ~/.bash_profile. - -I have received word that the recipe supplied above is insufficient for -machines running CDE. CDE has a maze of twisty little startup files, all -slightly different. - -If you cannot change your login shell in the password file to bash, you -will have to (apparently) live with CDE using the shell in the password -file to run its startup scripts. If you have changed your shell to bash, -there is code in the CDE startup files (on Solaris, at least) that attempts -to do the right thing. It is, however, often broken, and may require that -you use the $BASH_ENV trick described below. - -`dtterm' claims to use $SHELL as the default program to start, so if you -can change $SHELL in the CDE startup files, you should be able to use bash -in your terminal windows. - -Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program -to read your login shell's startup files. You may be able to use bash for -the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as -well, but I have not tried this. - -You can use the above `exec' recipe to start bash when not logging in with -CDE by testing the value of the DT variable: - - if [ -n "$DT" ]; then - [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login - fi - -If CDE starts its shells non-interactively during login, the login shell -startup files (~/.profile, ~/.bash_profile) will not be sourced at login. -To get around this problem, append a line similar to the following to your -~/.dtprofile: - - BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV - -and add the following line to the beginning of ~/.bash_profile: - - unset BASH_ENV - -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? - -You must add the full pathname to bash to the file /etc/shells. As -noted in the answer to the previous question, many systems require -this before you can make bash your login shell. - -Most versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -A9) What's the `POSIX Shell and Utilities 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 was originally developed by -IEEE Working Group 1003.2 (POSIX.2). Today it has been merged with -the original 1003.1 Working Group and is maintained by the Austin -Group (a joint working group of the IEEE, The Open Group and -ISO/IEC SC22/WG15). Today the Shell and Utilities are a volume -within the set of documents that make up IEEE Std 1003.1-2001, and -thus now the former POSIX.2 (from 1992) is now part of the current -POSIX.1 standard (POSIX 1003.1-2001). - -The Shell and Utilities volume concentrates on the command -interpreter interface and utility programs commonly executed from -the command line or by other programs. The standard is freely -available on the web at http://www.UNIX-systems.org/version3/ . -Work continues at the Austin Group on maintenance issues; see -http://www.opengroup.org/austin/ to join the discussions. - -Bash is concerned with the aspects of the shell's behavior defined -by the POSIX Shell and Utilities volume. 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 not -devoted to the shell which are commonly (and in some cases must -be) implemented as builtin commands, such as `read' and `test'. -POSIX 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. - -The latest version of the POSIX Shell and Utilities standard is -available (now updated to the 2003 Edition incorporating the -Technical Corrigendum 1), as part of the Single UNIX Specification -Version 3 at - -http://www.UNIX-systems.org/version3/ - -A10) What is the bash `posix mode'? - -Although bash is an implementation of the POSIX 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 or -'-o 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 POSIX in the bash distribution. -They are also listed in a section in the Bash Reference Manual -(from which that file is generated). - -Section B: The latest version - -B1) What's new in version 2.05b? - -The raison d'etre for bash-2.05b is to make a second intermediate -release containing the first of the new features to be available -in bash-3.0 and get feedback on those features before proceeding. -The major new feature is multibyte character support in both Bash -and Readline. - -Bash-2.05b contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-2.05b -distribution): - -o support for multibyte characters has been added to both bash and readline - -o the DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops - -o the shell now performs arithmetic in the largest integer size the machine - supports (intmax_t) - -o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) - and inserts the result into the expanded prompt - -o there is a new `here-string' redirection operator: <<< word - -o when displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -o `read' has a new `-u fd' option to read from a specified file descriptor - -o the bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better - -o the expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires - - -A short feature history dating from Bash-2.0: - -Bash-2.05a introduced the following new features: - -o The `printf' builtin has undergone major work - -o There is a new read-only `shopt' option: login_shell, which is set by - login shells and unset otherwise - -o New `\A' prompt string escape sequence; expanding to time in 24-hour - HH:MM format - -o New `-A group/-g' option to complete and compgen; goes group name - completion - -o New [+-]O invocation option to set and unset `shopt' options at startup - -o ksh-like `ERR' trap - -o `for' loops now allow empty word lists after the `in' reserved word - -o new `hard' and `soft' arguments for the `ulimit' builtin - -o Readline can be configured to place the user at the same point on the line - when retrieving commands from the history list - -o Readline can be configured to skip `hidden' files (filenames with a leading - `.' on Unix) when performing completion - -Bash-2.05 introduced the following new features: - -o This version has once again reverted to using locales and strcoll(3) when - processing pattern matching bracket expressions, as POSIX requires. -o Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. -o The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. -o `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces -o A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. -o When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -Bash-2.04 introduced the following new features: - -o Programmable word completion with the new `complete' and `compgen' builtins; - examples are provided in examples/complete/complete-examples -o `history' has a new `-d' option to delete a history entry -o `bind' has a new `-x' option to bind key sequences to shell commands -o The prompt expansion code has new `\j' and `\l' escape sequences -o The `no_empty_cmd_completion' shell option, if enabled, inhibits - command completion when TAB is typed on an empty line -o `help' has a new `-s' option to print a usage synopsis -o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) -o New ksh93-style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done -o `read' has new options: `-t', `-n', `-d', `-s' -o The redirection code handles several filenames specially: /dev/fd/N, - /dev/stdin, /dev/stdout, /dev/stderr -o The redirection code now recognizes /dev/tcp/HOST/PORT and - /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, - to the specified port on the specified host -o The ${!prefix*} expansion has been implemented -o A new FUNCNAME variable, which expands to the name of a currently-executing - function -o The GROUPS variable is no longer readonly -o A new shopt `xpg_echo' variable, to control the behavior of echo with - respect to backslash-escape sequences at runtime -o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned - -The version of Readline released with Bash-2.04, Readline-4.1, had several -new features as well: - -o Parentheses matching is always compiled into readline, and controllable - with the new `blink-matching-paren' variable -o The history-search-forward and history-search-backward functions now leave - point at the end of the line when the search string is empty, like - reverse-search-history, and forward-search-history -o A new function for applications: rl_on_new_line_with_prompt() -o New variables for applications: rl_already_prompted, and rl_gnu_readline_p - - -Bash-2.03 had very few new features, in keeping with the convention -that odd-numbered releases provide mainly bug fixes. A number of new -features were added to Readline, mostly at the request of the Cygnus -folks. - -A new shopt option, `restricted_shell', so that startup files can test - whether or not the shell was started in restricted mode -Filename generation is now performed on the words between ( and ) in - compound array assignments (this is really a bug fix) -OLDPWD is now auto-exported, as POSIX.2 requires -ENV and BASH_ENV are read-only variables in a restricted shell -Bash may now be linked against an already-installed Readline library, - as long as the Readline library is version 4 or newer -All shells begun with the `--login' option will source the login shell - startup files, even if the shell is not interactive - -There were lots of changes to the version of the Readline library released -along with Bash-2.03. For a complete list of the changes, read the file -CHANGES in the Bash-2.03 distribution. - -Bash-2.02 contained the following new features: - -a new version of malloc (based on the old GNU malloc code in previous - bash versions) that is more page-oriented, more conservative - with memory usage, does not `orphan' large blocks when they - are freed, is usable on 64-bit machines, and has allocation - checking turned on unconditionally -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -the ksh [[...]] extended conditional command -the ksh egrep-style extended pattern matching operators -a new `printf' builtin -the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- - prompt string special char translation and variable expansion - auto-export of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. - export -n/-f/-p/name=value, pwd -L/-P, - read -e/-p/-a/-t/-n/-d/-s/-u, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -m/-p/-u, - type -a/-p/-t/-f/-P, suspend -f, kill -n, - test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion with $((...)) and `let' builtin - the `[[...]]' extended conditional command - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing with programmable completion - command history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, compgen, complete, builtin, - declare/typeset, dirs, enable, fc, help, - history, logout, popd, pushd, disown, shopt, - printf - exported functions - filename generation when using output redirection (command >a*) - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - variable assignments preceding commands affect only that command, - even for builtins and functions - posix mode - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - -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' - $TIMEOUT (like bash $TMOUT) - `^' is a synonym for `|' - new SVR4.2 sh builtins: mldmode, priv - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS, using POSIX.2 - field splitting rules; sh splits all words on IFS - sh does not allow MAILCHECK to be unset (?) - sh does not allow traps on SIGALRM or SIGCHLD - bash allows multiple option arguments when invoked (e.g. -x -v); - sh allows only a single option argument (`sh -x -v' attempts - to open a file named `-v', and, on SunOS 4.1.4, dumps core. - On Solaris 2.4 and earlier versions, sh goes into an infinite - loop.) - sh exits a script if any builtin fails; bash exits only if one of - the POSIX.2 `special' builtins fails - -C2) How does bash differ from the Korn shell, version ksh88? - -Things bash has or uses that ksh88 does not: - long invocation options - [-+]O invocation option - -l invocation option - `!' reserved word - arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done - arithmetic in largest machine-supported size (intmax_t) - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - the ${!param} indirect parameter expansion operator - the ${!param*} prefix expansion operator - the ${param:offset[:length]} parameter substring operator - the ${param/pat[/string]} parameter pattern substitution operator - variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, - TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, - HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, - IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, - PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, - GROUPS, FUNCNAME, histchars, auto_resume - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- - more extensive and extensible editing and programmable completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, - jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, - read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, - set -o braceexpand/-o histexpand/-o interactive-comments/ - -o notify/-o physical/-o posix/-o hashall/-o onecmd/ - -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, - typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, - disown, printf, complete, compgen - `!' csh-style history expansion - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - `**' arithmetic operator to do exponentiation - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr - arrays of unlimited size - TMOUT is default timeout for `read' and `select' - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (|&, >&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence - using environment to pass attributes of exported variables - arithmetic evaluation done on arguments to some builtins - reads .profile from $PWD when invoked as login shell - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - bash has brace expansion by default (ksh88 compile-time option) - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - bash waits for all commands in pipeline to exit before returning status - emacs-mode editing has some slightly different key bindings - -C3) Which new features in ksh-93 are not in bash, and which are? - -New things in ksh-93 not in bash-2.05b: - associative arrays - floating point arithmetic and variables - math library functions - ${!name[sub]} name of subscript for associative array - `.' is allowed in variable names to create a hierarchical namespace - more extensive compound assignment syntax - discipline functions - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - KEYBD trap - variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, - .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT - backreferences in pattern matching (\N) - `&' operator in pattern lists for matching - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - exit statuses between 0 and 255 - set -o pipefail - `+=' variable assignment operator - FPATH and PATH mixing - getopts -a - -I invocation option - DEBUG trap now executed before each simple command, instead of after - printf %H, %P, %T, %Z modifiers, output base for %d - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - -New things in ksh-93 present in bash-2.05b: - [n]<&word- and [n]>&word- redirections (combination dup and close) - for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command - ?:, ++, --, `expr1 , expr2' arithmetic operators - expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, - ${!param*} - compound array assignment - the `!' reserved word - loadable builtins -- but ksh uses `builtin' while bash uses `enable' - `command', `builtin', `disown' builtins - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - set -o notify/-C - changes to kill builtin - read -A (bash uses read -a) - read -t/-d - trap -p - exec -c/-a - `.' restores the positional parameters when it completes - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion - ENV processed only for interactive shells - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? - -On many systems, `which' is actually a csh script that assumes -you're running csh. In tcsh, `which' and its cousin `where' -are builtins. On other Unix systems, `which' is a perl script -that uses the PATH environment variable. - -The csh script version 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. The bash `type' builtin does everything -`which' does, and will report correct results for the running -shell. If you're really wedded to the name `which', try adding -the following function definition to your .bashrc: - - which() - { - builtin type "$@" - } - -If you're moving from tcsh and would like to bring `where' along -as well, use this function: - - where() - { - builtin type -a "$@" - } - -D2) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least one unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -D3) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more cryptic, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -D4) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/misc/aliasconv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `aliasconv.sh', saving the -results into `bash_aliases': - - alias | bash aliasconv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of some csh specific -variables to the bash equivalents. The script converts $cwd to -$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt -to $PS1. You may also have to add quotes to avoid unwanted -expansion. - -For example, the csh alias: - - alias cd 'cd \!*; echo $cwd' - -is converted to the bash function: - - cd () { command cd "$@"; echo $PWD ; } - -The only thing that needs to be done is to quote $PWD: - - cd () { command cd "$@"; echo "$PWD" ; } - -Merge the edited file into your ~/.bashrc. - -There is an additional, more ambitious, script in -examples/misc/cshtobash that attempts to convert your entire csh -environment to its bash equivalent. This script can be run as -simply `cshtobash' to convert your normal interactive -environment, or as `cshtobash ~/.login' to convert your login -environment. - -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? - -Use - command 2>&1 | command2 - -The key is to remember that piping is performed before redirection, so -file descriptor 1 points to the pipe when it is duplicated onto file -descriptor 2. - -D6) 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 and ksh-93 that do not have direct bash -equivalents. Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -coprocesses named pipe pairs (one for read, one for write) -typeset +f declare -F -cd, print, whence function substitutes in examples/functions/kshenv -autoloaded functions examples/functions/autoload is the same as typeset -fu -read var?prompt read -p prompt var - -ksh-93 feature Bash equivalent --------------- --------------- -sleep, getconf Bash has loadable versions in examples/loadables -${.sh.version} $BASH_VERSION -print -f printf -hist alias hist=fc -$HISTEDIT $FCEDIT - -Section E: How can I get bash to do certain things, and why does bash do - things the way it does? - -E1) 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 - If first argument is `(' and third argument is `)', do the - one-argument test of the second argument. - 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. - -E2) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appears 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. - -You can build a version of bash that will not report SIGPIPE errors -by uncommenting the definition of DONT_REPORT_SIGPIPE in the file -config-top.h. - -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Readline, the line editing library that bash uses, 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. - -E4) 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. It affects all commands run in pipelines, not just -simple calls to `read'. For example, piping a command's output -into a `while' loop that repeatedly calls `read' will result in -the same behavior. - -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 of -a specified command. The output can then be assigned to 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. If you need to do this, you can either use the -command substitution above to read the output into a variable -and chop up the variable using the bash pattern removal -expansion operators or use some variant of the following -approach. - -Say /usr/local/bin/ipaddr is the following shell script: - -#! /bin/sh -host `hostname` | awk '/address/ {print $NF}' - -Instead of using - - /usr/local/bin/ipaddr | read A B C D - -to break the local machine's IP address into separate octets, use - - OIFS="$IFS" - IFS=. - set -- $(/usr/local/bin/ipaddr) - IFS="$OIFS" - A="$1" B="$2" C="$3" D="$4" - -Beware, however, that this will change the shell's positional -parameters. If you need them, you should save them before doing -this. - -This is the general approach -- in most cases you will not need to -set $IFS to a different value. - -Some other user-supplied alternatives include: - -read A B C D << HERE - $(IFS=.; echo $(/usr/local/bin/ipaddr)) -HERE - -and, where process substitution is available, - -read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) - -E5) 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 modeled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default; -it 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 configuration option that will make bash behave like -the System V echo and interpret things like `\t' by default. Run -configure with the --enable-xpg-echo-default option to turn this -on. Be aware that this will cause some of the tests run when you -type `make tests' to fail. - -There is a shell option, `xpg_echo', settable with `shopt', that will -change the behavior of echo at runtime. Enabling this option turns -on expansion of backslash-escape sequences. - -E6) Why doesn't a while or for loop get suspended when I type ^Z? - -This is a consequence of how job control works on Unix. The only -thing that can be suspended is the process group. This is a single -command or pipeline of commands that the shell forks and executes. - -When you run a while or for loop, the only thing that the shell forks -and executes are any commands in the while loop test and commands in -the loop bodies. These, therefore, are the only things that can be -suspended when you type ^Z. - -If you want to be able to stop the entire loop, you need to put it -within parentheses, which will force the loop into a subshell that -may be stopped (and subsequently restarted) as a single unit. - -E7) What about empty for loops in Makefiles? - -It's fairly common to see constructs like this in automatically-generated -Makefiles: - -SUBDIRS = @SUBDIRS@ - - ... - -subdirs-clean: - for d in ${SUBDIRS}; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -When SUBDIRS is empty, this results in a command like this being passed to -bash: - - for d in ; do - ( cd $d && ${MAKE} ${MFLAGS} clean ) - done - -In versions of bash before bash-2.05a, this was a syntax error. If the -reserved word `in' was present, a word must follow it before the semicolon -or newline. The language in the manual page referring to the list of words -being empty referred to the list after it is expanded. These versions of -bash required that there be at least one word following the `in' when the -construct was parsed. - -The idiomatic Makefile solution is something like: - -SUBDIRS = @SUBDIRS@ - -subdirs-clean: - subdirs=$SUBDIRS ; for d in $$subdirs; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -The latest drafts of the updated POSIX standard have changed this: the -word list is no longer required. Bash versions 2.05a and later accept -the new syntax. - -E8) Why does the arithmetic evaluation code complain about `08'? - -The bash arithmetic evaluation code (used for `let', $(()), (()), and in -other places), interprets a leading `0' in numeric constants as denoting -an octal number, and a leading `0x' as denoting hexadecimal. This is -in accordance with the POSIX.2 spec, section 2.9.2.1, which states that -arithmetic constants should be handled as signed long integers as defined -by the ANSI/ISO C standard. - -The POSIX.2 interpretation committee has confirmed this: - -http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html - -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? - -Bash-2.03, Bash-2.05 and later versions honor the current locale setting -when processing ranges within pattern matching bracket expressions ([A-Z]). -This is what POSIX.2 and SUSv3/XPG6 specify. - -The behavior of the matcher in bash-2.05 and later versions depends on the -current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will -result in the traditional behavior ([A-Z] matches all uppercase ASCII -characters). Many other locales, including the en_US locale (the default -on many US versions of Linux) collate the upper and lower case letters like -this: - - AaBb...Zz - -which means that [A-Z] matches every letter except `z'. Others collate like - - aAbBcC...zZ - -which means that [A-Z] matches every letter except `a'. - -The portable way to specify upper case letters is [:upper:] instead of -A-Z; lower case may be specified as [:lower:] instead of a-z. - -Look at the manual pages for setlocale(3), strcoll(3), and, if it is -present, locale(1). If you have locale(1), you can use it to find -your current locale information even if you do not have any of the -LC_ variables set. - -My advice is to put - - export LC_COLLATE=C - -into /etc/profile and inspect any shell scripts run from cron for -constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - -from removing every file in the current directory except those beginning -with `z' and still allow individual users to change the collation order. -Users may put the above command into their own profiles as well, of course. - -E10) Why does `cd //' leave $PWD as `//'? - -POSIX.2, in its description of `cd', says that *three* or more leading -slashes may be replaced with a single slash when canonicalizing the -current working directory. - -This is, I presume, for historical compatibility. Certain versions of -Unix, and early network file systems, used paths of the form -//hostname/path to access `path' on server `hostname'. - -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -This is another issue that deals with job control. - -The kernel maintains a notion of a current terminal process group. Members -of this process group (processes whose process group ID is equal to the -current terminal process group ID) receive terminal-generated signals like -SIGWINCH. (For more details, see the JOB CONTROL section of the bash -man page.) - -If a terminal is resized, the kernel sends SIGWINCH to each member of -the terminal's current process group (the `foreground' process group). - -When bash is running with job control enabled, each pipeline (which may be -a single command) is run in its own process group, different from bash's -process group. This foreground process group receives the SIGWINCH; bash -does not. Bash has no way of knowing that the terminal has been resized. - -There is a `checkwinsize' option, settable with the `shopt' builtin, that -will cause bash to check the window size and adjust its idea of the -terminal's dimensions each time a process stops or exits and returns control -of the terminal to bash. Enable it with `shopt -s checkwinsize'. - -E12) Why don't negative offsets in substring expansion work like I expect? - -When substring expansion of the form ${param:offset[:length} is used, -an `offset' that evaluates to a number less than zero counts back from -the end of the expanded value of $param. - -When a negative `offset' begins with a minus sign, however, unexpected things -can happen. Consider - - a=12345678 - echo ${a:-4} - -intending to print the last four characters of $a. The problem is that -${param:-word} already has a well-defined meaning: expand to word if the -expanded value of param is unset or null, and $param otherwise. - -To use negative offsets that begin with a minus sign, separate the -minus sign and the colon with a space. - -Section F: Things to watch out for on certain Unix versions - -F1) 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. - -If you must use cmdtool, you can use the termcap description in -examples/suncmd.termcap. Set the TERMCAP variable to the terminal -description contained in that file, i.e. - -TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' - -Then export TERMCAP and start a new cmdtool window from that shell. -The bash command-line editing should behave better in the new -cmdtool. If this works, you can put the assignment to TERMCAP -in your bashrc file. - -F2) 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 structures 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 configuring and 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. - -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion 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 -run configure with the `--without-gnu-malloc' option to use -the C library malloc and avoid the problem. - -F4) 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. - -F5) 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. - -This affects the mechanical transformation of commands that use `cat' -to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on -comp.unix.shell). While most commands of the form - - cat file | command - -can be converted to `< file command', shell control structures such as -loops and subshells require `command < file'. - -The file CWRU/sh-redir-hack in the bash-2.05a distribution is an -(unofficial) patch to parse.y that will modify the grammar to -support this construct. It will not apply with `patch'; you must -modify parse.y by hand. 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. - -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? - -The short answer is that Red Hat screwed up. - -The long answer is that they shipped an /etc/inputrc that only works -for emacs mode editing, and then screwed all the vi users by setting -INPUTRC to /etc/inputrc in /etc/profile. - -The short fix is to do one of the following: remove or rename -/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, -but make sure you export it if you do), remove the assignment to -INPUTRC from /etc/profile, add - - set keymap emacs - -to the beginning of /etc/inputrc, or bracket the key bindings in -/etc/inputrc with these lines - - $if mode=emacs - [...] - $endif - -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -HP/UX's support for long double is imperfect at best. - -GCC will support it without problems, but the HP C library functions -like strtold(3) and printf(3) don't actually work with long doubles. -HP implemented a `long_double' type as a 4-element array of 32-bit -ints, and that is what the library functions use. The ANSI C -`long double' type is a 128-bit floating point scalar. - -The easiest fix, until HP fixes things up, is to edit the generated -config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, -the compilation should complete successfully. - -Section G: How can I get bash to do certain common things? - -G1) 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 eighth 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. - -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is why the `command' and `builtin' builtins exist. 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. - -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Versions of Bash newer than Bash-2.0 support this directly. You can use - - ${!var} - -For example, the following sequence of commands will echo `z': - - var1=var2 - var2=z - echo ${!var1} - -For sh compatibility, 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. In versions of bash later than bash-2.0, - - echo ${!#} - -does the same thing. - -This is not the same thing as ksh93 `nameref' variables, though the syntax -is similar. I may add namerefs in a future bash version. - -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? - -The bash command timing code looks for a variable `TIMEFORMAT' and -uses its value as a format string to decide how to display the -timing statistics. - -The value of TIMEFORMAT is a string with `%' escapes expanded in a -fashion similar in spirit to printf(3). The manual page explains -the meanings of the escape sequences in the format string. - -If TIMEFORMAT is not set, bash acts as if the following assignment had -been performed: - - TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' - -The POSIX.2 default time format (used by `time -p command') is - - TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' - -The BSD /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' - -The System V /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' - -The ksh format can be emulated with: - - TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' - -G5) How do I get the current directory into my prompt? - -Bash provides a number of backslash-escape sequences which are expanded -when the prompt string (PS1 or PS2) is displayed. The full list is in -the manual page. - -The \w expansion gives the full pathname of the current directory, with -a tilde (`~') substituted for the current value of $HOME. The \W -expansion gives the basename of the current directory. To put the full -pathname of the current directory into the path without any tilde -subsitution, use $PWD. Here are some examples: - - PS1='\w$ ' # current directory with tilde - PS1='\W$ ' # basename of current directory - PS1='$PWD$ ' # full pathname of current directory - -The single quotes are important in the final example to prevent $PWD from -being expanded when the assignment to PS1 is performed. - -G6) How can I rename "*.foo" to "*.bar"? - -Use the pattern removal functionality described in D3. The following `for' -loop will do the trick: - - for f in *.foo; do - mv $f ${f%foo}bar - done - -G7) How can I translate a filename from uppercase to lowercase? - -The script examples/functions/lowercase, originally written by John DuBois, -will do the trick. The converse is left as an exercise. - -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -You must have set the `extglob' shell option using `shopt -s extglob' to use -this: - - echo .!(.|) * - -A solution that works without extended globbing is given in the Unix Shell -FAQ, posted periodically to comp.unix.shell. - -Section H: Where do I go from here? - -H1) 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@gnu.org, 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@gnu.org. - -H2) What kind of bash documentation is there? - -First, look in the doc directory in the bash distribution. It should -contain at least the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -bashref.texi a reference manual in GNU tex`info format -bashref.info an info version of the reference manual -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript, HTML, and ASCII files created from the above source are -available in the documentation distribution. - -There is additional documentation available for anonymous FTP from host -ftp.cwru.edu in the `pub/bash' directory. - -Cameron Newham and Bill Rosenblatt have written a book on bash, published -by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn -Shell book. The title is ``Learning the Bash Shell'', and the ISBN number -is 1-56592-147-X. Look for it in fine bookstores near you. This book -covers bash-1.14, but has an appendix describing some of the new features -in bash-2.0. - -A second edition of this book is available, published in January, 1998. -The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores -or on the web. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers -bash-2.0 and is available from most online bookstores (see -http://www.network-theory.co.uk/bash/manual/ for details). The publisher -will donate $1 to the Free Software Foundation for each copy sold. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -a better bash debugger (a minimally-tested version is included with bash-2.05b) -associative arrays -co-processes, but with a new-style syntax that looks like function declaration - -H4) What's on the bash `wish list' for future versions? - -These are features that may or may not appear in a future version of bash. - -breaking some of the shell functionality into embeddable libraries -a module system like zsh's, using dynamic loading like builtins -better internationalization using GNU `gettext' -date-stamped command history -a bash programmer's guide with a chapter on creating loadable builtins -a better loadable interface to perl with access to the shell builtins and - variables (contributions gratefully accepted) -ksh93-like `nameref' variables -ksh93-like `+=' variable assignment operator -ksh93-like `xx.yy' variables (including some of the .sh.* variables) and - associated disipline functions -Some of the new ksh93 pattern matching operators, like backreferencing - -H5) When will the next release appear? - -The next version will appear sometime in 2003. Never make predictions. - - -This document is Copyright 1995-2003 by Chester Ramey. - -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/doc/FAQ.orig b/doc/FAQ.orig deleted file mode 100644 index 1cff3c8ef..000000000 --- a/doc/FAQ.orig +++ /dev/null @@ -1,1745 +0,0 @@ -This is the Bash FAQ, version 3.24, for Bash version 2.05b. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet@po.cwru.edu. - -This document is available for anonymous FTP with the URL - -ftp://ftp.cwru.edu/pub/bash/FAQ - -The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html - ----------- -Contents: - -Section A: The Basics - -A1) What is it? -A2) What's the latest version? -A3) Where can I get it? -A4) On what machines will bash run? -A5) Will bash run on operating systems other than Unix? -A6) How can I build bash with gcc? -A7) How can I make bash my login shell? -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? -A9) What's the `POSIX 1003.2 standard'? -A10) What is the bash `posix mode'? - -Section B: The latest version - -B1) What's new in version 2.05b? -B2) Are there any user-visible incompatibilities between bash-2.05b and - bash-1.14.7? - -Section C: Differences from other Unix shells - -C1) How does bash differ from sh, the Bourne shell? -C2) How does bash differ from the Korn shell, version ksh88? -C3) Which new features in ksh-93 are not in bash, and which are? - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? -D2) Why doesn't bash treat brace expansions exactly like csh? -D3) Why doesn't bash have csh variable modifiers? -D4) How can I make my csh aliases work when I convert to bash? -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -Section E: Why does bash do certain things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? -E2) Why does bash sometimes say `Broken pipe'? -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -E4) 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? -E5) 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? -E6) Why doesn't a while or for loop get suspended when I type ^Z? -E7) What about empty for loops in Makefiles? -E8) Why does the arithmetic evaluation code complain about `08'? -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? -E10) Why does `cd //' leave $PWD as `//'? -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? -G5) How do I get the current directory into my prompt? -G6) How can I rename "*.foo" to "*.bar"? -G7) How can I translate a filename from uppercase to lowercase? -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? -H2) What kind of bash documentation is there? -H3) What's coming in future versions? -H4) What's on the bash `wish list'? -H5) When will the next release appear? - ----------- -Section A: The Basics - -A1) 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. - -A2) What's the latest version? - -The latest version is 2.05b, first made available on Wednesday, 17 -July, 2002. - -A3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, ftp.gnu.org, and its mirrors. The -latest version is also available for FTP from ftp.cwru.edu. -The following URLs tell how to get version 2.05b: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz - -A4) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `configure' and then `make'. The build process -will attempt to discover the version of UNIX you have and tailor -itself accordingly, using a script created by GNU autoconf. - -More information appears in the file `INSTALL' in the distribution. - -The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) -explains how to obtain binary versions of bash for most of the major -commercial Unix systems. - -A5) Will bash run on operating systems other than Unix? - -Configuration specifics for Unix-like systems such as QNX and -LynxOS are included in the distribution. Bash-2.05 and later -versions should compile and run on Minix 2.0 (patches were -contributed), but I don't believe anyone has built bash-2.x on -earlier Minix versions yet. - -Bash has been ported to versions of Windows implementing the Win32 -programming interface. This includes Windows 95 and Windows NT. -The port was done by Cygnus Solutions as part of their CYGWIN -project. For more information about the project, look at the URLs - -http://www.cygwin.com/ -http://sourceware.cygnus.com/cygwin - -Cygnus originally ported bash-1.14.7, and that port was part of their -early GNU-Win32 (the original name) releases. Cygnus has also done a -port of bash-2.05 to the CYGWIN environment, and it is available as -part of their current release. - -Bash-2.05b should require no local Cygnus changes to build and run under -CYGWIN. - -The Cygnus port works only on Intel machines. There is a port of bash -(I don't know which version) to the alpha/NT environment available from - -ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz - -DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part -of the DJGPP project. For more information on the project, see - -http://www.delorie.com/djgpp/ - -I have been told that the original DJGPP port was done by Daisuke Aoyama. - -Mark Elbrecht has sent me notice that bash-2.04 -is available for DJGPP V2. The files are available as: - -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source - -Mark has begun to work with bash-2.05, but I don't know the status. - -Ports of bash-1.12 and bash-2.0 are available for OS/2 from - -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip - -I haven't looked at either, but the second appears to be a binary-only -distribution. Beware. - -I have received word that Bash (I'm not sure which version, but I -believe that it's at least bash-2.02.1) is the standard shell on -BeOS. - -A6) How can I build bash with gcc? - -Bash configures to use gcc by default if it is available. Read the -file INSTALL in the distribution for more information. - -A7) How can I make bash my login shell? - -Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s' or `passwd -e'. If one of these works for -you, that's all you need. Note that many systems require the full -pathname to a shell to appear in /etc/shells before you can make it -your login shell. For this, you may need the assistance of your -friendly local system administrator. - -If you cannot do this, you can still use bash as your login shell, but -you need to perform some tricks. The basic idea is to add a command -to your login shell's startup file to replace your login shell with -bash. - -For example, if your login shell is csh or tcsh, and you have installed -bash in /usr/gnu/bin/bash, add the following line to ~/.login: - - if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login - -(the `--login' tells bash that it is a login shell). - -It's not a good idea to put this command into ~/.cshrc, because every -csh you run without the `-f' option, even ones started to run csh scripts, -reads that file. If you must put the command in ~/.cshrc, use something -like - - if ( $?prompt ) exec /usr/gnu/bin/bash --login - -to ensure that bash is exec'd only when the csh is interactive. - -If your login shell is sh or ksh, you have to do two things. - -First, create an empty file in your home directory named `.bash_profile'. -The existence of this file will prevent the exec'd bash from trying to -read ~/.profile, and re-execing itself over and over again. ~/.bash_profile -is the first file bash tries to read initialization commands from when -it is invoked as a login shell. - -Next, add a line similar to the above to ~/.profile: - - [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ - exec /usr/gnu/bin/bash --login - -This will cause login shells to replace themselves with bash running as -a login shell. Once you have this working, you can copy your initialization -code from ~/.profile to ~/.bash_profile. - -I have received word that the recipe supplied above is insufficient for -machines running CDE. CDE has a maze of twisty little startup files, all -slightly different. - -If you cannot change your login shell in the password file to bash, you -will have to (apparently) live with CDE using the shell in the password -file to run its startup scripts. If you have changed your shell to bash, -there is code in the CDE startup files (on Solaris, at least) that attempts -to do the right thing. It is, however, often broken, and may require that -you use the $BASH_ENV trick described below. - -`dtterm' claims to use $SHELL as the default program to start, so if you -can change $SHELL in the CDE startup files, you should be able to use bash -in your terminal windows. - -Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program -to read your login shell's startup files. You may be able to use bash for -the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as -well, but I have not tried this. - -You can use the above `exec' recipe to start bash when not logging in with -CDE by testing the value of the DT variable: - - if [ -n "$DT" ]; then - [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login - fi - -If CDE starts its shells non-interactively during login, the login shell -startup files (~/.profile, ~/.bash_profile) will not be sourced at login. -To get around this problem, append a line similar to the following to your -~/.dtprofile: - - BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV - -and add the following line to the beginning of ~/.bash_profile: - - unset BASH_ENV - -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? - -You must add the full pathname to bash to the file /etc/shells. As -noted in the answer to the previous question, many systems require -this before you can make bash your login shell. - -Most versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -A9) 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. - -The Open Group has made an older version of its Single Unix -Specification (version 2), which is very similar to POSIX.2, -available on the web at - -http://www.opengroup.org/onlinepubs/007908799/ - -The Single Unix Specification, version 3, is available on the web at - -http://www.opengroup.org/onlinepubs/007904975/ - -A10) 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 or -'-o 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 POSIX in the bash distribution. -They are also listed in a section in the Bash Reference Manual -(from which that file is generated). - -Section B: The latest version - -B1) What's new in version 2.05b? - -The raison d'etre for bash-2.05b is to make a second intermediate -release containing the first of the new features to be available -in bash-3.0 and get feedback on those features before proceeding. -The major new feature is multibyte character support in both Bash -and Readline. - -Bash-2.05b contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-2.05b -distribution): - -o support for multibyte characters has been added to both bash and readline - -o the DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops - -o the shell now performs arithmetic in the largest integer size the machine - supports (intmax_t) - -o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) - and inserts the result into the expanded prompt - -o there is a new `here-string' redirection operator: <<< word - -o when displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -o `read' has a new `-u fd' option to read from a specified file descriptor - -o the bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better - -o the expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires - - -A short feature history dating from Bash-2.0: - -Bash-2.05a introduced the following new features: - -o The `printf' builtin has undergone major work - -o There is a new read-only `shopt' option: login_shell, which is set by - login shells and unset otherwise - -o New `\A' prompt string escape sequence; expanding to time in 24-hour - HH:MM format - -o New `-A group/-g' option to complete and compgen; goes group name - completion - -o New [+-]O invocation option to set and unset `shopt' options at startup - -o ksh-like `ERR' trap - -o `for' loops now allow empty word lists after the `in' reserved word - -o new `hard' and `soft' arguments for the `ulimit' builtin - -o Readline can be configured to place the user at the same point on the line - when retrieving commands from the history list - -o Readline can be configured to skip `hidden' files (filenames with a leading - `.' on Unix) when performing completion - -Bash-2.05 introduced the following new features: - -o This version has once again reverted to using locales and strcoll(3) when - processing pattern matching bracket expressions, as POSIX requires. -o Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. -o The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. -o `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces -o A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. -o When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -Bash-2.04 introduced the following new features: - -o Programmable word completion with the new `complete' and `compgen' builtins; - examples are provided in examples/complete/complete-examples -o `history' has a new `-d' option to delete a history entry -o `bind' has a new `-x' option to bind key sequences to shell commands -o The prompt expansion code has new `\j' and `\l' escape sequences -o The `no_empty_cmd_completion' shell option, if enabled, inhibits - command completion when TAB is typed on an empty line -o `help' has a new `-s' option to print a usage synopsis -o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) -o New ksh93-style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done -o `read' has new options: `-t', `-n', `-d', `-s' -o The redirection code handles several filenames specially: /dev/fd/N, - /dev/stdin, /dev/stdout, /dev/stderr -o The redirection code now recognizes /dev/tcp/HOST/PORT and - /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, - to the specified port on the specified host -o The ${!prefix*} expansion has been implemented -o A new FUNCNAME variable, which expands to the name of a currently-executing - function -o The GROUPS variable is no longer readonly -o A new shopt `xpg_echo' variable, to control the behavior of echo with - respect to backslash-escape sequences at runtime -o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned - -The version of Readline released with Bash-2.04, Readline-4.1, had several -new features as well: - -o Parentheses matching is always compiled into readline, and controllable - with the new `blink-matching-paren' variable -o The history-search-forward and history-search-backward functions now leave - point at the end of the line when the search string is empty, like - reverse-search-history, and forward-search-history -o A new function for applications: rl_on_new_line_with_prompt() -o New variables for applications: rl_already_prompted, and rl_gnu_readline_p - - -Bash-2.03 had very few new features, in keeping with the convention -that odd-numbered releases provide mainly bug fixes. A number of new -features were added to Readline, mostly at the request of the Cygnus -folks. - -A new shopt option, `restricted_shell', so that startup files can test - whether or not the shell was started in restricted mode -Filename generation is now performed on the words between ( and ) in - compound array assignments (this is really a bug fix) -OLDPWD is now auto-exported, as POSIX.2 requires -ENV and BASH_ENV are read-only variables in a restricted shell -Bash may now be linked against an already-installed Readline library, - as long as the Readline library is version 4 or newer -All shells begun with the `--login' option will source the login shell - startup files, even if the shell is not interactive - -There were lots of changes to the version of the Readline library released -along with Bash-2.03. For a complete list of the changes, read the file -CHANGES in the Bash-2.03 distribution. - -Bash-2.02 contained the following new features: - -a new version of malloc (based on the old GNU malloc code in previous - bash versions) that is more page-oriented, more conservative - with memory usage, does not `orphan' large blocks when they - are freed, is usable on 64-bit machines, and has allocation - checking turned on unconditionally -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -the ksh [[...]] extended conditional command -the ksh egrep-style extended pattern matching operators -a new `printf' builtin -the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- - prompt string special char translation and variable expansion - auto-export of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. - export -n/-f/-p/name=value, pwd -L/-P, - read -e/-p/-a/-t/-n/-d/-s/-u, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -m/-p/-u, - type -a/-p/-t/-f/-P, suspend -f, kill -n, - test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion with $((...)) and `let' builtin - the `[[...]]' extended conditional command - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing with programmable completion - command history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, compgen, complete, builtin, - declare/typeset, dirs, enable, fc, help, - history, logout, popd, pushd, disown, shopt, - printf - exported functions - filename generation when using output redirection (command >a*) - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - variable assignments preceding commands affect only that command, - even for builtins and functions - posix mode - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - -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' - $TIMEOUT (like bash $TMOUT) - `^' is a synonym for `|' - new SVR4.2 sh builtins: mldmode, priv - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS, using POSIX.2 - field splitting rules; sh splits all words on IFS - sh does not allow MAILCHECK to be unset (?) - sh does not allow traps on SIGALRM or SIGCHLD - bash allows multiple option arguments when invoked (e.g. -x -v); - sh allows only a single option argument (`sh -x -v' attempts - to open a file named `-v', and, on SunOS 4.1.4, dumps core. - On Solaris 2.4 and earlier versions, sh goes into an infinite - loop.) - sh exits a script if any builtin fails; bash exits only if one of - the POSIX.2 `special' builtins fails - -C2) How does bash differ from the Korn shell, version ksh88? - -Things bash has or uses that ksh88 does not: - long invocation options - [-+]O invocation option - -l invocation option - `!' reserved word - arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done - arithmetic in largest machine-supported size (intmax_t) - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - the ${!param} indirect parameter expansion operator - the ${!param*} prefix expansion operator - the ${param:offset[:length]} parameter substring operator - the ${param/pat[/string]} parameter pattern substitution operator - variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, - TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, - HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, - IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, - PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, - GROUPS, FUNCNAME, histchars, auto_resume - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- - more extensive and extensible editing and programmable completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, - jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, - read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, - set -o braceexpand/-o histexpand/-o interactive-comments/ - -o notify/-o physical/-o posix/-o hashall/-o onecmd/ - -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, - typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, - disown, printf, complete, compgen - `!' csh-style history expansion - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - `**' arithmetic operator to do exponentiation - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr - arrays of unlimited size - TMOUT is default timeout for `read' and `select' - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (|&, >&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence - using environment to pass attributes of exported variables - arithmetic evaluation done on arguments to some builtins - reads .profile from $PWD when invoked as login shell - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - bash has brace expansion by default (ksh88 compile-time option) - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - bash waits for all commands in pipeline to exit before returning status - emacs-mode editing has some slightly different key bindings - -C3) Which new features in ksh-93 are not in bash, and which are? - -New things in ksh-93 not in bash-2.05b: - associative arrays - floating point arithmetic and variables - math library functions - ${!name[sub]} name of subscript for associative array - `.' is allowed in variable names to create a hierarchical namespace - more extensive compound assignment syntax - discipline functions - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - KEYBD trap - variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, - .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT - backreferences in pattern matching (\N) - `&' operator in pattern lists for matching - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - exit statuses between 0 and 255 - set -o pipefail - `+=' variable assignment operator - FPATH and PATH mixing - getopts -a - -I invocation option - DEBUG trap now executed before each simple command, instead of after - printf %H, %P, %T, %Z modifiers, output base for %d - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - -New things in ksh-93 present in bash-2.05b: - [n]<&word- and [n]>&word- redirections (combination dup and close) - for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command - ?:, ++, --, `expr1 , expr2' arithmetic operators - expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, - ${!param*} - compound array assignment - the `!' reserved word - loadable builtins -- but ksh uses `builtin' while bash uses `enable' - `command', `builtin', `disown' builtins - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - set -o notify/-C - changes to kill builtin - read -A (bash uses read -a) - read -t/-d - trap -p - exec -c/-a - `.' restores the positional parameters when it completes - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion - ENV processed only for interactive shells - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? - -On many systems, `which' is actually a csh script that assumes -you're running csh. In tcsh, `which' and its cousin `where' -are builtins. On other Unix systems, `which' is a perl script -that uses the PATH environment variable. - -The csh script version 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. The bash `type' builtin does everything -`which' does, and will report correct results for the running -shell. If you're really wedded to the name `which', try adding -the following function definition to your .bashrc: - - which() - { - builtin type "$@" - } - -If you're moving from tcsh and would like to bring `where' along -as well, use this function: - - where() - { - builtin type -a "$@" - } - -D2) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least one unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -D3) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more cryptic, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -D4) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/misc/aliasconv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `aliasconv.sh', saving the -results into `bash_aliases': - - alias | bash aliasconv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of some csh specific -variables to the bash equivalents. The script converts $cwd to -$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt -to $PS1. You may also have to add quotes to avoid unwanted -expansion. - -For example, the csh alias: - - alias cd 'cd \!*; echo $cwd' - -is converted to the bash function: - - cd () { command cd "$@"; echo $PWD ; } - -The only thing that needs to be done is to quote $PWD: - - cd () { command cd "$@"; echo "$PWD" ; } - -Merge the edited file into your ~/.bashrc. - -There is an additional, more ambitious, script in -examples/misc/cshtobash that attempts to convert your entire csh -environment to its bash equivalent. This script can be run as -simply `cshtobash' to convert your normal interactive -environment, or as `cshtobash ~/.login' to convert your login -environment. - -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? - -Use - command 2>&1 | command2 - -The key is to remember that piping is performed before redirection, so -file descriptor 1 points to the pipe when it is duplicated onto file -descriptor 2. - -D6) 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 and ksh-93 that do not have direct bash -equivalents. Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -coprocesses named pipe pairs (one for read, one for write) -typeset +f declare -F -cd, print, whence function substitutes in examples/functions/kshenv -autoloaded functions examples/functions/autoload is the same as typeset -fu -read var?prompt read -p prompt var - -ksh-93 feature Bash equivalent --------------- --------------- -sleep, getconf Bash has loadable versions in examples/loadables -${.sh.version} $BASH_VERSION -print -f printf -hist alias hist=fc -$HISTEDIT $FCEDIT - -Section E: How can I get bash to do certain things, and why does bash do - things the way it does? - -E1) 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 - If first argument is `(' and third argument is `)', do the - one-argument test of the second argument. - 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. - -E2) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appears 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. - -You can build a version of bash that will not report SIGPIPE errors -by uncommenting the definition of DONT_REPORT_SIGPIPE in the file -config-top.h. - -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Readline, the line editing library that bash uses, 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. - -E4) 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. It affects all commands run in pipelines, not just -simple calls to `read'. For example, piping a command's output -into a `while' loop that repeatedly calls `read' will result in -the same behavior. - -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 of -a specified command. The output can then be assigned to 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. If you need to do this, you can either use the -command substitution above to read the output into a variable -and chop up the variable using the bash pattern removal -expansion operators or use some variant of the following -approach. - -Say /usr/local/bin/ipaddr is the following shell script: - -#! /bin/sh -host `hostname` | awk '/address/ {print $NF}' - -Instead of using - - /usr/local/bin/ipaddr | read A B C D - -to break the local machine's IP address into separate octets, use - - OIFS="$IFS" - IFS=. - set -- $(/usr/local/bin/ipaddr) - IFS="$OIFS" - A="$1" B="$2" C="$3" D="$4" - -Beware, however, that this will change the shell's positional -parameters. If you need them, you should save them before doing -this. - -This is the general approach -- in most cases you will not need to -set $IFS to a different value. - -Some other user-supplied alternatives include: - -read A B C D << HERE - $(IFS=.; echo $(/usr/local/bin/ipaddr)) -HERE - -and, where process substitution is available, - -read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) - -E5) 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 modeled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default; -it 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 configuration option that will make bash behave like -the System V echo and interpret things like `\t' by default. Run -configure with the --enable-xpg-echo-default option to turn this -on. Be aware that this will cause some of the tests run when you -type `make tests' to fail. - -There is a shell option, `xpg_echo', settable with `shopt', that will -change the behavior of echo at runtime. Enabling this option turns -on expansion of backslash-escape sequences. - -E6) Why doesn't a while or for loop get suspended when I type ^Z? - -This is a consequence of how job control works on Unix. The only -thing that can be suspended is the process group. This is a single -command or pipeline of commands that the shell forks and executes. - -When you run a while or for loop, the only thing that the shell forks -and executes are any commands in the while loop test and commands in -the loop bodies. These, therefore, are the only things that can be -suspended when you type ^Z. - -If you want to be able to stop the entire loop, you need to put it -within parentheses, which will force the loop into a subshell that -may be stopped (and subsequently restarted) as a single unit. - -E7) What about empty for loops in Makefiles? - -It's fairly common to see constructs like this in automatically-generated -Makefiles: - -SUBDIRS = @SUBDIRS@ - - ... - -subdirs-clean: - for d in ${SUBDIRS}; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -When SUBDIRS is empty, this results in a command like this being passed to -bash: - - for d in ; do - ( cd $d && ${MAKE} ${MFLAGS} clean ) - done - -In versions of bash before bash-2.05a, this was a syntax error. If the -reserved word `in' was present, a word must follow it before the semicolon -or newline. The language in the manual page referring to the list of words -being empty referred to the list after it is expanded. These versions of -bash required that there be at least one word following the `in' when the -construct was parsed. - -The idiomatic Makefile solution is something like: - -SUBDIRS = @SUBDIRS@ - -subdirs-clean: - subdirs=$SUBDIRS ; for d in $$subdirs; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -The latest drafts of the updated POSIX standard have changed this: the -word list is no longer required. Bash versions 2.05a and later accept -the new syntax. - -E8) Why does the arithmetic evaluation code complain about `08'? - -The bash arithmetic evaluation code (used for `let', $(()), (()), and in -other places), interprets a leading `0' in numeric constants as denoting -an octal number, and a leading `0x' as denoting hexadecimal. This is -in accordance with the POSIX.2 spec, section 2.9.2.1, which states that -arithmetic constants should be handled as signed long integers as defined -by the ANSI/ISO C standard. - -The POSIX.2 interpretation committee has confirmed this: - -http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html - -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? - -Bash-2.03, Bash-2.05 and later versions honor the current locale setting -when processing ranges within pattern matching bracket expressions ([A-Z]). -This is what POSIX.2 and SUSv3/XPG6 specify. - -The behavior of the matcher in bash-2.05 and later versions depends on the -current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will -result in the traditional behavior ([A-Z] matches all uppercase ASCII -characters). Many other locales, including the en_US locale (the default -on many US versions of Linux) collate the upper and lower case letters like -this: - - AaBb...Zz - -which means that [A-Z] matches every letter except `z'. Others collate like - - aAbBcC...zZ - -which means that [A-Z] matches every letter except `a'. - -The portable way to specify upper case letters is [:upper:] instead of -A-Z; lower case may be specified as [:lower:] instead of a-z. - -Look at the manual pages for setlocale(3), strcoll(3), and, if it is -present, locale(1). If you have locale(1), you can use it to find -your current locale information even if you do not have any of the -LC_ variables set. - -My advice is to put - - export LC_COLLATE=C - -into /etc/profile and inspect any shell scripts run from cron for -constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - -from removing every file in the current directory except those beginning -with `z' and still allow individual users to change the collation order. -Users may put the above command into their own profiles as well, of course. - -E10) Why does `cd //' leave $PWD as `//'? - -POSIX.2, in its description of `cd', says that *three* or more leading -slashes may be replaced with a single slash when canonicalizing the -current working directory. - -This is, I presume, for historical compatibility. Certain versions of -Unix, and early network file systems, used paths of the form -//hostname/path to access `path' on server `hostname'. - -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -This is another issue that deals with job control. - -The kernel maintains a notion of a current terminal process group. Members -of this process group (processes whose process group ID is equal to the -current terminal process group ID) receive terminal-generated signals like -SIGWINCH. (For more details, see the JOB CONTROL section of the bash -man page.) - -If a terminal is resized, the kernel sends SIGWINCH to each member of -the terminal's current process group (the `foreground' process group). - -When bash is running with job control enabled, each pipeline (which may be -a single command) is run in its own process group, different from bash's -process group. This foreground process group receives the SIGWINCH; bash -does not. Bash has no way of knowing that the terminal has been resized. - -There is a `checkwinsize' option, settable with the `shopt' builtin, that -will cause bash to check the window size and adjust its idea of the -terminal's dimensions each time a process stops or exits and returns control -of the terminal to bash. Enable it with `shopt -s checkwinsize'. - -Section F: Things to watch out for on certain Unix versions - -F1) 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. - -If you must use cmdtool, you can use the termcap description in -examples/suncmd.termcap. Set the TERMCAP variable to the terminal -description contained in that file, i.e. - -TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' - -Then export TERMCAP and start a new cmdtool window from that shell. -The bash command-line editing should behave better in the new -cmdtool. If this works, you can put the assignment to TERMCAP -in your bashrc file. - -F2) 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 structures 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 configuring and 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. - -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion 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 -run configure with the `--without-gnu-malloc' option to use -the C library malloc and avoid the problem. - -F4) 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. - -F5) 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. - -This affects the mechanical transformation of commands that use `cat' -to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on -comp.unix.shell). While most commands of the form - - cat file | command - -can be converted to `< file command', shell control structures such as -loops and subshells require `command < file'. - -The file CWRU/sh-redir-hack in the bash-2.05a distribution is an -(unofficial) patch to parse.y that will modify the grammar to -support this construct. It will not apply with `patch'; you must -modify parse.y by hand. 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. - -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? - -The short answer is that Red Hat screwed up. - -The long answer is that they shipped an /etc/inputrc that only works -for emacs mode editing, and then screwed all the vi users by setting -INPUTRC to /etc/inputrc in /etc/profile. - -The short fix is to do one of the following: remove or rename -/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, -but make sure you export it if you do), remove the assignment to -INPUTRC from /etc/profile, add - - set keymap emacs - -to the beginning of /etc/inputrc, or bracket the key bindings in -/etc/inputrc with these lines - - $if mode=emacs - [...] - $endif - -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -HP/UX's support for long double is imperfect at best. - -GCC will support it without problems, but the HP C library functions -like strtold(3) and printf(3) don't actually work with long doubles. -HP implemented a `long_double' type as a 4-element array of 32-bit -ints, and that is what the library functions use. The ANSI C -`long double' type is a 128-bit floating point scalar. - -The easiest fix, until HP fixes things up, is to edit the generated -config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, -the compilation should complete successfully. - -Section G: How can I get bash to do certain common things? - -G1) 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 eighth 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. - -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is why the `command' and `builtin' builtins exist. 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. - -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Versions of Bash newer than Bash-2.0 support this directly. You can use - - ${!var} - -For example, the following sequence of commands will echo `z': - - var1=var2 - var2=z - echo ${!var1} - -For sh compatibility, 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. In versions of bash later than bash-2.0, - - echo ${!#} - -does the same thing. - -This is not the same thing as ksh93 `nameref' variables, though the syntax -is similar. I may add namerefs in a future bash version. - -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? - -The bash command timing code looks for a variable `TIMEFORMAT' and -uses its value as a format string to decide how to display the -timing statistics. - -The value of TIMEFORMAT is a string with `%' escapes expanded in a -fashion similar in spirit to printf(3). The manual page explains -the meanings of the escape sequences in the format string. - -If TIMEFORMAT is not set, bash acts as if the following assignment had -been performed: - - TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' - -The POSIX.2 default time format (used by `time -p command') is - - TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' - -The BSD /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' - -The System V /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' - -The ksh format can be emulated with: - - TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' - -G5) How do I get the current directory into my prompt? - -Bash provides a number of backslash-escape sequences which are expanded -when the prompt string (PS1 or PS2) is displayed. The full list is in -the manual page. - -The \w expansion gives the full pathname of the current directory, with -a tilde (`~') substituted for the current value of $HOME. The \W -expansion gives the basename of the current directory. To put the full -pathname of the current directory into the path without any tilde -subsitution, use $PWD. Here are some examples: - - PS1='\w$ ' # current directory with tilde - PS1='\W$ ' # basename of current directory - PS1='$PWD$ ' # full pathname of current directory - -The single quotes are important in the final example to prevent $PWD from -being expanded when the assignment to PS1 is performed. - -G6) How can I rename "*.foo" to "*.bar"? - -Use the pattern removal functionality described in D3. The following `for' -loop will do the trick: - - for f in *.foo; do - mv $f ${f%foo}bar - done - -G7) How can I translate a filename from uppercase to lowercase? - -The script examples/functions/lowercase, originally written by John DuBois, -will do the trick. The converse is left as an exercise. - -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -You must have set the `extglob' shell option using `shopt -s extglob' to use -this: - - echo .!(.|) * - -A solution that works without extended globbing is given in the Unix Shell -FAQ, posted periodically to comp.unix.shell. - -Section H: Where do I go from here? - -H1) 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@gnu.org, 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@gnu.org. - -H2) What kind of bash documentation is there? - -First, look in the doc directory in the bash distribution. It should -contain at least the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -bashref.texi a reference manual in GNU tex`info format -bashref.info an info version of the reference manual -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript, HTML, and ASCII files created from the above source are -available in the documentation distribution. - -There is additional documentation available for anonymous FTP from host -ftp.cwru.edu in the `pub/bash' directory. - -Cameron Newham and Bill Rosenblatt have written a book on bash, published -by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn -Shell book. The title is ``Learning the Bash Shell'', and the ISBN number -is 1-56592-147-X. Look for it in fine bookstores near you. This book -covers bash-1.14, but has an appendix describing some of the new features -in bash-2.0. - -A second edition of this book is available, published in January, 1998. -The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores -or on the web. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers -bash-2.0 and is available from most online bookstores (see -http://www.network-theory.co.uk/bash/manual/ for details). The publisher -will donate $1 to the Free Software Foundation for each copy sold. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -a better bash debugger (a minimally-tested version is included with bash-2.05b) -associative arrays -co-processes, but with a new-style syntax that looks like function declaration - -H4) What's on the bash `wish list' for future versions? - -These are features that may or may not appear in a future version of bash. - -breaking some of the shell functionality into embeddable libraries -a module system like zsh's, using dynamic loading like builtins -better internationalization using GNU `gettext' -date-stamped command history -a bash programmer's guide with a chapter on creating loadable builtins -a better loadable interface to perl with access to the shell builtins and - variables (contributions gratefully accepted) -ksh93-like `nameref' variables -ksh93-like `+=' variable assignment operator -ksh93-like `xx.yy' variables (including some of the .sh.* variables) and - associated disipline functions -Some of the new ksh93 pattern matching operators, like backreferencing - -H5) When will the next release appear? - -The next version will appear sometime in 2002. Never make predictions. - - -This document is Copyright 1995-2003 by Chester Ramey. - -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/doc/FAQ.save b/doc/FAQ.save deleted file mode 100644 index 1cff3c8ef..000000000 --- a/doc/FAQ.save +++ /dev/null @@ -1,1745 +0,0 @@ -This is the Bash FAQ, version 3.24, for Bash version 2.05b. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet@po.cwru.edu. - -This document is available for anonymous FTP with the URL - -ftp://ftp.cwru.edu/pub/bash/FAQ - -The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html - ----------- -Contents: - -Section A: The Basics - -A1) What is it? -A2) What's the latest version? -A3) Where can I get it? -A4) On what machines will bash run? -A5) Will bash run on operating systems other than Unix? -A6) How can I build bash with gcc? -A7) How can I make bash my login shell? -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? -A9) What's the `POSIX 1003.2 standard'? -A10) What is the bash `posix mode'? - -Section B: The latest version - -B1) What's new in version 2.05b? -B2) Are there any user-visible incompatibilities between bash-2.05b and - bash-1.14.7? - -Section C: Differences from other Unix shells - -C1) How does bash differ from sh, the Bourne shell? -C2) How does bash differ from the Korn shell, version ksh88? -C3) Which new features in ksh-93 are not in bash, and which are? - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? -D2) Why doesn't bash treat brace expansions exactly like csh? -D3) Why doesn't bash have csh variable modifiers? -D4) How can I make my csh aliases work when I convert to bash? -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -Section E: Why does bash do certain things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? -E2) Why does bash sometimes say `Broken pipe'? -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -E4) 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? -E5) 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? -E6) Why doesn't a while or for loop get suspended when I type ^Z? -E7) What about empty for loops in Makefiles? -E8) Why does the arithmetic evaluation code complain about `08'? -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? -E10) Why does `cd //' leave $PWD as `//'? -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? -G5) How do I get the current directory into my prompt? -G6) How can I rename "*.foo" to "*.bar"? -G7) How can I translate a filename from uppercase to lowercase? -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? -H2) What kind of bash documentation is there? -H3) What's coming in future versions? -H4) What's on the bash `wish list'? -H5) When will the next release appear? - ----------- -Section A: The Basics - -A1) 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. - -A2) What's the latest version? - -The latest version is 2.05b, first made available on Wednesday, 17 -July, 2002. - -A3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, ftp.gnu.org, and its mirrors. The -latest version is also available for FTP from ftp.cwru.edu. -The following URLs tell how to get version 2.05b: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz - -A4) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `configure' and then `make'. The build process -will attempt to discover the version of UNIX you have and tailor -itself accordingly, using a script created by GNU autoconf. - -More information appears in the file `INSTALL' in the distribution. - -The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) -explains how to obtain binary versions of bash for most of the major -commercial Unix systems. - -A5) Will bash run on operating systems other than Unix? - -Configuration specifics for Unix-like systems such as QNX and -LynxOS are included in the distribution. Bash-2.05 and later -versions should compile and run on Minix 2.0 (patches were -contributed), but I don't believe anyone has built bash-2.x on -earlier Minix versions yet. - -Bash has been ported to versions of Windows implementing the Win32 -programming interface. This includes Windows 95 and Windows NT. -The port was done by Cygnus Solutions as part of their CYGWIN -project. For more information about the project, look at the URLs - -http://www.cygwin.com/ -http://sourceware.cygnus.com/cygwin - -Cygnus originally ported bash-1.14.7, and that port was part of their -early GNU-Win32 (the original name) releases. Cygnus has also done a -port of bash-2.05 to the CYGWIN environment, and it is available as -part of their current release. - -Bash-2.05b should require no local Cygnus changes to build and run under -CYGWIN. - -The Cygnus port works only on Intel machines. There is a port of bash -(I don't know which version) to the alpha/NT environment available from - -ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz - -DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part -of the DJGPP project. For more information on the project, see - -http://www.delorie.com/djgpp/ - -I have been told that the original DJGPP port was done by Daisuke Aoyama. - -Mark Elbrecht has sent me notice that bash-2.04 -is available for DJGPP V2. The files are available as: - -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source - -Mark has begun to work with bash-2.05, but I don't know the status. - -Ports of bash-1.12 and bash-2.0 are available for OS/2 from - -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip - -I haven't looked at either, but the second appears to be a binary-only -distribution. Beware. - -I have received word that Bash (I'm not sure which version, but I -believe that it's at least bash-2.02.1) is the standard shell on -BeOS. - -A6) How can I build bash with gcc? - -Bash configures to use gcc by default if it is available. Read the -file INSTALL in the distribution for more information. - -A7) How can I make bash my login shell? - -Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s' or `passwd -e'. If one of these works for -you, that's all you need. Note that many systems require the full -pathname to a shell to appear in /etc/shells before you can make it -your login shell. For this, you may need the assistance of your -friendly local system administrator. - -If you cannot do this, you can still use bash as your login shell, but -you need to perform some tricks. The basic idea is to add a command -to your login shell's startup file to replace your login shell with -bash. - -For example, if your login shell is csh or tcsh, and you have installed -bash in /usr/gnu/bin/bash, add the following line to ~/.login: - - if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login - -(the `--login' tells bash that it is a login shell). - -It's not a good idea to put this command into ~/.cshrc, because every -csh you run without the `-f' option, even ones started to run csh scripts, -reads that file. If you must put the command in ~/.cshrc, use something -like - - if ( $?prompt ) exec /usr/gnu/bin/bash --login - -to ensure that bash is exec'd only when the csh is interactive. - -If your login shell is sh or ksh, you have to do two things. - -First, create an empty file in your home directory named `.bash_profile'. -The existence of this file will prevent the exec'd bash from trying to -read ~/.profile, and re-execing itself over and over again. ~/.bash_profile -is the first file bash tries to read initialization commands from when -it is invoked as a login shell. - -Next, add a line similar to the above to ~/.profile: - - [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ - exec /usr/gnu/bin/bash --login - -This will cause login shells to replace themselves with bash running as -a login shell. Once you have this working, you can copy your initialization -code from ~/.profile to ~/.bash_profile. - -I have received word that the recipe supplied above is insufficient for -machines running CDE. CDE has a maze of twisty little startup files, all -slightly different. - -If you cannot change your login shell in the password file to bash, you -will have to (apparently) live with CDE using the shell in the password -file to run its startup scripts. If you have changed your shell to bash, -there is code in the CDE startup files (on Solaris, at least) that attempts -to do the right thing. It is, however, often broken, and may require that -you use the $BASH_ENV trick described below. - -`dtterm' claims to use $SHELL as the default program to start, so if you -can change $SHELL in the CDE startup files, you should be able to use bash -in your terminal windows. - -Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program -to read your login shell's startup files. You may be able to use bash for -the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as -well, but I have not tried this. - -You can use the above `exec' recipe to start bash when not logging in with -CDE by testing the value of the DT variable: - - if [ -n "$DT" ]; then - [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login - fi - -If CDE starts its shells non-interactively during login, the login shell -startup files (~/.profile, ~/.bash_profile) will not be sourced at login. -To get around this problem, append a line similar to the following to your -~/.dtprofile: - - BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV - -and add the following line to the beginning of ~/.bash_profile: - - unset BASH_ENV - -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? - -You must add the full pathname to bash to the file /etc/shells. As -noted in the answer to the previous question, many systems require -this before you can make bash your login shell. - -Most versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -A9) 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. - -The Open Group has made an older version of its Single Unix -Specification (version 2), which is very similar to POSIX.2, -available on the web at - -http://www.opengroup.org/onlinepubs/007908799/ - -The Single Unix Specification, version 3, is available on the web at - -http://www.opengroup.org/onlinepubs/007904975/ - -A10) 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 or -'-o 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 POSIX in the bash distribution. -They are also listed in a section in the Bash Reference Manual -(from which that file is generated). - -Section B: The latest version - -B1) What's new in version 2.05b? - -The raison d'etre for bash-2.05b is to make a second intermediate -release containing the first of the new features to be available -in bash-3.0 and get feedback on those features before proceeding. -The major new feature is multibyte character support in both Bash -and Readline. - -Bash-2.05b contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-2.05b -distribution): - -o support for multibyte characters has been added to both bash and readline - -o the DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops - -o the shell now performs arithmetic in the largest integer size the machine - supports (intmax_t) - -o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) - and inserts the result into the expanded prompt - -o there is a new `here-string' redirection operator: <<< word - -o when displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -o `read' has a new `-u fd' option to read from a specified file descriptor - -o the bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better - -o the expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires - - -A short feature history dating from Bash-2.0: - -Bash-2.05a introduced the following new features: - -o The `printf' builtin has undergone major work - -o There is a new read-only `shopt' option: login_shell, which is set by - login shells and unset otherwise - -o New `\A' prompt string escape sequence; expanding to time in 24-hour - HH:MM format - -o New `-A group/-g' option to complete and compgen; goes group name - completion - -o New [+-]O invocation option to set and unset `shopt' options at startup - -o ksh-like `ERR' trap - -o `for' loops now allow empty word lists after the `in' reserved word - -o new `hard' and `soft' arguments for the `ulimit' builtin - -o Readline can be configured to place the user at the same point on the line - when retrieving commands from the history list - -o Readline can be configured to skip `hidden' files (filenames with a leading - `.' on Unix) when performing completion - -Bash-2.05 introduced the following new features: - -o This version has once again reverted to using locales and strcoll(3) when - processing pattern matching bracket expressions, as POSIX requires. -o Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. -o The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. -o `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces -o A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. -o When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -Bash-2.04 introduced the following new features: - -o Programmable word completion with the new `complete' and `compgen' builtins; - examples are provided in examples/complete/complete-examples -o `history' has a new `-d' option to delete a history entry -o `bind' has a new `-x' option to bind key sequences to shell commands -o The prompt expansion code has new `\j' and `\l' escape sequences -o The `no_empty_cmd_completion' shell option, if enabled, inhibits - command completion when TAB is typed on an empty line -o `help' has a new `-s' option to print a usage synopsis -o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) -o New ksh93-style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done -o `read' has new options: `-t', `-n', `-d', `-s' -o The redirection code handles several filenames specially: /dev/fd/N, - /dev/stdin, /dev/stdout, /dev/stderr -o The redirection code now recognizes /dev/tcp/HOST/PORT and - /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, - to the specified port on the specified host -o The ${!prefix*} expansion has been implemented -o A new FUNCNAME variable, which expands to the name of a currently-executing - function -o The GROUPS variable is no longer readonly -o A new shopt `xpg_echo' variable, to control the behavior of echo with - respect to backslash-escape sequences at runtime -o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned - -The version of Readline released with Bash-2.04, Readline-4.1, had several -new features as well: - -o Parentheses matching is always compiled into readline, and controllable - with the new `blink-matching-paren' variable -o The history-search-forward and history-search-backward functions now leave - point at the end of the line when the search string is empty, like - reverse-search-history, and forward-search-history -o A new function for applications: rl_on_new_line_with_prompt() -o New variables for applications: rl_already_prompted, and rl_gnu_readline_p - - -Bash-2.03 had very few new features, in keeping with the convention -that odd-numbered releases provide mainly bug fixes. A number of new -features were added to Readline, mostly at the request of the Cygnus -folks. - -A new shopt option, `restricted_shell', so that startup files can test - whether or not the shell was started in restricted mode -Filename generation is now performed on the words between ( and ) in - compound array assignments (this is really a bug fix) -OLDPWD is now auto-exported, as POSIX.2 requires -ENV and BASH_ENV are read-only variables in a restricted shell -Bash may now be linked against an already-installed Readline library, - as long as the Readline library is version 4 or newer -All shells begun with the `--login' option will source the login shell - startup files, even if the shell is not interactive - -There were lots of changes to the version of the Readline library released -along with Bash-2.03. For a complete list of the changes, read the file -CHANGES in the Bash-2.03 distribution. - -Bash-2.02 contained the following new features: - -a new version of malloc (based on the old GNU malloc code in previous - bash versions) that is more page-oriented, more conservative - with memory usage, does not `orphan' large blocks when they - are freed, is usable on 64-bit machines, and has allocation - checking turned on unconditionally -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -the ksh [[...]] extended conditional command -the ksh egrep-style extended pattern matching operators -a new `printf' builtin -the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- - prompt string special char translation and variable expansion - auto-export of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. - export -n/-f/-p/name=value, pwd -L/-P, - read -e/-p/-a/-t/-n/-d/-s/-u, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -m/-p/-u, - type -a/-p/-t/-f/-P, suspend -f, kill -n, - test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion with $((...)) and `let' builtin - the `[[...]]' extended conditional command - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing with programmable completion - command history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, compgen, complete, builtin, - declare/typeset, dirs, enable, fc, help, - history, logout, popd, pushd, disown, shopt, - printf - exported functions - filename generation when using output redirection (command >a*) - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - variable assignments preceding commands affect only that command, - even for builtins and functions - posix mode - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - -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' - $TIMEOUT (like bash $TMOUT) - `^' is a synonym for `|' - new SVR4.2 sh builtins: mldmode, priv - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS, using POSIX.2 - field splitting rules; sh splits all words on IFS - sh does not allow MAILCHECK to be unset (?) - sh does not allow traps on SIGALRM or SIGCHLD - bash allows multiple option arguments when invoked (e.g. -x -v); - sh allows only a single option argument (`sh -x -v' attempts - to open a file named `-v', and, on SunOS 4.1.4, dumps core. - On Solaris 2.4 and earlier versions, sh goes into an infinite - loop.) - sh exits a script if any builtin fails; bash exits only if one of - the POSIX.2 `special' builtins fails - -C2) How does bash differ from the Korn shell, version ksh88? - -Things bash has or uses that ksh88 does not: - long invocation options - [-+]O invocation option - -l invocation option - `!' reserved word - arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done - arithmetic in largest machine-supported size (intmax_t) - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - the ${!param} indirect parameter expansion operator - the ${!param*} prefix expansion operator - the ${param:offset[:length]} parameter substring operator - the ${param/pat[/string]} parameter pattern substitution operator - variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, - TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, - HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, - IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, - PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, - GROUPS, FUNCNAME, histchars, auto_resume - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- - more extensive and extensible editing and programmable completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, - jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, - read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, - set -o braceexpand/-o histexpand/-o interactive-comments/ - -o notify/-o physical/-o posix/-o hashall/-o onecmd/ - -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, - typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, - disown, printf, complete, compgen - `!' csh-style history expansion - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - `**' arithmetic operator to do exponentiation - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr - arrays of unlimited size - TMOUT is default timeout for `read' and `select' - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (|&, >&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence - using environment to pass attributes of exported variables - arithmetic evaluation done on arguments to some builtins - reads .profile from $PWD when invoked as login shell - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - bash has brace expansion by default (ksh88 compile-time option) - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - bash waits for all commands in pipeline to exit before returning status - emacs-mode editing has some slightly different key bindings - -C3) Which new features in ksh-93 are not in bash, and which are? - -New things in ksh-93 not in bash-2.05b: - associative arrays - floating point arithmetic and variables - math library functions - ${!name[sub]} name of subscript for associative array - `.' is allowed in variable names to create a hierarchical namespace - more extensive compound assignment syntax - discipline functions - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - KEYBD trap - variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, - .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT - backreferences in pattern matching (\N) - `&' operator in pattern lists for matching - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - exit statuses between 0 and 255 - set -o pipefail - `+=' variable assignment operator - FPATH and PATH mixing - getopts -a - -I invocation option - DEBUG trap now executed before each simple command, instead of after - printf %H, %P, %T, %Z modifiers, output base for %d - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - -New things in ksh-93 present in bash-2.05b: - [n]<&word- and [n]>&word- redirections (combination dup and close) - for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command - ?:, ++, --, `expr1 , expr2' arithmetic operators - expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, - ${!param*} - compound array assignment - the `!' reserved word - loadable builtins -- but ksh uses `builtin' while bash uses `enable' - `command', `builtin', `disown' builtins - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - set -o notify/-C - changes to kill builtin - read -A (bash uses read -a) - read -t/-d - trap -p - exec -c/-a - `.' restores the positional parameters when it completes - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion - ENV processed only for interactive shells - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? - -On many systems, `which' is actually a csh script that assumes -you're running csh. In tcsh, `which' and its cousin `where' -are builtins. On other Unix systems, `which' is a perl script -that uses the PATH environment variable. - -The csh script version 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. The bash `type' builtin does everything -`which' does, and will report correct results for the running -shell. If you're really wedded to the name `which', try adding -the following function definition to your .bashrc: - - which() - { - builtin type "$@" - } - -If you're moving from tcsh and would like to bring `where' along -as well, use this function: - - where() - { - builtin type -a "$@" - } - -D2) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least one unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -D3) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more cryptic, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -D4) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/misc/aliasconv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `aliasconv.sh', saving the -results into `bash_aliases': - - alias | bash aliasconv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of some csh specific -variables to the bash equivalents. The script converts $cwd to -$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt -to $PS1. You may also have to add quotes to avoid unwanted -expansion. - -For example, the csh alias: - - alias cd 'cd \!*; echo $cwd' - -is converted to the bash function: - - cd () { command cd "$@"; echo $PWD ; } - -The only thing that needs to be done is to quote $PWD: - - cd () { command cd "$@"; echo "$PWD" ; } - -Merge the edited file into your ~/.bashrc. - -There is an additional, more ambitious, script in -examples/misc/cshtobash that attempts to convert your entire csh -environment to its bash equivalent. This script can be run as -simply `cshtobash' to convert your normal interactive -environment, or as `cshtobash ~/.login' to convert your login -environment. - -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? - -Use - command 2>&1 | command2 - -The key is to remember that piping is performed before redirection, so -file descriptor 1 points to the pipe when it is duplicated onto file -descriptor 2. - -D6) 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 and ksh-93 that do not have direct bash -equivalents. Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -coprocesses named pipe pairs (one for read, one for write) -typeset +f declare -F -cd, print, whence function substitutes in examples/functions/kshenv -autoloaded functions examples/functions/autoload is the same as typeset -fu -read var?prompt read -p prompt var - -ksh-93 feature Bash equivalent --------------- --------------- -sleep, getconf Bash has loadable versions in examples/loadables -${.sh.version} $BASH_VERSION -print -f printf -hist alias hist=fc -$HISTEDIT $FCEDIT - -Section E: How can I get bash to do certain things, and why does bash do - things the way it does? - -E1) 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 - If first argument is `(' and third argument is `)', do the - one-argument test of the second argument. - 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. - -E2) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appears 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. - -You can build a version of bash that will not report SIGPIPE errors -by uncommenting the definition of DONT_REPORT_SIGPIPE in the file -config-top.h. - -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Readline, the line editing library that bash uses, 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. - -E4) 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. It affects all commands run in pipelines, not just -simple calls to `read'. For example, piping a command's output -into a `while' loop that repeatedly calls `read' will result in -the same behavior. - -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 of -a specified command. The output can then be assigned to 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. If you need to do this, you can either use the -command substitution above to read the output into a variable -and chop up the variable using the bash pattern removal -expansion operators or use some variant of the following -approach. - -Say /usr/local/bin/ipaddr is the following shell script: - -#! /bin/sh -host `hostname` | awk '/address/ {print $NF}' - -Instead of using - - /usr/local/bin/ipaddr | read A B C D - -to break the local machine's IP address into separate octets, use - - OIFS="$IFS" - IFS=. - set -- $(/usr/local/bin/ipaddr) - IFS="$OIFS" - A="$1" B="$2" C="$3" D="$4" - -Beware, however, that this will change the shell's positional -parameters. If you need them, you should save them before doing -this. - -This is the general approach -- in most cases you will not need to -set $IFS to a different value. - -Some other user-supplied alternatives include: - -read A B C D << HERE - $(IFS=.; echo $(/usr/local/bin/ipaddr)) -HERE - -and, where process substitution is available, - -read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) - -E5) 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 modeled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default; -it 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 configuration option that will make bash behave like -the System V echo and interpret things like `\t' by default. Run -configure with the --enable-xpg-echo-default option to turn this -on. Be aware that this will cause some of the tests run when you -type `make tests' to fail. - -There is a shell option, `xpg_echo', settable with `shopt', that will -change the behavior of echo at runtime. Enabling this option turns -on expansion of backslash-escape sequences. - -E6) Why doesn't a while or for loop get suspended when I type ^Z? - -This is a consequence of how job control works on Unix. The only -thing that can be suspended is the process group. This is a single -command or pipeline of commands that the shell forks and executes. - -When you run a while or for loop, the only thing that the shell forks -and executes are any commands in the while loop test and commands in -the loop bodies. These, therefore, are the only things that can be -suspended when you type ^Z. - -If you want to be able to stop the entire loop, you need to put it -within parentheses, which will force the loop into a subshell that -may be stopped (and subsequently restarted) as a single unit. - -E7) What about empty for loops in Makefiles? - -It's fairly common to see constructs like this in automatically-generated -Makefiles: - -SUBDIRS = @SUBDIRS@ - - ... - -subdirs-clean: - for d in ${SUBDIRS}; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -When SUBDIRS is empty, this results in a command like this being passed to -bash: - - for d in ; do - ( cd $d && ${MAKE} ${MFLAGS} clean ) - done - -In versions of bash before bash-2.05a, this was a syntax error. If the -reserved word `in' was present, a word must follow it before the semicolon -or newline. The language in the manual page referring to the list of words -being empty referred to the list after it is expanded. These versions of -bash required that there be at least one word following the `in' when the -construct was parsed. - -The idiomatic Makefile solution is something like: - -SUBDIRS = @SUBDIRS@ - -subdirs-clean: - subdirs=$SUBDIRS ; for d in $$subdirs; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -The latest drafts of the updated POSIX standard have changed this: the -word list is no longer required. Bash versions 2.05a and later accept -the new syntax. - -E8) Why does the arithmetic evaluation code complain about `08'? - -The bash arithmetic evaluation code (used for `let', $(()), (()), and in -other places), interprets a leading `0' in numeric constants as denoting -an octal number, and a leading `0x' as denoting hexadecimal. This is -in accordance with the POSIX.2 spec, section 2.9.2.1, which states that -arithmetic constants should be handled as signed long integers as defined -by the ANSI/ISO C standard. - -The POSIX.2 interpretation committee has confirmed this: - -http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html - -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? - -Bash-2.03, Bash-2.05 and later versions honor the current locale setting -when processing ranges within pattern matching bracket expressions ([A-Z]). -This is what POSIX.2 and SUSv3/XPG6 specify. - -The behavior of the matcher in bash-2.05 and later versions depends on the -current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will -result in the traditional behavior ([A-Z] matches all uppercase ASCII -characters). Many other locales, including the en_US locale (the default -on many US versions of Linux) collate the upper and lower case letters like -this: - - AaBb...Zz - -which means that [A-Z] matches every letter except `z'. Others collate like - - aAbBcC...zZ - -which means that [A-Z] matches every letter except `a'. - -The portable way to specify upper case letters is [:upper:] instead of -A-Z; lower case may be specified as [:lower:] instead of a-z. - -Look at the manual pages for setlocale(3), strcoll(3), and, if it is -present, locale(1). If you have locale(1), you can use it to find -your current locale information even if you do not have any of the -LC_ variables set. - -My advice is to put - - export LC_COLLATE=C - -into /etc/profile and inspect any shell scripts run from cron for -constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - -from removing every file in the current directory except those beginning -with `z' and still allow individual users to change the collation order. -Users may put the above command into their own profiles as well, of course. - -E10) Why does `cd //' leave $PWD as `//'? - -POSIX.2, in its description of `cd', says that *three* or more leading -slashes may be replaced with a single slash when canonicalizing the -current working directory. - -This is, I presume, for historical compatibility. Certain versions of -Unix, and early network file systems, used paths of the form -//hostname/path to access `path' on server `hostname'. - -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -This is another issue that deals with job control. - -The kernel maintains a notion of a current terminal process group. Members -of this process group (processes whose process group ID is equal to the -current terminal process group ID) receive terminal-generated signals like -SIGWINCH. (For more details, see the JOB CONTROL section of the bash -man page.) - -If a terminal is resized, the kernel sends SIGWINCH to each member of -the terminal's current process group (the `foreground' process group). - -When bash is running with job control enabled, each pipeline (which may be -a single command) is run in its own process group, different from bash's -process group. This foreground process group receives the SIGWINCH; bash -does not. Bash has no way of knowing that the terminal has been resized. - -There is a `checkwinsize' option, settable with the `shopt' builtin, that -will cause bash to check the window size and adjust its idea of the -terminal's dimensions each time a process stops or exits and returns control -of the terminal to bash. Enable it with `shopt -s checkwinsize'. - -Section F: Things to watch out for on certain Unix versions - -F1) 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. - -If you must use cmdtool, you can use the termcap description in -examples/suncmd.termcap. Set the TERMCAP variable to the terminal -description contained in that file, i.e. - -TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' - -Then export TERMCAP and start a new cmdtool window from that shell. -The bash command-line editing should behave better in the new -cmdtool. If this works, you can put the assignment to TERMCAP -in your bashrc file. - -F2) 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 structures 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 configuring and 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. - -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion 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 -run configure with the `--without-gnu-malloc' option to use -the C library malloc and avoid the problem. - -F4) 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. - -F5) 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. - -This affects the mechanical transformation of commands that use `cat' -to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on -comp.unix.shell). While most commands of the form - - cat file | command - -can be converted to `< file command', shell control structures such as -loops and subshells require `command < file'. - -The file CWRU/sh-redir-hack in the bash-2.05a distribution is an -(unofficial) patch to parse.y that will modify the grammar to -support this construct. It will not apply with `patch'; you must -modify parse.y by hand. 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. - -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? - -The short answer is that Red Hat screwed up. - -The long answer is that they shipped an /etc/inputrc that only works -for emacs mode editing, and then screwed all the vi users by setting -INPUTRC to /etc/inputrc in /etc/profile. - -The short fix is to do one of the following: remove or rename -/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, -but make sure you export it if you do), remove the assignment to -INPUTRC from /etc/profile, add - - set keymap emacs - -to the beginning of /etc/inputrc, or bracket the key bindings in -/etc/inputrc with these lines - - $if mode=emacs - [...] - $endif - -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -HP/UX's support for long double is imperfect at best. - -GCC will support it without problems, but the HP C library functions -like strtold(3) and printf(3) don't actually work with long doubles. -HP implemented a `long_double' type as a 4-element array of 32-bit -ints, and that is what the library functions use. The ANSI C -`long double' type is a 128-bit floating point scalar. - -The easiest fix, until HP fixes things up, is to edit the generated -config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, -the compilation should complete successfully. - -Section G: How can I get bash to do certain common things? - -G1) 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 eighth 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. - -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is why the `command' and `builtin' builtins exist. 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. - -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Versions of Bash newer than Bash-2.0 support this directly. You can use - - ${!var} - -For example, the following sequence of commands will echo `z': - - var1=var2 - var2=z - echo ${!var1} - -For sh compatibility, 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. In versions of bash later than bash-2.0, - - echo ${!#} - -does the same thing. - -This is not the same thing as ksh93 `nameref' variables, though the syntax -is similar. I may add namerefs in a future bash version. - -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? - -The bash command timing code looks for a variable `TIMEFORMAT' and -uses its value as a format string to decide how to display the -timing statistics. - -The value of TIMEFORMAT is a string with `%' escapes expanded in a -fashion similar in spirit to printf(3). The manual page explains -the meanings of the escape sequences in the format string. - -If TIMEFORMAT is not set, bash acts as if the following assignment had -been performed: - - TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' - -The POSIX.2 default time format (used by `time -p command') is - - TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' - -The BSD /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' - -The System V /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' - -The ksh format can be emulated with: - - TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' - -G5) How do I get the current directory into my prompt? - -Bash provides a number of backslash-escape sequences which are expanded -when the prompt string (PS1 or PS2) is displayed. The full list is in -the manual page. - -The \w expansion gives the full pathname of the current directory, with -a tilde (`~') substituted for the current value of $HOME. The \W -expansion gives the basename of the current directory. To put the full -pathname of the current directory into the path without any tilde -subsitution, use $PWD. Here are some examples: - - PS1='\w$ ' # current directory with tilde - PS1='\W$ ' # basename of current directory - PS1='$PWD$ ' # full pathname of current directory - -The single quotes are important in the final example to prevent $PWD from -being expanded when the assignment to PS1 is performed. - -G6) How can I rename "*.foo" to "*.bar"? - -Use the pattern removal functionality described in D3. The following `for' -loop will do the trick: - - for f in *.foo; do - mv $f ${f%foo}bar - done - -G7) How can I translate a filename from uppercase to lowercase? - -The script examples/functions/lowercase, originally written by John DuBois, -will do the trick. The converse is left as an exercise. - -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -You must have set the `extglob' shell option using `shopt -s extglob' to use -this: - - echo .!(.|) * - -A solution that works without extended globbing is given in the Unix Shell -FAQ, posted periodically to comp.unix.shell. - -Section H: Where do I go from here? - -H1) 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@gnu.org, 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@gnu.org. - -H2) What kind of bash documentation is there? - -First, look in the doc directory in the bash distribution. It should -contain at least the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -bashref.texi a reference manual in GNU tex`info format -bashref.info an info version of the reference manual -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript, HTML, and ASCII files created from the above source are -available in the documentation distribution. - -There is additional documentation available for anonymous FTP from host -ftp.cwru.edu in the `pub/bash' directory. - -Cameron Newham and Bill Rosenblatt have written a book on bash, published -by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn -Shell book. The title is ``Learning the Bash Shell'', and the ISBN number -is 1-56592-147-X. Look for it in fine bookstores near you. This book -covers bash-1.14, but has an appendix describing some of the new features -in bash-2.0. - -A second edition of this book is available, published in January, 1998. -The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores -or on the web. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers -bash-2.0 and is available from most online bookstores (see -http://www.network-theory.co.uk/bash/manual/ for details). The publisher -will donate $1 to the Free Software Foundation for each copy sold. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -a better bash debugger (a minimally-tested version is included with bash-2.05b) -associative arrays -co-processes, but with a new-style syntax that looks like function declaration - -H4) What's on the bash `wish list' for future versions? - -These are features that may or may not appear in a future version of bash. - -breaking some of the shell functionality into embeddable libraries -a module system like zsh's, using dynamic loading like builtins -better internationalization using GNU `gettext' -date-stamped command history -a bash programmer's guide with a chapter on creating loadable builtins -a better loadable interface to perl with access to the shell builtins and - variables (contributions gratefully accepted) -ksh93-like `nameref' variables -ksh93-like `+=' variable assignment operator -ksh93-like `xx.yy' variables (including some of the .sh.* variables) and - associated disipline functions -Some of the new ksh93 pattern matching operators, like backreferencing - -H5) When will the next release appear? - -The next version will appear sometime in 2002. Never make predictions. - - -This document is Copyright 1995-2003 by Chester Ramey. - -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/doc/bash.1.orig b/doc/bash.1.orig deleted file mode 100644 index 828ec966b..000000000 --- a/doc/bash.1.orig +++ /dev/null @@ -1,8583 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Information Network Services -.\" Case Western Reserve University -.\" chet@po.CWRU.Edu -.\" -.\" Last Change: Mon Apr 14 17:57:24 EDT 2003 -.\" -.\" bash_builtins, strip all but Built-Ins section -.if \n(zZ=1 .ig zZ -.if \n(zY=1 .ig zY -.TH BASH 1 "2003 April 14" "GNU Bash-3.0" -.\" -.\" 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-2002 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989-2002 by the Free Software Foundation, Inc. -.SH DESCRIPTION -.B Bash -is an \fBsh\fR-compatible command language interpreter that -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 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 options when it is invoked: -.PP -.PD 0 -.TP 10 -.BI \-c "\| string\^" -If the -.B \-c -option 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 -option is present, the shell is -.IR interactive . -.TP -.B \-l -Make -.B bash -act as if it had been invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-r -If the -.B \-r -option is present, the shell becomes -.I restricted -(see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-s -If the -.B \-s -option 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 \-D -A list of all double-quoted strings preceded by \fB$\fP -is printed on the standard ouput. -These are the strings that -are subject to language translation when the current locale -is not \fBC\fP or \fBPOSIX\fP. -This implies the \fB\-n\fP option; no commands will be executed. -.TP -.B [\-+]O [\fIshopt_option\fP] -\fIshopt_option\fP is one of the shell options accepted by the -\fBshopt\fP builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -If \fIshopt_option\fP is present, \fB\-O\fP sets the value of that option; -\fB+O\fP unsets it. -If \fIshopt_option\fP is not supplied, the names and values of the shell -options accepted by \fBshopt\fP are printed on the standard output. -If the invocation option is \fB+O\fP, the output is displayed in a format -that may be reused as input. -.TP -.B \-\- -A -.B \-\- -signals the end of options and disables further option processing. -Any arguments after the -.B \-\- -are treated as filenames and arguments. An argument of -.B \- -is equivalent to \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 -.B \-\-debugger -Arrange for the debugger profile to be executed before the shell -starts. Turns on extended debugging mode (see the description of the -.B extdebug -option to the -.B shopt -builtin below) and shell function tracing (see the description of the -\fB\-o functrace\fP option to the -.B set -builtin below). -.TP -.B \-\-dump\-po\-strings -Equivalent to \fB\-D\fP, but the output is in the GNU \fIgettext\fP -\fBpo\fP (portable object) file format. -.TP -.B \-\-dump\-strings -Equivalent to \fB\-D\fP. -.TP -.B \-\-help -Display a usage message on standard output and exit successfully. -.TP -\fB\-\-init\-file\fP \fIfile\fP -.PD 0 -.TP -\fB\-\-rcfile\fP \fIfile\fP -.PD -Execute commands from -.I file -instead of the standard personal initialization file -.I ~/.bashrc -if the shell is interactive (see -.SM -.B INVOCATION -below). -.TP -.B \-\-login -Equivalent to \fB\-l\fP. -.TP -.B \-\-noediting -Do not use the GNU -.B readline -library to read command lines when the shell is interactive. -.TP -.B \-\-noprofile -Do not read either the system-wide startup file -.FN /etc/profile -or any of the personal initialization files -.IR ~/.bash_profile , -.IR ~/.bash_login , -or -.IR ~/.profile . -By default, -.B bash -reads these files when it is invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-\-norc -Do not read and execute the personal initialization file -.I ~/.bashrc -if the shell is interactive. -This option is on by default if the shell is invoked as -.BR sh . -.TP -.B \-\-posix -Change the behavior of \fBbash\fP where the default operation differs -from the POSIX 1003.2 standard to match the standard (\fIposix mode\fP). -.TP -.B \-\-restricted -The shell becomes restricted (see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-\-verbose -Equivalent to \fB\-v\fP. -.TP -.B \-\-version -Show version information for this instance of -.B bash -on the standard output and exit successfully. -.PD -.SH ARGUMENTS -If arguments remain after option processing, and neither the -.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. -\fBBash\fP's exit status is the exit status of the last command -executed in the script. -If no commands are executed, the exit status is 0. -An attempt is first made to open the file in the current directory, and, -if no file is found, then the shell searches the directories in -.SM -.B PATH -for the script. -.SH INVOCATION -A \fIlogin shell\fP is one whose first character of argument zero is a -.BR \- , -or one started with the -.B \-\-login -option. -.PP -An \fIinteractive\fP shell is one started without non-option arguments -and without the -.B \-c -option -whose standard input and output are -both connected to terminals (as determined by -.IR isatty (3)), -or one started with the -.B \-i -option. -.SM -.B PS1 -is set and -.B $\- -includes -.B i -if -.B bash -is interactive, -allowing a shell script or a startup file to test this state. -.PP -The following paragraphs describe how -.B bash -executes its startup files. -If any of the files exist but cannot be read, -.B bash -reports an error. -Tildes are expanded in file names as described below under -.B "Tilde Expansion" -in the -.SM -.B EXPANSION -section. -.PP -When -.B bash -is invoked as an interactive login shell, or as a non-interactive shell -with the \fB\-\-login\fP option, it first reads and -executes commands from the file \fI/etc/profile\fP, if that -file exists. -After reading that file, it looks for \fI~/.bash_profile\fP, -\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads -and executes commands from the first one that exists and is readable. -The -.B \-\-noprofile -option may be used when the shell is started to inhibit this behavior. -.PP -When a login shell exits, -.B bash -reads and executes commands from the file \fI~/.bash_logout\fP, if it -exists. -.PP -When an interactive shell that is not a login shell is started, -.B bash -reads and executes commands from \fI~/.bashrc\fP, if that file exists. -This may be inhibited by using the -.B \-\-norc -option. -The \fB\-\-rcfile\fP \fIfile\fP option will force -.B bash -to read and execute commands from \fIfile\fP instead of \fI~/.bashrc\fP. -.PP -When -.B bash -is started non-interactively, to run a shell script, for example, it -looks for the variable -.SM -.B BASH_ENV -in the environment, expands its value if it appears there, and uses the -expanded value as the name of a file to read and execute. -.B Bash -behaves as if the following command were executed: -.sp .5 -.RS -.if t \f(CWif [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\fP -.if n if [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi -.RE -.sp .5 -but the value of the -.SM -.B PATH -variable is not used to search for the file name. -.PP -If -.B bash -is invoked with the name -.BR sh , -it tries to mimic the startup behavior of historical versions of -.B sh -as closely as possible, -while conforming to the POSIX standard as well. -When invoked as an interactive login shell, or a non-interactive -shell with the \fB\-\-login\fP option, it first attempts to -read and execute commands from -.I /etc/profile -and -.IR ~/.profile , -in that order. -The -.B \-\-noprofile -option may be used to inhibit this behavior. -When invoked as an interactive shell with the name -.BR sh , -.B bash -looks for the variable -.SM -.BR ENV , -expands its value if it is defined, and uses the -expanded value as the name of a file to read and execute. -Since a shell invoked as -.B sh -does not attempt to read and execute commands from any other startup -files, the -.B \-\-rcfile -option has no effect. -A non-interactive shell invoked with the name -.B sh -does not attempt to read any other startup files. -When invoked as -.BR sh , -.B bash -enters -.I posix -mode after the startup files are read. -.PP -When -.B bash -is started in -.I posix -mode, as with the -.B \-\-posix -command line option, it follows the POSIX standard for startup files. -In this mode, interactive shells expand the -.SM -.B ENV -variable and commands are read and executed from the file -whose name is the expanded value. -No other startup files are read. -.PP -.B Bash -attempts to determine when it is being run by the remote shell -daemon, usually \fIrshd\fP. -If -.B bash -determines it is being run by \fIrshd\fP, it reads and executes -commands from \fI~/.bashrc\fP, if that file exists and is readable. -It will not do this if invoked as \fBsh\fP. -The -.B \-\-norc -option may be used to inhibit this behavior, and the -.B \-\-rcfile -option may be used to force another file to be read, but -\fIrshd\fP does not generally invoke the shell with those options -or allow them to be specified. -.PP -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, no startup -files are read, shell functions are not inherited from the environment, the -.SM -.B SHELLOPTS -variable, if it appears in the environment, is ignored, -and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. -.SH DEFINITIONS -.PP -The following definitions are used throughout the rest of this -document. -.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 { } time [[ ]] -.if t ! case do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t .RE -.RE -.SH "SHELL GRAMMAR" -.SS Simple Commands -.PP -A \fIsimple command\fP is a sequence of optional variable assignments -followed by \fBblank\fP-separated words and redirections, and -terminated by a \fIcontrol operator\fP. The first word -specifies the command to be executed, and is passed as argument zero. -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 -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ] -.RE -.PP -The standard output of -.I command -is connected via a pipe 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 -If the -.B time -reserved word precedes a pipeline, the elapsed as well as user and -system time consumed by its execution are reported when the pipeline -terminates. -The \fB\-p\fP option changes the output format to that specified by POSIX. -The -.SM -.B TIMEFORMAT -variable may be set to a format string that specifies how the timing -information should be displayed; see the description of -.SM -.B TIMEFORMAT -under -.B "Shell Variables" -below. -.PP -Each command in a pipeline is executed as a separate process (i.e., in a -subshell). -.SS Lists -.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 optionally 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 -A sequence of one or more newlines may appear in a \fIlist\fP instead -of a semicolon to delimit commands. -.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 -\fIcommand1\fP \fB&&\fP \fIcommand2\fP -.RE -.PP -.I command2 -is executed if, and only if, -.I command1 -returns an exit status of zero. -.PP -An OR list has the form -.RS -.PP -\fIcommand1\fP \fB\(bv\(bv\fP \fIcommand2\fP -.PP -.RE -.PP -.I command2 -is executed if and only if -.I command1 -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. -\fIlist\fP must be terminated with a newline or semicolon. -This is known as a \fIgroup command\fP. -The return status is the exit status of -\fIlist\fP. -Note that unlike the metacharacters \fB(\fP and \fB)\fP, \fB{\fP and -\fB}\fP are \fIreserved words\fP and must occur where a reserved -word is permitted to be recognized. Since they do not cause a word -break, they must be separated from \fIlist\fP by whitespace. -.TP -((\fIexpression\fP)) -The \fIexpression\fP is evaluated according to the rules described -below under -.SM -.BR "ARITHMETIC EVALUATION" . -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -\fBlet "\fIexpression\fP"\fR. -.TP -\fB[[\fP \fIexpression\fP \fB]]\fP -Return a status of 0 or 1 depending on the evaluation of -the conditional expression \fIexpression\fP. -Expressions are composed of the primaries described below under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -Word splitting and pathname expansion are not performed on the words -between the \fB[[\fP and \fB]]\fP; tilde expansion, parameter and -variable expansion, arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as \fB\-f\fP must be unquoted to be recognized -as primaries. -.if t .sp 0.5 -.if n .sp 1 -When the \fB==\fP and \fB!=\fP operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below under \fBPattern Matching\fP. -The return value is 0 if the string matches or does not match -the pattern, respectively, and 1 otherwise. -Any part of the pattern may be quoted to force it to be matched as a -string. -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence: -.if t .sp 0.5 -.if n .sp 1 -.RS -.PD 0 -.TP -.B ( \fIexpression\fP ) -Returns the value of \fIexpression\fP. -This may be used to override the normal precedence of operators. -.TP -.B ! \fIexpression\fP -True if -.I expression -is false. -.TP -\fIexpression1\fP \fB&&\fP \fIexpression2\fP -True if both -.I expression1 -and -.I expression2 -are true. -.TP -.if t \fIexpression1\fP \fB\(bv\(bv\fP \fIexpression2\fP -.if n \fIexpression1\fP \fB||\fP \fIexpression2\fP -True if either -.I expression1 -or -.I expression2 -is true. -.PD -.LP -The \fB&&\fP and -.if t \fB\(bv\(bv\fP -.if n \fB||\fP -operators do not evaluate \fIexpression2\fP if the value of -\fIexpression1\fP is sufficient to determine the return value of -the entire conditional expression. -.RE -.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). -The return status is the exit status of the last command that executes. -If the expansion of the items following \fBin\fP results in an empty -list, no commands are executed, and the return status is 0. -.TP -\fBfor\fP (( \fIexpr1\fP ; \fIexpr2\fP ; \fIexpr3\fP )) ; \fBdo\fP \fIlist\fP ; \fBdone\fP -First, the arithmetic expression \fIexpr1\fP is evaluated according -to the rules described below under -.SM -.BR "ARITHMETIC EVALUATION" . -The arithmetic expression \fIexpr2\fP is then evaluated repeatedly -until it evaluates to zero. -Each time \fIexpr2\fP evaluates to a non-zero value, \fIlist\fP is -executed and the arithmetic expression \fIexpr3\fP is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in \fIlist\fP -that is executed, or false if any of the expressions is invalid. -.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 a number corresponding to one of -the displayed words, then the value of -.I name -is set to that word. If the line is empty, the words and prompt -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 -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 -pattern matches. Otherwise, it is the exit status of the -last command executed in \fIlist\fP. -.TP -\fBif\fP \fIlist\fP; \fBthen\fP \fIlist;\fP \ -[ \fBelif\fP \fIlist\fP; \fBthen\fP \fIlist\fP; ] ... \ -[ \fBelse\fP \fIlist\fP; ] \fBfi\fP -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 -\fBwhile\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP -.PD 0 -.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 interactive_comments -option to the -.B shopt -builtin is enabled (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), a word beginning with -.B # -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the -.B interactive_comments -option enabled does not allow comments. The -.B interactive_comments -option is on by default in interactive shells. -.SH QUOTING -\fIQuoting\fP is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -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 it is to -represent itself. -.PP -When the command history expansion facilities are being used, the -\fIhistory expansion\fP character, usually \fB!\fP, must be quoted -to prevent history expansion. -.PP -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 itself quoted, the \fB\e\fP -is treated as a line continuation (that is, it is removed from the -input stream and 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. -When command history is being used, the double quote may not be used to -quote the history expansion character. -.PP -The special parameters -.B * -and -.B @ -have special meaning when in double -quotes (see -.SM -.B PARAMETERS -below). -.PP -Words of the form \fB$\fP'\fIstring\fP' are treated specially. The -word expands to \fIstring\fP, with backslash-escaped characters replaced -as specifed by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ee -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e' -single quote -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.TP -.B \ec\fIx\fP -a control-\fIx\fP character -.PD -.RE -.LP -The expanded result is single-quoted, as if the dollar sign had -not been present. -.PP -A double-quoted string preceded by a dollar sign (\fB$\fP) will cause -the string to be translated according to the current locale. -If the current locale is \fBC\fP or \fBPOSIX\fP, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. -.SH PARAMETERS -A -.I parameter -is an entity that stores values. -It can be a -.IR name , -a number, or one of the special characters listed below under -.BR "Special Parameters" . -A -.I variable -is a parameter denoted by a -.IR name . -A variable has a \fIvalue\fP and zero or more \fIattributes\fP. -Attributes are assigned using the -.B declare -builtin command (see -.B declare -below in -.SM -.BR "SHELL BUILTIN COMMANDS" ). -.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 (see -.SM -.B EXPANSION -below). If the variable has its -.B integer -attribute set, then -.I value -is evaluated as an arithmetic expression even if the $((...)) expansion is -not used (see -.B "Arithmetic Expansion" -below). -Word splitting is not performed, with the exception -of \fB"$@"\fP as explained below under -.BR "Special Parameters" . -Pathname expansion is not performed. -Assignment statements may also appear as arguments to the -.BR declare , -.BR typeset , -.BR export , -.BR readonly , -and -.B local -builtin commands. -.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 unset, the parameters are separated by spaces. -If -.SM -.B IFS -is null, the parameters are joined without intervening separators. -.TP -.B @ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, "\fB$@\fP" is equivalent to -"\fB$1\fP" "\fB$2\fP" ... -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 -option). -.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 file name used to invoke -.BR bash , -as given by argument zero. -.TP -.B _ -At shell startup, set to the absolute file name of the shell or shell -script being executed as passed in the argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full file name of each command executed and placed in -the environment exported to that command. -When checking mail, this parameter holds the name of the mail file -currently being checked. -.PD -.SS Shell Variables -.PP -The following variables are set by the shell: -.PP -.PD 0 -.TP -.B BASH -Expands to the full file name used to invoke this instance of -.BR bash . -.TP -.B BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current bash execution call stack. The number of -parameters to the current subroutine (shell function or script executed -with \fB.\fP or \fBsource\fP) is at the top of the stack. When a -subroutine is executed, the number of parameters passed is pushed onto -\fBBASH_ARGC\fP. -.TP -.B BASH_ARGV -An array variable containing all of the parameters in the current bash -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto \fBBASH_ARGV\fP. -.TP -.B BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. -.TP -.B BASH_EXECUTION_STRING -The command argument to the \fB\-c\fP invocation option. -.TP -.B BASH_LINENO -An array variable whose members are the line numbers in source files -corresponding to each member of @var{FUNCNAME}. -\fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -file where \fB${FUNCNAME[\fP\fI$i + 1\fP\fB]}\fP was called. -The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i + 1\fP\fB]}\fB. -Use \fBLINENO\fP to obtain the current line number. -.TP -.B BASH_SOURCE -An array variable whose members are the source filenames corresponding -to the elements in the \fBFUNCNAME\fP array variable. -.TP -.B BASH_SUBSHELL -Incremented by one each time a subshell or subshell environment is spawned. -The initial value is 0. -.TP -.B BASH_VERSINFO -A readonly array variable whose members hold version information for -this instance of -.BR bash . -The values assigned to the array members are as follows: -.sp .5 -.RS -.PD 0 -.TP 24 -.B BASH_VERSINFO[\fR0\fP] -The major version number (the \fIrelease\fP). -.TP -.B BASH_VERSINFO[\fR1\fP] -The minor version number (the \fIversion\fP). -.TP -.B BASH_VERSINFO[\fR2\fP] -The patch level. -.TP -.B BASH_VERSINFO[\fR3\fP] -The build version. -.TP -.B BASH_VERSINFO[\fR4\fP] -The release status (e.g., \fIbeta1\fP). -.TP -.B BASH_VERSINFO[\fR5\fP] -The value of \fBMACHTYPE\fP. -.PD -.RE -.TP -.B BASH_VERSION -Expands to a string describing the version of this instance of -.BR bash . -.TP -.B COMP_CWORD -An index into \fB${COMP_WORDS}\fP of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to \fB${#COMP_LINE}\fP. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_WORDBREAKS -The set of characters that the Readline library treats as word -separators when performing word completion. -If -.SM -.B COMP_WORDBREAKS -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B COMP_WORDS -An array variable (see \fBArrays\fP below) consisting of the individual -words in the current command line. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B DIRSTACK -An array variable (see -.B Arrays -below) containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -.B dirs -builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the -.B pushd -and -.B popd -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If -.SM -.B DIRSTACK -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B EUID -Expands to the effective user ID of the current user, initialized at -shell startup. This variable is readonly. -.TP -.B FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element is "main". -This variable exists only when a shell function is executing. -Assignments to -.SM -.B FUNCNAME -have no effect and return an error status. -If -.SM -.B FUNCNAME -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to -.SM -.B GROUPS -have no effect and return an error status. -If -.SM -.B GROUPS -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 HOSTNAME -Automatically set to the name of the current host. -.TP -.B HOSTTYPE -Automatically set to a string that uniquely -describes the type of machine on which -.B bash -is executing. -The default is system-dependent. -.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. -If -.SM -.B LINENO -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B MACHTYPE -Automatically set to a string that fully describes the system -type on which -.B bash -is executing, in the standard GNU \fIcpu-company-system\fP format. -The default is system-dependent. -.TP -.B OLDPWD -The previous working directory as set by the -.B cd -command. -.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 OSTYPE -Automatically set to a string that -describes the operating system on which -.B bash -is executing. -The default is system-dependent. -.TP -.B PIPESTATUS -An array variable (see -.B Arrays -below) containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). -.TP -.B PPID -The process ID of the shell's parent. This variable is readonly. -.TP -.B PWD -The current working directory as set by the -.B cd -command. -.TP -.B RANDOM -Each time this parameter is referenced, a random integer between -0 and 32767 is -generated. The sequence of random numbers may be initialized by assigning -a value to -.SM -.BR RANDOM . -If -.SM -.B RANDOM -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B REPLY -Set to the line of input read by the -.B read -builtin command when no arguments are supplied. -.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 SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the -.B \-o -option to the -.B set -builtin command (see -.SM -.B "SHELL BUILTIN COMMANDS" -below). The options appearing in -.SM -.B SHELLOPTS -are those reported as -.I on -by \fBset \-o\fP. -If this variable is in the environment when -.B bash -starts up, each shell option in the list will be enabled before -reading any startup files. -This variable is read-only. -.TP -.B SHLVL -Incremented by one each time an instance of -.B bash -is started. -.TP -.B UID -Expands to the user ID of the current user, initialized at shell startup. -This variable is readonly. -.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 BASH_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 BASH_ENV -is subjected to parameter expansion, command substitution, and arithmetic -expansion before being interpreted as a file name. -.SM -.B PATH -is not used to search for the resultant file name. -.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 -.if t \f(CW".:~:/usr"\fP. -.if n ".:~:/usr". -.TP -.B COLUMNS -Used by the \fBselect\fP builtin command to determine the terminal width -when printing selection lists. Automatically set upon receipt of a SIGWINCH. -.TP -.B COMPREPLY -An array variable from which \fBbash\fP reads the possible completions -generated by a shell function invoked by the programmable completion -facility (see \fBProgrammable Completion\fP below). -.TP -.B EMACS -If \fBbash\fP finds this variable in the environment when the shell starts -with value -.if t \f(CWt\fP, -.if n "t", -it assumes that the shell is running in an emacs shell buffer and disables -line editing. -.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 -.if t \f(CW".o:~"\fP. -.if n ".o:~". -.TP -.B GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by pathname expansion. -If a filename matched by a pathname expansion pattern also matches one -of the patterns in -.SM -.BR GLOBIGNORE , -it is removed from the list of matches. -.TP -.B HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes -.IR ignorespace , -lines which begin with a -.B space -character are not saved in the history list. -A value of -.I ignoredups -causes lines matching the previous history entry to not be saved. -A value of -.I ignoreboth -is shorthand for \fIignorespace\fP and \fIignoredups\fP. -A value of -.IR erasedups -causes all previous lines matching the current line to be removed from -the history list before that line is saved. -Any value not in the above list is ignored. -If \fBHISTCONTROL\fP is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of -.BR HISTIGNORE . -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.BR HISTCONTROL . -.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. The history file is also truncated to this size after -writing it when an interactive shell exits. -.TP -.B HISTIGNORE -A colon-separated list of patterns used to decide which command lines -should be saved on the history list. Each pattern is anchored at the -beginning of the line and must match the complete line (no implicit -`\fB*\fP' is appended). Each pattern is tested against the line -after the checks specified by -.B HISTCONTROL -are applied. -In addition to the normal shell pattern matching characters, `\fB&\fP' -matches the previous history line. `\fB&\fP' may be escaped using a -backslash; the backslash is removed before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.BR HISTIGNORE . -.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 HOME -The home directory of the current user; the default argument for the -\fBcd\fP builtin command. -The value of this variable is also used when performing tilde expansion. -.TP -.B HOSTFILE -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 list of possible hostname completions may be changed while the -shell is running; -the next time hostname completion is attempted after the -value is changed, -.B bash -adds the contents of the new file to the existing list. -If -.SM -.B HOSTFILE -is set, but has no value, \fBbash\fP attempts to read -.FN /etc/hosts -to obtain the list of possible hostname completions. -When -.SM -.B HOSTFILE -is unset, the hostname list is cleared. -.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 IGNOREEOF -Controls the -action of an interactive shell on receipt of an -.SM -.B EOF -character as the sole input. If set, the value is the number of -consecutive -.SM -.B EOF -characters which must be -typed as the first characters on an input line before -.B bash -exits. If the variable exists but does not have a numeric value, or -has no value, the default value is 10. If it does not exist, -.SM -.B EOF -signifies the end of input to the shell. -.TP -.B INPUTRC -The filename for the -.B readline -startup file, overriding the default of -.FN ~/.inputrc -(see -.SM -.B READLINE -below). -.TP -.B LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with \fBLC_\fP. -.TP -.B LC_ALL -This variable overrides the value of \fBLANG\fP and any other -\fBLC_\fP variable specifying a locale category. -.TP -.B LC_COLLATE -This variable determines the collation order used when sorting the -results of pathname expansion, and determines the behavior of range -expressions, equivalence classes, and collating sequences within -pathname expansion and pattern matching. -.TP -.B LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within pathname expansion and pattern -matching. -.TP -.B LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a \fB$\fP. -.TP -.B LC_NUMERIC -This variable determines the locale category used for number formatting. -.TP -.B LINES -Used by the \fBselect\fP builtin command to determine the column length -for printing selection lists. Automatically set upon receipt of a SIGWINCH. -.TP -.B MAIL -If this parameter is set to a file name 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 displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. -.TP -.B MAILPATH -A colon-separated list of file names to be checked for mail. -The message to be printed when mail arrives in a particular file -may be specified by separating the file name from the message with a `?'. -When used in the text of the message, \fB$_\fP expands to the name of -the current mailfile. -Example: -.RS -.PP -\fBMAILPATH\fP='/var/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., /var/mail/\fB$USER\fP). -.RE -.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 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). -A zero-length (null) directory name in the value of \fBPATH\fP indicates the -current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. -The default path is system-dependent, -and is set by the administrator who installs -.BR bash . -A common value is -.if t \f(CW/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.\fP. -.if n ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''. -.TP -.B POSIXLY_CORRECT -If this variable is in the environment when \fBbash\fP starts, the shell -enters \fIposix mode\fP before reading the startup files, as if the -.B \-\-posix -invocation option had been supplied. If it is set while the shell is -running, \fBbash\fP enables \fIposix mode\fP, as if the command -.if t \f(CWset -o posix\fP -.if n \fIset -o posix\fP -had been executed. -.TP -.B PROMPT_COMMAND -If set, the value is executed as a command prior to issuing each primary -prompt. -.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 -``\fB\es\-\ev\e$ \fP''. -.TP -.B PS2 -The value of this parameter is expanded as with -.B PS1 -and used as the secondary prompt string. The default is -``\fB> \fP''. -.TP -.B PS3 -The value of this parameter is used as the prompt for the -.B select -command (see -.SM -.B SHELL GRAMMAR -above). -.TP -.B PS4 -The value of this parameter is expanded as with -.B PS1 -and the value is printed before each command -.B bash -displays during an execution trace. The first character of -.SM -.B PS4 -is replicated multiple times, as necessary, to indicate multiple -levels of indirection. The default is ``\fB+ \fP''. -.TP -.B TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the -.B time -reserved word should be displayed. -The \fB%\fP character introduces an escape sequence that is -expanded to a time value or other information. -The escape sequences and their meanings are as follows; the -braces denote optional portions. -.sp .5 -.RS -.PD 0 -.TP 10 -.B %% -A literal \fB%\fP. -.TP -.B %[\fIp\fP][l]R -The elapsed time in seconds. -.TP -.B %[\fIp\fP][l]U -The number of CPU seconds spent in user mode. -.TP -.B %[\fIp\fP][l]S -The number of CPU seconds spent in system mode. -.TP -.B %P -The CPU percentage, computed as (%U + %S) / %R. -.PD -.RE -.IP -The optional \fIp\fP is a digit specifying the \fIprecision\fP, -the number of fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; -values of \fIp\fP greater than 3 are changed to 3. -If \fIp\fP is not specified, the value 3 is used. -.IP -The optional \fBl\fP specifies a longer format, including -minutes, of the form \fIMM\fPm\fISS\fP.\fIFF\fPs. -The value of \fIp\fP determines whether or not the fraction is -included. -.IP -If this variable is not set, \fBbash\fP acts as if it had the -value \fB$'\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS'\fP. -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. -.TP -.B TMOUT -If set to a value greater than zero, \fBTMOUT\fP is treated as the -default timeout for the \fBread\fP builtin. -The \fBselect\fP command terminates if input does not arrive -after \fBTMOUT\fP seconds when input is coming from a terminal. -In an interactive shell, 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 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 identifier (see -.SM -.B JOB CONTROL -below). If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the -.B % -job identifier. -.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 \fIhistory expansion\fP character, -the character which signals the start of a history -expansion, normally `\fB!\fP'. -The second character is the \fIquick substitution\fP -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 indicates 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. -.PD -.SS Arrays -.B Bash -provides one-dimensional array variables. Any variable may be used as -an array; the -.B declare -builtin will explicitly declare an array. There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. Arrays are indexed using -integers and are zero-based. -.PP -An array is created automatically if any variable is assigned to using -the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The -.I subscript -is treated as an arithmetic expression that must evaluate to a number -greater than or equal to zero. To explicitly declare an array, use -.B declare \-a \fIname\fP -(see -.SM -.B SHELL BUILTIN COMMANDS -below). -.B declare \-a \fIname\fP[\fIsubscript\fP] -is also accepted; the \fIsubscript\fP is ignored. Attributes may be -specified for an array variable using the -.B declare -and -.B readonly -builtins. Each attribute applies to all members of an array. -.PP -Arrays are assigned to using compound assignments of the form -\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each -\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. Only -\fIstring\fP is required. If -the optional brackets and subscript are supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. -This syntax is also accepted by the -.B declare -builtin. Individual array elements may be assigned to using the -\fIname\fP[\fIsubscript\fP]=\fIvalue\fP syntax introduced above. -.PP -Any element of an array may be referenced using -${\fIname\fP[\fIsubscript\fP]}. The braces are required to avoid -conflicts with pathname expansion. If -\fIsubscript\fP is \fB@\fP or \fB*\fP, the word expands to -all members of \fIname\fP. These subscripts differ only when the -word appears within double quotes. If the word is double-quoted, -${\fIname\fP[*]} expands to a single -word with the value of each array member separated by the first -character of the -.SM -.B IFS -special variable, and ${\fIname\fP[@]} expands each element of -\fIname\fP to a separate word. When there are no array members, -${\fIname\fP[@]} expands to nothing. This is analogous to the expansion -of the special parameters \fB*\fP and \fB@\fP (see -.B Special Parameters -above). ${#\fIname\fP[\fIsubscript\fP]} expands to the length of -${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or -\fB@\fP, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing element zero. -.PP -The -.B unset -builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] -destroys the array element at index \fIsubscript\fP. -\fBunset\fP \fIname\fP, where \fIname\fP is an array, or -\fBunset\fP \fIname\fP[\fIsubscript\fP], where -\fIsubscript\fP is \fB*\fP or \fB@\fP, removes the entire array. -.PP -The -.BR declare , -.BR local , -and -.B readonly -builtins each accept a -.B \-a -option to specify an array. The -.B read -builtin accepts a -.B \-a -option to assign a list of words read from the standard input -to an array. The -.B set -and -.B declare -builtins display array values in a way that allows them to be -reused as assignments. -.SH EXPANSION -Expansion is performed on the command line after it has been split into -words. There are seven kinds of expansion performed: -.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 and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and pathname -expansion. -.PP -On systems that can support it, there is an additional expansion -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 only exceptions to this are the expansions of -"\fB$@\fP" and "\fB${\fP\fIname\fP\fB[@]}\fP" -as explained above (see -.SM -.BR PARAMETERS ). -.SS Brace Expansion -.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 either a series of comma-separated strings or -a sequence expression between a pair of braces, followed by -an optional -.IR postscript . -The preamble is prefixed to each string contained -within the braces, and the postscript 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 -A sequence expression takes the form \fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB}\fP, -where \fIx\fP and \fIy\fP are either integers or single characters. -When integers are supplied, the expression expands to each number between -\fIx\fP and \fIy\fP, inclusive. -When characters are supplied, the expression expands to each character -lexicographically between \fIx\fP and \fIy\fP, inclusive. Note that -both \fIx\fP and \fIy\fP must be of the same type. -.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 or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. -A \fB{\fP or \fB,\fP may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string \fB${\fP -is not considered eligible for brace expansion. -.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 -historical versions of -.BR sh . -.B sh -does not treat opening or closing braces specially when they -appear as part of a word, and preserves them in the output. -.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 +B -option or disable brace expansion with the -.B +B -option to the -.B set -command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS Tilde Expansion -.PP -If a word begins with an unquoted tilde character (`\fB~\fP'), all of -the characters preceding the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a \fItilde-prefix\fP. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible \fIlogin name\fP. -If this login name is the null string, the tilde is replaced with the -value of the shell parameter -.SM -.BR HOME . -If -.SM -.B HOME -is unset, the home directory of the user executing the shell is -substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. -.PP -If the tilde-prefix is a `~+', the value of the shell variable -.SM -.B PWD -replaces the tilde-prefix. -If the tilde-prefix is a `~\-', the value of the shell variable -.SM -.BR OLDPWD , -if it is set, is substituted. -If the characters following the tilde in the tilde-prefix consist -of a number \fIN\fP, optionally prefixed -by a `+' or a `\-', the tilde-prefix is replaced with the corresponding -element from the directory stack, as it would be displayed by the -.B dirs -builtin invoked with the tilde-prefix as an argument. -If the characters following the tilde in the tilde-prefix consist of a -number without a leading `+' or `\-', `+' is assumed. -.PP -If the login name is invalid, or the tilde expansion fails, the word -is unchanged. -.PP -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a -.B : -or -.BR = . -In these cases, tilde expansion is also performed. -Consequently, one may use file names 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 -When braces are used, the matching ending brace is the first `\fB}\fP' -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or paramter -expansion. -.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 -If the first character of \fIparameter\fP is an exclamation point, -a level of variable indirection is introduced. -\fBBash\fP uses the value of the variable formed from the rest of -\fIparameter\fP as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of \fIparameter\fP itself. -This is known as \fIindirect expansion\fP. -The exceptions to this are the expansions of ${!\fIprefix\fP*} and -${\fB!\fP\fIname\fP[\fI@\fP]} described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. -.PP -In each of the cases below, \fIword\fP is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. -When not performing substring expansion, \fBbash\fP tests for a parameter -that is unset or null; omitting the colon results in a test only for a -parameter that is unset. -.PP -.PD 0 -.TP -${\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 -${\fIparameter\fP\fB:\fP\fIoffset\fP} -.PD 0 -.TP -${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP} -.PD -\fBSubstring Expansion.\fP -Expands to up to \fIlength\fP characters of \fIparameter\fP -starting at the character specified by \fIoffset\fP. -If \fIlength\fP is omitted, expands to the substring of -\fIparameter\fP starting at the character specified by \fIoffset\fP. -\fIlength\fP and \fIoffset\fP are arithmetic expressions (see -.SM -.B -ARITHMETIC EVALUATION -below). -\fIlength\fP must evaluate to a number greater than or equal to zero. -If \fIoffset\fP evaluates to a number less than zero, the value -is used as an offset from the end of the value of \fIparameter\fP. -If \fIparameter\fP is \fB@\fP, the result is \fIlength\fP positional -parameters beginning at \fIoffset\fP. -If \fIparameter\fP is an array name indexed by @ or *, -the result is the \fIlength\fP -members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1. -.TP -${\fB!\fP\fIprefix\fP\fB*\fP} -.PD 0 -.TP -${\fB!\fP\fIprefix\fP\fB@\fP} -.PD -Expands to the names of variables whose names begin with \fIprefix\fP, -separated by the first character of the -.SM -.B IFS -special variable. -.TP -${\fB!\fP\fIname\fP[\fI@\fP]} -.PD 0 -.TP -${\fB!\fP\fIname\fP[\fI*\fP]} -.PD -If \fIname\fP is an array variable, expands to the list of array indices -(keys) assigned in \fIname\fP. -If \fIname\fP is not an array, expands to 0 if \fIname\fP is set and null -otherwise. -When \fI@\fP is used and the expansion appears within double quotes, each -key expands to a separate word. -.TP -${\fB#\fP\fIparameter\fP} -The length in characters of the value of \fIparameter\fP is substituted. -If -.I parameter -is -.B * -or -.BR @ , -the value substituted is the number of positional parameters. -If -.I parameter -is an array name subscripted by -.B * -or -.BR @ , -the value substituted is the number of elements in the array. -.TP -${\fIparameter\fP\fB#\fP\fIword\fP} -.PD 0 -.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 result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB#\fP'' case) or the -longest matching pattern (the ``\fB##\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB%\fP\fIword\fP} -.PD 0 -.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 expanded value of -.IR parameter , -then the result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB%\fP'' case) or the -longest matching pattern (the ``\fB%%\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB/\fP\fIpattern\fP\fB/\fP\fIstring\fP} -.PD 0 -.TP -${\fIparameter\fP\fB//\fP\fIpattern\fP\fB/\fP\fIstring\fP} -.PD -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -\fIParameter\fP is expanded and the longest match of \fIpattern\fP -against its value is replaced with \fIstring\fP. -In the first form, only the first match is replaced. -The second form causes all matches of \fIpattern\fP to be -replaced with \fIstring\fP. -If \fIpattern\fP begins with \fB#\fP, it must match at the beginning -of the expanded value of \fIparameter\fP. -If \fIpattern\fP begins with \fB%\fP, it must match at the end -of the expanded value of \fIparameter\fP. -If \fIstring\fP is null, matches of \fIpattern\fP are deleted -and the \fB/\fP following \fIpattern\fP may be omitted. -If -.I parameter -is -.B @ -or -.BR * , -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.SS Command Substitution -.PP -\fICommand substitution\fP allows the output of a command to replace -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. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution \fB$(cat \fIfile\fP)\fR can be replaced by -the equivalent but faster \fB$(< \fIfile\fP)\fR. -.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 . -The first backquote not preceded by a backslash terminates the -command substitution. -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 backquoted 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. The format for arithmetic expansion is: -.RS -.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 parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, string -expansion, command substitution, and quote removal. -Arithmetic expansions 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 -When available, process substitution is performed -simultaneously with parameter and variable expansion, -command substitution, -and 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 -.SM -.B IFS -is unset, or its -value 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. -.PP -Explicit null arguments (\^\f3"\^"\fP or \^\f3'\^'\fP\^) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. -.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 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 -file names matching the pattern. -If no matching file names are found, -and the shell option -.B nullglob -is disabled, the word is left unchanged. -If the -.B nullglob -option is set, and no matches are found, -the word is removed. -If the shell option -.B nocaseglob -is enabled, the match is performed without regard to the case -of alphabetic characters. -When a pattern is used for pathname expansion, -the character -.B ``.'' -at the start of a name or immediately following a slash -must be matched explicitly, unless the shell option -.B dotglob -is set. -When matching a pathname, the slash character must always be -matched explicitly. -In other cases, the -.B ``.'' -character is not treated specially. -See the description of -.B shopt -below under -.SM -.B SHELL BUILTIN COMMANDS -for a description of the -.BR nocaseglob , -.BR nullglob , -and -.B dotglob -shell options. -.PP -The -.SM -.B GLOBIGNORE -shell variable may be used to restrict the set of file names matching a -.IR pattern . -If -.SM -.B GLOBIGNORE -is set, each matching file name that also matches one of the patterns in -.SM -.B GLOBIGNORE -is removed from the list of matches. -The file names -.B ``.'' -and -.B ``..'' -are always ignored when -.SM -.B GLOBIGNORE -is set and not null. However, setting -.SM -.B GLOBIGNORE -to a non-null value has the effect of enabling the -.B dotglob -shell option, so all other file names beginning with a -.B ``.'' -will match. -To get the old behavior of ignoring file names beginning with a -.BR ``.'' , -make -.B ``.*'' -one of the patterns in -.SM -.BR GLOBIGNORE . -The -.B dotglob -option is disabled when -.SM -.B GLOBIGNORE -is unset. -.PP -\fBPattern Matching\fP -.PP -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. The NUL character may not -occur in a pattern. A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if -they are to be matched literally. -.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 hyphen denotes a -\fIrange expression\fP; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -.B [ -is a -.B ! -or a -.B ^ -then any character not enclosed is matched. -The sorting order of characters in range expressions is determined by -the current locale and the value of the \fBLC_COLLATE\fP shell variable, -if set. -A -.B \- -may be matched by including it as the first or last character -in the set. -A -.B ] -may be matched by including it as the first character -in the set. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -\fIcharacter classes\fP can be specified using the syntax -\fB[:\fP\fIclass\fP\fB:]\fP, where \fIclass\fP is one of the -following classes defined in the POSIX.2 standard: -.PP -.RS -.B -.if n alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.if t alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.br -A character class matches any character belonging to that class. -The \fBword\fP character class matches letters, digits, and the character _. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -an \fIequivalence class\fP can be specified using the syntax -\fB[=\fP\fIc\fP\fB=]\fP, which matches all characters with the -same collation weight (as defined by the current locale) as -the character \fIc\fP. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -the syntax \fB[.\fP\fIsymbol\fP\fB.]\fP matches the collating symbol -\fIsymbol\fP. -.RE -.PD -.PP -If the \fBextglob\fP shell option is enabled using the \fBshopt\fP -builtin, several extended pattern matching operators are recognized. -In the following description, a \fIpattern-list\fP is a list of one -or more patterns separated by a \fB|\fP. -Composite patterns may be formed using one or more of the following -sub-patterns: -.sp 1 -.PD 0 -.RS -.TP -\fB?(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or one occurrence of the given patterns -.TP -\fB*(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or more occurrences of the given patterns -.TP -\fB+(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches one or more occurrences of the given patterns -.TP -\fB@(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches exactly one of the given patterns -.TP -\fB!(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches anything except one of the given patterns -.RE -.PD -.SS Quote Removal -.PP -After the preceding expansions, all unquoted occurrences of the -characters -.BR \e , -.BR ' , -and \^\f3"\fP\^ that did not result from one of the above -expansions are removed. -.SH REDIRECTION -Before a command is executed, its input and output -may be -.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 following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to brace expansion, -tilde expansion, parameter expansion, command substitution, arithmetic -expansion, quote removal, pathname expansion, and word splitting. -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 . -.PP -\fBBash\fP handles several filenames specially when they are used in -redirections, as described in the following table: -.RS -.PP -.PD 0 -.TP -.B /dev/fd/\fIfd\fP -If \fIfd\fP is a valid integer, file descriptor \fIfd\fP is duplicated. -.TP -.B /dev/stdin -File descriptor 0 is duplicated. -.TP -.B /dev/stdout -File descriptor 1 is duplicated. -.TP -.B /dev/stderr -File descriptor 2 is duplicated. -.TP -.B /dev/tcp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -a TCP connection to the corresponding socket. -.TP -.B /dev/udp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -a UDP connection to the corresponding socket. -.PD -.RE -.PP -A failure to open or create a file causes the redirection to fail. -.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 > , -and the -.B noclobber -option to the -.B set -builtin has been enabled, the redirection will fail if the file -whose name results from the expansion of \fIword\fP exists and is -a regular file. -If the redirection operator is -.BR >| , -or the redirection operator is -.B > -and the -.B noclobber -option to the -.B set -builtin command is not enabled, the redirection is attempted even -if the file named by \fIword\fP exists. -.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: -.RS -.PP -.nf -\fB<<\fP[\fB\-\fP]\fIword\fP - \fIhere-document\fP -\fIdelimiter\fP -.fi -.RE -.PP -No parameter expansion, command substitution, arithmetic expansion, -or pathname 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. -If \fIword\fP is unquoted, -all lines of the here-document are subjected to parameter expansion, -command substitution, and arithmetic expansion. In the latter -case, the character sequence -.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 "Here Strings" -A variant of here documents, the format is: -.RS -.PP -.nf -\fB<<<\fP\fIword\fP -.fi -.RE -.PP -The \fIword\fP is expanded and supplied to the command on its standard -input. -.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 the digits in -.I word -do not specify a file descriptor open for input, a redirection error occurs. -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. -If the digits in -.I word -do not specify a file descriptor open for output, a redirection error occurs. -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 "Moving File Descriptors" -.PP -The redirection operator -.RS -.PP -[\fIn\fP]\fB<&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard input (file descriptor 0) if \fIn\fP is not specified. -\fIdigit\fP is closed after being duplicated to \fIn\fP. -.PP -Similarly, the redirection operator -.RS -.PP -[\fIn\fP]\fB>&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard output (file descriptor 1) if \fIn\fP is not specified. -.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 on file descriptor 0 if -.I n -is not specified. If the file does not exist, it is created. -.SH ALIASES -\fIAliases\fP allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of 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. -If arguments are needed, a shell function should be used (see -.SM -.B FUNCTIONS -below). -.PP -Aliases are not expanded when the shell is not interactive, unless -the -.B expand_aliases -shell option is set using -.B shopt -(see the description of -.B shopt -under -.SM -\fBSHELL BUILTIN COMMANDS\fP -below). -.PP -The rules concerning the definition and use of aliases are -somewhat confusing. -.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. -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 a 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 -For almost every purpose, aliases are superseded by -shell functions. -.SH FUNCTIONS -A shell function, defined as described above under -.SM -.BR "SHELL GRAMMAR" , -stores a series of commands for later execution. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -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. -The first element of the -.SM -.B FUNCNAME -variable is set to the name of the function while the function -is executing. -All other aspects of the shell execution -environment are identical between a function and its caller -with the exception that the -.SM -.B DEBUG -trap (see the description of the -.B trap -builtin under -.SM -.B SHELL BUILTIN COMMANDS -below) is not inherited unless the function has been given the -\fBtrace\fP attribute (see the description of the -.SM -.B declare -builtin below) or the -\fB\-o functrace\fP shell option has been enabled with -the \fBset\fP builtin -(in which case all functions inherit the \fBDEBUG\fP trap). -.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. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter -.B # -are restored to the values they had prior to the function's -execution. -.PP -Function names and definitions may be listed with the -.B \-f -option to the -.B declare -or -.B typeset -builtin commands. The -.B \-F -option to -.B declare -or -.B typeset -will list the function names only -(and optionally the source file and line number, if the \fBextdebug\fP -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -.B \-f -option to the -.B export -builtin. -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. -.PP -Functions may be recursive. No limit is imposed on the number -of recursive calls. -.SH "ARITHMETIC EVALUATION" -The shell allows arithmetic expressions to be evaluated, under -certain circumstances (see the \fBlet\fP and \fBdeclare\fP builtin -commands and \fBArithmetic Expansion\fP). -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -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 \fIid\fP++ \fIid\fP\-\- -variable post-increment and post-decrement -.TP -.B ++\fIid\fP \-\-\fIid\fP -variable pre-increment and pre-decrement -.TP -.B \- + -unary minus and plus -.TP -.B ! ~ -logical and bitwise negation -.TP -.B ** -exponentiation -.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 \fIexpr\fP?\fIexpr\fP:\fIexpr\fP -conditional operator -.TP -.B = *= /= %= += \-= <<= >>= &= ^= |= -assignment -.TP -.B \fIexpr1\fP , \fIexpr2\fP -comma -.PD -.PP -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -\fIinteger\fP attribute using \fBdeclare -i\fP is assigned a value. -A null value evaluates to 0. -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 0x or 0X denotes hexadecimal. -Otherwise, numbers take the form [\fIbase#\fP]n, where \fIbase\fP -is a decimal number between 2 and 64 representing the arithmetic -base, and \fIn\fP is a number in that base. -If \fIbase#\fP is omitted, then base 10 is used. -The digits greater than 9 are represented by the lowercase letters, -the uppercase letters, @, and _, in that order. -If \fIbase\fP is less than or equal to 36, lowercase and uppercase -letters may be used interchangably to represent numbers between 10 -and 35. -.PP -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. -.SH "CONDITIONAL EXPRESSIONS" -Conditional expressions are used by the \fB[[\fP compound command and -the \fBtest\fP and \fB[\fP builtin commands to test file attributes -and perform string and arithmetic comparisons. -Expressions are formed from the following unary or binary primaries. -If any \fIfile\fP argument to one of the primaries is of the form -\fI/dev/fd/n\fP, then file descriptor \fIn\fP is checked. -If the \fIfile\fP argument to one of the primaries is one of -\fI/dev/stdin\fP, \fI/dev/stdout\fP, or \fI/dev/stderr\fP, file -descriptor 0, 1, or 2, respectively, is checked. -.sp 1 -.PD 0 -.TP -.B \-a \fIfile\fP -True if \fIfile\fP exists. -.TP -.B \-b \fIfile\fP -True if \fIfile\fP exists and is a block special file. -.TP -.B \-c \fIfile\fP -True if \fIfile\fP exists and is a character special file. -.TP -.B \-d \fIfile\fP -True if \fIfile\fP exists and is a directory. -.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 \-h \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-k \fIfile\fP -True if \fIfile\fP exists and its ``sticky'' bit is set. -.TP -.B \-p \fIfile\fP -True if \fIfile\fP exists and is a named pipe (FIFO). -.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 \-t \fIfd\fP -True if file descriptor -.I fd -is open and refers to 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 -.B \-L \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-S \fIfile\fP -True if \fIfile\fP exists and is a socket. -.TP -.B \-N \fIfile\fP -True if \fIfile\fP exists and has been modified since it was last read. -.TP -\fIfile1\fP \-\fBnt\fP \fIfile2\fP -True if \fIfile1\fP is newer (according to modification date) than \fIfile2\fP, -or if \fIfile1\fP exists and \fPfile2\fP does not. -.TP -\fIfile1\fP \-\fBot\fP \fIfile2\fP -True if \fIfile1\fP is older than \fIfile2\fP, or if \fIfile2\fP exists -and \fIfile1\fP does not. -.TP -\fIfile1\fP \fB\-ef\fP \fIfile2\fP -True if \fIfile1\fP and \fIfile2\fP refer to the same device and -inode numbers. -.TP -.B \-o \fIoptname\fP -True if shell option -.I optname -is enabled. -See the list of options under the description of the -.B \-o -option to the -.B set -builtin below. -.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. \fB=\fP may be used in place of -\fB==\fP for strict POSIX compliance. -.TP -\fIstring1\fP \fB!=\fP \fIstring2\fP -True if the strings are not equal. -.TP -\fIstring1\fP \fB<\fP \fIstring2\fP -True if \fIstring1\fP sorts before \fIstring2\fP lexicographically -in the current locale. -.TP -\fIstring1\fP \fB>\fP \fIstring2\fP -True if \fIstring1\fP sorts after \fIstring2\fP lexicographically -in the current locale. -.TP -.I \fIarg1\fP \fBOP\fP \fIarg2\fP -.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 to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to \fIarg2\fP, respectively. -.I Arg1 -and -.I arg2 -may be positive or negative integers. -.PD -.SH "SIMPLE COMMAND EXPANSION" -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. -.IP 1. -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. -.IP 2. -The words that are not variable assignments or redirections are -expanded. If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. -.IP 3. -Redirections are performed as described above under -.SM -.BR REDIRECTION . -.IP 4. -The text after the \fB=\fP in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -.PP -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. -.PP -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. -.PP -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. -.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. -.B Bash -uses a hash table to remember the full pathnames of executable -files (see -.B hash -under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -A full search of the directories in -.SM -.B PATH -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell prints an error -message and returns an exit status of 127. -.PP -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in a -separate execution environment. -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 COMMAND EXECUTION ENVIRONMENT -The shell has an \fIexecution environment\fP, which consists of the -following: -.sp 1 -.IP \(bu -open files inherited by the shell at invocation, as modified by -redirections supplied to the \fBexec\fP builtin -.IP \(bu -the current working directory as set by \fBcd\fP, \fBpushd\fP, or -\fBpopd\fP, or inherited by the shell at invocation -.IP \(bu -the file creation mode mask as set by \fBumask\fP or inherited from -the shell's parent -.IP \(bu -current traps set by \fBtrap\fP -.IP \(bu -shell parameters that are set by variable assignment or with \fBset\fP -or inherited from the shell's parent in the environment -.IP \(bu -shell functions defined during execution or inherited from the shell's -parent in the environment -.IP \(bu -options enabled at invocation (either by default or with command-line -arguments) or by \fBset\fP -.IP \(bu -options enabled by \fBshopt\fP -.IP \(bu -shell aliases defined with \fBalias\fP -.IP \(bu -various process IDs, including those of background jobs, the value -of \fB$$\fP, and the value of \fB$PPID\fP -.PP -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. -.sp 1 -.IP \(bu -the shell's open files, plus any modifications and additions specified -by redirections to the command -.IP \(bu -the current working directory -.IP \(bu -the file creation mode mask -.IP \(bu -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment -.IP \(bu -traps caught by the shell are reset to the values the inherited -from the shell's parent, and traps ignored by the shell are ignored -.PP -A command invoked in this separate environment cannot affect the -shell's execution environment. -.PP -Command substitution and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed in a -subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. -.PP -If a command is followed by a \fB&\fP and job control is not active, the -default standard input for the command is the empty file \fI/dev/null\fP. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. -.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 provides several ways to manipulate the environment. -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 -option is set (see the -.B set -builtin command below), then -.I all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. -.PP -When -.B bash -invokes an external command, the variable -.B _ -is set to the full file name of the command and passed to that -command in its environment. -.SH "EXIT STATUS" -For the shell's purposes, 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 \fIN\fP, \fBbash\fP uses -the value of 128+\fIN\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 -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. -.PP -Shell builtin commands return a status of 0 (\fItrue\fP) if -successful, and non-zero (\fIfalse\fP) if an error occurs -while they execute. -All builtins return an exit status of 2 to indicate incorrect usage. -.PP -\fBBash\fP itself returns the exit status of the last command -executed, unless a syntax error occurs, in which case it exits -with a non-zero value. See also the \fBexit\fP builtin -command below. -.SH SIGNALS -When \fBbash\fP is interactive, in the absence of any traps, 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 signal handlers -set to the values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore -.SM -.B SIGINT -and -.SM -.B SIGQUIT -as well. -Commands run as a result of command substitution ignore the -keyboard-generated job control signals -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . -.PP -The shell exits by default upon receipt of a -.SM -.BR SIGHUP . -Before exiting, an interactive shell resends the -.SM -.B SIGHUP -to all jobs, running or stopped. -Stopped jobs are sent -.SM -.B SIGCONT -to ensure that they receive the -.SM -.BR SIGHUP . -To prevent the shell from -sending the signal to a particular job, it should be removed from the -jobs table with the -.B disown -builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below) or marked -to not receive -.SM -.B SIGHUP -using -.BR "disown \-h" . -.PP -If the -.B huponexit -shell option has been set with -.BR shopt , -.B bash -sends a -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.PP -When \fBbash\fP receives a signal for which a trap has been set while -waiting for a command to complete, the trap will not be executed until -the command completes. -When \fBbash\fP is waiting for an asynchronous command via the \fBwait\fP -builtin, the reception of a signal for which a trap has been set will -cause the \fBwait\fP builtin to return immediately with an exit status -greater than 128, immediately after which the trap is executed. -.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 operating 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 -contains facilities 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 control 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 . -The user 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 or started in the background. -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 enabled, -.B bash -reports such changes immediately. -Any trap on -.SM -.B SIGCHLD -is executed for each child that exits. -.PP -If an attempt to exit -.B bash -is made while jobs are stopped, the shell prints a warning message. The -.B jobs -command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -the shell does not print another warning, and the stopped -jobs are terminated. -.SH PROMPTING -When executing interactively, -.B bash -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 \ea -an ASCII bell character (07) -.TP -.B \ed -the date in "Weekday Month Date" format (e.g., "Tue May 26") -.TP -.B \eD{\fIformat\fP} -the \fIformat\fP is passed to \fIstrftime\fP(3) and the result is inserted -into the prompt string; an empty \fIformat\fP results in a locale-specific -time representation. The braces are required -.TP -.B \ee -an ASCII escape character (033) -.TP -.B \eh -the hostname up to the first `.' -.TP -.B \eH -the hostname -.TP -.B \ej -the number of jobs currently managed by the shell -.TP -.B \el -the basename of the shell's terminal device name -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \es -the name of the shell, the basename of -.B $0 -(the portion following the final slash) -.TP -.B \et -the current time in 24-hour HH:MM:SS format -.TP -.B \eT -the current time in 12-hour HH:MM:SS format -.TP -.B \e@ -the current time in 12-hour am/pm format -.TP -.B \eA -the current time in 24-hour HH:MM format -.TP -.B \eu -the username of the current user -.TP -.B \ev -the version of \fBbash\fP (e.g., 2.00) -.TP -.B \eV -the release of \fBbash\fP, version + patchelvel (e.g., 2.00.0) -.TP -.B \ew -the current working directory -.TP -.B \eW -the basename of the current working directory -.TP -.B \e! -the history number of this command -.TP -.B \e# -the command number of this command -.TP -.B \e$ -if the effective UID is 0, a -.BR # , -otherwise a -.B $ -.TP -.B \e\fInnn\fP -the character corresponding to the octal number \fInnn\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 quote removal, subject to the value of the -.B promptvars -shell option (see the description of the -.B shopt -command under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -.SH READLINE -This is the library that handles reading input when using an interactive -shell, unless the -.B \-\-noediting -option is given at shell invocation. -By default, the line editing commands are similar to those of emacs. -A vi-style line editing interface is also available. -To turn off line editing after the shell is running, use the -.B +o emacs -or -.B +o vi -options to the -.B set -builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS "Readline Notation" -.PP -In this section, the emacs-style notation is used to denote -keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n -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 -below. -.PP -When a command is described as \fIkilling\fP text, the text -deleted is saved for possible future retrieval -(\fIyanking\fP). The killed text is saved in a -\fIkill ring\fP. Consecutive kills cause the text to be -accumulated into one unit, which can be yanked all at once. -Commands which do not kill text separate the chunks of text -on the kill ring. -.SS "Readline Initialization" -.PP -Readline is customized by putting commands in an initialization -file (the \fIinputrc\fP file). -The name of this file is taken from the value of the -.SM -.B INPUTRC -variable. If that variable is unset, the default is -.IR ~/.inputrc . -When a program which uses the readline library starts up, the -initialization file is read, and the key bindings and variables -are set. -There are only a few basic constructs allowed in the -readline initialization file. -Blank lines are ignored. -Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional constructs. -Other lines denote key bindings and variable settings. -.PP -The default key-bindings may be changed with an -.I inputrc -file. -Other programs that use this library may add their own commands -and bindings. -.PP -For example, placing -.RS -.PP -M\-Control\-u: universal\-argument -.RE -or -.RS -C\-Meta\-u: universal\-argument -.RE -into the -.I 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 . -.PP -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). -.SS "Readline Key Bindings" -.PP -The syntax for controlling key bindings in the -.I inputrc -file is simple. All that is required is the name of the -command or the text of a macro and a key sequence to which -it should be bound. The name may be specified in one of two ways: -as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP -prefixes, or as a key sequence. -.PP -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 -.if t \f(CW> output\fP -.if n ``> 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, but the symbolic character names -are not recognized. -.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 -.if t \f(CWFunction Key 1\fP. -.if n ``Function Key 1''. -.PP -The full set of GNU Emacs style escape sequences is -.RS -.PD 0 -.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 -.PD -.PP -In addition to the GNU Emacs style escape sequences, a second -set of backslash escapes is available: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ed -delete -.TP -.B \ef -form feed -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.RE -.PD -.PP -When entering the text of a macro, single or double quotes must -be used to indicate a macro definition. -Unquoted text is assumed to be a function name. -In the macro body, the backslash escapes described above are expanded. -Backslash will quote any other character in the macro text, -including " and '. -.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). -.SS "Readline 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 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 when the readline -.B insert\-comment -command is executed. -This command is bound to -.B M\-# -in emacs mode and to -.B # -in vi command mode. -.TP -.B completion\-ignore\-case (Off) -If set to \fBOn\fP, readline performs filename matching and completion -in a case\-insensitive fashion. -.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 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 prefixing an -escape character (in effect, using escape as the \fImeta prefix\fP). -.TP -.B disable\-completion (Off) -If set to \fBOn\fP, readline will inhibit word completion. Completion -characters will be inserted into the line as if they had been -mapped to \fBself-insert\fP. -.TP -.B editing\-mode (emacs) -Controls whether readline begins with a set of key bindings similar -to \fIemacs\fP or \fIvi\fP. -.B editing\-mode -can be set to either -.B emacs -or -.BR vi . -.TP -.B enable\-keypad (Off) -When set to \fBOn\fP, readline will try to enable the application -keypad when it is called. Some systems need this to enable the -arrow keys. -.TP -.B expand\-tilde (Off) -If set to \fBon\fP, tilde expansion is performed when readline -attempts word completion. -.TP -.B history-preserve-point -If set to \fBon\fP, the history code attempts to place point at the -same location on each history line retrived with \fBprevious-history\fP -or \fBnext-history\fP. -.TP -.B horizontal\-scroll\-mode (Off) -When set to \fBOn\fP, makes readline use a single line for display, -scrolling the input horizontally on a single screen line when it -becomes longer than the screen width rather than wrapping to a new line. -.TP -.B input\-meta (Off) -If set to \fBOn\fP, readline will enable eight-bit input (that is, -it will not strip the high bit from the characters it reads), -regardless of what the terminal claims it can support. The name -.B meta\-flag -is a synonym for this variable. -.TP -.B isearch\-terminators (``C\-[C\-J'') -The string of characters that should terminate an incremental -search without subsequently executing the character as a command. -If this variable has not been given a value, the characters -\fIESC\fP and \fIC\-J\fP will terminate an incremental search. -.TP -.B keymap (emacs) -Set the current readline keymap. The set of valid keymap names is -\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, -vi\-command\fP, and -.IR vi\-insert . -\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is -equivalent to \fIemacs\-standard\fP. The default value is -.IR emacs ; -the value of -.B editing\-mode -also affects the default keymap. -.TP -.B mark\-directories (On) -If set to \fBOn\fP, completed directory names have a slash -appended. -.TP -.B mark\-modified\-lines (Off) -If set to \fBOn\fP, history lines that have been modified are displayed -with a preceding asterisk (\fB*\fP). -.TP -.B mark\-symlinked\-directories (Off) -If set to \fBOn\fP, completed names which are symbolic links to directories -have a slash appended (subject to the value of -\fBmark\-directories\fP). -.TP -.B match\-hidden\-files (On) -This variable, when set to \fBOn\fP, causes readline to match files whose -names begin with a `.' (hidden files) when performing filename -completion, unless the leading `.' is -supplied by the user in the filename to be completed. -.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 page\-completions (On) -If set to \fBOn\fP, readline uses an internal \fImore\fP-like pager -to display a screenful of possible completions at a time. -.TP -.B print\-completions\-horizontally (Off) -If set to \fBOn\fP, readline will display completions with matches -sorted horizontally in alphabetical order, rather than down the screen. -.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 visible\-stats (Off) -If set to \fBOn\fP, a character denoting a file's type as reported -by \fIstat\fP(2) is appended to the filename when listing possible -completions. -.PD -.SS "Readline Conditional Constructs" -.PP -Readline implements a facility similar in spirit to the conditional -compilation features of the C preprocessor which allows key -bindings and variable settings to be performed as the result -of tests. There are four 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 both 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: -.sp 1 -.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 seen 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. -.IP \fB$include\fP -This directive takes a single filename as an argument and reads commands -and bindings from that file. For example, the following directive -would read \fI/etc/inputrc\fP: -.sp 1 -.RS -.nf -\fB$include\fP \^ \fI/etc/inputrc\fP -.fi -.RE -.SS Searching -.PP -Readline provides commands for searching through the command history -(see -.SM -.B HISTORY -below) for lines containing a specified string. -There are two search modes: -.I incremental -and -.IR non-incremental . -.PP -Incremental searches begin before the user has finished typing the -search string. -As each character of the search string is typed, readline displays -the next entry from the history matching the string typed so far. -An incremental search requires only as many characters as needed to -find the desired history entry. -The characters present in the value of the \fBisearch-terminators\fP -variable are used to terminate an incremental search. -If that variable has not been assigned a value the Escape and -Control-J characters will terminate an incremental search. -Control-G will abort an incremental search and restore the original -line. -When the search is terminated, the history entry containing the -search string becomes the current line. -.PP -To find other matching entries in the history list, type Control-S or -Control-R as appropriate. -This will search backward or forward in the history for the next -entry matching the search string typed so far. -Any other key sequence bound to a readline command will terminate -the search and execute that command. -For instance, a \fInewline\fP will terminate the search and accept -the line, thereby executing the command from the history list. -.PP -Readline remembers the last incremental search string. If two -Control-Rs are typed without any intervening characters defining a -new search string, any remembered search string is used. -.PP -Non-incremental searches read the entire search string before starting -to search for matching history lines. The search string may be -typed by the user or be part of the contents of the current line. -.SS "Readline Command Names" -.PP -The following is a list of the names of the commands and the default -key sequences to which they are bound. -Command names without an accompanying key sequence are unbound by default. -In the following descriptions, \fIpoint\fP refers to the current cursor -position, and \fImark\fP refers to a cursor position saved by the -\fBset\-mark\fP command. -The text between the point and mark is referred to as the \fIregion\fP. -.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 the current or 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. -.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 point. -This is a non-incremental search. -.TP -.B history\-search\-backward -Search backward through the history for the string of characters -between the start of the current line and the point. -This is a non-incremental search. -.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. -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 of -the previous history entry). With an argument, -behave exactly like \fByank\-nth\-arg\fP. -Successive calls to \fByank\-last\-arg\fP move back through the history -list, inserting the last argument of each line in turn. -.TP -.B shell\-expand\-line (M\-C\-e) -Expand the line as the shell does. 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 magic\-space -Perform history expansion on the current line and insert a space. -See -.SM -.B HISTORY EXPANSION -below for a description of history expansion. -.TP -.B alias\-expand\-line -Perform alias expansion on the current line. -See -.SM -.B ALIASES -above for a description of alias expansion. -.TP -.B history\-and\-alias\-expand\-line -Perform history and alias expansion on the current line. -.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. -.TP -.B edit\-and\-execute\-command (C\-xC\-e) -Invoke an editor on the current command line, and execute the result as shell -commands. -\fBBash\fP attempts to invoke -.SM -.BR $FCEDIT , -.SM -.BR $EDITOR , -and \fIemacs\fP as the editor, in that order. -.PD -.SS Commands for Changing Text -.PP -.PD 0 -.TP -.B delete\-char (C\-d) -Delete the character at point. If point is at the -beginning of the line, there are no characters in the line, and -the last character typed was not bound to \fBdelete\-char\fP, -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 forward\-backward\-delete\-char -Delete the character under the cursor, unless the cursor is at the -end of the line, in which case the character behind the cursor is -deleted. -.TP -.B quoted\-insert (C\-q, C\-v) -Add the next character typed 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, -moving point forward as well. -If point is at the end of the line, then this transposes -the two characters before point. -Negative arguments have no effect. -.TP -.B transpose\-words (M\-t) -Drag the word before point past the word after point, -moving point over that word as well. -If point is at the end of the line, this transposes -the last two words on the line. -.TP -.B upcase\-word (M\-u) -Uppercase the current (or following) word. With a negative argument, -uppercase the previous word, but do not move point. -.TP -.B downcase\-word (M\-l) -Lowercase the current (or following) word. With a negative argument, -lowercase the previous word, but do not move point. -.TP -.B capitalize\-word (M\-c) -Capitalize the current (or following) word. With a negative argument, -capitalize the previous word, but do not move point. -.TP -.B overwrite\-mode -Toggle overwrite mode. With an explicit positive numeric argument, -switches to overwrite mode. With an explicit non-positive numeric -argument, switches to insert mode. This command affects only -\fBemacs\fP mode; \fBvi\fP mode does overwrite differently. -Each call to \fIreadline()\fP starts in insert mode. -In overwrite mode, characters bound to \fBself\-insert\fP replace -the text at point rather than pushing the text to the right. -Characters bound to \fBbackward\-delete\-char\fP replace the character -before point with a space. By default, this command is unbound. -.PD -.SS Killing and Yanking -.PP -.PD 0 -.TP -.B kill\-line (C\-k) -Kill the text from point 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. -The killed text is saved on the kill-ring. -.\" 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 point is. -.TP -.B kill\-word (M\-d) -Kill from point 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 point. -Word boundaries are the same as those used by \fBbackward\-word\fP. -.TP -.B unix\-word\-rubout (C\-w) -Kill the word behind point, using white space as a word boundary. -The killed text is saved on the kill-ring. -.TP -.B delete\-horizontal\-space (M\-\e) -Delete all spaces and tabs around point. -.TP -.B kill\-region -Kill the text in the current region. -.TP -.B copy\-region\-as\-kill -Copy the text in the region to the kill buffer. -.TP -.B copy\-backward\-word -Copy the word before point to the kill buffer. -The word boundaries are the same as \fBbackward\-word\fP. -.TP -.B copy\-forward\-word -Copy the word following point to the kill buffer. -The word boundaries are the same as \fBforward\-word\fP. -.TP -.B yank (C\-y) -Yank the top of the kill ring into the buffer at point. -.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 -This is another way to specify an argument. -If this command is followed by one or more digits, optionally with a -leading minus sign, those digits define the argument. -If the command is followed by digits, executing -.B universal\-argument -again ends the numeric argument, but is otherwise ignored. -As a special case, if this command is immediately followed by a -character that is neither a digit or minus sign, the argument count -for the next command is multiplied by four. -The argument count is initially one, so executing this function the -first time makes the argument count four, a second time makes the -argument count sixteen, and so on. -.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 (M\-*) -Insert all completions of the text before point -that would have been generated by -\fBpossible\-completions\fP. -.TP -.B menu\-complete -Similar to \fBcomplete\fP, but replaces the word to be completed -with a single match from the list of possible completions. -Repeated execution of \fBmenu\-complete\fP steps through the list -of possible completions, inserting each match in turn. -At the end of the list of completions, the bell is rung -(subject to the setting of \fBbell\-style\fP) -and the original text is restored. -An argument of \fIn\fP moves \fIn\fP positions forward in the list -of matches; a negative argument may be used to move backward -through the list. -This command is intended to be bound to \fBTAB\fP, but is unbound -by default. -.TP -.B delete\-char\-or\-list -Deletes the character under the cursor if not at the beginning or -end of the line (like \fBdelete\-char\fP). -If at the end of the line, behaves identically to -\fBpossible\-completions\fP. -This command is unbound by default. -.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, shell 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 insert 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 store 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 the \fIinputrc\fP 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, M\-\fIx\fP, ...) -If the metafied character \fIx\fP is lowercase, run the command -that is bound to the corresponding uppercase character. -.TP -.B prefix\-meta (ESC) -Metafy the next character typed. -.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 executing 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 set\-mark (C\-@, M\-) -Set the mark to the point. If a -numeric argument is supplied, the mark is set to that position. -.TP -.B exchange\-point\-and\-mark (C\-x C\-x) -Swap the point with the mark. The current cursor position is set to -the saved position, and the old cursor position is saved as the mark. -.TP -.B character\-search (C\-]) -A character is read and point is moved to the next occurrence of that -character. A negative count searches for previous occurrences. -.TP -.B character\-search\-backward (M\-C\-]) -A character is read and point is moved to the previous occurrence of that -character. A negative count searches for subsequent occurrences. -.TP -.B insert\-comment (M\-#) -Without a numeric argument, the value of the readline -.B comment\-begin -variable is inserted at the beginning of the current line. -If a numeric argument is supplied, this command acts as a toggle: if -the characters at the beginning of the line do not match the value -of \fBcomment\-begin\fP, the value is inserted, otherwise -the characters in \fBcomment-begin\fP are deleted from the beginning of -the line. -In either case, the line is accepted as if a newline had been typed. -The default value of -\fBcomment\-begin\fP causes this command to make the current line -a shell comment. -If a numeric argument causes the comment character to be removed, the line -will be executed by the shell. -.TP -.B glob\-complete\-word (M\-g) -The word before point is treated as a pattern for pathname expansion, -with an asterisk implicitly appended. This pattern is used to -generate a list of matching file names for possible completions. -.TP -.B glob\-expand\-word (C\-x *) -The word before point is treated as a pattern for pathname expansion, -and the list of matching file names is inserted, replacing the word. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B glob\-list\-expansions (C\-x g) -The list of expansions that would have been generated by -.B glob\-expand\-word -is displayed, and the line is redrawn. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B dump\-functions -Print all of the functions and their key bindings to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-variables -Print all of the settable readline variables and their values to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-macros -Print all of the readline key sequences bound to macros and the -strings they ouput. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B display\-shell\-version (C\-x C\-v) -Display version information about the current instance of -.BR bash . -.PD -.SS Programmable Completion -.PP -When word completion is attempted for an argument to a command for -which a completion specification (a \fIcompspec\fP) has been defined -using the \fBcomplete\fP builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), the programmable completion facilities are invoked. -.PP -First, the command name is identified. -If a compspec has been defined for that command, the -compspec is used to generate the list of possible completions for the word. -If the command word is a full pathname, a compspec for the full -pathname is searched for first. -If no compspec is found for the full pathname, an attempt is made to -find a compspec for the portion following the final slash. -.PP -Once a compspec has been found, it is used to generate the list of -matching words. -If a compspec is not found, the default \fBbash\fP completion as -described above under \fBCompleting\fP is performed. -.PP -First, the actions specified by the compspec are used. -Only matches which are prefixed by the word being completed are -returned. -When the -.B \-f -or -.B \-d -option is used for filename or directory name completion, the shell -variable -.SM -.B FIGNORE -is used to filter the matches. -.PP -Any completions specified by a filename expansion pattern to the -\fB\-G\fP option are generated next. -The words generated by the pattern need not match the word -being completed. -The -.SM -.B GLOBIGNORE -shell variable is not used to filter the matches, but the -.SM -.B FIGNORE -variable is used. -.PP -Next, the string specified as the argument to the \fB\-W\fP option -is considered. -The string is first split using the characters in the -.SM -.B IFS -special variable as delimiters. -Shell quoting is honored. -Each word is then expanded using -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and pathname expansion, -as described above under -.SM -.BR EXPANSION . -The results are split using the rules described above under -\fBWord Splitting\fP. -The results of the expansion are prefix-matched against the word being -completed, and the matching words become the possible completions. -.PP -After these matches have been generated, any shell function or command -specified with the \fB\-F\fP and \fB\-C\fP options is invoked. -When the command or function is invoked, the -.SM -.B COMP_LINE -and -.SM -.B COMP_POINT -variables are assigned values as described above under -\fBShell Variables\fP. -If a shell function is being invoked, the -.SM -.B COMP_WORDS -and -.SM -.B COMP_CWORD -variables are also set. -When the function or command is invoked, the first argument is the -name of the command whose arguments are being completed, the -second argument is the word being completed, and the third argument -is the word preceding the word being completed on the current command line. -No filtering of the generated completions against the word being completed -is performed; the function or command has complete freedom in generating -the matches. -.PP -Any function specified with \fB\-F\fP is invoked first. -The function may use any of the shell facilities, including the -\fBcompgen\fP builtin described below, to generate the matches. -It must put the possible completions in the -.SM -.B COMPREPLY -array variable. -.PP -Next, any command specified with the \fB\-C\fP option is invoked -in an environment equivalent to command substitution. -It should print a list of completions, one per line, to the -standard output. -Backslash may be used to escape a newline, if necessary. -.PP -After all of the possible completions are generated, any filter -specified with the \fB\-X\fP option is applied to the list. -The filter is a pattern as used for pathname expansion; a \fB&\fP -in the pattern is replaced with the text of the word being completed. -A literal \fB&\fP may be escaped with a backslash; the backslash -is removed before attempting a match. -Any completion that matches the pattern will be removed from the list. -A leading \fB!\fP negates the pattern; in this case any completion -not matching the pattern will be removed. -.PP -Finally, any prefix and suffix specified with the \fB\-P\fP and \fB\-S\fP -options are added to each member of the completion list, and the result is -returned to the readline completion code as the list of possible -completions. -.PP -If the previously-applied actions do not generate any matches, and the -\fB\-o dirnames\fP option was supplied to \fBcomplete\fP when the -compspec was defined, directory name completion is attempted. -.PP -By default, if a compspec is found, whatever it generates is returned -to the completion code as the full set of possible completions. -The default \fBbash\fP completions are not attempted, and the readline -default of filename completion is disabled. -If the \fB-o default\fP option was supplied to \fBcomplete\fP when the -compspec was defined, readline's default completion will be performed -if the compspec generates no matches. -.PP -When a compspec indicates that directory name completion is desired, -the programmable completion functions force readline to append a slash -to completed names which are symbolic links to directories, subject to -the value of the \fBmark\-directories\fP readline variable, regardless -of the setting of the \fBmark-symlinked\-directories\fP readline variable. -.SH HISTORY -When the -.B \-o history -option to the -.B set -builtin is enabled, the shell provides access to the -\fIcommand history\fP, -the list of commands previously typed. -The value of the \fBHISTSIZE\fP variable is used as the -number of commands to save in a history list. -The text of the last -.SM -.B HISTSIZE -commands (default 500) is saved. 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 -.SM -.B HISTIGNORE -and -.SM -.BR HISTCONTROL . -.PP -On startup, the history is initialized from the file named by -the variable -.SM -.B HISTFILE -(default \fI~/.bash_history\fP). -The file named by the value of -.SM -.B HISTFILE -is truncated, if necessary, to contain no more than -the number of lines specified by the value of -.SM -.BR HISTFILESIZE . -When an interactive shell exits, the last -.SM -.B $HISTSIZE -lines are copied from the history list to -.SM -.BR $HISTFILE . -If the -.B histappend -shell option is enabled -(see the description of -.B shopt -under -.SM -.B "SHELL BUILTIN COMMANDS" -below), the lines are appended to the history file, -otherwise the history file is overwritten. -If -.SM -.B HISTFILE -is unset, or if the history file is unwritable, the history is -not saved. After saving the history, the history file is truncated -to contain no more than -.SM -.B HISTFILESIZE -lines. If -.SM -.B HISTFILESIZE -is not set, no truncation is performed. -.PP -The builtin command -.B fc -(see -.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 may be used to display or modify the history list and -manipulate the history file. -When using command-line editing, search commands -are available in each editing mode that provide access to the -history list. -.PP -The shell allows control over which commands are saved on the history -list. The -.SM -.B HISTCONTROL -and -.SM -.B HISTIGNORE -variables may be set to cause the shell to save only a subset of the -commands entered. -The -.B cmdhist -shell option, if enabled, causes the shell to attempt to save each -line of a multi-line command in the same history entry, adding -semicolons where necessary to preserve syntactic correctness. -The -.B lithist -shell option causes the shell to save the command with embedded newlines -instead of semicolons. See the description of the -.B shopt -builtin below under -.SM -.B "SHELL BUILTIN COMMANDS" -for information on setting and unsetting shell options. -.SH "HISTORY EXPANSION" -.PP -The shell supports a history expansion feature that -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 -by default. -.PP -History expansions introduce words from the history list into -the input stream, making it easy to repeat commands, insert the -arguments to a previous command into the current input line, or -fix errors in previous commands quickly. -.PP -History expansion is performed immediately after a complete line -is read, before the shell breaks it into words. -It takes place in two parts. -The first is to determine which line from the history list -to use during substitution. -The second is to select portions of that line for inclusion into -the current one. -The line selected from the history is the \fIevent\fP, -and the portions of that line that are acted upon are \fIwords\fP. -Various \fImodifiers\fP are available to manipulate the selected words. -The line is broken into words in the same fashion as when reading input, -so that several \fImetacharacter\fP-separated words surrounded by -quotes are considered one word. -History expansions are introduced by the appearance of the -history expansion character, which is \^\fB!\fP\^ by default. -Only backslash (\^\fB\e\fP\^) and single quotes can quote -the history expansion character. -.PP -Several shell options settable with the -.B shopt -builtin may be used to tailor the behavior of history expansion. -If the -.B histverify -shell option is enabled (see the description of the -.B shopt -builtin), and -.B readline -is being used, history substitutions are not immediately passed to -the shell parser. -Instead, the expanded line is reloaded into the -.B readline -editing buffer for further modification. -If -.B readline -is being used, and the -.B histreedit -shell option is enabled, a failed history substitution will be reloaded -into the -.B readline -editing buffer for correction. -The -.B \-p -option to the -.B history -builtin command may be used to see what a history expansion will -do before using it. -The -.B \-s -option to the -.B history -builtin may be used to add commands to the end of the history list -without actually executing them, so that they are available for -subsequent recall. -.PP -The shell allows control of the various characters used by the -history expansion mechanism (see the description of -.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 ( (when the \fBextglob\fP shell option is enabled using -the \fBshopt\fP builtin). -.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 !! -Refer to the previous command. This is a synonym for `!\-1'. -.TP -.B !\fIstring\fR -Refer to the most recent command starting with -.IR string . -.TP -.B !?\fIstring\fR\fB[?]\fR -Refer to the most recent command containing -.IR string . -The trailing \fB?\fP may be omitted if -.I string -is followed immediately by a newline. -.TP -.B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u -Quick substitution. Repeat the last command, replacing -.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 -Word designators are used to select desired words from the event. -A -.B : -separates the event specification from the word designator. -It may be omitted if the word designator begins with a -.BR ^ , -.BR $ , -.BR * , -.BR \- , -or -.BR % . -Words are numbered from the beginning of the line, -with the first word being denoted by 0 (zero). -Words are inserted into the current line separated by single spaces. -.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 -.PP -If a word designator is supplied without an event specification, the -previous command is used as the event. -.SS Modifiers -.PP -After the optional word designator, there may appear a sequence of -one or more of the following modifiers, each preceded by a `:'. -.PP -.PD 0 -.PP -.TP -.B h -Remove a trailing file name component, leaving only the head. -.TP -.B t -Remove all leading file name components, leaving the tail. -.TP -.B r -Remove a trailing suffix of the form \fI.xxx\fP, leaving the -basename. -.TP -.B e -Remove all but the trailing suffix. -.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 &. If -.I old -is null, it is set to the last -.I old -substituted, or, if no previous history substitutions took place, -the last -.I string -in a -.B !?\fIstring\fR\fB[?]\fR -search. -.TP -.B & -Repeat the previous substitution. -.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. -An \fBa\fP may be used as a synonym for \fBg\fP. -.TP -.B G -Apply the following `\fBs\fP' modifier once to each word in the event line. -.PD -.SH "SHELL BUILTIN COMMANDS" -.\" start of bash_builtins -.zZ -.PP -Unless otherwise noted, each builtin command documented in this -section as accepting options preceded by -.B \- -accepts -.B \-\- -to signify the end of the options. -.sp .5 -.PD 0 -.TP -\fB:\fP [\fIarguments\fP] -.PD -No effect; the command does nothing beyond expanding -.I arguments -and performing any specified -redirections. A zero exit code is returned. -.TP -\fB .\| \fP \fIfilename\fP [\fIarguments\fP] -.PD 0 -.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, file names 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. -When \fBbash\fP is not in \fIposix mode\fP, the current directory is -searched if no file is found in -.SM -.BR PATH . -If the -.B sourcepath -option to the -.B shopt -builtin command is turned off, the -.SM -.B PATH -is not searched. -If any \fIarguments\fP are supplied, they become the positional -parameters when \fIfilename\fP is executed. Otherwise the positional -parameters are unchanged. -The return status is the status of the last command exited within -the script (0 if no commands are executed), and false if -.I filename -is not found or cannot be read. -.TP -\fBalias\fP [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -\fBAlias\fP with no arguments or with the -.B \-p -option prints the list of aliases in the form -\fBalias\fP \fIname\fP=\fIvalue\fP on standard output. -When arguments are supplied, an alias is defined for -each \fIname\fP whose \fIvalue\fP is given. -A trailing space in \fIvalue\fP causes the next word to be -checked for alias substitution when the alias is expanded. -For each \fIname\fP in the argument list for which no \fIvalue\fP -is supplied, the name and value of the alias is printed. -\fBAlias\fP returns true unless a \fIname\fP is given for which -no alias has been defined. -.TP -\fBbg\fP [\fIjobspec\fP] -Resume the suspended job \fIjobspec\fP in the background, as if it -had been started with -.BR & . -If \fIjobspec\fP is not present, the shell's notion of the -\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 -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP] -.PD 0 -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-q\fP \fIfunction\fP] [\fB\-u\fP \fIfunction\fP] [\fB\-r\fP \fIkeyseq\fP] -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-f\fP \fIfilename\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-x\fP \fIkeyseq\fP:\fIshell\-command\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\fP:\fIfunction\-name\fP -.TP -\fBbind\fP \fIreadline\-command\fP -.PD -Display current -.B readline -key and function bindings, bind a key sequence to a -.B readline -function or macro, or set a -.B readline -variable. -Each non-option argument is a command as it would appear in -.IR .inputrc , -but each binding or command 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 \-p -Display \fBreadline\fP function names and bindings in such a way -that they can be re-read. -.TP -.B \-P -List current \fBreadline\fP function names and bindings. -.TP -.B \-v -Display \fBreadline\fP variable names and values in such a way that they -can be re-read. -.TP -.B \-V -List current \fBreadline\fP variable names and values. -.TP -.B \-s -Display \fBreadline\fP key sequences bound to macros and the strings -they output in such a way that they can be re-read. -.TP -.B \-S -Display \fBreadline\fP key sequences bound to macros and the strings -they output. -.TP -.B \-f \fIfilename\fP -Read key bindings from \fIfilename\fP. -.TP -.B \-q \fIfunction\fP -Query about which keys invoke the named \fIfunction\fP. -.TP -.B \-u \fIfunction\fP -Unbind all keys bound to the named \fIfunction\fP. -.TP -.B \-r \fIkeyseq\fP -Remove any current binding for \fIkeyseq\fP. -.TP -.B \-x \fIkeyseq\fP:\fIshell\-command\fP -Cause \fIshell\-command\fP to be executed whenever \fIkeyseq\fP is -entered. -.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 , -.BR until , -or -.B select -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 defining a -function whose name is the same as a shell builtin, -retaining the functionality of the builtin within the function. -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 [\fB\-L|-P\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 in -.SM -.B CDPATH -are separated by a colon (:). A null directory name in -.SM -.B CDPATH -is the same as the current directory, i.e., ``\fB.\fP''. If -.I dir -begins with a slash (/), -then -.SM -.B CDPATH -is not used. The -.B \-P -option says to use the physical directory structure instead of -following symbolic links (see also the -.B \-P -option to the -.B set -builtin command); the -.B \-L -option forces symbolic links to be followed. An argument of -.B \- -is equivalent to -.SM -.BR $OLDPWD . -The return value is true if the directory was successfully changed; -false otherwise. -.TP -\fBcaller\fP [\fIexpr\fP] -Returns the context of any active subroutine call (a shell function or -a script executed with the \fB.\fP or \fBsource\fP builtins. -Without \fIexpr\fP, \fBcaller\fP displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as \fIexpr\fP, \fBcaller\fP -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. -The return value is 0 unless the shell is not executing a subroutine -call or \fIexpr\fP does not correspond to a valid position in the -call stack. -.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 file name -used to invoke -.I command -to be displayed; the -.B \-V -option produces a more verbose description. -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 -\fBcompgen\fP [\fIoption\fP] [\fIword\fP] -Generate possible completion matches for \fIword\fP according to -the \fIoption\fPs, which may be any option accepted by the -.B complete -builtin with the exception of \fB\-p\fP and \fB\-r\fP, and write -the matches to the standard output. -When using the \fB\-F\fP or \fB\-C\fP options, the various shell variables -set by the programmable completion facilities, while available, will not -have useful values. -.sp 1 -The matches will be generated in the same way as if the programmable -completion code had generated them directly from a completion specification -with the same flags. -If \fIword\fP is specified, only those completions matching \fIword\fP -will be displayed. -.sp 1 -The return value is true unless an invalid option is supplied, or no -matches were generated. -.TP -\fBcomplete\fP [\fB\-abcdefgjksuv\fP] [\fB\-o\fP \fIcomp-option\fP] [\fB\-A\fP \fIaction\fP] [\fB\-G\fP \fIglobpat\fP] [\fB\-W\fP \fIwordlist\fP] [\fB\-P\fP \fIprefix\fP] [\fB\-S\fP \fIsuffix\fP] -.br -[\fB\-X\fP \fIfilterpat\fP] [\fB\-F\fP \fIfunction\fP] [\fB\-C\fP \fIcommand\fP] \fIname\fP [\fIname ...\fP] -.PD 0 -.TP -\fBcomplete\fP \fB\-pr\fP [\fIname\fP ...] -.PD -Specify how arguments to each \fIname\fP should be completed. -If the \fB\-p\fP option is supplied, or if no options are supplied, -existing completion specifications are printed in a way that allows -them to be reused as input. -The \fB\-r\fP option removes a completion specification for -each \fIname\fP, or, if no \fIname\fPs are supplied, all -completion specifications. -.sp 1 -The process of applying these completion specifications when word completion -is attempted is described above under \fBProgrammable Completion\fP. -.sp 1 -Other options, if specified, have the following meanings. -The arguments to the \fB\-G\fP, \fB\-W\fP, and \fB\-X\fP options -(and, if necessary, the \fB\-P\fP and \fB\-S\fP options) -should be quoted to protect them from expansion before the -.B complete -builtin is invoked. -.RS -.PD 0 -.TP 8 -\fB\-o\fP \fIcomp-option\fP -The \fIcomp-option\fP controls several aspects of the compspec's behavior -beyond the simple generation of completions. -\fIcomp-option\fP may be one of: -.RS -.TP 8 -.B default -Use readline's default filename completion if the compspec generates -no matches. -.TP 8 -.B dirnames -Perform directory name completion if the compspec generates no matches. -.TP 8 -.B filenames -Tell readline that the compspec generates filenames, so it can perform any -filename\-specific processing (like adding a slash to directory names or -suppressing trailing spaces). Intended to be used with shell functions. -.TP 8 -.B nospace -Tell readline not to append a space (the default) to words completed at -the end of the line. -.RE -.TP 8 -\fB\-A\fP \fIaction\fP -The \fIaction\fP may be one of the following to generate a list of possible -completions: -.RS -.TP 8 -.B alias -Alias names. May also be specified as \fB\-a\fP. -.TP 8 -.B arrayvar -Array variable names. -.TP 8 -.B binding -\fBReadline\fP key binding names. -.TP 8 -.B builtin -Names of shell builtin commands. May also be specified as \fB\-b\fP. -.TP 8 -.B command -Command names. May also be specified as \fB\-c\fP. -.TP 8 -.B directory -Directory names. May also be specified as \fB\-d\fP. -.TP 8 -.B disabled -Names of disabled shell builtins. -.TP 8 -.B enabled -Names of enabled shell builtins. -.TP 8 -.B export -Names of exported shell variables. May also be specified as \fB\-e\fP. -.TP 8 -.B file -File names. May also be specified as \fB\-f\fP. -.TP 8 -.B function -Names of shell functions. -.TP 8 -.B group -Group names. May also be specified as \fB\-g\fP. -.TP 8 -.B helptopic -Help topics as accepted by the \fBhelp\fP builtin. -.TP 8 -.B hostname -Hostnames, as taken from the file specified by the -.SM -.B HOSTFILE -shell variable. -.TP 8 -.B job -Job names, if job control is active. May also be specified as \fB\-j\fP. -.TP 8 -.B keyword -Shell reserved words. May also be specified as \fB\-k\fP. -.TP 8 -.B running -Names of running jobs, if job control is active. -.TP 8 -.B service -Service names. May also be specified as \fB\-s\fP. -.TP 8 -.B setopt -Valid arguments for the \fB\-o\fP option to the \fBset\fP builtin. -.TP 8 -.B shopt -Shell option names as accepted by the \fBshopt\fP builtin. -.TP 8 -.B signal -Signal names. -.TP 8 -.B stopped -Names of stopped jobs, if job control is active. -.TP 8 -.B user -User names. May also be specified as \fB\-u\fP. -.TP 8 -.B variable -Names of all shell variables. May also be specified as \fB\-v\fP. -.RE -.TP 8 -\fB\-G\fP \fIglobpat\fP -The filename expansion pattern \fIglobpat\fP is expanded to generate -the possible completions. -.TP 8 -\fB\-W\fP \fIwordlist\fP -The \fIwordlist\fP is split using the characters in the -.SM -.B IFS -special variable as delimiters, and each resultant word is expanded. -The possible completions are the members of the resultant list which -match the word being completed. -.TP 8 -\fB\-C\fP \fIcommand\fP -\fIcommand\fP is executed in a subshell environment, and its output is -used as the possible completions. -.TP 8 -\fB\-F\fP \fIfunction\fP -The shell function \fIfunction\fP is executed in the current shell -environment. -When it finishes, the possible completions are retrieved from the value -of the -.SM -.B COMPREPLY -array variable. -.TP 8 -\fB\-X\fP \fIfilterpat\fP -\fIfilterpat\fP is a pattern as used for filename expansion. -It is applied to the list of possible completions generated by the -preceding options and arguments, and each completion matching -\fIfilterpat\fP is removed from the list. -A leading \fB!\fP in \fIfilterpat\fP negates the pattern; in this -case, any completion not matching \fIfilterpat\fP is removed. -.TP 8 -\fB\-P\fP \fIprefix\fP -\fIprefix\fP is added at the beginning of each possible completion -after all other options have been applied. -.TP 8 -\fB\-S\fP \fIsuffix\fP -\fIsuffix\fP is appended to each possible completion -after all other options have been applied. -.PD -.PP -The return value is true unless an invalid option is supplied, an option -other than \fB\-p\fP or \fB\-r\fP is supplied without a \fIname\fP -argument, an attempt is made to remove a completion specification for -a \fIname\fP for which no specification exists, or -an error occurs adding a completion specification. -.RE -.TP -\fBcontinue\fP [\fIn\fP] -Resume the next iteration of the enclosing -.BR for , -.BR while , -.BR until , -or -.B select -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 -\fBdeclare\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD 0 -.TP -\fBtypeset\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD -Declare variables and/or give them attributes. -If no \fIname\fPs are given then display the values of variables. -The -.B \-p -option will display the attributes and values of each -.IR name . -When -.B \-p -is used, additional options are ignored. -The -.B \-F -option inhibits the display of function definitions; only the -function name and attributes are printed. -If the \fBextdebug\fP shell option is enabled using \fBshopt\fP, -the source file name and line number where the function is defined -are displayed as well. The -.B \-F -option implies -.BR \-f . -The following options can -be used to restrict output to variables with the specified attribute or -to give variables attributes: -.RS -.PD 0 -.TP -.B \-a -Each \fIname\fP is an array variable (see -.B Arrays -above). -.TP -.B \-f -Use function names only. -.TP -.B \-i -The variable is treated as an integer; arithmetic evaluation (see -.SM -.B "ARITHMETIC EVALUATION" ") " -is performed when the variable is assigned a value. -.TP -.B \-r -Make \fIname\fPs readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. -.TP -.B \-t -Give each \fIname\fP the \fItrace\fP attribute. -Traced functions inherit the \fBDEBUG\fP trap from the calling shell. -The trace attribute has no special meaning for variables. -.TP -.B \-x -Mark \fIname\fPs for export to subsequent commands via the environment. -.PD -.PP -Using `+' instead of `\-' -turns off the attribute instead, with the exception that \fB+a\fP -may not be used to destroy an array variable. When used in a function, -makes each -\fIname\fP local, as with the -.B local -command. -If a variable name is followed by =\fIvalue\fP, the value of -the variable is set to \fIvalue\fP. -The return value is 0 unless an invalid option is encountered, -an attempt is made to define a function using -.if n ``\-f foo=bar'', -.if t \f(CW\-f foo=bar\fP, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (see -.B Arrays -above), one of the \fInames\fP is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with \fB\-f\fP. -.RE -.TP -.B dirs [\fB\-clpv\fP] [+\fIn\fP] [\-\fIn\fP] -Without options, displays the list of currently remembered directories. -The default display is on a single line with directory names separated -by spaces. -Directories are added to the list with the -.B pushd -command; the -.B popd -command removes entries from the list. -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Displays the \fIn\fPth entry counting from the left of the list -shown by -.B dirs -when invoked without options, starting with zero. -.TP -\fB\-\fP\fIn\fP -Displays the \fIn\fPth entry counting from the right of the list -shown by -.B dirs -when invoked without options, starting with zero. -.TP -.B \-c -Clears the directory stack by deleting all of the entries. -.TP -.B \-l -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -.TP -.B \-p -Print the directory stack with one entry per line. -.TP -.B \-v -Print the directory stack with one entry per line, -prefixing each entry with its index in the stack. -.PD -.PP -The return value is 0 unless an -invalid option is supplied or \fIn\fP indexes beyond the end -of the directory stack. -.RE -.TP -\fBdisown\fP [\fB\-ar\fP] [\fB\-h\fP] [\fIjobspec\fP ...] -Without options, each -.I jobspec -is removed from the table of active jobs. -If the \fB\-h\fP option is given, each -.I jobspec -is not removed from the table, but is marked so that -.SM -.B SIGHUP -is not sent to the job if the shell receives a -.SM -.BR SIGHUP . -If no -.I jobspec -is present, and neither the -.B \-a -nor the -.B \-r -option is supplied, the \fIcurrent job\fP is used. -If no -.I jobspec -is supplied, the -.B \-a -option means to remove or mark all jobs; the -.B \-r -option without a -.I jobspec -argument restricts operation to running jobs. -The return value is 0 unless a -.I jobspec -does not specify a valid job. -.TP -\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...] -Output the \fIarg\fPs, separated by spaces, followed by a newline. -The return status is always 0. -If \fB\-n\fP is specified, the trailing newline is -suppressed. If the \fB\-e\fP option is given, interpretation of -the following backslash-escaped characters is enabled. The -.B \-E -option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The \fBxpg_echo\fP shell option may be used to -dynamically determine whether or not \fBecho\fP expands these -escape characters by default. -.B echo -does not interpret -.B \-\- -to mean the end of options. -.B echo -interprets the following escape sequences: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ec -suppress trailing newline -.TP -.B \ee -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e0\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(zero to three octal digits) -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three octal digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.PD -.RE -.TP -\fBenable\fP [\fB\-adnps\fP] [\fB\-f\fP \fIfilename\fP] [\fIname\fP ...] -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -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, run -.if t \f(CWenable -n test\fP. -.if n ``enable -n test''. -The -.B \-f -option means to load the new builtin command -.I name -from shared object -.IR filename , -on systems that support dynamic loading. The -.B \-d -option will delete a builtin previously loaded with -.BR \-f . -If no \fIname\fP arguments are given, or if the -.B \-p -option is supplied, a list of shell builtins is printed. -With no other option arguments, the list consists of all enabled -shell builtins. -If \fB\-n\fP is supplied, only disabled builtins are printed. -If \fB\-a\fP is supplied, the list printed includes all builtins, with an -indication of whether or not each is enabled. -If \fB\-s\fP is supplied, the output is restricted to the POSIX -\fIspecial\fP builtins. -The return value is 0 unless a -.I name -is not a shell builtin or there is an error loading a new builtin -from a shared object. -.TP -\fBeval\fP [\fIarg\fP ...] -The \fIarg\fPs are read and concatenated together into a single -command. This command is then read and executed by the shell, and -its exit status is returned as the value of -.BR eval . -If there are no -.IR args , -or only null arguments, -.B eval -returns 0. -.TP -\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP [\fIarguments\fP]] -If -.I command -is specified, it replaces the shell. -No new process is created. The -.I arguments -become the arguments to \fIcommand\fP. -If the -.B \-l -option is supplied, -the shell places a dash at the beginning of the zeroth arg passed to -.IR command . -This is what -.IR login (1) -does. The -.B \-c -option causes -.I command -to be executed with an empty environment. If -.B \-a -is supplied, the shell passes -.I name -as the zeroth argument to the executed command. If -.I command -cannot be executed for some reason, a non-interactive shell exits, -unless the shell option -.B execfail -is enabled, in which case it returns failure. -An interactive shell returns failure if the file cannot be executed. -If -.I command -is not specified, any redirections take effect in the current shell, -and the return status is 0. If there is a redirection error, the -return status is 1. -.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 -\fBexport\fP [\fB\-fn\fP\^] [\fIname\fP[=\fIword\fP]] ... -.PD 0 -.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. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -.B export -returns an exit status of 0 unless an invalid option is -encountered, -one of the \fInames\fP is not a valid shell variable name, or -.B \-f -is supplied with a -.I name -that is not a function. -.TP -\fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-nlr\fP] [\fIfirst\fP] [\fIlast\fP] -.PD 0 -.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 -.if n ``fc \-l \-10'' -.if t \f(CWfc \-l \-10\fP -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 -option suppresses -the command numbers when listing. The -.B \-r -option reverses the order of -the commands. If the -.B \-l -option 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 -.if n ``r="fc -s"'', -.if t \f(CWr='fc \-s'\fP, -so that typing -.if n ``r cc'' -.if t \f(CWr cc\fP -runs the last command beginning with -.if n ``cc'' -.if t \f(CWcc\fP -and typing -.if n ``r'' -.if t \f(CWr\fP -re-executes the last command. -.sp 1 -If the first form is used, the return value is 0 unless an invalid -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] -Resume -.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 characters to be recognized; if a character -is followed by a colon, the option is expected to have an -argument, which should be separated from it by white space. -The colon and question mark characters may not be used as -option characters. -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 -When the end of options is encountered, \fBgetopts\fP exits with a -return value greater than zero. -\fBOPTIND\fP is set to the index of the first non-option argument, -and \fBname\fP is set to ?. -.sp 1 -.B getopts -normally parses the positional parameters, but if more arguments are -given in -.IR args , -.B getopts -parses those instead. -.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 invalid options or missing option arguments are -encountered. -If the variable -.SM -.B OPTERR -is set to 0, no error messages will be displayed, even if the first -character of -.I optstring -is not a colon. -.sp 1 -If an invalid 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 , -.SM -.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 -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\-lr\fP] [\fB\-p\fP \fIfilename\fP] [\fB\-dt\fP] [\fIname\fP] -For each -.IR name , -the full file name of the command is determined by searching -the directories in -.B $PATH -and remembered. -If the -.B \-p -option is supplied, no path search is performed, and -.I filename -is used as the full file name of the command. -The -.B \-r -option causes the shell to forget all -remembered locations. -The -.B \-d -option causes the shell to forget the remembered location of each \fIname\fP. -If the -.B \-t -option is supplied, the full pathname to which each \fIname\fP corresponds -is printed. If multiple \fIname\fP arguments are supplied with \fB\-t\fP, -the \fIname\fP is printed before the hashed full pathname. -The -.B \-l -option causes output to be displayed in a format that may be reused as input. -If no arguments are given, or if only \fB\-l\fP is supplied, -information about remembered commands is printed. -The return status is true unless a -.I name -is not found or an invalid option is supplied. -.TP -\fBhelp\fP [\fB\-s\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 help for all the builtins and shell control structures -is printed. -The \fB\-s\fP option restricts the information displayed to a short -usage synopsis. -The return status is 0 unless no command matches -.IR pattern . -.TP -\fBhistory [\fIn\fP] -.PD 0 -.TP -\fBhistory\fP \fB\-c\fP -.TP -\fBhistory \-d\fP \fIoffset\fP -.TP -\fBhistory\fP \fB\-anrw\fP [\fIfilename\fP] -.TP -\fBhistory\fP \fB\-p\fP \fIarg\fP [\fIarg ...\fP] -.TP -\fBhistory\fP \fB\-s\fP \fIarg\fP [\fIarg ...\fP] -.PD -With no options, display the command -history list with line numbers. Lines listed -with a -.B * -have been modified. An argument of -.I n -lists only the last -.I n -lines. If \fIfilename\fP 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 \-c -Clear the history list by deleting all the entries. -.TP -\fB\-d\fP \fIoffset\fP -Delete the history entry at position \fIoffset\fP. -.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 \-p -Perform history substitution on the following \fIargs\fP and display -the result on the standard output. -Does not store the results in the history list. -Each \fIarg\fP must be quoted to disable normal history expansion. -.TP -.B \-s -Store the -.I args -in the history list as a single entry. The last command in the -history list is removed before the -.I args -are added. -.PD -.PP -The return value is 0 unless an invalid option is encountered, an -error occurs while reading or writing the history file, an invalid -\fIoffset\fP is supplied as an argument to \fB\-d\fP, or the -history expansion supplied as an argument to \fB\-p\fP fails. -.RE -.TP -\fBjobs\fP [\fB\-lnprs\fP] [ \fIjobspec\fP ... ] -.PD 0 -.TP -\fBjobs\fP \fB\-x\fP \fIcommand\fP [ \fIargs\fP ... ] -.PD -The first form lists the active jobs. The options have the following -meanings: -.RS -.PD 0 -.TP -.B \-l -List process IDs -in addition to the normal information. -.TP -.B \-p -List only the process ID of the job's process group -leader. -.TP -.B \-n -Display information only about jobs that have changed status since -the user was last notified of their status. -.TP -.B \-r -Restrict output to running jobs. -.TP -.B \-s -Restrict output to stopped jobs. -.PD -.PP -If -.I jobspec -is given, output is restricted to information about that job. -The return status is 0 unless an invalid option is encountered -or an invalid -.I jobspec -is supplied. -.PP -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. -.RE -.TP -\fBkill\fP [\fB\-s\fP \fIsigspec\fP | \fB\-n\fP \fIsignum\fP | \fB\-\fP\fIsigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... -.PD 0 -.TP -\fBkill\fP \fB\-l\fP [\fIsigspec\fP | \fIexit_status\fP] -.PD -Send the signal named by -.I sigspec -or -.I signum -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; -.I signum -is a signal number. If -.I sigspec -is a signal name, the name may be -given with or without the -.SM -.B SIG -prefix. -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 signals corresponding to the arguments are -listed, and the return status is 0. -The \fIexit_status\fP argument to -.B \-l -is a number specifying either a signal number or the exit status of -a process terminated by a signal. -.B kill -returns true if at least one signal was successfully sent, or false -if an error occurs or an invalid 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 [\fIoption\fP] [\fIname\fP[=\fIvalue\fP] ...] -For each argument, a local variable named -.I name -is created, and assigned -.IR value . -The \fIoption\fP can be any of the options accepted by \fBdeclare\fP. -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, an invalid -.I name -is supplied, or -\fIname\fP is a readonly variable. -.TP -.B logout -Exit a login shell. -.TP -\fBpopd\fP [\-\fBn\fP] [+\fIn\fP] [\-\fIn\fP] -Removes entries from the directory stack. With no arguments, -removes the top directory from the stack, and performs a -.B cd -to the new top directory. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Removes the \fIn\fPth entry counting from the left of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd +0'' -.if t \f(CWpopd +0\fP -removes the first directory, -.if n ``popd +1'' -.if t \f(CWpopd +1\fP -the second. -.TP -\fB\-\fP\fIn\fP -Removes the \fIn\fPth entry counting from the right of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd -0'' -.if t \f(CWpopd -0\fP -removes the last directory, -.if n ``popd -1'' -.if t \f(CWpopd -1\fP -the next to last. -.TP -.B \-n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -.PD -.PP -If the -.B popd -command is successful, a -.B dirs -is performed as well, and the return status is 0. -.B popd -returns false if an invalid option is encountered, the directory stack -is empty, a non-existent directory stack entry is specified, or the -directory change fails. -.RE -.TP -\fBprintf\fP \fIformat\fP [\fIarguments\fP] -Write the formatted \fIarguments\fP to the standard output under the -control of the \fIformat\fP. -The \fIformat\fP is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -\fIargument\fP. -In addition to the standard \fIprintf\fP(1) formats, \fB%b\fP causes -\fBprintf\fP to expand backslash escape sequences in the corresponding -\fIargument\fP, and \fB%q\fP causes \fBprintf\fP to output the corresponding -\fIargument\fP in a format that can be reused as shell input. -.sp 1 -The \fIformat\fP is reused as necessary to consume all of the \fIarguments\fP. -If the \fIformat\fP requires more \fIarguments\fP than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. -.TP -\fBpushd\fP [\fB\-n\fP] [\fIdir\fP] -.PD 0 -.TP -\fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] -.PD -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories -and returns 0, unless the directory stack is empty. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the left of the list shown by -.BR dirs , -starting with zero) -is at the top. -.TP -\fB\-\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the right of the list shown by -.BR dirs , -starting with zero) is at the top. -.TP -.B \-n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -.TP -.I 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-existent directory stack element is specified, -or the directory change to the specified new current directory -fails. -.RE -.TP -\fBpwd\fP [\fB\-LP\fP] -Print the absolute pathname of the current working directory. -The pathname printed contains no symbolic links if the -.B \-P -option is supplied or the -.B \-o physical -option to the -.B set -builtin command is enabled. -If the -.B \-L -option is used, the pathname printed may contain symbolic links. -The return status is 0 unless an error occurs while -reading the name of the current directory or an -invalid option is supplied. -.TP -\fBread\fP [\fB\-ers\fP] [\fB\-u\fP \fIfd\fP] [\fB\-t\fP \fItimeout\fP] [\fB\-a\fP \fIaname\fP] [\fB\-p\fP \fIprompt\fP] [\fB\-n\fP \fInchars\fP] [\fB\-d\fP \fIdelim\fP] [\fIname\fP ...] -One line is read from the standard input, or from the file descriptor -\fIfd\fP supplied as an argument to the \fB\-u\fP option, 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 and their intervening separators assigned -to the last -.IR name . -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in -.SM -.B IFS -are used to split the line into words. -The backslash character (\fB\e\fP) may be used to remove any special -meaning for the next character read and for line continuation. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-a \fIaname\fP -The words are assigned to sequential indices -of the array variable -.IR aname , -starting at 0. -.I aname -is unset before any new values are assigned. -Other \fIname\fP arguments are ignored. -.TP -.B \-d \fIdelim\fP -The first character of \fIdelim\fP is used to terminate the input line, -rather than newline. -.TP -.B \-e -If the standard input -is coming from a terminal, -.B readline -(see -.SM -.B READLINE -above) is used to obtain the line. -.TP -.B \-n \fInchars\fP -\fBread\fP returns after reading \fInchars\fP characters rather than -waiting for a complete line of input. -.TP -.B \-p \fIprompt\fP -Display \fIprompt\fP on standard error, without a -trailing newline, before attempting to read any input. The prompt -is displayed only if input is coming from a terminal. -.TP -.B \-r -Backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. -.TP -.B \-s -Silent mode. If input is coming from a terminal, characters are -not echoed. -.TP -.B \-t \fItimeout\fP -Cause \fBread\fP to time out and return failure if a complete line of -input is not read within \fItimeout\fP seconds. -This option has no effect if \fBread\fP is not reading input from the -terminal or a pipe. -.TP -.B \-u \fIfd\FP -Read input from file descriptor \fIfd\fP. -.PD -.PP -If no -.I names -are supplied, the line read is assigned to the variable -.SM -.BR REPLY . -The return code is zero, unless end-of-file is encountered, \fBread\fP -times out, or an invalid file descriptor is supplied as the argument to -\fB\-u\fP. -.RE -.TP -\fBreadonly\fP [\fB\-apf\fP] [\fIname\fP[=\fIword\fP] ...] -.PD -The given -\fInames\fP are marked readonly; the values of these -.I names -may not be changed by subsequent assignment. -If the -.B \-f -option is supplied, the functions corresponding to the -\fInames\fP are so -marked. -The -.B \-a -option restricts the variables to arrays. -If no -.I name -arguments are given, or if the -.B \-p -option is supplied, a list of all readonly names is printed. -The -.B \-p -option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -The return status is 0 unless an invalid option is encountered, -one of the -.I names -is not a valid 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. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes after the function or script. -.TP -\fBset\fP [\fB\-\-abefhkmnptuvxBCHP\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...] -Without options, the name and value of each shell variable are displayed -in a format that can be reused as input. -The output is sorted according to the current locale. -When options are specified, they set or unset shell attributes. -Any arguments remaining after the options are processed are treated -as values for the positional parameters and are assigned, in order, to -.BR $1 , -.BR $2 , -.B ... -.BR $\fIn\fP . -Options, if specified, have the following meanings: -.RS -.PD 0 -.TP 8 -.B \-a -Automatically mark variables and functions which are modified or created -for export to the environment of subsequent commands. -.TP 8 -.B \-b -Report the status of terminated background jobs -immediately, rather than before the next primary prompt. This is -effective only when job control is enabled. -.TP 8 -.B \-e -Exit immediately if a \fIsimple command\fP (see -.SM -.B SHELL GRAMMAR -above) exits with a non-zero status. -The shell does not exit if the -command that fails is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test in 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 ! . -A trap on \fBERR\fP, if set, is executed before the shell exits. -.TP 8 -.B \-f -Disable pathname expansion. -.TP 8 -.B \-h -Remember the location of commands as they are looked up for execution. -This is enabled by default. -.TP 8 -.B \-k -All arguments in the form of assignment statements -are placed in the environment for a command, not just -those that precede the command name. -.TP 8 -.B \-m -Monitor mode. Job control is enabled. This option 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 by -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 -Same as -.BR \-B . -.TP 8 -.B emacs -Use an emacs-style command line editing interface. This is enabled -by default when the shell is interactive, unless the shell is started -with the -.B \-\-noediting -option. -.TP 8 -.B errtrace -Same as -.BR \-E . -.TP 8 -.B functrace -Same as -.BR \-T . -.TP 8 -.B errexit -Same as -.BR \-e . -.TP 8 -.B hashall -Same as -.BR \-h . -.TP 8 -.B histexpand -Same as -.BR \-H . -.TP 8 -.B history -Enable command history, as described above under -.SM -.BR HISTORY . -This option is on by default in interactive shells. -.TP 8 -.B ignoreeof -The effect is as if the shell command -.if t \f(CWIGNOREEOF=10\fP -.if n ``IGNOREEOF=10'' -had been executed -(see -.B Shell Variables -above). -.TP 8 -.B keyword -Same as -.BR \-k . -.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 . -.B nolog -Currently ignored. -.TP 8 -.B notify -Same as -.BR \-b . -.TP 8 -.B nounset -Same as -.BR \-u . -.TP 8 -.B onecmd -Same as -.BR \-t . -.TP 8 -.B physical -Same as -.BR \-P . -.TP 8 -.B posix -Change the behavior of -.B bash -where the default operation differs -from the POSIX 1003.2 standard to match the standard (\fIposix mode\fP). -.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 . -.sp .5 -.PP -If -.B \-o -is supplied with no \fIoption\-name\fP, the values of the current options are -printed. -If -.B +o -is supplied with no \fIoption\-name\fP, a series of -.B set -commands to recreate the current option settings is displayed on -the standard output. -.RE -.TP 8 -.B \-p -Turn on -.I privileged -mode. In this mode, the -.SM -.B $ENV -and -.SM -.B $BASH_ENV -files are not processed, shell functions are not inherited from the -environment, and the -.SM -.B SHELLOPTS -variable, if it appears in the environment, is ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at startup, the effective user id is -not reset. -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 \fIsimple command\fP, -\fBfor\fP command, \fBcase\fP command, \fBselect\fP command, or -arithmetic \fBfor\fP command, display the expanded value of -.SM -.BR PS4 , -followed by the command and its expanded arguments -or associated word list. -.TP 8 -.B \-B -The shell performs brace expansion (see -.B Brace Expansion -above). This is on by default. -.TP 8 -.B \-C -If set, -.B bash -does not overwrite an existing file with the -.BR > , -.BR >& , -and -.B <> -redirection operators. This may be overridden when -creating output files by using the redirection operator -.B >| -instead of -.BR > . -.TP 8 -.B \-E -If set, any trap on \fBERR\fP is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The \fBERR\fP trap is normally not inherited in such cases. -.TP 8 -.B \-H -Enable -.B ! -style history substitution. This option is on by -default when the shell is interactive. -.TP 8 -.B \-P -If set, the shell does not follow symbolic links when executing -commands such as -.B cd -that change the current working directory. It uses the -physical directory structure instead. By default, -.B bash -follows the logical chain of directories when performing commands -which change the current directory. -.TP 8 -.B \-T -If set, any trap on \fBDEBUG\fP is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The \fBDEBUG\fP trap is normally not inherited in such cases. -.TP 8 -.B \-\- -If no arguments follow this option, then the positional parameters are -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 options are off by default unless otherwise noted. -Using + rather than \- causes these options to be turned off. -The options can also be specified as arguments to an invocation of -the shell. -The current set of options may be found in -.BR $\- . -The return status is always true unless an invalid 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. -.I n -must be a non-negative number less than or equal to \fB$#\fP. -If -.I n -is 0, no parameters are changed. -If -.I n -is not given, it is assumed to be 1. -If -.I n -is greater than \fB$#\fP, the positional parameters are not changed. -The return status is greater than zero if -.I n -is greater than -.B $# -or less than zero; otherwise 0. -.TP -\fBshopt\fP [\fB\-pqsu\fP] [\fB\-o\fP] [\fIoptname\fP ...] -Toggle the values of variables controlling optional shell behavior. -With no options, or with the -.B \-p -option, a list of all settable options is displayed, with -an indication of whether or not each is set. -The \fB\-p\fP option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: -.RS -.PD 0 -.TP -.B \-s -Enable (set) each \fIoptname\fP. -.TP -.B \-u -Disable (unset) each \fIoptname\fP. -.TP -.B \-q -Suppresses normal output (quiet mode); the return status indicates -whether the \fIoptname\fP is set or unset. -If multiple \fIoptname\fP arguments are given with -.BR \-q , -the return status is zero if all \fIoptnames\fP are enabled; non-zero -otherwise. -.TP -.B \-o -Restricts the values of \fIoptname\fP to be those defined for the -.B \-o -option to the -.B set -builtin. -.PD -.PP -If either -.B \-s -or -.B \-u -is used with no \fIoptname\fP arguments, the display is limited to -those options which are set or unset, respectively. -Unless otherwise noted, the \fBshopt\fP options are disabled (unset) -by default. -.PP -The return status when listing options is zero if all \fIoptnames\fP -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an \fIoptname\fP is not a valid shell -option. -.PP -The list of \fBshopt\fP options is: -.if t .sp .5v -.if n .sp 1v -.PD 0 -.TP 8 -.B cdable_vars -If set, an argument to the -.B cd -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. -.TP 8 -.B cdspell -If set, minor errors in the spelling of a directory component in a -.B cd -command will be corrected. -The errors checked for are transposed characters, -a missing character, and one character too many. -If a correction is found, the corrected file name is printed, -and the command proceeds. -This option is only used by interactive shells. -.TP 8 -.B checkhash -If set, \fBbash\fP checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. -.TP 8 -.B checkwinsize -If set, \fBbash\fP checks the window size after each command -and, if necessary, updates the values of -.SM -.B LINES -and -.SM -.BR COLUMNS . -.TP 8 -.B cmdhist -If set, -.B bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. -.TP 8 -.B dotglob -If set, -.B bash -includes filenames beginning with a `.' in the results of pathname -expansion. -.TP 8 -.B execfail -If set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the -.B exec -builtin command. An interactive shell does not exit if -.B exec -fails. -.TP 8 -.B expand_aliases -If set, aliases are expanded as described above under -.SM -.BR ALIASES . -This option is enabled by default for interactive shells. -.TP 8 -.B extdebug -If set, behavior intended for use by debuggers is enabled: -.RS -.TP -.B 1. -The \fB\-F\fP option to the \fBdeclare\fP builtin displays the source -file name and line number corresponding to each function name supplied -as an argument. -.TP -.B 2. -If the command run by the \fBDEBUG\fP trap returns a non-zero value, the -next command is skipped and not executed. -.TP -.B 3. -If the command run by the \fBDEBUG\fP trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the \fB.\fP or \fBsource\fP builtins), a call to -\fBreturn\fP is simulated. -.RE -.TP 8 -.B extglob -If set, the extended pattern matching features described above under -\fBPathname Expansion\fP are enabled. -.TP 8 -.B extquote -If set, \fB$\fP'\fIstring\fP' and \fB$\fP"\fIstring\fP" quoting is -performed within \fB${\fP\fIparameter\fP\fB}\fP expansions -enclosed in double quotes. This option is enabled by default. -.TP 8 -.B histappend -If set, the history list is appended to the file named by the value -of the -.B HISTFILE -variable when the shell exits, rather than overwriting the file. -.TP 8 -.B histreedit -If set, and -.B readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. -.TP 8 -.B histverify -If set, and -.B readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the \fBreadline\fP editing buffer, allowing further modification. -.TP 8 -.B hostcomplete -If set, and -.B readline -is being used, \fBbash\fP will attempt to perform hostname completion when a -word containing a \fB@\fP is being completed (see -.B Completing -under -.SM -.B READLINE -above). -This is enabled by default. -.TP 8 -.B huponexit -If set, \fBbash\fP will send -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.TP 8 -.B interactive_comments -If set, allow a word beginning with -.B # -to cause that word and all remaining characters on that -line to be ignored in an interactive shell (see -.SM -.B COMMENTS -above). This option is enabled by default. -.TP 8 -.B lithist -If set, and the -.B cmdhist -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. -.TP 8 -.B login_shell -The shell sets this option if it is started as a login shell (see -.SM -.B "INVOCATION" -above). -The value may not be changed. -.TP 8 -.B mailwarn -If set, and a file that \fBbash\fP is checking for mail has been -accessed since the last time it was checked, the message ``The mail in -\fImailfile\fP has been read'' is displayed. -.TP 8 -.B no_empty_cmd_completion -If set, and -.B readline -is being used, -.B bash -will not attempt to search the \fBPATH\fP for possible completions when -completion is attempted on an empty line. -.TP 8 -.B nocaseglob -If set, -.B bash -matches filenames in a case\-insensitive fashion when performing pathname -expansion (see -.B Pathname Expansion -above). -.TP 8 -.B nullglob -If set, -.B bash -allows patterns which match no -files (see -.B Pathname Expansion -above) -to expand to a null string, rather than themselves. -.TP 8 -.B progcomp -If set, the programmable completion facilities (see -\fBProgrammable Completion\fP above) are enabled. -This option is enabled by default. -.TP 8 -.B promptvars -If set, prompt strings undergo variable and parameter expansion after -being expanded as described in -.SM -.B PROMPTING -above. This option is enabled by default. -.TP 8 -.B restricted_shell -The shell sets this option if it is started in restricted mode (see -.SM -.B "RESTRICTED SHELL" -below). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. -.TP 8 -.B shift_verbose -If set, the -.B shift -builtin prints an error message when the shift count exceeds the -number of positional parameters. -.TP 8 -.B sourcepath -If set, the -\fBsource\fP (\fB.\fP) builtin uses the value of -.SM -.B PATH -to find the directory containing the file supplied as an argument. -This option is enabled by default. -.TP 8 -.B xpg_echo -If set, the \fBecho\fP builtin expands backslash-escape sequences -by default. -.RE -.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 -\fBtest\fP \fIexpr\fP -.PD 0 -.TP -\fB[\fP \fIexpr\fP \fB]\fP -Return a status of 0 or 1 depending on -the evaluation of the conditional expression -.IR expr . -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described above under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence. -.RS -.PD 0 -.TP -.B ! \fIexpr\fP -True if -.I expr -is false. -.TP -.B ( \fIexpr\fP ) -Returns the value of \fIexpr\fP. -This may be used to override the normal precedence of operators. -.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. -.PD -.PP -\fBtest\fP and \fB[\fP evaluate conditional -expressions using a set of rules based on the number of arguments. -.if t .sp 0.5 -.if n .sp 1 -.PD 0 -.TP -0 arguments -The expression is false. -.TP -1 argument -The expression is true if and only if the argument is not null. -.TP -2 arguments -If the first argument is \fB!\fP, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the expression is true if the unary test is true. -If the first argument is not a valid unary conditional operator, the expression -is false. -.TP -3 arguments -If the second argument is one of the binary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the result of the expression is the result of the binary test using -the first and third arguments as operands. -If the first argument is \fB!\fP, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly \fB(\fP and the third argument is -exactly \fB)\fP, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -in this case. -.TP -4 arguments -If the first argument is \fB!\fP, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. -.TP -5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -.RE -.PD -.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\-lp\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 the signal specified by each -.I sigspec -is ignored by the shell and by the commands it invokes. -If -.I arg -is not present and -.B \-p -has been supplied, then the trap commands associated with each -.I sigspec -are displayed. -If no arguments are supplied or if only -.B \-p -is given, -.B trap -prints the list of commands associated with each signal number. -The -.B \-l -option causes the shell to print a list of signal names and -their corresponding numbers. -Each -.I sigspec -is either -a signal name defined in <\fIsignal.h\fP>, or a signal number. -If a -.I sigspec -is -.SM -.B EXIT -(0) the command -.I arg -is executed on exit from the shell. -If a -.I sigspec -is -.SM -.BR DEBUG , -the command -.I arg -is executed before every \fIsimple command\fP, \fIfor\fP command, -\fIcase\fP command, \fIselect\fP command, every arithmetic \fIfor\fP -command, and before the first command executes in a shell function (see -.SM -.B SHELL GRAMMAR -above). -Refer to the description of the \fBextglob\fP option to the -\fBshopt\fP builtin for details of its effect on the \fBDEBUG\fP trap. -If a -.I sigspec -is -.SM -.BR ERR , -the command -.I arg -is executed whenever a simple command has a non\-zero exit status. -The -.SM -.B ERR -trap is not executed if the failed -command is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test in 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 ! . -If a -.I sigspec -is -.SM -.BR RETURN , -the command -.I arg -is executed each time a shell function or a script executed with the -\fB.\fP or \fBsource\fP builtins finishes executing. -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 any -.I sigspec -is invalid; otherwise -.B trap -returns true. -.TP -\fBtype\fP [\fB\-aftpP\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 \-t -option is used, -.B type -prints a string 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 -.I name -is not found, then nothing is printed, and an exit status of false -is returned. -If the -.B \-p -option 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 -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -The -.B \-P -option forces a -.SM -.B PATH -search for each \fIname\fP, even if -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -If a command is hashed, -.B \-p -and -.B \-P -print the hashed value, not necessarily the file that appears -first in -.SM -.BR PATH . -If the -.B \-a -option 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 \-p -option is not also used. -The table of hashed commands is not consulted -when using -.BR \-a . -The -.B \-f -option suppresses shell function lookup, as with the \fBcommand\fP builtin. -.B type -returns true if any of the arguments are found, false if -none are found. -.TP -\fBulimit\fP [\fB\-SHacdflmnpstuv\fP [\fIlimit\fP]] -Provides control over the resources available to the shell and to -processes started by it, on systems that allow such control. -The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is -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 \fB\-H\fP nor \fB\-S\fP is specified, both the soft and hard -limits are set. -The value of -.I limit -can be a number in the unit specified for the resource -or one of the special values -.BR hard , -.BR soft , -or -.BR unlimited , -which stand for the current hard limit, the current soft limit, and -no limit, respectively. -If -.I limit -is omitted, the current value of the soft limit of the resource is -printed, unless the \fB\-H\fP option is given. When more than one -resource is specified, the limit name and unit are printed before the value. -Other options are interpreted as follows: -.RS -.PD 0 -.TP -.B \-a -All current limits are reported -.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 \-l -The maximum size that may be locked into memory -.TP -.B \-m -The maximum resident set size -.TP -.B \-n -The maximum number of open file descriptors (most systems do not -allow this value to be set) -.TP -.B \-p -The pipe size in 512-byte blocks (this may not be set) -.TP -.B \-s -The maximum stack size -.TP -.B \-t -The maximum amount of cpu time in seconds -.TP -.B \-u -The maximum number of processes available to a single user -.TP -.B \-v -The maximum amount of virtual memory available to the shell -.PD -.PP -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 invalid option or argument is supplied, -or an error occurs while setting a new limit. -.RE -.TP -\fBumask\fP [\fB\-p\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, 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. -If the -.B \-p -option is supplied, and -.I mode -is omitted, the output is in a form that may be reused as input. -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 each \fIname\fP 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 function. -If no options are supplied, or the -.B \-v -option is given, each -.I name -refers to a shell variable. -Read-only variables may not be unset. -If -.B \-f -is specifed, -each -.I name -refers to a shell function, and the function definition -is removed. -Each unset variable or function is removed from the environment -passed to subsequent commands. -If any of -.SM -.BR RANDOM , -.SM -.BR SECONDS , -.SM -.BR LINENO , -.SM -.BR HISTCMD , -.SM -.BR FUNCNAME , -.SM -.BR GROUPS , -or -.SM -.B DIRSTACK -are unset, they lose their special properties, even if they are -subsequently reset. The exit status is true unless a -.I name -is readonly. -.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-existent process or job, the return status is -127. Otherwise, the return status is the exit status of the last -process or job waited for. -.\" bash_builtins -.if \n(zZ=1 .ig zZ -.SH "RESTRICTED SHELL" -.\" rbash.1 -.zY -.PP -If -.B bash -is started with the name -.BR rbash , -or the -.B \-r -option is supplied at invocation, -the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -It behaves identically to -.B bash -with the exception that the following are disallowed or not performed: -.IP \(bu -changing directories with \fBcd\fP -.IP \(bu -setting or unsetting the values of -.BR SHELL , -.BR PATH , -.BR ENV , -or -.B BASH_ENV -.IP \(bu -specifying command names containing -.B / -.IP \(bu -specifying a file name containing a -.B / -as an argument to the -.B . -builtin command -.IP \(bu -Specifying a filename containing a slash as an argument to the -.B \-p -option to the -.B hash -builtin command -.IP \(bu -importing function definitions from the shell environment at startup -.IP \(bu -parsing the value of \fBSHELLOPTS\fP from the shell environment at startup -.IP \(bu -redirecting output using the >, >|, <>, >&, &>, and >> redirection operators -.IP \(bu -using the -.B exec -builtin command to replace the shell with another command -.IP \(bu -adding or deleting builtin commands with the -.B \-f -and -.B \-d -options to the -.B enable -builtin command -.IP \(bu -Using the \fBenable\fP builtin command to enable disabled shell builtins -.IP \(bu -specifying the -.B \-p -option to the -.B command -builtin command -.IP \(bu -turning off restricted mode with -\fBset +r\fP or \fBset +o restricted\fP. -.PP -These restrictions are enforced after any startup files are read. -.PP -When a command that is found to be a shell script is executed (see -.SM -.B "COMMAND EXECUTION" -above), -.B rbash -turns off any restrictions in the shell spawned to execute the -script. -.\" end of rbash.1 -.if \n(zY=1 .ig zY -.SH "SEE ALSO" -.PD 0 -.TP -\fIBash Reference Manual\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 -\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 ~/.bash_logout -The individual login shell cleanup file, executed when a login shell exits -.TP -.FN ~/.inputrc -Individual \fIreadline\fP initialization file -.PD -.SH AUTHORS -Brian Fox, Free Software Foundation -.br -bfox@gnu.org -.PP -Chet Ramey, Case Western Reserve University -.br -chet@po.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 -.BR bash . -The latest version is always available from -\fIftp://ftp.gnu.org/pub/bash/\fP. -.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 encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to \fIbug-bash@gnu.org\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@po.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. -.PP -Shell builtin commands and functions are not stoppable/restartable. -.PP -Compound commands and command sequences of the form `a ; b ; c' -are not handled gracefully when process suspension is attempted. -When a process is stopped, the shell immediately executes the next -command in the sequence. -It suffices to place the sequence of commands between -parentheses to force it into a subshell, which may be stopped as -a unit. -.PP -Commands inside of \fB$(\fP...\fB)\fP command substitution are not -parsed until substitution is attempted. This will delay error -reporting until some time after the command is entered. -.PP -Array variables may not (yet) be exported. -.zZ -.zY diff --git a/doc/bash.1~ b/doc/bash.1~ deleted file mode 100644 index c10d5484a..000000000 --- a/doc/bash.1~ +++ /dev/null @@ -1,8740 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Information Network Services -.\" Case Western Reserve University -.\" chet@po.CWRU.Edu -.\" -.\" Last Change: Thu May 27 21:40:47 EDT 2004 -.\" -.\" bash_builtins, strip all but Built-Ins section -.if \n(zZ=1 .ig zZ -.if \n(zY=1 .ig zY -.TH BASH 1 "2004 May 27" "GNU Bash-3.0" -.\" -.\" 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-2004 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989-2004 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 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 options when it is invoked: -.PP -.PD 0 -.TP 10 -.BI \-c "\| string\^" -If the -.B \-c -option 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 -option is present, the shell is -.IR interactive . -.TP -.B \-l -Make -.B bash -act as if it had been invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-r -If the -.B \-r -option is present, the shell becomes -.I restricted -(see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-s -If the -.B \-s -option 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 \-D -A list of all double-quoted strings preceded by \fB$\fP -is printed on the standard ouput. -These are the strings that -are subject to language translation when the current locale -is not \fBC\fP or \fBPOSIX\fP. -This implies the \fB\-n\fP option; no commands will be executed. -.TP -.B [\-+]O [\fIshopt_option\fP] -\fIshopt_option\fP is one of the shell options accepted by the -\fBshopt\fP builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -If \fIshopt_option\fP is present, \fB\-O\fP sets the value of that option; -\fB+O\fP unsets it. -If \fIshopt_option\fP is not supplied, the names and values of the shell -options accepted by \fBshopt\fP are printed on the standard output. -If the invocation option is \fB+O\fP, the output is displayed in a format -that may be reused as input. -.TP -.B \-\- -A -.B \-\- -signals the end of options and disables further option processing. -Any arguments after the -.B \-\- -are treated as filenames and arguments. An argument of -.B \- -is equivalent to \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 -.B \-\-debugger -Arrange for the debugger profile to be executed before the shell -starts. Turns on extended debugging mode (see the description of the -.B extdebug -option to the -.B shopt -builtin below) and shell function tracing (see the description of the -\fB\-o functrace\fP option to the -.B set -builtin below). -.TP -.B \-\-dump\-po\-strings -Equivalent to \fB\-D\fP, but the output is in the GNU \fIgettext\fP -\fBpo\fP (portable object) file format. -.TP -.B \-\-dump\-strings -Equivalent to \fB\-D\fP. -.TP -.B \-\-help -Display a usage message on standard output and exit successfully. -.TP -\fB\-\-init\-file\fP \fIfile\fP -.PD 0 -.TP -\fB\-\-rcfile\fP \fIfile\fP -.PD -Execute commands from -.I file -instead of the standard personal initialization file -.I ~/.bashrc -if the shell is interactive (see -.SM -.B INVOCATION -below). -.TP -.B \-\-login -Equivalent to \fB\-l\fP. -.TP -.B \-\-noediting -Do not use the GNU -.B readline -library to read command lines when the shell is interactive. -.TP -.B \-\-noprofile -Do not read either the system-wide startup file -.FN /etc/profile -or any of the personal initialization files -.IR ~/.bash_profile , -.IR ~/.bash_login , -or -.IR ~/.profile . -By default, -.B bash -reads these files when it is invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-\-norc -Do not read and execute the personal initialization file -.I ~/.bashrc -if the shell is interactive. -This option is on by default if the shell is invoked as -.BR sh . -.TP -.B \-\-posix -Change the behavior of \fBbash\fP where the default operation differs -from the POSIX 1003.2 standard to match the standard (\fIposix mode\fP). -.TP -.B \-\-restricted -The shell becomes restricted (see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-\-verbose -Equivalent to \fB\-v\fP. -.TP -.B \-\-version -Show version information for this instance of -.B bash -on the standard output and exit successfully. -.PD -.SH ARGUMENTS -If arguments remain after option processing, and neither the -.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. -\fBBash\fP's exit status is the exit status of the last command -executed in the script. -If no commands are executed, the exit status is 0. -An attempt is first made to open the file in the current directory, and, -if no file is found, then the shell searches the directories in -.SM -.B PATH -for the script. -.SH INVOCATION -A \fIlogin shell\fP is one whose first character of argument zero is a -.BR \- , -or one started with the -.B \-\-login -option. -.PP -An \fIinteractive\fP shell is one started without non-option arguments -and without the -.B \-c -option -whose standard input and output are -both connected to terminals (as determined by -.IR isatty (3)), -or one started with the -.B \-i -option. -.SM -.B PS1 -is set and -.B $\- -includes -.B i -if -.B bash -is interactive, -allowing a shell script or a startup file to test this state. -.PP -The following paragraphs describe how -.B bash -executes its startup files. -If any of the files exist but cannot be read, -.B bash -reports an error. -Tildes are expanded in file names as described below under -.B "Tilde Expansion" -in the -.SM -.B EXPANSION -section. -.PP -When -.B bash -is invoked as an interactive login shell, or as a non-interactive shell -with the \fB\-\-login\fP option, it first reads and -executes commands from the file \fI/etc/profile\fP, if that -file exists. -After reading that file, it looks for \fI~/.bash_profile\fP, -\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads -and executes commands from the first one that exists and is readable. -The -.B \-\-noprofile -option may be used when the shell is started to inhibit this behavior. -.PP -When a login shell exits, -.B bash -reads and executes commands from the file \fI~/.bash_logout\fP, if it -exists. -.PP -When an interactive shell that is not a login shell is started, -.B bash -reads and executes commands from \fI~/.bashrc\fP, if that file exists. -This may be inhibited by using the -.B \-\-norc -option. -The \fB\-\-rcfile\fP \fIfile\fP option will force -.B bash -to read and execute commands from \fIfile\fP instead of \fI~/.bashrc\fP. -.PP -When -.B bash -is started non-interactively, to run a shell script, for example, it -looks for the variable -.SM -.B BASH_ENV -in the environment, expands its value if it appears there, and uses the -expanded value as the name of a file to read and execute. -.B Bash -behaves as if the following command were executed: -.sp .5 -.RS -.if t \f(CWif [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\fP -.if n if [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi -.RE -.sp .5 -but the value of the -.SM -.B PATH -variable is not used to search for the file name. -.PP -If -.B bash -is invoked with the name -.BR sh , -it tries to mimic the startup behavior of historical versions of -.B sh -as closely as possible, -while conforming to the POSIX standard as well. -When invoked as an interactive login shell, or a non-interactive -shell with the \fB\-\-login\fP option, it first attempts to -read and execute commands from -.I /etc/profile -and -.IR ~/.profile , -in that order. -The -.B \-\-noprofile -option may be used to inhibit this behavior. -When invoked as an interactive shell with the name -.BR sh , -.B bash -looks for the variable -.SM -.BR ENV , -expands its value if it is defined, and uses the -expanded value as the name of a file to read and execute. -Since a shell invoked as -.B sh -does not attempt to read and execute commands from any other startup -files, the -.B \-\-rcfile -option has no effect. -A non-interactive shell invoked with the name -.B sh -does not attempt to read any other startup files. -When invoked as -.BR sh , -.B bash -enters -.I posix -mode after the startup files are read. -.PP -When -.B bash -is started in -.I posix -mode, as with the -.B \-\-posix -command line option, it follows the POSIX standard for startup files. -In this mode, interactive shells expand the -.SM -.B ENV -variable and commands are read and executed from the file -whose name is the expanded value. -No other startup files are read. -.PP -.B Bash -attempts to determine when it is being run by the remote shell -daemon, usually \fIrshd\fP. -If -.B bash -determines it is being run by \fIrshd\fP, it reads and executes -commands from \fI~/.bashrc\fP, if that file exists and is readable. -It will not do this if invoked as \fBsh\fP. -The -.B \-\-norc -option may be used to inhibit this behavior, and the -.B \-\-rcfile -option may be used to force another file to be read, but -\fIrshd\fP does not generally invoke the shell with those options -or allow them to be specified. -.PP -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, no startup -files are read, shell functions are not inherited from the environment, the -.SM -.B SHELLOPTS -variable, if it appears in the environment, is ignored, -and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. -.SH DEFINITIONS -.PP -The following definitions are used throughout the rest of this -document. -.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 { } time [[ ]] -.if t ! case do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t .RE -.RE -.SH "SHELL GRAMMAR" -.SS Simple Commands -.PP -A \fIsimple command\fP is a sequence of optional variable assignments -followed by \fBblank\fP-separated words and redirections, and -terminated by a \fIcontrol operator\fP. The first word -specifies the command to be executed, and is passed as argument zero. -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 -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ] -.RE -.PP -The standard output of -.I command -is connected via a pipe to the standard input of -.IR command2 . -This connection is performed before any redirections specified by the -command (see -.SM -.B REDIRECTION -below). -.PP -The return status of a pipeline is the exit status of the last -command, unless the \fBpipefail\fP option is enabled. -If \fBpipefail\fP is enabled, the pipeline's return status is the -value of the last (rightmost) command to exit with a non-zero status, -or zero if all commands exit successfully. -If the reserved word -.B ! -precedes a pipeline, the exit status of that pipeline is the logical -negation of the exit status as described above. -The shell waits for all commands in the pipeline to -terminate before returning a value. -.PP -If the -.B time -reserved word precedes a pipeline, the elapsed as well as user and -system time consumed by its execution are reported when the pipeline -terminates. -The \fB\-p\fP option changes the output format to that specified by POSIX. -The -.SM -.B TIMEFORMAT -variable may be set to a format string that specifies how the timing -information should be displayed; see the description of -.SM -.B TIMEFORMAT -under -.B "Shell Variables" -below. -.PP -Each command in a pipeline is executed as a separate process (i.e., in a -subshell). -.SS Lists -.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 optionally 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 -A sequence of one or more newlines may appear in a \fIlist\fP instead -of a semicolon to delimit commands. -.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 -\fIcommand1\fP \fB&&\fP \fIcommand2\fP -.RE -.PP -.I command2 -is executed if, and only if, -.I command1 -returns an exit status of zero. -.PP -An OR list has the form -.RS -.PP -\fIcommand1\fP \fB\(bv\(bv\fP \fIcommand2\fP -.PP -.RE -.PP -.I command2 -is executed if and only if -.I command1 -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 environment (see -.SM -\fBCOMMAND EXECUTION ENVIRONMENT\fP -below). -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. -\fIlist\fP must be terminated with a newline or semicolon. -This is known as a \fIgroup command\fP. -The return status is the exit status of -\fIlist\fP. -Note that unlike the metacharacters \fB(\fP and \fB)\fP, \fB{\fP and -\fB}\fP are \fIreserved words\fP and must occur where a reserved -word is permitted to be recognized. Since they do not cause a word -break, they must be separated from \fIlist\fP by whitespace. -.TP -((\fIexpression\fP)) -The \fIexpression\fP is evaluated according to the rules described -below under -.SM -.BR "ARITHMETIC EVALUATION" . -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -\fBlet "\fIexpression\fP"\fR. -.TP -\fB[[\fP \fIexpression\fP \fB]]\fP -Return a status of 0 or 1 depending on the evaluation of -the conditional expression \fIexpression\fP. -Expressions are composed of the primaries described below under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -Word splitting and pathname expansion are not performed on the words -between the \fB[[\fP and \fB]]\fP; tilde expansion, parameter and -variable expansion, arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as \fB\-f\fP must be unquoted to be recognized -as primaries. -.if t .sp 0.5 -.if n .sp 1 -When the \fB==\fP and \fB!=\fP operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below under \fBPattern Matching\fP. -The return value is 0 if the string matches or does not match -the pattern, respectively, and 1 otherwise. -Any part of the pattern may be quoted to force it to be matched as a -string. -.if t .sp 0.5 -.if n .sp 1 -An additional binary operator, \fB=~\fP, is available, with the same -precedence as \fB==\fP and \fB!=\fP. -When it is used, the string to the right of the operator is considered -an extended regular expression and matched accordingly (as in \fIregex\fP(3)). -The return value is 0 if the string matches -the pattern, and 1 otherwise. -If the regular expression is syntactically incorrect, the conditional -expression's return value is 2. -If the shell option -.B nocaseglob -is enabled, the match is performed without regard to the case -of alphabetic characters. -Substrings matched by parenthesized subexpressions within the regular -expression are saved in the array variable \fBBASH_REMATCH\fP. -The element of \fBBASH_REMATCH\fP with index 0 is the portion of the string -matching the entire regular expression. -The element of \fBBASH_REMATCH\fP with index \fIn\fP is the portion of the -string matching the \fIn\fPth parenthesized subexpression. -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence: -.if t .sp 0.5 -.if n .sp 1 -.RS -.PD 0 -.TP -.B ( \fIexpression\fP ) -Returns the value of \fIexpression\fP. -This may be used to override the normal precedence of operators. -.TP -.B ! \fIexpression\fP -True if -.I expression -is false. -.TP -\fIexpression1\fP \fB&&\fP \fIexpression2\fP -True if both -.I expression1 -and -.I expression2 -are true. -.TP -.if t \fIexpression1\fP \fB\(bv\(bv\fP \fIexpression2\fP -.if n \fIexpression1\fP \fB||\fP \fIexpression2\fP -True if either -.I expression1 -or -.I expression2 -is true. -.PD -.LP -The \fB&&\fP and -.if t \fB\(bv\(bv\fP -.if n \fB||\fP -operators do not evaluate \fIexpression2\fP if the value of -\fIexpression1\fP is sufficient to determine the return value of -the entire conditional expression. -.RE -.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). -The return status is the exit status of the last command that executes. -If the expansion of the items following \fBin\fP results in an empty -list, no commands are executed, and the return status is 0. -.TP -\fBfor\fP (( \fIexpr1\fP ; \fIexpr2\fP ; \fIexpr3\fP )) ; \fBdo\fP \fIlist\fP ; \fBdone\fP -First, the arithmetic expression \fIexpr1\fP is evaluated according -to the rules described below under -.SM -.BR "ARITHMETIC EVALUATION" . -The arithmetic expression \fIexpr2\fP is then evaluated repeatedly -until it evaluates to zero. -Each time \fIexpr2\fP evaluates to a non-zero value, \fIlist\fP is -executed and the arithmetic expression \fIexpr3\fP is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in \fIlist\fP -that is executed, or false if any of the expressions is invalid. -.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 a number corresponding to one of -the displayed words, then the value of -.I name -is set to that word. If the line is empty, the words and prompt -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 -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 -pattern matches. Otherwise, it is the exit status of the -last command executed in \fIlist\fP. -.TP -\fBif\fP \fIlist\fP; \fBthen\fP \fIlist;\fP \ -[ \fBelif\fP \fIlist\fP; \fBthen\fP \fIlist\fP; ] ... \ -[ \fBelse\fP \fIlist\fP; ] \fBfi\fP -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 -\fBwhile\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP -.PD 0 -.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. -.SS Shell Function Definitions -.PP -A shell function is an object that is called like a simple command and -executes a compound command with a new set of positional parameters. -Shell functions are declared as follows: -.TP -[ \fBfunction\fP ] \fIname\fP () \fIcompound\-command\fP [\fIredirection\fP] -This defines a function named \fIname\fP. -The reserved word \fBfunction\fP is optional. -If the \fBfunction\fP reserved word is supplied, the parentheses are optional. -The \fIbody\fP of the function is the compound command -.I compound\-command -(see \fBCompound Commands\fP above). -That command is usually a \fIlist\fP of commands between { and }, but -may be any command listed under \fBCompound Commands\fP above. -\fIcompound\-command\fP is executed whenever \fIname\fP is specified as the -name of a simple command. -Any redirections (see -.SM -.B REDIRECTION -below) specified when a function is defined are performed -when the function is executed. -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -last command executed in the body. (See -.SM -.B FUNCTIONS -below.) -.SH COMMENTS -In a non-interactive shell, or an interactive shell in which the -.B interactive_comments -option to the -.B shopt -builtin is enabled (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), a word beginning with -.B # -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the -.B interactive_comments -option enabled does not allow comments. The -.B interactive_comments -option is on by default in interactive shells. -.SH QUOTING -\fIQuoting\fP is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -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 it is to -represent itself. -.PP -When the command history expansion facilities are being used, the -\fIhistory expansion\fP character, usually \fB!\fP, must be quoted -to prevent history expansion. -.PP -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 itself quoted, the \fB\e\fP -is treated as a line continuation (that is, it is removed from the -input stream and 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. -When command history is being used, the double quote may not be used to -quote the history expansion character. -.PP -The special parameters -.B * -and -.B @ -have special meaning when in double -quotes (see -.SM -.B PARAMETERS -below). -.PP -Words of the form \fB$\fP'\fIstring\fP' are treated specially. The -word expands to \fIstring\fP, with backslash-escaped characters replaced -as specifed by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ee -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e' -single quote -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.TP -.B \ec\fIx\fP -a control-\fIx\fP character -.PD -.RE -.LP -The expanded result is single-quoted, as if the dollar sign had -not been present. -.PP -A double-quoted string preceded by a dollar sign (\fB$\fP) will cause -the string to be translated according to the current locale. -If the current locale is \fBC\fP or \fBPOSIX\fP, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. -.SH PARAMETERS -A -.I parameter -is an entity that stores values. -It can be a -.IR name , -a number, or one of the special characters listed below under -.BR "Special Parameters" . -A -.I variable -is a parameter denoted by a -.IR name . -A variable has a \fIvalue\fP and zero or more \fIattributes\fP. -Attributes are assigned using the -.B declare -builtin command (see -.B declare -below in -.SM -.BR "SHELL BUILTIN COMMANDS" ). -.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 (see -.SM -.B EXPANSION -below). If the variable has its -.B integer -attribute set, then -.I value -is evaluated as an arithmetic expression even if the $((...)) expansion is -not used (see -.B "Arithmetic Expansion" -below). -Word splitting is not performed, with the exception -of \fB"$@"\fP as explained below under -.BR "Special Parameters" . -Pathname expansion is not performed. -Assignment statements may also appear as arguments to the -.BR alias , -.BR declare , -.BR typeset , -.BR export , -.BR readonly , -and -.B local -builtin commands. -.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 unset, the parameters are separated by spaces. -If -.SM -.B IFS -is null, the parameters are joined without intervening separators. -.TP -.B @ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, "\fB$@\fP" is equivalent to -"\fB$1\fP" "\fB$2\fP" ... -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 -option). -.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 file name used to invoke -.BR bash , -as given by argument zero. -.TP -.B _ -At shell startup, set to the absolute file name of the shell or shell -script being executed as passed in the argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full file name of each command executed and placed in -the environment exported to that command. -When checking mail, this parameter holds the name of the mail file -currently being checked. -.PD -.SS Shell Variables -.PP -The following variables are set by the shell: -.PP -.PD 0 -.TP -.B BASH -Expands to the full file name used to invoke this instance of -.BR bash . -.TP -.B BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current bash execution call stack. The number of -parameters to the current subroutine (shell function or script executed -with \fB.\fP or \fBsource\fP) is at the top of the stack. When a -subroutine is executed, the number of parameters passed is pushed onto -\fBBASH_ARGC\fP. -.TP -.B BASH_ARGV -An array variable containing all of the parameters in the current bash -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto \fBBASH_ARGV\fP. -.TP -.B BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. -.TP -.B BASH_EXECUTION_STRING -The command argument to the \fB\-c\fP invocation option. -.TP -.B BASH_LINENO -An array variable whose members are the line numbers in source files -corresponding to each member of @var{FUNCNAME}. -\fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -file where \fB${FUNCNAME[\fP\fI$i + 1\fP\fB]}\fP was called. -The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i + 1\fP\fB]}\fB. -Use \fBLINENO\fP to obtain the current line number. -.TP -.B BASH_REMATCH -An array variable whose members are assigned by the \fB=~\fP binary -operator to the \fB[[\fP conditional command. -The element with index 0 is the portion of the string -matching the entire regular expression. -The element with index \fIn\fP is the portion of the -string matching the \fIn\fPth parenthesized subexpression. -This variable is read-only. -.TP -.B BASH_SOURCE -An array variable whose members are the source filenames corresponding -to the elements in the \fBFUNCNAME\fP array variable. -.TP -.B BASH_SUBSHELL -Incremented by one each time a subshell or subshell environment is spawned. -The initial value is 0. -.TP -.B BASH_VERSINFO -A readonly array variable whose members hold version information for -this instance of -.BR bash . -The values assigned to the array members are as follows: -.sp .5 -.RS -.PD 0 -.TP 24 -.B BASH_VERSINFO[\fR0\fP] -The major version number (the \fIrelease\fP). -.TP -.B BASH_VERSINFO[\fR1\fP] -The minor version number (the \fIversion\fP). -.TP -.B BASH_VERSINFO[\fR2\fP] -The patch level. -.TP -.B BASH_VERSINFO[\fR3\fP] -The build version. -.TP -.B BASH_VERSINFO[\fR4\fP] -The release status (e.g., \fIbeta1\fP). -.TP -.B BASH_VERSINFO[\fR5\fP] -The value of \fBMACHTYPE\fP. -.PD -.RE -.TP -.B BASH_VERSION -Expands to a string describing the version of this instance of -.BR bash . -.TP -.B COMP_CWORD -An index into \fB${COMP_WORDS}\fP of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to \fB${#COMP_LINE}\fP. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_WORDBREAKS -The set of characters that the Readline library treats as word -separators when performing word completion. -If -.SM -.B COMP_WORDBREAKS -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B COMP_WORDS -An array variable (see \fBArrays\fP below) consisting of the individual -words in the current command line. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B DIRSTACK -An array variable (see -.B Arrays -below) containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -.B dirs -builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the -.B pushd -and -.B popd -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If -.SM -.B DIRSTACK -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B EUID -Expands to the effective user ID of the current user, initialized at -shell startup. This variable is readonly. -.TP -.B FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element is "main". -This variable exists only when a shell function is executing. -Assignments to -.SM -.B FUNCNAME -have no effect and return an error status. -If -.SM -.B FUNCNAME -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to -.SM -.B GROUPS -have no effect and return an error status. -If -.SM -.B GROUPS -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 HOSTNAME -Automatically set to the name of the current host. -.TP -.B HOSTTYPE -Automatically set to a string that uniquely -describes the type of machine on which -.B bash -is executing. -The default is system-dependent. -.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. -If -.SM -.B LINENO -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B MACHTYPE -Automatically set to a string that fully describes the system -type on which -.B bash -is executing, in the standard GNU \fIcpu-company-system\fP format. -The default is system-dependent. -.TP -.B OLDPWD -The previous working directory as set by the -.B cd -command. -.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 OSTYPE -Automatically set to a string that -describes the operating system on which -.B bash -is executing. -The default is system-dependent. -.TP -.B PIPESTATUS -An array variable (see -.B Arrays -below) containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). -.TP -.B PPID -The process ID of the shell's parent. This variable is readonly. -.TP -.B PWD -The current working directory as set by the -.B cd -command. -.TP -.B RANDOM -Each time this parameter is referenced, a random integer between -0 and 32767 is -generated. The sequence of random numbers may be initialized by assigning -a value to -.SM -.BR RANDOM . -If -.SM -.B RANDOM -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B REPLY -Set to the line of input read by the -.B read -builtin command when no arguments are supplied. -.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 SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the -.B \-o -option to the -.B set -builtin command (see -.SM -.B "SHELL BUILTIN COMMANDS" -below). The options appearing in -.SM -.B SHELLOPTS -are those reported as -.I on -by \fBset \-o\fP. -If this variable is in the environment when -.B bash -starts up, each shell option in the list will be enabled before -reading any startup files. -This variable is read-only. -.TP -.B SHLVL -Incremented by one each time an instance of -.B bash -is started. -.TP -.B UID -Expands to the user ID of the current user, initialized at shell startup. -This variable is readonly. -.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 BASH_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 BASH_ENV -is subjected to parameter expansion, command substitution, and arithmetic -expansion before being interpreted as a file name. -.SM -.B PATH -is not used to search for the resultant file name. -.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 -.if t \f(CW".:~:/usr"\fP. -.if n ".:~:/usr". -.TP -.B COLUMNS -Used by the \fBselect\fP builtin command to determine the terminal width -when printing selection lists. Automatically set upon receipt of a SIGWINCH. -.TP -.B COMPREPLY -An array variable from which \fBbash\fP reads the possible completions -generated by a shell function invoked by the programmable completion -facility (see \fBProgrammable Completion\fP below). -.TP -.B EMACS -If \fBbash\fP finds this variable in the environment when the shell starts -with value -.if t \f(CWt\fP, -.if n "t", -it assumes that the shell is running in an emacs shell buffer and disables -line editing. -.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 -.if t \f(CW".o:~"\fP. -.if n ".o:~". -.TP -.B GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by pathname expansion. -If a filename matched by a pathname expansion pattern also matches one -of the patterns in -.SM -.BR GLOBIGNORE , -it is removed from the list of matches. -.TP -.B HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes -.IR ignorespace , -lines which begin with a -.B space -character are not saved in the history list. -A value of -.I ignoredups -causes lines matching the previous history entry to not be saved. -A value of -.I ignoreboth -is shorthand for \fIignorespace\fP and \fIignoredups\fP. -A value of -.IR erasedups -causes all previous lines matching the current line to be removed from -the history list before that line is saved. -Any value not in the above list is ignored. -If \fBHISTCONTROL\fP is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of -.BR HISTIGNORE . -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.BR HISTCONTROL . -.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. The history file is also truncated to this size after -writing it when an interactive shell exits. -.TP -.B HISTIGNORE -A colon-separated list of patterns used to decide which command lines -should be saved on the history list. Each pattern is anchored at the -beginning of the line and must match the complete line (no implicit -`\fB*\fP' is appended). Each pattern is tested against the line -after the checks specified by -.B HISTCONTROL -are applied. -In addition to the normal shell pattern matching characters, `\fB&\fP' -matches the previous history line. `\fB&\fP' may be escaped using a -backslash; the backslash is removed before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.BR HISTIGNORE . -.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 HISTTIMEFORMAT -If this variable is set and not null, its value is used as a format string -for \fIstrftime\fP(3) to print the time stamp associated with each history -entry displayed by the \fBhistory\fP builtin. -If this variable is set, time stamps are written to the history file so -they may be preserved across shell sessions. -.TP -.B HOME -The home directory of the current user; the default argument for the -\fBcd\fP builtin command. -The value of this variable is also used when performing tilde expansion. -.TP -.B HOSTFILE -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 list of possible hostname completions may be changed while the -shell is running; -the next time hostname completion is attempted after the -value is changed, -.B bash -adds the contents of the new file to the existing list. -If -.SM -.B HOSTFILE -is set, but has no value, \fBbash\fP attempts to read -.FN /etc/hosts -to obtain the list of possible hostname completions. -When -.SM -.B HOSTFILE -is unset, the hostname list is cleared. -.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 IGNOREEOF -Controls the -action of an interactive shell on receipt of an -.SM -.B EOF -character as the sole input. If set, the value is the number of -consecutive -.SM -.B EOF -characters which must be -typed as the first characters on an input line before -.B bash -exits. If the variable exists but does not have a numeric value, or -has no value, the default value is 10. If it does not exist, -.SM -.B EOF -signifies the end of input to the shell. -.TP -.B INPUTRC -The filename for the -.B readline -startup file, overriding the default of -.FN ~/.inputrc -(see -.SM -.B READLINE -below). -.TP -.B LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with \fBLC_\fP. -.TP -.B LC_ALL -This variable overrides the value of \fBLANG\fP and any other -\fBLC_\fP variable specifying a locale category. -.TP -.B LC_COLLATE -This variable determines the collation order used when sorting the -results of pathname expansion, and determines the behavior of range -expressions, equivalence classes, and collating sequences within -pathname expansion and pattern matching. -.TP -.B LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within pathname expansion and pattern -matching. -.TP -.B LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a \fB$\fP. -.TP -.B LC_NUMERIC -This variable determines the locale category used for number formatting. -.TP -.B LINES -Used by the \fBselect\fP builtin command to determine the column length -for printing selection lists. Automatically set upon receipt of a SIGWINCH. -.TP -.B MAIL -If this parameter is set to a file name 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 displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. -.TP -.B MAILPATH -A colon-separated list of file names to be checked for mail. -The message to be printed when mail arrives in a particular file -may be specified by separating the file name from the message with a `?'. -When used in the text of the message, \fB$_\fP expands to the name of -the current mailfile. -Example: -.RS -.PP -\fBMAILPATH\fP='/var/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., /var/mail/\fB$USER\fP). -.RE -.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 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). -A zero-length (null) directory name in the value of \fBPATH\fP indicates the -current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. -The default path is system-dependent, -and is set by the administrator who installs -.BR bash . -A common value is -.if t \f(CW/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin\fP. -.if n ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin''. -.TP -.B POSIXLY_CORRECT -If this variable is in the environment when \fBbash\fP starts, the shell -enters \fIposix mode\fP before reading the startup files, as if the -.B \-\-posix -invocation option had been supplied. If it is set while the shell is -running, \fBbash\fP enables \fIposix mode\fP, as if the command -.if t \f(CWset -o posix\fP -.if n \fIset -o posix\fP -had been executed. -.TP -.B PROMPT_COMMAND -If set, the value is executed as a command prior to issuing each primary -prompt. -.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 -``\fB\es\-\ev\e$ \fP''. -.TP -.B PS2 -The value of this parameter is expanded as with -.B PS1 -and used as the secondary prompt string. The default is -``\fB> \fP''. -.TP -.B PS3 -The value of this parameter is used as the prompt for the -.B select -command (see -.SM -.B SHELL GRAMMAR -above). -.TP -.B PS4 -The value of this parameter is expanded as with -.B PS1 -and the value is printed before each command -.B bash -displays during an execution trace. The first character of -.SM -.B PS4 -is replicated multiple times, as necessary, to indicate multiple -levels of indirection. The default is ``\fB+ \fP''. -.TP -.B SHELL -The full pathname to the shell is kept in this environment variable. -If it is not set when the shell starts, -.B bash -assigns to it the full pathname of the current user's login shell. -.TP -.B TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the -.B time -reserved word should be displayed. -The \fB%\fP character introduces an escape sequence that is -expanded to a time value or other information. -The escape sequences and their meanings are as follows; the -braces denote optional portions. -.sp .5 -.RS -.PD 0 -.TP 10 -.B %% -A literal \fB%\fP. -.TP -.B %[\fIp\fP][l]R -The elapsed time in seconds. -.TP -.B %[\fIp\fP][l]U -The number of CPU seconds spent in user mode. -.TP -.B %[\fIp\fP][l]S -The number of CPU seconds spent in system mode. -.TP -.B %P -The CPU percentage, computed as (%U + %S) / %R. -.PD -.RE -.IP -The optional \fIp\fP is a digit specifying the \fIprecision\fP, -the number of fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; -values of \fIp\fP greater than 3 are changed to 3. -If \fIp\fP is not specified, the value 3 is used. -.IP -The optional \fBl\fP specifies a longer format, including -minutes, of the form \fIMM\fPm\fISS\fP.\fIFF\fPs. -The value of \fIp\fP determines whether or not the fraction is -included. -.IP -If this variable is not set, \fBbash\fP acts as if it had the -value \fB$'\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS'\fP. -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. -.TP -.B TMOUT -If set to a value greater than zero, \fBTMOUT\fP is treated as the -default timeout for the \fBread\fP builtin. -The \fBselect\fP command terminates if input does not arrive -after \fBTMOUT\fP seconds when input is coming from a terminal. -In an interactive shell, 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 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 identifier (see -.SM -.B JOB CONTROL -below). If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the -.B % -job identifier. -.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 \fIhistory expansion\fP character, -the character which signals the start of a history -expansion, normally `\fB!\fP'. -The second character is the \fIquick substitution\fP -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 indicates 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. -.PD -.SS Arrays -.B Bash -provides one-dimensional array variables. Any variable may be used as -an array; the -.B declare -builtin will explicitly declare an array. There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. Arrays are indexed using -integers and are zero-based. -.PP -An array is created automatically if any variable is assigned to using -the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The -.I subscript -is treated as an arithmetic expression that must evaluate to a number -greater than or equal to zero. To explicitly declare an array, use -.B declare \-a \fIname\fP -(see -.SM -.B SHELL BUILTIN COMMANDS -below). -.B declare \-a \fIname\fP[\fIsubscript\fP] -is also accepted; the \fIsubscript\fP is ignored. Attributes may be -specified for an array variable using the -.B declare -and -.B readonly -builtins. Each attribute applies to all members of an array. -.PP -Arrays are assigned to using compound assignments of the form -\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each -\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. Only -\fIstring\fP is required. If -the optional brackets and subscript are supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. -This syntax is also accepted by the -.B declare -builtin. Individual array elements may be assigned to using the -\fIname\fP[\fIsubscript\fP]=\fIvalue\fP syntax introduced above. -.PP -Any element of an array may be referenced using -${\fIname\fP[\fIsubscript\fP]}. The braces are required to avoid -conflicts with pathname expansion. If -\fIsubscript\fP is \fB@\fP or \fB*\fP, the word expands to -all members of \fIname\fP. These subscripts differ only when the -word appears within double quotes. If the word is double-quoted, -${\fIname\fP[*]} expands to a single -word with the value of each array member separated by the first -character of the -.SM -.B IFS -special variable, and ${\fIname\fP[@]} expands each element of -\fIname\fP to a separate word. When there are no array members, -${\fIname\fP[@]} expands to nothing. This is analogous to the expansion -of the special parameters \fB*\fP and \fB@\fP (see -.B Special Parameters -above). ${#\fIname\fP[\fIsubscript\fP]} expands to the length of -${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or -\fB@\fP, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing element zero. -.PP -The -.B unset -builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] -destroys the array element at index \fIsubscript\fP. -\fBunset\fP \fIname\fP, where \fIname\fP is an array, or -\fBunset\fP \fIname\fP[\fIsubscript\fP], where -\fIsubscript\fP is \fB*\fP or \fB@\fP, removes the entire array. -.PP -The -.BR declare , -.BR local , -and -.B readonly -builtins each accept a -.B \-a -option to specify an array. The -.B read -builtin accepts a -.B \-a -option to assign a list of words read from the standard input -to an array. The -.B set -and -.B declare -builtins display array values in a way that allows them to be -reused as assignments. -.SH EXPANSION -Expansion is performed on the command line after it has been split into -words. There are seven kinds of expansion performed: -.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 and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and pathname -expansion. -.PP -On systems that can support it, there is an additional expansion -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 only exceptions to this are the expansions of -"\fB$@\fP" and "\fB${\fP\fIname\fP\fB[@]}\fP" -as explained above (see -.SM -.BR PARAMETERS ). -.SS Brace Expansion -.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 either a series of comma-separated strings or -a sequence expression between a pair of braces, followed by -an optional -.IR postscript . -The preamble is prefixed to each string contained -within the braces, and the postscript 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 -A sequence expression takes the form \fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB}\fP, -where \fIx\fP and \fIy\fP are either integers or single characters. -When integers are supplied, the expression expands to each number between -\fIx\fP and \fIy\fP, inclusive. -When characters are supplied, the expression expands to each character -lexicographically between \fIx\fP and \fIy\fP, inclusive. Note that -both \fIx\fP and \fIy\fP must be of the same type. -.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 or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. -A \fB{\fP or \fB,\fP may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string \fB${\fP -is not considered eligible for brace expansion. -.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 -historical versions of -.BR sh . -.B sh -does not treat opening or closing braces specially when they -appear as part of a word, and preserves them in the output. -.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 +B -option or disable brace expansion with the -.B +B -option to the -.B set -command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS Tilde Expansion -.PP -If a word begins with an unquoted tilde character (`\fB~\fP'), all of -the characters preceding the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a \fItilde-prefix\fP. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible \fIlogin name\fP. -If this login name is the null string, the tilde is replaced with the -value of the shell parameter -.SM -.BR HOME . -If -.SM -.B HOME -is unset, the home directory of the user executing the shell is -substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. -.PP -If the tilde-prefix is a `~+', the value of the shell variable -.SM -.B PWD -replaces the tilde-prefix. -If the tilde-prefix is a `~\-', the value of the shell variable -.SM -.BR OLDPWD , -if it is set, is substituted. -If the characters following the tilde in the tilde-prefix consist -of a number \fIN\fP, optionally prefixed -by a `+' or a `\-', the tilde-prefix is replaced with the corresponding -element from the directory stack, as it would be displayed by the -.B dirs -builtin invoked with the tilde-prefix as an argument. -If the characters following the tilde in the tilde-prefix consist of a -number without a leading `+' or `\-', `+' is assumed. -.PP -If the login name is invalid, or the tilde expansion fails, the word -is unchanged. -.PP -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a -.B : -or -.BR = . -In these cases, tilde expansion is also performed. -Consequently, one may use file names 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 -When braces are used, the matching ending brace is the first `\fB}\fP' -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or paramter -expansion. -.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 -If the first character of \fIparameter\fP is an exclamation point, -a level of variable indirection is introduced. -\fBBash\fP uses the value of the variable formed from the rest of -\fIparameter\fP as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of \fIparameter\fP itself. -This is known as \fIindirect expansion\fP. -The exceptions to this are the expansions of ${!\fIprefix\fP*} and -${\fB!\fP\fIname\fP[\fI@\fP]} described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. -.PP -In each of the cases below, \fIword\fP is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. -When not performing substring expansion, \fBbash\fP tests for a parameter -that is unset or null; omitting the colon results in a test only for a -parameter that is unset. -.PP -.PD 0 -.TP -${\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 -${\fIparameter\fP\fB:\fP\fIoffset\fP} -.PD 0 -.TP -${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP} -.PD -\fBSubstring Expansion.\fP -Expands to up to \fIlength\fP characters of \fIparameter\fP -starting at the character specified by \fIoffset\fP. -If \fIlength\fP is omitted, expands to the substring of -\fIparameter\fP starting at the character specified by \fIoffset\fP. -\fIlength\fP and \fIoffset\fP are arithmetic expressions (see -.SM -.B -ARITHMETIC EVALUATION -below). -\fIlength\fP must evaluate to a number greater than or equal to zero. -If \fIoffset\fP evaluates to a number less than zero, the value -is used as an offset from the end of the value of \fIparameter\fP. -If \fIparameter\fP is \fB@\fP, the result is \fIlength\fP positional -parameters beginning at \fIoffset\fP. -If \fIparameter\fP is an array name indexed by @ or *, -the result is the \fIlength\fP -members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1. -.TP -${\fB!\fP\fIprefix\fP\fB*\fP} -.PD 0 -.TP -${\fB!\fP\fIprefix\fP\fB@\fP} -.PD -Expands to the names of variables whose names begin with \fIprefix\fP, -separated by the first character of the -.SM -.B IFS -special variable. -.TP -${\fB!\fP\fIname\fP[\fI@\fP]} -.PD 0 -.TP -${\fB!\fP\fIname\fP[\fI*\fP]} -.PD -If \fIname\fP is an array variable, expands to the list of array indices -(keys) assigned in \fIname\fP. -If \fIname\fP is not an array, expands to 0 if \fIname\fP is set and null -otherwise. -When \fI@\fP is used and the expansion appears within double quotes, each -key expands to a separate word. -.TP -${\fB#\fP\fIparameter\fP} -The length in characters of the value of \fIparameter\fP is substituted. -If -.I parameter -is -.B * -or -.BR @ , -the value substituted is the number of positional parameters. -If -.I parameter -is an array name subscripted by -.B * -or -.BR @ , -the value substituted is the number of elements in the array. -.TP -${\fIparameter\fP\fB#\fP\fIword\fP} -.PD 0 -.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 result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB#\fP'' case) or the -longest matching pattern (the ``\fB##\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB%\fP\fIword\fP} -.PD 0 -.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 expanded value of -.IR parameter , -then the result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB%\fP'' case) or the -longest matching pattern (the ``\fB%%\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB/\fP\fIpattern\fP\fB/\fP\fIstring\fP} -.PD 0 -.TP -${\fIparameter\fP\fB//\fP\fIpattern\fP\fB/\fP\fIstring\fP} -.PD -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -\fIParameter\fP is expanded and the longest match of \fIpattern\fP -against its value is replaced with \fIstring\fP. -In the first form, only the first match is replaced. -The second form causes all matches of \fIpattern\fP to be -replaced with \fIstring\fP. -If \fIpattern\fP begins with \fB#\fP, it must match at the beginning -of the expanded value of \fIparameter\fP. -If \fIpattern\fP begins with \fB%\fP, it must match at the end -of the expanded value of \fIparameter\fP. -If \fIstring\fP is null, matches of \fIpattern\fP are deleted -and the \fB/\fP following \fIpattern\fP may be omitted. -If -.I parameter -is -.B @ -or -.BR * , -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.SS Command Substitution -.PP -\fICommand substitution\fP allows the output of a command to replace -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. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution \fB$(cat \fIfile\fP)\fR can be replaced by -the equivalent but faster \fB$(< \fIfile\fP)\fR. -.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 . -The first backquote not preceded by a backslash terminates the -command substitution. -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 backquoted 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. The format for arithmetic expansion is: -.RS -.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 parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, string -expansion, command substitution, and quote removal. -Arithmetic expansions 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 -When available, process substitution is performed -simultaneously with parameter and variable expansion, -command substitution, -and 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 -.SM -.B IFS -is unset, or its -value 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. -.PP -Explicit null arguments (\^\f3"\^"\fP or \^\f3'\^'\fP\^) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. -.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 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 -file names matching the pattern. -If no matching file names are found, -and the shell option -.B nullglob -is disabled, the word is left unchanged. -If the -.B nullglob -option is set, and no matches are found, -the word is removed. -If the -.B failglob -shell option is set, and no matches are found, an error message -is printed and the command is not executed. -If the shell option -.B nocaseglob -is enabled, the match is performed without regard to the case -of alphabetic characters. -When a pattern is used for pathname expansion, -the character -.B ``.'' -at the start of a name or immediately following a slash -must be matched explicitly, unless the shell option -.B dotglob -is set. -When matching a pathname, the slash character must always be -matched explicitly. -In other cases, the -.B ``.'' -character is not treated specially. -See the description of -.B shopt -below under -.SM -.B SHELL BUILTIN COMMANDS -for a description of the -.BR nocaseglob , -.BR nullglob , -.BR failglob , -and -.B dotglob -shell options. -.PP -The -.SM -.B GLOBIGNORE -shell variable may be used to restrict the set of file names matching a -.IR pattern . -If -.SM -.B GLOBIGNORE -is set, each matching file name that also matches one of the patterns in -.SM -.B GLOBIGNORE -is removed from the list of matches. -The file names -.B ``.'' -and -.B ``..'' -are always ignored when -.SM -.B GLOBIGNORE -is set and not null. However, setting -.SM -.B GLOBIGNORE -to a non-null value has the effect of enabling the -.B dotglob -shell option, so all other file names beginning with a -.B ``.'' -will match. -To get the old behavior of ignoring file names beginning with a -.BR ``.'' , -make -.B ``.*'' -one of the patterns in -.SM -.BR GLOBIGNORE . -The -.B dotglob -option is disabled when -.SM -.B GLOBIGNORE -is unset. -.PP -\fBPattern Matching\fP -.PP -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. The NUL character may not -occur in a pattern. A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if -they are to be matched literally. -.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 hyphen denotes a -\fIrange expression\fP; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -.B [ -is a -.B ! -or a -.B ^ -then any character not enclosed is matched. -The sorting order of characters in range expressions is determined by -the current locale and the value of the \fBLC_COLLATE\fP shell variable, -if set. -A -.B \- -may be matched by including it as the first or last character -in the set. -A -.B ] -may be matched by including it as the first character -in the set. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -\fIcharacter classes\fP can be specified using the syntax -\fB[:\fP\fIclass\fP\fB:]\fP, where \fIclass\fP is one of the -following classes defined in the POSIX.2 standard: -.PP -.RS -.B -.if n alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.if t alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.br -A character class matches any character belonging to that class. -The \fBword\fP character class matches letters, digits, and the character _. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -an \fIequivalence class\fP can be specified using the syntax -\fB[=\fP\fIc\fP\fB=]\fP, which matches all characters with the -same collation weight (as defined by the current locale) as -the character \fIc\fP. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -the syntax \fB[.\fP\fIsymbol\fP\fB.]\fP matches the collating symbol -\fIsymbol\fP. -.RE -.PD -.PP -If the \fBextglob\fP shell option is enabled using the \fBshopt\fP -builtin, several extended pattern matching operators are recognized. -In the following description, a \fIpattern-list\fP is a list of one -or more patterns separated by a \fB|\fP. -Composite patterns may be formed using one or more of the following -sub-patterns: -.sp 1 -.PD 0 -.RS -.TP -\fB?(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or one occurrence of the given patterns -.TP -\fB*(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or more occurrences of the given patterns -.TP -\fB+(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches one or more occurrences of the given patterns -.TP -\fB@(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches exactly one of the given patterns -.TP -\fB!(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches anything except one of the given patterns -.RE -.PD -.SS Quote Removal -.PP -After the preceding expansions, all unquoted occurrences of the -characters -.BR \e , -.BR ' , -and \^\f3"\fP\^ that did not result from one of the above -expansions are removed. -.SH REDIRECTION -Before a command is executed, its input and output -may be -.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 following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to brace expansion, -tilde expansion, parameter expansion, command substitution, arithmetic -expansion, quote removal, pathname expansion, and word splitting. -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 . -.PP -\fBBash\fP handles several filenames specially when they are used in -redirections, as described in the following table: -.RS -.PP -.PD 0 -.TP -.B /dev/fd/\fIfd\fP -If \fIfd\fP is a valid integer, file descriptor \fIfd\fP is duplicated. -.TP -.B /dev/stdin -File descriptor 0 is duplicated. -.TP -.B /dev/stdout -File descriptor 1 is duplicated. -.TP -.B /dev/stderr -File descriptor 2 is duplicated. -.TP -.B /dev/tcp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -a TCP connection to the corresponding socket. -.TP -.B /dev/udp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -a UDP connection to the corresponding socket. -.PD -.RE -.PP -A failure to open or create a file causes the redirection to fail. -.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 > , -and the -.B noclobber -option to the -.B set -builtin has been enabled, the redirection will fail if the file -whose name results from the expansion of \fIword\fP exists and is -a regular file. -If the redirection operator is -.BR >| , -or the redirection operator is -.B > -and the -.B noclobber -option to the -.B set -builtin command is not enabled, the redirection is attempted even -if the file named by \fIword\fP exists. -.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: -.RS -.PP -.nf -\fB<<\fP[\fB\-\fP]\fIword\fP - \fIhere-document\fP -\fIdelimiter\fP -.fi -.RE -.PP -No parameter expansion, command substitution, arithmetic expansion, -or pathname 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. -If \fIword\fP is unquoted, -all lines of the here-document are subjected to parameter expansion, -command substitution, and arithmetic expansion. In the latter -case, the character sequence -.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 "Here Strings" -A variant of here documents, the format is: -.RS -.PP -.nf -\fB<<<\fP\fIword\fP -.fi -.RE -.PP -The \fIword\fP is expanded and supplied to the command on its standard -input. -.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 the digits in -.I word -do not specify a file descriptor open for input, a redirection error occurs. -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. -If the digits in -.I word -do not specify a file descriptor open for output, a redirection error occurs. -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 "Moving File Descriptors" -.PP -The redirection operator -.RS -.PP -[\fIn\fP]\fB<&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard input (file descriptor 0) if \fIn\fP is not specified. -\fIdigit\fP is closed after being duplicated to \fIn\fP. -.PP -Similarly, the redirection operator -.RS -.PP -[\fIn\fP]\fB>&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard output (file descriptor 1) if \fIn\fP is not specified. -.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 on file descriptor 0 if -.I n -is not specified. If the file does not exist, it is created. -.SH ALIASES -\fIAliases\fP allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of 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 simple command, if unquoted, -is checked to see if it has an -alias. If so, that word is replaced by the text of the alias. -The characters \fB/\fP, \fB$\fP, \fB`\fP, and \fB=\fP and -any of the shell \fImetacharacters\fP or quoting characters -listed above may not appear in an alias name. -The replacement text may contain any valid shell input, -including shell metacharacters. -The first word of the replacement text is tested -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. -If arguments are needed, a shell function should be used (see -.SM -.B FUNCTIONS -below). -.PP -Aliases are not expanded when the shell is not interactive, unless -the -.B expand_aliases -shell option is set using -.B shopt -(see the description of -.B shopt -under -.SM -\fBSHELL BUILTIN COMMANDS\fP -below). -.PP -The rules concerning the definition and use of aliases are -somewhat confusing. -.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. -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 a 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 -For almost every purpose, aliases are superseded by -shell functions. -.SH FUNCTIONS -A shell function, defined as described above under -.SM -.BR "SHELL GRAMMAR" , -stores a series of commands for later execution. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -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. Special parameter 0 -is unchanged. -The first element of the -.SM -.B FUNCNAME -variable is set to the name of the function while the function -is executing. -All other aspects of the shell execution -environment are identical between a function and its caller -with the exception that the -.SM -.B DEBUG -trap (see the description of the -.B trap -builtin under -.SM -.B SHELL BUILTIN COMMANDS -below) is not inherited unless the function has been given the -\fBtrace\fP attribute (see the description of the -.SM -.B declare -builtin below) or the -\fB\-o functrace\fP shell option has been enabled with -the \fBset\fP builtin -(in which case all functions inherit the \fBDEBUG\fP trap). -.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. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter -.B # -are restored to the values they had prior to the function's -execution. -.PP -Function names and definitions may be listed with the -.B \-f -option to the -.B declare -or -.B typeset -builtin commands. The -.B \-F -option to -.B declare -or -.B typeset -will list the function names only -(and optionally the source file and line number, if the \fBextdebug\fP -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -.B \-f -option to the -.B export -builtin. -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. -.PP -Functions may be recursive. No limit is imposed on the number -of recursive calls. -.SH "ARITHMETIC EVALUATION" -The shell allows arithmetic expressions to be evaluated, under -certain circumstances (see the \fBlet\fP and \fBdeclare\fP builtin -commands and \fBArithmetic Expansion\fP). -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -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 \fIid\fP++ \fIid\fP\-\- -variable post-increment and post-decrement -.TP -.B ++\fIid\fP \-\-\fIid\fP -variable pre-increment and pre-decrement -.TP -.B \- + -unary minus and plus -.TP -.B ! ~ -logical and bitwise negation -.TP -.B ** -exponentiation -.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 \fIexpr\fP?\fIexpr\fP:\fIexpr\fP -conditional operator -.TP -.B = *= /= %= += \-= <<= >>= &= ^= |= -assignment -.TP -.B \fIexpr1\fP , \fIexpr2\fP -comma -.PD -.PP -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -\fIinteger\fP attribute using \fBdeclare -i\fP is assigned a value. -A null value evaluates to 0. -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 0x or 0X denotes hexadecimal. -Otherwise, numbers take the form [\fIbase#\fP]n, where \fIbase\fP -is a decimal number between 2 and 64 representing the arithmetic -base, and \fIn\fP is a number in that base. -If \fIbase#\fP is omitted, then base 10 is used. -The digits greater than 9 are represented by the lowercase letters, -the uppercase letters, @, and _, in that order. -If \fIbase\fP is less than or equal to 36, lowercase and uppercase -letters may be used interchangably to represent numbers between 10 -and 35. -.PP -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. -.SH "CONDITIONAL EXPRESSIONS" -Conditional expressions are used by the \fB[[\fP compound command and -the \fBtest\fP and \fB[\fP builtin commands to test file attributes -and perform string and arithmetic comparisons. -Expressions are formed from the following unary or binary primaries. -If any \fIfile\fP argument to one of the primaries is of the form -\fI/dev/fd/n\fP, then file descriptor \fIn\fP is checked. -If the \fIfile\fP argument to one of the primaries is one of -\fI/dev/stdin\fP, \fI/dev/stdout\fP, or \fI/dev/stderr\fP, file -descriptor 0, 1, or 2, respectively, is checked. -.sp 1 -.PD 0 -.TP -.B \-a \fIfile\fP -True if \fIfile\fP exists. -.TP -.B \-b \fIfile\fP -True if \fIfile\fP exists and is a block special file. -.TP -.B \-c \fIfile\fP -True if \fIfile\fP exists and is a character special file. -.TP -.B \-d \fIfile\fP -True if \fIfile\fP exists and is a directory. -.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 \-h \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-k \fIfile\fP -True if \fIfile\fP exists and its ``sticky'' bit is set. -.TP -.B \-p \fIfile\fP -True if \fIfile\fP exists and is a named pipe (FIFO). -.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 \-t \fIfd\fP -True if file descriptor -.I fd -is open and refers to 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 -.B \-L \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-S \fIfile\fP -True if \fIfile\fP exists and is a socket. -.TP -.B \-N \fIfile\fP -True if \fIfile\fP exists and has been modified since it was last read. -.TP -\fIfile1\fP \-\fBnt\fP \fIfile2\fP -True if \fIfile1\fP is newer (according to modification date) than \fIfile2\fP, -or if \fIfile1\fP exists and \fPfile2\fP does not. -.TP -\fIfile1\fP \-\fBot\fP \fIfile2\fP -True if \fIfile1\fP is older than \fIfile2\fP, or if \fIfile2\fP exists -and \fIfile1\fP does not. -.TP -\fIfile1\fP \fB\-ef\fP \fIfile2\fP -True if \fIfile1\fP and \fIfile2\fP refer to the same device and -inode numbers. -.TP -.B \-o \fIoptname\fP -True if shell option -.I optname -is enabled. -See the list of options under the description of the -.B \-o -option to the -.B set -builtin below. -.TP -.B \-z \fIstring\fP -True if the length of \fIstring\fP is zero. -.TP -\fIstring\fP -.PD 0 -.TP -.B \-n \fIstring\fP -.PD -True if the length of -.I string -is non-zero. -.TP -\fIstring1\fP \fB==\fP \fIstring2\fP -True if the strings are equal. \fB=\fP may be used in place of -\fB==\fP for strict POSIX compliance. -.TP -\fIstring1\fP \fB!=\fP \fIstring2\fP -True if the strings are not equal. -.TP -\fIstring1\fP \fB<\fP \fIstring2\fP -True if \fIstring1\fP sorts before \fIstring2\fP lexicographically -in the current locale. -.TP -\fIstring1\fP \fB>\fP \fIstring2\fP -True if \fIstring1\fP sorts after \fIstring2\fP lexicographically -in the current locale. -.TP -.I \fIarg1\fP \fBOP\fP \fIarg2\fP -.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 to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to \fIarg2\fP, respectively. -.I Arg1 -and -.I arg2 -may be positive or negative integers. -.PD -.SH "SIMPLE COMMAND EXPANSION" -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. -.IP 1. -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. -.IP 2. -The words that are not variable assignments or redirections are -expanded. If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. -.IP 3. -Redirections are performed as described above under -.SM -.BR REDIRECTION . -.IP 4. -The text after the \fB=\fP in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -.PP -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. -.PP -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. -.PP -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. -.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. -.B Bash -uses a hash table to remember the full pathnames of executable -files (see -.B hash -under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -A full search of the directories in -.SM -.B PATH -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell prints an error -message and returns an exit status of 127. -.PP -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in a -separate execution environment. -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 COMMAND EXECUTION ENVIRONMENT -The shell has an \fIexecution environment\fP, which consists of the -following: -.sp 1 -.IP \(bu -open files inherited by the shell at invocation, as modified by -redirections supplied to the \fBexec\fP builtin -.IP \(bu -the current working directory as set by \fBcd\fP, \fBpushd\fP, or -\fBpopd\fP, or inherited by the shell at invocation -.IP \(bu -the file creation mode mask as set by \fBumask\fP or inherited from -the shell's parent -.IP \(bu -current traps set by \fBtrap\fP -.IP \(bu -shell parameters that are set by variable assignment or with \fBset\fP -or inherited from the shell's parent in the environment -.IP \(bu -shell functions defined during execution or inherited from the shell's -parent in the environment -.IP \(bu -options enabled at invocation (either by default or with command-line -arguments) or by \fBset\fP -.IP \(bu -options enabled by \fBshopt\fP -.IP \(bu -shell aliases defined with \fBalias\fP -.IP \(bu -various process IDs, including those of background jobs, the value -of \fB$$\fP, and the value of \fB$PPID\fP -.PP -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. -.sp 1 -.IP \(bu -the shell's open files, plus any modifications and additions specified -by redirections to the command -.IP \(bu -the current working directory -.IP \(bu -the file creation mode mask -.IP \(bu -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment -.IP \(bu -traps caught by the shell are reset to the values inherited from the -shell's parent, and traps ignored by the shell are ignored -.PP -A command invoked in this separate environment cannot affect the -shell's execution environment. -.PP -Command substitution, commands grouped with parentheses, -and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed in a -subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. -.PP -If a command is followed by a \fB&\fP and job control is not active, the -default standard input for the command is the empty file \fI/dev/null\fP. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. -.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 provides several ways to manipulate the environment. -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 -option is set (see the -.B set -builtin command below), then -.I all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. -.PP -When -.B bash -invokes an external command, the variable -.B _ -is set to the full file name of the command and passed to that -command in its environment. -.SH "EXIT STATUS" -For the shell's purposes, 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 \fIN\fP, \fBbash\fP uses -the value of 128+\fIN\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 -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. -.PP -Shell builtin commands return a status of 0 (\fItrue\fP) if -successful, and non-zero (\fIfalse\fP) if an error occurs -while they execute. -All builtins return an exit status of 2 to indicate incorrect usage. -.PP -\fBBash\fP itself returns the exit status of the last command -executed, unless a syntax error occurs, in which case it exits -with a non-zero value. See also the \fBexit\fP builtin -command below. -.SH SIGNALS -When \fBbash\fP is interactive, in the absence of any traps, 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 -Non-builtin commands run by \fBbash\fP have signal handlers -set to the values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore -.SM -.B SIGINT -and -.SM -.B SIGQUIT -in addition to these inherited handlers. -Commands run as a result of command substitution ignore the -keyboard-generated job control signals -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . -.PP -The shell exits by default upon receipt of a -.SM -.BR SIGHUP . -Before exiting, an interactive shell resends the -.SM -.B SIGHUP -to all jobs, running or stopped. -Stopped jobs are sent -.SM -.B SIGCONT -to ensure that they receive the -.SM -.BR SIGHUP . -To prevent the shell from -sending the signal to a particular job, it should be removed from the -jobs table with the -.B disown -builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below) or marked -to not receive -.SM -.B SIGHUP -using -.BR "disown \-h" . -.PP -If the -.B huponexit -shell option has been set with -.BR shopt , -.B bash -sends a -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.PP -If \Bbash\fP is waiting for a command to complete and receives a signal -for which a trap has been set, the trap will not be executed until -the command completes. -When \fBbash\fP is waiting for an asynchronous command via the \fBwait\fP -builtin, the reception of a signal for which a trap has been set will -cause the \fBwait\fP builtin to return immediately with an exit status -greater than 128, immediately after which the trap is executed. -.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 operating 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 -contains facilities 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 control 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 . -The user 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 or started in the background. -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 enabled, -.B bash -reports such changes immediately. -Any trap on -.SM -.B SIGCHLD -is executed for each child that exits. -.PP -If an attempt to exit -.B bash -is made while jobs are stopped, the shell prints a warning message. The -.B jobs -command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -the shell does not print another warning, and the stopped -jobs are terminated. -.SH PROMPTING -When executing interactively, -.B bash -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 \ea -an ASCII bell character (07) -.TP -.B \ed -the date in "Weekday Month Date" format (e.g., "Tue May 26") -.TP -.B \eD{\fIformat\fP} -the \fIformat\fP is passed to \fIstrftime\fP(3) and the result is inserted -into the prompt string; an empty \fIformat\fP results in a locale-specific -time representation. The braces are required -.TP -.B \ee -an ASCII escape character (033) -.TP -.B \eh -the hostname up to the first `.' -.TP -.B \eH -the hostname -.TP -.B \ej -the number of jobs currently managed by the shell -.TP -.B \el -the basename of the shell's terminal device name -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \es -the name of the shell, the basename of -.B $0 -(the portion following the final slash) -.TP -.B \et -the current time in 24-hour HH:MM:SS format -.TP -.B \eT -the current time in 12-hour HH:MM:SS format -.TP -.B \e@ -the current time in 12-hour am/pm format -.TP -.B \eA -the current time in 24-hour HH:MM format -.TP -.B \eu -the username of the current user -.TP -.B \ev -the version of \fBbash\fP (e.g., 2.00) -.TP -.B \eV -the release of \fBbash\fP, version + patchelvel (e.g., 2.00.0) -.TP -.B \ew -the current working directory, with \fB$HOME\fP abbreviated with a tilde -.TP -.B \eW -the basename of the current working directory, with \fB$HOME\fP -abbreviated with a tilde -.TP -.B \e! -the history number of this command -.TP -.B \e# -the command number of this command -.TP -.B \e$ -if the effective UID is 0, a -.BR # , -otherwise a -.B $ -.TP -.B \e\fInnn\fP -the character corresponding to the octal number \fInnn\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 quote removal, subject to the value of the -.B promptvars -shell option (see the description of the -.B shopt -command under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -.SH READLINE -This is the library that handles reading input when using an interactive -shell, unless the -.B \-\-noediting -option is given at shell invocation. -By default, the line editing commands are similar to those of emacs. -A vi-style line editing interface is also available. -To turn off line editing after the shell is running, use the -.B +o emacs -or -.B +o vi -options to the -.B set -builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS "Readline Notation" -.PP -In this section, the emacs-style notation is used to denote -keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n -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 -below. -.PP -When a command is described as \fIkilling\fP text, the text -deleted is saved for possible future retrieval -(\fIyanking\fP). The killed text is saved in a -\fIkill ring\fP. Consecutive kills cause the text to be -accumulated into one unit, which can be yanked all at once. -Commands which do not kill text separate the chunks of text -on the kill ring. -.SS "Readline Initialization" -.PP -Readline is customized by putting commands in an initialization -file (the \fIinputrc\fP file). -The name of this file is taken from the value of the -.SM -.B INPUTRC -variable. If that variable is unset, the default is -.IR ~/.inputrc . -When a program which uses the readline library starts up, the -initialization file is read, and the key bindings and variables -are set. -There are only a few basic constructs allowed in the -readline initialization file. -Blank lines are ignored. -Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional constructs. -Other lines denote key bindings and variable settings. -.PP -The default key-bindings may be changed with an -.I inputrc -file. -Other programs that use this library may add their own commands -and bindings. -.PP -For example, placing -.RS -.PP -M\-Control\-u: universal\-argument -.RE -or -.RS -C\-Meta\-u: universal\-argument -.RE -into the -.I 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 . -.PP -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). -.SS "Readline Key Bindings" -.PP -The syntax for controlling key bindings in the -.I inputrc -file is simple. All that is required is the name of the -command or the text of a macro and a key sequence to which -it should be bound. The name may be specified in one of two ways: -as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP -prefixes, or as a key sequence. -.PP -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 -.if t \f(CW> output\fP -.if n ``> 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, but the symbolic character names -are not recognized. -.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 -.if t \f(CWFunction Key 1\fP. -.if n ``Function Key 1''. -.PP -The full set of GNU Emacs style escape sequences is -.RS -.PD 0 -.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 -.PD -.PP -In addition to the GNU Emacs style escape sequences, a second -set of backslash escapes is available: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ed -delete -.TP -.B \ef -form feed -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.RE -.PD -.PP -When entering the text of a macro, single or double quotes must -be used to indicate a macro definition. -Unquoted text is assumed to be a function name. -In the macro body, the backslash escapes described above are expanded. -Backslash will quote any other character in the macro text, -including " and '. -.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). -.SS "Readline 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 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 when the readline -.B insert\-comment -command is executed. -This command is bound to -.B M\-# -in emacs mode and to -.B # -in vi command mode. -.TP -.B completion\-ignore\-case (Off) -If set to \fBOn\fP, readline performs filename matching and completion -in a case\-insensitive fashion. -.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 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 prefixing an -escape character (in effect, using escape as the \fImeta prefix\fP). -.TP -.B disable\-completion (Off) -If set to \fBOn\fP, readline will inhibit word completion. Completion -characters will be inserted into the line as if they had been -mapped to \fBself-insert\fP. -.TP -.B editing\-mode (emacs) -Controls whether readline begins with a set of key bindings similar -to \fIemacs\fP or \fIvi\fP. -.B editing\-mode -can be set to either -.B emacs -or -.BR vi . -.TP -.B enable\-keypad (Off) -When set to \fBOn\fP, readline will try to enable the application -keypad when it is called. Some systems need this to enable the -arrow keys. -.TP -.B expand\-tilde (Off) -If set to \fBon\fP, tilde expansion is performed when readline -attempts word completion. -.TP -.B history-preserve-point -If set to \fBon\fP, the history code attempts to place point at the -same location on each history line retrived with \fBprevious-history\fP -or \fBnext-history\fP. -.TP -.B horizontal\-scroll\-mode (Off) -When set to \fBOn\fP, makes readline use a single line for display, -scrolling the input horizontally on a single screen line when it -becomes longer than the screen width rather than wrapping to a new line. -.TP -.B input\-meta (Off) -If set to \fBOn\fP, readline will enable eight-bit input (that is, -it will not strip the high bit from the characters it reads), -regardless of what the terminal claims it can support. The name -.B meta\-flag -is a synonym for this variable. -.TP -.B isearch\-terminators (``C\-[C\-J'') -The string of characters that should terminate an incremental -search without subsequently executing the character as a command. -If this variable has not been given a value, the characters -\fIESC\fP and \fIC\-J\fP will terminate an incremental search. -.TP -.B keymap (emacs) -Set the current readline keymap. The set of valid keymap names is -\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, -vi\-command\fP, and -.IR vi\-insert . -\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is -equivalent to \fIemacs\-standard\fP. The default value is -.IR emacs ; -the value of -.B editing\-mode -also affects the default keymap. -.TP -.B mark\-directories (On) -If set to \fBOn\fP, completed directory names have a slash -appended. -.TP -.B mark\-modified\-lines (Off) -If set to \fBOn\fP, history lines that have been modified are displayed -with a preceding asterisk (\fB*\fP). -.TP -.B mark\-symlinked\-directories (Off) -If set to \fBOn\fP, completed names which are symbolic links to directories -have a slash appended (subject to the value of -\fBmark\-directories\fP). -.TP -.B match\-hidden\-files (On) -This variable, when set to \fBOn\fP, causes readline to match files whose -names begin with a `.' (hidden files) when performing filename -completion, unless the leading `.' is -supplied by the user in the filename to be completed. -.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 page\-completions (On) -If set to \fBOn\fP, readline uses an internal \fImore\fP-like pager -to display a screenful of possible completions at a time. -.TP -.B print\-completions\-horizontally (Off) -If set to \fBOn\fP, readline will display completions with matches -sorted horizontally in alphabetical order, rather than down the screen. -.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 show\-all\-if\-unmodified (Off) -This alters the default behavior of the completion functions in -a fashion similar to \fBshow\-all\-if\-ambiguous\fP. -If set to -.BR on , -words which have more than one possible completion without any -possible partial completion (the possible completions don't share -a common prefix) cause the matches to be listed immediately instead -of ringing the bell. -.TP -.B visible\-stats (Off) -If set to \fBOn\fP, a character denoting a file's type as reported -by \fIstat\fP(2) is appended to the filename when listing possible -completions. -.PD -.SS "Readline Conditional Constructs" -.PP -Readline implements a facility similar in spirit to the conditional -compilation features of the C preprocessor which allows key -bindings and variable settings to be performed as the result -of tests. There are four 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 both 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: -.sp 1 -.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 seen 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. -.IP \fB$include\fP -This directive takes a single filename as an argument and reads commands -and bindings from that file. For example, the following directive -would read \fI/etc/inputrc\fP: -.sp 1 -.RS -.nf -\fB$include\fP \^ \fI/etc/inputrc\fP -.fi -.RE -.SS Searching -.PP -Readline provides commands for searching through the command history -(see -.SM -.B HISTORY -below) for lines containing a specified string. -There are two search modes: -.I incremental -and -.IR non-incremental . -.PP -Incremental searches begin before the user has finished typing the -search string. -As each character of the search string is typed, readline displays -the next entry from the history matching the string typed so far. -An incremental search requires only as many characters as needed to -find the desired history entry. -The characters present in the value of the \fBisearch-terminators\fP -variable are used to terminate an incremental search. -If that variable has not been assigned a value the Escape and -Control-J characters will terminate an incremental search. -Control-G will abort an incremental search and restore the original -line. -When the search is terminated, the history entry containing the -search string becomes the current line. -.PP -To find other matching entries in the history list, type Control-S or -Control-R as appropriate. -This will search backward or forward in the history for the next -entry matching the search string typed so far. -Any other key sequence bound to a readline command will terminate -the search and execute that command. -For instance, a \fInewline\fP will terminate the search and accept -the line, thereby executing the command from the history list. -.PP -Readline remembers the last incremental search string. If two -Control-Rs are typed without any intervening characters defining a -new search string, any remembered search string is used. -.PP -Non-incremental searches read the entire search string before starting -to search for matching history lines. The search string may be -typed by the user or be part of the contents of the current line. -.SS "Readline Command Names" -.PP -The following is a list of the names of the commands and the default -key sequences to which they are bound. -Command names without an accompanying key sequence are unbound by default. -In the following descriptions, \fIpoint\fP refers to the current cursor -position, and \fImark\fP refers to a cursor position saved by the -\fBset\-mark\fP command. -The text between the point and mark is referred to as the \fIregion\fP. -.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 the current or 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. -.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 point. -This is a non-incremental search. -.TP -.B history\-search\-backward -Search backward through the history for the string of characters -between the start of the current line and the point. -This is a non-incremental search. -.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. -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 of -the previous history entry). With an argument, -behave exactly like \fByank\-nth\-arg\fP. -Successive calls to \fByank\-last\-arg\fP move back through the history -list, inserting the last argument of each line in turn. -.TP -.B shell\-expand\-line (M\-C\-e) -Expand the line as the shell does. 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 magic\-space -Perform history expansion on the current line and insert a space. -See -.SM -.B HISTORY EXPANSION -below for a description of history expansion. -.TP -.B alias\-expand\-line -Perform alias expansion on the current line. -See -.SM -.B ALIASES -above for a description of alias expansion. -.TP -.B history\-and\-alias\-expand\-line -Perform history and alias expansion on the current line. -.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. -.TP -.B edit\-and\-execute\-command (C\-xC\-e) -Invoke an editor on the current command line, and execute the result as shell -commands. -\fBBash\fP attempts to invoke -.SM -.BR $FCEDIT , -.SM -.BR $EDITOR , -and \fIemacs\fP as the editor, in that order. -.PD -.SS Commands for Changing Text -.PP -.PD 0 -.TP -.B delete\-char (C\-d) -Delete the character at point. If point is at the -beginning of the line, there are no characters in the line, and -the last character typed was not bound to \fBdelete\-char\fP, -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 forward\-backward\-delete\-char -Delete the character under the cursor, unless the cursor is at the -end of the line, in which case the character behind the cursor is -deleted. -.TP -.B quoted\-insert (C\-q, C\-v) -Add the next character typed 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, -moving point forward as well. -If point is at the end of the line, then this transposes -the two characters before point. -Negative arguments have no effect. -.TP -.B transpose\-words (M\-t) -Drag the word before point past the word after point, -moving point over that word as well. -If point is at the end of the line, this transposes -the last two words on the line. -.TP -.B upcase\-word (M\-u) -Uppercase the current (or following) word. With a negative argument, -uppercase the previous word, but do not move point. -.TP -.B downcase\-word (M\-l) -Lowercase the current (or following) word. With a negative argument, -lowercase the previous word, but do not move point. -.TP -.B capitalize\-word (M\-c) -Capitalize the current (or following) word. With a negative argument, -capitalize the previous word, but do not move point. -.TP -.B overwrite\-mode -Toggle overwrite mode. With an explicit positive numeric argument, -switches to overwrite mode. With an explicit non-positive numeric -argument, switches to insert mode. This command affects only -\fBemacs\fP mode; \fBvi\fP mode does overwrite differently. -Each call to \fIreadline()\fP starts in insert mode. -In overwrite mode, characters bound to \fBself\-insert\fP replace -the text at point rather than pushing the text to the right. -Characters bound to \fBbackward\-delete\-char\fP replace the character -before point with a space. By default, this command is unbound. -.PD -.SS Killing and Yanking -.PP -.PD 0 -.TP -.B kill\-line (C\-k) -Kill the text from point 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. -The killed text is saved on the kill-ring. -.\" 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 point is. -.TP -.B kill\-word (M\-d) -Kill from point 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 point. -Word boundaries are the same as those used by \fBbackward\-word\fP. -.TP -.B unix\-word\-rubout (C\-w) -Kill the word behind point, using white space as a word boundary. -The killed text is saved on the kill-ring. -.TP -.B unix\-filename\-rubout -Kill the word behind point, using white space and the slash character -as the word boundaries. -The killed text is saved on the kill-ring. -.TP -.B delete\-horizontal\-space (M\-\e) -Delete all spaces and tabs around point. -.TP -.B kill\-region -Kill the text in the current region. -.TP -.B copy\-region\-as\-kill -Copy the text in the region to the kill buffer. -.TP -.B copy\-backward\-word -Copy the word before point to the kill buffer. -The word boundaries are the same as \fBbackward\-word\fP. -.TP -.B copy\-forward\-word -Copy the word following point to the kill buffer. -The word boundaries are the same as \fBforward\-word\fP. -.TP -.B yank (C\-y) -Yank the top of the kill ring into the buffer at point. -.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 -This is another way to specify an argument. -If this command is followed by one or more digits, optionally with a -leading minus sign, those digits define the argument. -If the command is followed by digits, executing -.B universal\-argument -again ends the numeric argument, but is otherwise ignored. -As a special case, if this command is immediately followed by a -character that is neither a digit or minus sign, the argument count -for the next command is multiplied by four. -The argument count is initially one, so executing this function the -first time makes the argument count four, a second time makes the -argument count sixteen, and so on. -.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 (M\-*) -Insert all completions of the text before point -that would have been generated by -\fBpossible\-completions\fP. -.TP -.B menu\-complete -Similar to \fBcomplete\fP, but replaces the word to be completed -with a single match from the list of possible completions. -Repeated execution of \fBmenu\-complete\fP steps through the list -of possible completions, inserting each match in turn. -At the end of the list of completions, the bell is rung -(subject to the setting of \fBbell\-style\fP) -and the original text is restored. -An argument of \fIn\fP moves \fIn\fP positions forward in the list -of matches; a negative argument may be used to move backward -through the list. -This command is intended to be bound to \fBTAB\fP, but is unbound -by default. -.TP -.B delete\-char\-or\-list -Deletes the character under the cursor if not at the beginning or -end of the line (like \fBdelete\-char\fP). -If at the end of the line, behaves identically to -\fBpossible\-completions\fP. -This command is unbound by default. -.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, shell 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 insert 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 store 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 the \fIinputrc\fP 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, M\-\fIx\fP, ...) -If the metafied character \fIx\fP is lowercase, run the command -that is bound to the corresponding uppercase character. -.TP -.B prefix\-meta (ESC) -Metafy the next character typed. -.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 executing 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 set\-mark (C\-@, M\-) -Set the mark to the point. If a -numeric argument is supplied, the mark is set to that position. -.TP -.B exchange\-point\-and\-mark (C\-x C\-x) -Swap the point with the mark. The current cursor position is set to -the saved position, and the old cursor position is saved as the mark. -.TP -.B character\-search (C\-]) -A character is read and point is moved to the next occurrence of that -character. A negative count searches for previous occurrences. -.TP -.B character\-search\-backward (M\-C\-]) -A character is read and point is moved to the previous occurrence of that -character. A negative count searches for subsequent occurrences. -.TP -.B insert\-comment (M\-#) -Without a numeric argument, the value of the readline -.B comment\-begin -variable is inserted at the beginning of the current line. -If a numeric argument is supplied, this command acts as a toggle: if -the characters at the beginning of the line do not match the value -of \fBcomment\-begin\fP, the value is inserted, otherwise -the characters in \fBcomment-begin\fP are deleted from the beginning of -the line. -In either case, the line is accepted as if a newline had been typed. -The default value of -\fBcomment\-begin\fP causes this command to make the current line -a shell comment. -If a numeric argument causes the comment character to be removed, the line -will be executed by the shell. -.TP -.B glob\-complete\-word (M\-g) -The word before point is treated as a pattern for pathname expansion, -with an asterisk implicitly appended. This pattern is used to -generate a list of matching file names for possible completions. -.TP -.B glob\-expand\-word (C\-x *) -The word before point is treated as a pattern for pathname expansion, -and the list of matching file names is inserted, replacing the word. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B glob\-list\-expansions (C\-x g) -The list of expansions that would have been generated by -.B glob\-expand\-word -is displayed, and the line is redrawn. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B dump\-functions -Print all of the functions and their key bindings to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-variables -Print all of the settable readline variables and their values to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-macros -Print all of the readline key sequences bound to macros and the -strings they ouput. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B display\-shell\-version (C\-x C\-v) -Display version information about the current instance of -.BR bash . -.PD -.SS Programmable Completion -.PP -When word completion is attempted for an argument to a command for -which a completion specification (a \fIcompspec\fP) has been defined -using the \fBcomplete\fP builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), the programmable completion facilities are invoked. -.PP -First, the command name is identified. -If a compspec has been defined for that command, the -compspec is used to generate the list of possible completions for the word. -If the command word is a full pathname, a compspec for the full -pathname is searched for first. -If no compspec is found for the full pathname, an attempt is made to -find a compspec for the portion following the final slash. -.PP -Once a compspec has been found, it is used to generate the list of -matching words. -If a compspec is not found, the default \fBbash\fP completion as -described above under \fBCompleting\fP is performed. -.PP -First, the actions specified by the compspec are used. -Only matches which are prefixed by the word being completed are -returned. -When the -.B \-f -or -.B \-d -option is used for filename or directory name completion, the shell -variable -.SM -.B FIGNORE -is used to filter the matches. -.PP -Any completions specified by a filename expansion pattern to the -\fB\-G\fP option are generated next. -The words generated by the pattern need not match the word -being completed. -The -.SM -.B GLOBIGNORE -shell variable is not used to filter the matches, but the -.SM -.B FIGNORE -variable is used. -.PP -Next, the string specified as the argument to the \fB\-W\fP option -is considered. -The string is first split using the characters in the -.SM -.B IFS -special variable as delimiters. -Shell quoting is honored. -Each word is then expanded using -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and pathname expansion, -as described above under -.SM -.BR EXPANSION . -The results are split using the rules described above under -\fBWord Splitting\fP. -The results of the expansion are prefix-matched against the word being -completed, and the matching words become the possible completions. -.PP -After these matches have been generated, any shell function or command -specified with the \fB\-F\fP and \fB\-C\fP options is invoked. -When the command or function is invoked, the -.SM -.B COMP_LINE -and -.SM -.B COMP_POINT -variables are assigned values as described above under -\fBShell Variables\fP. -If a shell function is being invoked, the -.SM -.B COMP_WORDS -and -.SM -.B COMP_CWORD -variables are also set. -When the function or command is invoked, the first argument is the -name of the command whose arguments are being completed, the -second argument is the word being completed, and the third argument -is the word preceding the word being completed on the current command line. -No filtering of the generated completions against the word being completed -is performed; the function or command has complete freedom in generating -the matches. -.PP -Any function specified with \fB\-F\fP is invoked first. -The function may use any of the shell facilities, including the -\fBcompgen\fP builtin described below, to generate the matches. -It must put the possible completions in the -.SM -.B COMPREPLY -array variable. -.PP -Next, any command specified with the \fB\-C\fP option is invoked -in an environment equivalent to command substitution. -It should print a list of completions, one per line, to the -standard output. -Backslash may be used to escape a newline, if necessary. -.PP -After all of the possible completions are generated, any filter -specified with the \fB\-X\fP option is applied to the list. -The filter is a pattern as used for pathname expansion; a \fB&\fP -in the pattern is replaced with the text of the word being completed. -A literal \fB&\fP may be escaped with a backslash; the backslash -is removed before attempting a match. -Any completion that matches the pattern will be removed from the list. -A leading \fB!\fP negates the pattern; in this case any completion -not matching the pattern will be removed. -.PP -Finally, any prefix and suffix specified with the \fB\-P\fP and \fB\-S\fP -options are added to each member of the completion list, and the result is -returned to the readline completion code as the list of possible -completions. -.PP -If the previously-applied actions do not generate any matches, and the -\fB\-o dirnames\fP option was supplied to \fBcomplete\fP when the -compspec was defined, directory name completion is attempted. -.PP -If the \fB\-o plusdirs\fP option was supplied to \fBcomplete\fP when the -compspec was defined, directory name completion is attempted and any -matches are added to the results of the other actions. -.PP -By default, if a compspec is found, whatever it generates is returned -to the completion code as the full set of possible completions. -The default \fBbash\fP completions are not attempted, and the readline -default of filename completion is disabled. -If the \fB\-o bashdefault\fP option was supplied to \fBcomplete\fP when -the compspec was defined, the \fBbash\fP default completions are attempted -if the compspec generates no matches. -If the \fB\-o default\fP option was supplied to \fBcomplete\fP when the -compspec was defined, readline's default completion will be performed -if the compspec (and, if attempted, the default \fBbash\fP completions) -generate no matches. -.PP -When a compspec indicates that directory name completion is desired, -the programmable completion functions force readline to append a slash -to completed names which are symbolic links to directories, subject to -the value of the \fBmark\-directories\fP readline variable, regardless -of the setting of the \fBmark-symlinked\-directories\fP readline variable. -.SH HISTORY -When the -.B \-o history -option to the -.B set -builtin is enabled, the shell provides access to the -\fIcommand history\fP, -the list of commands previously typed. -The value of the \fBHISTSIZE\fP variable is used as the -number of commands to save in a history list. -The text of the last -.SM -.B HISTSIZE -commands (default 500) is saved. 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 -.SM -.B HISTIGNORE -and -.SM -.BR HISTCONTROL . -.PP -On startup, the history is initialized from the file named by -the variable -.SM -.B HISTFILE -(default \fI~/.bash_history\fP). -The file named by the value of -.SM -.B HISTFILE -is truncated, if necessary, to contain no more than -the number of lines specified by the value of -.SM -.BR HISTFILESIZE . -When an interactive shell exits, the last -.SM -.B $HISTSIZE -lines are copied from the history list to -.SM -.BR $HISTFILE . -If the -.B histappend -shell option is enabled -(see the description of -.B shopt -under -.SM -.B "SHELL BUILTIN COMMANDS" -below), the lines are appended to the history file, -otherwise the history file is overwritten. -If -.SM -.B HISTFILE -is unset, or if the history file is unwritable, the history is -not saved. After saving the history, the history file is truncated -to contain no more than -.SM -.B HISTFILESIZE -lines. If -.SM -.B HISTFILESIZE -is not set, no truncation is performed. -.PP -The builtin command -.B fc -(see -.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 may be used to display or modify the history list and -manipulate the history file. -When using command-line editing, search commands -are available in each editing mode that provide access to the -history list. -.PP -The shell allows control over which commands are saved on the history -list. The -.SM -.B HISTCONTROL -and -.SM -.B HISTIGNORE -variables may be set to cause the shell to save only a subset of the -commands entered. -The -.B cmdhist -shell option, if enabled, causes the shell to attempt to save each -line of a multi-line command in the same history entry, adding -semicolons where necessary to preserve syntactic correctness. -The -.B lithist -shell option causes the shell to save the command with embedded newlines -instead of semicolons. See the description of the -.B shopt -builtin below under -.SM -.B "SHELL BUILTIN COMMANDS" -for information on setting and unsetting shell options. -.SH "HISTORY EXPANSION" -.PP -The shell supports a history expansion feature that -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 -by default. -.PP -History expansions introduce words from the history list into -the input stream, making it easy to repeat commands, insert the -arguments to a previous command into the current input line, or -fix errors in previous commands quickly. -.PP -History expansion is performed immediately after a complete line -is read, before the shell breaks it into words. -It takes place in two parts. -The first is to determine which line from the history list -to use during substitution. -The second is to select portions of that line for inclusion into -the current one. -The line selected from the history is the \fIevent\fP, -and the portions of that line that are acted upon are \fIwords\fP. -Various \fImodifiers\fP are available to manipulate the selected words. -The line is broken into words in the same fashion as when reading input, -so that several \fImetacharacter\fP-separated words surrounded by -quotes are considered one word. -History expansions are introduced by the appearance of the -history expansion character, which is \^\fB!\fP\^ by default. -Only backslash (\^\fB\e\fP\^) and single quotes can quote -the history expansion character. -.PP -Several characters inhibit history expansion if found immediately -following the history expansion character, even if it is unquoted: -space, tab, newline, carriage return, and \fB=\fP. -If the \fBextglob\fP shell option is enabled, \fB(\fP will also -inhibit expansion. -.PP -Several shell options settable with the -.B shopt -builtin may be used to tailor the behavior of history expansion. -If the -.B histverify -shell option is enabled (see the description of the -.B shopt -builtin), and -.B readline -is being used, history substitutions are not immediately passed to -the shell parser. -Instead, the expanded line is reloaded into the -.B readline -editing buffer for further modification. -If -.B readline -is being used, and the -.B histreedit -shell option is enabled, a failed history substitution will be reloaded -into the -.B readline -editing buffer for correction. -The -.B \-p -option to the -.B history -builtin command may be used to see what a history expansion will -do before using it. -The -.B \-s -option to the -.B history -builtin may be used to add commands to the end of the history list -without actually executing them, so that they are available for -subsequent recall. -.PP -The shell allows control of the various characters used by the -history expansion mechanism (see the description of -.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, carriage return, = -or ( (when the \fBextglob\fP shell option is enabled using -the \fBshopt\fP builtin). -.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 !! -Refer to the previous command. This is a synonym for `!\-1'. -.TP -.B !\fIstring\fR -Refer to the most recent command starting with -.IR string . -.TP -.B !?\fIstring\fR\fB[?]\fR -Refer to the most recent command containing -.IR string . -The trailing \fB?\fP may be omitted if -.I string -is followed immediately by a newline. -.TP -.B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u -Quick substitution. Repeat the last command, replacing -.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 -Word designators are used to select desired words from the event. -A -.B : -separates the event specification from the word designator. -It may be omitted if the word designator begins with a -.BR ^ , -.BR $ , -.BR * , -.BR \- , -or -.BR % . -Words are numbered from the beginning of the line, -with the first word being denoted by 0 (zero). -Words are inserted into the current line separated by single spaces. -.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 -.PP -If a word designator is supplied without an event specification, the -previous command is used as the event. -.SS Modifiers -.PP -After the optional word designator, there may appear a sequence of -one or more of the following modifiers, each preceded by a `:'. -.PP -.PD 0 -.PP -.TP -.B h -Remove a trailing file name component, leaving only the head. -.TP -.B t -Remove all leading file name components, leaving the tail. -.TP -.B r -Remove a trailing suffix of the form \fI.xxx\fP, leaving the -basename. -.TP -.B e -Remove all but the trailing suffix. -.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 &. If -.I old -is null, it is set to the last -.I old -substituted, or, if no previous history substitutions took place, -the last -.I string -in a -.B !?\fIstring\fR\fB[?]\fR -search. -.TP -.B & -Repeat the previous substitution. -.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. -An \fBa\fP may be used as a synonym for \fBg\fP. -.TP -.B G -Apply the following `\fBs\fP' modifier once to each word in the event line. -.PD -.SH "SHELL BUILTIN COMMANDS" -.\" start of bash_builtins -.zZ -.PP -Unless otherwise noted, each builtin command documented in this -section as accepting options preceded by -.B \- -accepts -.B \-\- -to signify the end of the options. -.sp .5 -.PD 0 -.TP -\fB:\fP [\fIarguments\fP] -.PD -No effect; the command does nothing beyond expanding -.I arguments -and performing any specified -redirections. A zero exit code is returned. -.TP -\fB .\| \fP \fIfilename\fP [\fIarguments\fP] -.PD 0 -.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, file names 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. -When \fBbash\fP is not in \fIposix mode\fP, the current directory is -searched if no file is found in -.SM -.BR PATH . -If the -.B sourcepath -option to the -.B shopt -builtin command is turned off, the -.SM -.B PATH -is not searched. -If any \fIarguments\fP are supplied, they become the positional -parameters when \fIfilename\fP is executed. Otherwise the positional -parameters are unchanged. -The return status is the status of the last command exited within -the script (0 if no commands are executed), and false if -.I filename -is not found or cannot be read. -.TP -\fBalias\fP [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -\fBAlias\fP with no arguments or with the -.B \-p -option prints the list of aliases in the form -\fBalias\fP \fIname\fP=\fIvalue\fP on standard output. -When arguments are supplied, an alias is defined for -each \fIname\fP whose \fIvalue\fP is given. -A trailing space in \fIvalue\fP causes the next word to be -checked for alias substitution when the alias is expanded. -For each \fIname\fP in the argument list for which no \fIvalue\fP -is supplied, the name and value of the alias is printed. -\fBAlias\fP returns true unless a \fIname\fP is given for which -no alias has been defined. -.TP -\fBbg\fP [\fIjobspec\fP] -Resume the suspended job \fIjobspec\fP in the background, as if it -had been started with -.BR & . -If \fIjobspec\fP is not present, the shell's notion of the -\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 -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP] -.PD 0 -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-q\fP \fIfunction\fP] [\fB\-u\fP \fIfunction\fP] [\fB\-r\fP \fIkeyseq\fP] -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-f\fP \fIfilename\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-x\fP \fIkeyseq\fP:\fIshell\-command\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\fP:\fIfunction\-name\fP -.TP -\fBbind\fP \fIreadline\-command\fP -.PD -Display current -.B readline -key and function bindings, bind a key sequence to a -.B readline -function or macro, or set a -.B readline -variable. -Each non-option argument is a command as it would appear in -.IR .inputrc , -but each binding or command 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 \-p -Display \fBreadline\fP function names and bindings in such a way -that they can be re-read. -.TP -.B \-P -List current \fBreadline\fP function names and bindings. -.TP -.B \-v -Display \fBreadline\fP variable names and values in such a way that they -can be re-read. -.TP -.B \-V -List current \fBreadline\fP variable names and values. -.TP -.B \-s -Display \fBreadline\fP key sequences bound to macros and the strings -they output in such a way that they can be re-read. -.TP -.B \-S -Display \fBreadline\fP key sequences bound to macros and the strings -they output. -.TP -.B \-f \fIfilename\fP -Read key bindings from \fIfilename\fP. -.TP -.B \-q \fIfunction\fP -Query about which keys invoke the named \fIfunction\fP. -.TP -.B \-u \fIfunction\fP -Unbind all keys bound to the named \fIfunction\fP. -.TP -.B \-r \fIkeyseq\fP -Remove any current binding for \fIkeyseq\fP. -.TP -.B \-x \fIkeyseq\fP:\fIshell\-command\fP -Cause \fIshell\-command\fP to be executed whenever \fIkeyseq\fP is -entered. -.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 , -.BR until , -or -.B select -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 defining a -function whose name is the same as a shell builtin, -retaining the functionality of the builtin within the function. -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 [\fB\-L|-P\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 in -.SM -.B CDPATH -are separated by a colon (:). A null directory name in -.SM -.B CDPATH -is the same as the current directory, i.e., ``\fB.\fP''. If -.I dir -begins with a slash (/), -then -.SM -.B CDPATH -is not used. The -.B \-P -option says to use the physical directory structure instead of -following symbolic links (see also the -.B \-P -option to the -.B set -builtin command); the -.B \-L -option forces symbolic links to be followed. An argument of -.B \- -is equivalent to -.SM -.BR $OLDPWD . -If a non-empty directory name from \fBCDPATH\fP is used, or if -\fB\-\fP is the first argument, and the directory change is -successful, the absolute pathname of the new working directory is -written to the standard output. -The return value is true if the directory was successfully changed; -false otherwise. -.TP -\fBcaller\fP [\fIexpr\fP] -Returns the context of any active subroutine call (a shell function or -a script executed with the \fB.\fP or \fBsource\fP builtins. -Without \fIexpr\fP, \fBcaller\fP displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as \fIexpr\fP, \fBcaller\fP -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. -The return value is 0 unless the shell is not executing a subroutine -call or \fIexpr\fP does not correspond to a valid position in the -call stack. -.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 file name -used to invoke -.I command -to be displayed; the -.B \-V -option produces a more verbose description. -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 -\fBcompgen\fP [\fIoption\fP] [\fIword\fP] -Generate possible completion matches for \fIword\fP according to -the \fIoption\fPs, which may be any option accepted by the -.B complete -builtin with the exception of \fB\-p\fP and \fB\-r\fP, and write -the matches to the standard output. -When using the \fB\-F\fP or \fB\-C\fP options, the various shell variables -set by the programmable completion facilities, while available, will not -have useful values. -.sp 1 -The matches will be generated in the same way as if the programmable -completion code had generated them directly from a completion specification -with the same flags. -If \fIword\fP is specified, only those completions matching \fIword\fP -will be displayed. -.sp 1 -The return value is true unless an invalid option is supplied, or no -matches were generated. -.TP -\fBcomplete\fP [\fB\-abcdefgjksuv\fP] [\fB\-o\fP \fIcomp-option\fP] [\fB\-A\fP \fIaction\fP] [\fB\-G\fP \fIglobpat\fP] [\fB\-W\fP \fIwordlist\fP] [\fB\-P\fP \fIprefix\fP] [\fB\-S\fP \fIsuffix\fP] -.br -[\fB\-X\fP \fIfilterpat\fP] [\fB\-F\fP \fIfunction\fP] [\fB\-C\fP \fIcommand\fP] \fIname\fP [\fIname ...\fP] -.PD 0 -.TP -\fBcomplete\fP \fB\-pr\fP [\fIname\fP ...] -.PD -Specify how arguments to each \fIname\fP should be completed. -If the \fB\-p\fP option is supplied, or if no options are supplied, -existing completion specifications are printed in a way that allows -them to be reused as input. -The \fB\-r\fP option removes a completion specification for -each \fIname\fP, or, if no \fIname\fPs are supplied, all -completion specifications. -.sp 1 -The process of applying these completion specifications when word completion -is attempted is described above under \fBProgrammable Completion\fP. -.sp 1 -Other options, if specified, have the following meanings. -The arguments to the \fB\-G\fP, \fB\-W\fP, and \fB\-X\fP options -(and, if necessary, the \fB\-P\fP and \fB\-S\fP options) -should be quoted to protect them from expansion before the -.B complete -builtin is invoked. -.RS -.PD 0 -.TP 8 -\fB\-o\fP \fIcomp-option\fP -The \fIcomp-option\fP controls several aspects of the compspec's behavior -beyond the simple generation of completions. -\fIcomp-option\fP may be one of: -.RS -.TP 8 -.B bashdefault -Perform the rest of the default \fBbash\fP completions if the compspec -generates no matches. -.TP 8 -.B default -Use readline's default filename completion if the compspec generates -no matches. -.TP 8 -.B dirnames -Perform directory name completion if the compspec generates no matches. -.TP 8 -.B filenames -Tell readline that the compspec generates filenames, so it can perform any -filename\-specific processing (like adding a slash to directory names or -suppressing trailing spaces). Intended to be used with shell functions. -.TP 8 -.B nospace -Tell readline not to append a space (the default) to words completed at -the end of the line. -.RE -.TP 8 -\fB\-A\fP \fIaction\fP -The \fIaction\fP may be one of the following to generate a list of possible -completions: -.RS -.TP 8 -.B alias -Alias names. May also be specified as \fB\-a\fP. -.TP 8 -.B arrayvar -Array variable names. -.TP 8 -.B binding -\fBReadline\fP key binding names. -.TP 8 -.B builtin -Names of shell builtin commands. May also be specified as \fB\-b\fP. -.TP 8 -.B command -Command names. May also be specified as \fB\-c\fP. -.TP 8 -.B directory -Directory names. May also be specified as \fB\-d\fP. -.TP 8 -.B disabled -Names of disabled shell builtins. -.TP 8 -.B enabled -Names of enabled shell builtins. -.TP 8 -.B export -Names of exported shell variables. May also be specified as \fB\-e\fP. -.TP 8 -.B file -File names. May also be specified as \fB\-f\fP. -.TP 8 -.B function -Names of shell functions. -.TP 8 -.B group -Group names. May also be specified as \fB\-g\fP. -.TP 8 -.B helptopic -Help topics as accepted by the \fBhelp\fP builtin. -.TP 8 -.B hostname -Hostnames, as taken from the file specified by the -.SM -.B HOSTFILE -shell variable. -.TP 8 -.B job -Job names, if job control is active. May also be specified as \fB\-j\fP. -.TP 8 -.B keyword -Shell reserved words. May also be specified as \fB\-k\fP. -.TP 8 -.B running -Names of running jobs, if job control is active. -.TP 8 -.B service -Service names. May also be specified as \fB\-s\fP. -.TP 8 -.B setopt -Valid arguments for the \fB\-o\fP option to the \fBset\fP builtin. -.TP 8 -.B shopt -Shell option names as accepted by the \fBshopt\fP builtin. -.TP 8 -.B signal -Signal names. -.TP 8 -.B stopped -Names of stopped jobs, if job control is active. -.TP 8 -.B user -User names. May also be specified as \fB\-u\fP. -.TP 8 -.B variable -Names of all shell variables. May also be specified as \fB\-v\fP. -.RE -.TP 8 -\fB\-G\fP \fIglobpat\fP -The filename expansion pattern \fIglobpat\fP is expanded to generate -the possible completions. -.TP 8 -\fB\-W\fP \fIwordlist\fP -The \fIwordlist\fP is split using the characters in the -.SM -.B IFS -special variable as delimiters, and each resultant word is expanded. -The possible completions are the members of the resultant list which -match the word being completed. -.TP 8 -\fB\-C\fP \fIcommand\fP -\fIcommand\fP is executed in a subshell environment, and its output is -used as the possible completions. -.TP 8 -\fB\-F\fP \fIfunction\fP -The shell function \fIfunction\fP is executed in the current shell -environment. -When it finishes, the possible completions are retrieved from the value -of the -.SM -.B COMPREPLY -array variable. -.TP 8 -\fB\-X\fP \fIfilterpat\fP -\fIfilterpat\fP is a pattern as used for filename expansion. -It is applied to the list of possible completions generated by the -preceding options and arguments, and each completion matching -\fIfilterpat\fP is removed from the list. -A leading \fB!\fP in \fIfilterpat\fP negates the pattern; in this -case, any completion not matching \fIfilterpat\fP is removed. -.TP 8 -\fB\-P\fP \fIprefix\fP -\fIprefix\fP is added at the beginning of each possible completion -after all other options have been applied. -.TP 8 -\fB\-S\fP \fIsuffix\fP -\fIsuffix\fP is appended to each possible completion -after all other options have been applied. -.PD -.PP -The return value is true unless an invalid option is supplied, an option -other than \fB\-p\fP or \fB\-r\fP is supplied without a \fIname\fP -argument, an attempt is made to remove a completion specification for -a \fIname\fP for which no specification exists, or -an error occurs adding a completion specification. -.RE -.TP -\fBcontinue\fP [\fIn\fP] -Resume the next iteration of the enclosing -.BR for , -.BR while , -.BR until , -or -.B select -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 -\fBdeclare\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD 0 -.TP -\fBtypeset\fP [\fB\-afFirtx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD -Declare variables and/or give them attributes. -If no \fIname\fPs are given then display the values of variables. -The -.B \-p -option will display the attributes and values of each -.IR name . -When -.B \-p -is used, additional options are ignored. -The -.B \-F -option inhibits the display of function definitions; only the -function name and attributes are printed. -If the \fBextdebug\fP shell option is enabled using \fBshopt\fP, -the source file name and line number where the function is defined -are displayed as well. The -.B \-F -option implies -.BR \-f . -The following options can -be used to restrict output to variables with the specified attribute or -to give variables attributes: -.RS -.PD 0 -.TP -.B \-a -Each \fIname\fP is an array variable (see -.B Arrays -above). -.TP -.B \-f -Use function names only. -.TP -.B \-i -The variable is treated as an integer; arithmetic evaluation (see -.SM -.B "ARITHMETIC EVALUATION" ") " -is performed when the variable is assigned a value. -.TP -.B \-r -Make \fIname\fPs readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. -.TP -.B \-t -Give each \fIname\fP the \fItrace\fP attribute. -Traced functions inherit the \fBDEBUG\fP trap from the calling shell. -The trace attribute has no special meaning for variables. -.TP -.B \-x -Mark \fIname\fPs for export to subsequent commands via the environment. -.PD -.PP -Using `+' instead of `\-' -turns off the attribute instead, with the exception that \fB+a\fP -may not be used to destroy an array variable. When used in a function, -makes each -\fIname\fP local, as with the -.B local -command. -If a variable name is followed by =\fIvalue\fP, the value of -the variable is set to \fIvalue\fP. -The return value is 0 unless an invalid option is encountered, -an attempt is made to define a function using -.if n ``\-f foo=bar'', -.if t \f(CW\-f foo=bar\fP, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (see -.B Arrays -above), one of the \fInames\fP is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with \fB\-f\fP. -.RE -.TP -.B dirs [\fB\-clpv\fP] [+\fIn\fP] [\-\fIn\fP] -Without options, displays the list of currently remembered directories. -The default display is on a single line with directory names separated -by spaces. -Directories are added to the list with the -.B pushd -command; the -.B popd -command removes entries from the list. -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Displays the \fIn\fPth entry counting from the left of the list -shown by -.B dirs -when invoked without options, starting with zero. -.TP -\fB\-\fP\fIn\fP -Displays the \fIn\fPth entry counting from the right of the list -shown by -.B dirs -when invoked without options, starting with zero. -.TP -.B \-c -Clears the directory stack by deleting all of the entries. -.TP -.B \-l -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -.TP -.B \-p -Print the directory stack with one entry per line. -.TP -.B \-v -Print the directory stack with one entry per line, -prefixing each entry with its index in the stack. -.PD -.PP -The return value is 0 unless an -invalid option is supplied or \fIn\fP indexes beyond the end -of the directory stack. -.RE -.TP -\fBdisown\fP [\fB\-ar\fP] [\fB\-h\fP] [\fIjobspec\fP ...] -Without options, each -.I jobspec -is removed from the table of active jobs. -If the \fB\-h\fP option is given, each -.I jobspec -is not removed from the table, but is marked so that -.SM -.B SIGHUP -is not sent to the job if the shell receives a -.SM -.BR SIGHUP . -If no -.I jobspec -is present, and neither the -.B \-a -nor the -.B \-r -option is supplied, the \fIcurrent job\fP is used. -If no -.I jobspec -is supplied, the -.B \-a -option means to remove or mark all jobs; the -.B \-r -option without a -.I jobspec -argument restricts operation to running jobs. -The return value is 0 unless a -.I jobspec -does not specify a valid job. -.TP -\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...] -Output the \fIarg\fPs, separated by spaces, followed by a newline. -The return status is always 0. -If \fB\-n\fP is specified, the trailing newline is -suppressed. If the \fB\-e\fP option is given, interpretation of -the following backslash-escaped characters is enabled. The -.B \-E -option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The \fBxpg_echo\fP shell option may be used to -dynamically determine whether or not \fBecho\fP expands these -escape characters by default. -.B echo -does not interpret -.B \-\- -to mean the end of options. -.B echo -interprets the following escape sequences: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ec -suppress trailing newline -.TP -.B \ee -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e0\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(zero to three octal digits) -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three octal digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.PD -.RE -.TP -\fBenable\fP [\fB\-adnps\fP] [\fB\-f\fP \fIfilename\fP] [\fIname\fP ...] -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -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, run -.if t \f(CWenable -n test\fP. -.if n ``enable -n test''. -The -.B \-f -option means to load the new builtin command -.I name -from shared object -.IR filename , -on systems that support dynamic loading. The -.B \-d -option will delete a builtin previously loaded with -.BR \-f . -If no \fIname\fP arguments are given, or if the -.B \-p -option is supplied, a list of shell builtins is printed. -With no other option arguments, the list consists of all enabled -shell builtins. -If \fB\-n\fP is supplied, only disabled builtins are printed. -If \fB\-a\fP is supplied, the list printed includes all builtins, with an -indication of whether or not each is enabled. -If \fB\-s\fP is supplied, the output is restricted to the POSIX -\fIspecial\fP builtins. -The return value is 0 unless a -.I name -is not a shell builtin or there is an error loading a new builtin -from a shared object. -.TP -\fBeval\fP [\fIarg\fP ...] -The \fIarg\fPs are read and concatenated together into a single -command. This command is then read and executed by the shell, and -its exit status is returned as the value of -.BR eval . -If there are no -.IR args , -or only null arguments, -.B eval -returns 0. -.TP -\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP [\fIarguments\fP]] -If -.I command -is specified, it replaces the shell. -No new process is created. The -.I arguments -become the arguments to \fIcommand\fP. -If the -.B \-l -option is supplied, -the shell places a dash at the beginning of the zeroth arg passed to -.IR command . -This is what -.IR login (1) -does. The -.B \-c -option causes -.I command -to be executed with an empty environment. If -.B \-a -is supplied, the shell passes -.I name -as the zeroth argument to the executed command. If -.I command -cannot be executed for some reason, a non-interactive shell exits, -unless the shell option -.B execfail -is enabled, in which case it returns failure. -An interactive shell returns failure if the file cannot be executed. -If -.I command -is not specified, any redirections take effect in the current shell, -and the return status is 0. If there is a redirection error, the -return status is 1. -.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 -\fBexport\fP [\fB\-fn\fP\^] [\fIname\fP[=\fIword\fP]] ... -.PD 0 -.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 each -\fIname\fP. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -.B export -returns an exit status of 0 unless an invalid option is -encountered, -one of the \fInames\fP is not a valid shell variable name, or -.B \-f -is supplied with a -.I name -that is not a function. -.TP -\fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-nlr\fP] [\fIfirst\fP] [\fIlast\fP] -.PD 0 -.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 -.if n ``fc \-l \-10'' -.if t \f(CWfc \-l \-10\fP -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 -option suppresses -the command numbers when listing. The -.B \-r -option reverses the order of -the commands. If the -.B \-l -option 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 -.if n ``r="fc -s"'', -.if t \f(CWr='fc \-s'\fP, -so that typing -.if n ``r cc'' -.if t \f(CWr cc\fP -runs the last command beginning with -.if n ``cc'' -.if t \f(CWcc\fP -and typing -.if n ``r'' -.if t \f(CWr\fP -re-executes the last command. -.sp 1 -If the first form is used, the return value is 0 unless an invalid -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] -Resume -.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 characters to be recognized; if a character -is followed by a colon, the option is expected to have an -argument, which should be separated from it by white space. -The colon and question mark characters may not be used as -option characters. -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 -When the end of options is encountered, \fBgetopts\fP exits with a -return value greater than zero. -\fBOPTIND\fP is set to the index of the first non-option argument, -and \fBname\fP is set to ?. -.sp 1 -.B getopts -normally parses the positional parameters, but if more arguments are -given in -.IR args , -.B getopts -parses those instead. -.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 invalid options or missing option arguments are -encountered. -If the variable -.SM -.B OPTERR -is set to 0, no error messages will be displayed, even if the first -character of -.I optstring -is not a colon. -.sp 1 -If an invalid 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 , -.SM -.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 -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\-lr\fP] [\fB\-p\fP \fIfilename\fP] [\fB\-dt\fP] [\fIname\fP] -For each -.IR name , -the full file name of the command is determined by searching -the directories in -.B $PATH -and remembered. -If the -.B \-p -option is supplied, no path search is performed, and -.I filename -is used as the full file name of the command. -The -.B \-r -option causes the shell to forget all -remembered locations. -The -.B \-d -option causes the shell to forget the remembered location of each \fIname\fP. -If the -.B \-t -option is supplied, the full pathname to which each \fIname\fP corresponds -is printed. If multiple \fIname\fP arguments are supplied with \fB\-t\fP, -the \fIname\fP is printed before the hashed full pathname. -The -.B \-l -option causes output to be displayed in a format that may be reused as input. -If no arguments are given, or if only \fB\-l\fP is supplied, -information about remembered commands is printed. -The return status is true unless a -.I name -is not found or an invalid option is supplied. -.TP -\fBhelp\fP [\fB\-s\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 help for all the builtins and shell control structures -is printed. -The \fB\-s\fP option restricts the information displayed to a short -usage synopsis. -The return status is 0 unless no command matches -.IR pattern . -.TP -\fBhistory [\fIn\fP] -.PD 0 -.TP -\fBhistory\fP \fB\-c\fP -.TP -\fBhistory \-d\fP \fIoffset\fP -.TP -\fBhistory\fP \fB\-anrw\fP [\fIfilename\fP] -.TP -\fBhistory\fP \fB\-p\fP \fIarg\fP [\fIarg ...\fP] -.TP -\fBhistory\fP \fB\-s\fP \fIarg\fP [\fIarg ...\fP] -.PD -With no options, display the command -history list with line numbers. Lines listed -with a -.B * -have been modified. An argument of -.I n -lists only the last -.I n -lines. -If the shell variable \fBHISTTIMEFORMAT\fP is set and not null, -it is used as a format string for \fIstrftime\fP(3) to display -the time stamp associated with each displayed history entry. -No intervening blank is printed between the formatted time stamp -and the history line. -If \fIfilename\fP is supplied, it is used as the -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 \-c -Clear the history list by deleting all the entries. -.TP -\fB\-d\fP \fIoffset\fP -Delete the history entry at position \fIoffset\fP. -.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 \-p -Perform history substitution on the following \fIargs\fP and display -the result on the standard output. -Does not store the results in the history list. -Each \fIarg\fP must be quoted to disable normal history expansion. -.TP -.B \-s -Store the -.I args -in the history list as a single entry. The last command in the -history list is removed before the -.I args -are added. -.PD -.PP -If the \fBHISTTIMEFORMAT\fP is set, the time stamp information -associated with each history entry is written to the history file. -The return value is 0 unless an invalid option is encountered, an -error occurs while reading or writing the history file, an invalid -\fIoffset\fP is supplied as an argument to \fB\-d\fP, or the -history expansion supplied as an argument to \fB\-p\fP fails. -.RE -.TP -\fBjobs\fP [\fB\-lnprs\fP] [ \fIjobspec\fP ... ] -.PD 0 -.TP -\fBjobs\fP \fB\-x\fP \fIcommand\fP [ \fIargs\fP ... ] -.PD -The first form lists the active jobs. The options have the following -meanings: -.RS -.PD 0 -.TP -.B \-l -List process IDs -in addition to the normal information. -.TP -.B \-p -List only the process ID of the job's process group -leader. -.TP -.B \-n -Display information only about jobs that have changed status since -the user was last notified of their status. -.TP -.B \-r -Restrict output to running jobs. -.TP -.B \-s -Restrict output to stopped jobs. -.PD -.PP -If -.I jobspec -is given, output is restricted to information about that job. -The return status is 0 unless an invalid option is encountered -or an invalid -.I jobspec -is supplied. -.PP -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. -.RE -.TP -\fBkill\fP [\fB\-s\fP \fIsigspec\fP | \fB\-n\fP \fIsignum\fP | \fB\-\fP\fIsigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... -.PD 0 -.TP -\fBkill\fP \fB\-l\fP [\fIsigspec\fP | \fIexit_status\fP] -.PD -Send the signal named by -.I sigspec -or -.I signum -to the processes named by -.I pid -or -.IR jobspec . -.I sigspec -is either a case-insensitive signal name such as -.SM -.B SIGKILL -(with or without the -.SM -.B SIG -prefix) or a signal number; -.I signum -is a signal number. -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 signals corresponding to the arguments are -listed, and the return status is 0. -The \fIexit_status\fP argument to -.B \-l -is a number specifying either a signal number or the exit status of -a process terminated by a signal. -.B kill -returns true if at least one signal was successfully sent, or false -if an error occurs or an invalid 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 [\fIoption\fP] [\fIname\fP[=\fIvalue\fP] ...] -For each argument, a local variable named -.I name -is created, and assigned -.IR value . -The \fIoption\fP can be any of the options accepted by \fBdeclare\fP. -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, an invalid -.I name -is supplied, or -\fIname\fP is a readonly variable. -.TP -.B logout -Exit a login shell. -.TP -\fBpopd\fP [\-\fBn\fP] [+\fIn\fP] [\-\fIn\fP] -Removes entries from the directory stack. With no arguments, -removes the top directory from the stack, and performs a -.B cd -to the new top directory. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Removes the \fIn\fPth entry counting from the left of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd +0'' -.if t \f(CWpopd +0\fP -removes the first directory, -.if n ``popd +1'' -.if t \f(CWpopd +1\fP -the second. -.TP -\fB\-\fP\fIn\fP -Removes the \fIn\fPth entry counting from the right of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd -0'' -.if t \f(CWpopd -0\fP -removes the last directory, -.if n ``popd -1'' -.if t \f(CWpopd -1\fP -the next to last. -.TP -.B \-n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -.PD -.PP -If the -.B popd -command is successful, a -.B dirs -is performed as well, and the return status is 0. -.B popd -returns false if an invalid option is encountered, the directory stack -is empty, a non-existent directory stack entry is specified, or the -directory change fails. -.RE -.TP -\fBprintf\fP \fIformat\fP [\fIarguments\fP] -Write the formatted \fIarguments\fP to the standard output under the -control of the \fIformat\fP. -The \fIformat\fP is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -\fIargument\fP. -In addition to the standard \fIprintf\fP(1) formats, \fB%b\fP causes -\fBprintf\fP to expand backslash escape sequences in the corresponding -\fIargument\fP (except that \fB\ec\fP terminates output, backslashes in -\fB\e'\fP, \fB\e"\fP, and \fB\e?\fP are not removed, and octal escapes -beginning with \fB\e0\fP may contain up to four digits), -and \fB%q\fP causes \fBprintf\fP to output the corresponding -\fIargument\fP in a format that can be reused as shell input. -.sp 1 -The \fIformat\fP is reused as necessary to consume all of the \fIarguments\fP. -If the \fIformat\fP requires more \fIarguments\fP than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. -.TP -\fBpushd\fP [\fB\-n\fP] [\fIdir\fP] -.PD 0 -.TP -\fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] -.PD -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories -and returns 0, unless the directory stack is empty. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -\fB+\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the left of the list shown by -.BR dirs , -starting with zero) -is at the top. -.TP -\fB\-\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the right of the list shown by -.BR dirs , -starting with zero) is at the top. -.TP -.B \-n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -.TP -.I 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-existent directory stack element is specified, -or the directory change to the specified new current directory -fails. -.RE -.TP -\fBpwd\fP [\fB\-LP\fP] -Print the absolute pathname of the current working directory. -The pathname printed contains no symbolic links if the -.B \-P -option is supplied or the -.B \-o physical -option to the -.B set -builtin command is enabled. -If the -.B \-L -option is used, the pathname printed may contain symbolic links. -The return status is 0 unless an error occurs while -reading the name of the current directory or an -invalid option is supplied. -.TP -\fBread\fP [\fB\-ers\fP] [\fB\-u\fP \fIfd\fP] [\fB\-t\fP \fItimeout\fP] [\fB\-a\fP \fIaname\fP] [\fB\-p\fP \fIprompt\fP] [\fB\-n\fP \fInchars\fP] [\fB\-d\fP \fIdelim\fP] [\fIname\fP ...] -One line is read from the standard input, or from the file descriptor -\fIfd\fP supplied as an argument to the \fB\-u\fP option, 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 and their intervening separators assigned -to the last -.IR name . -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in -.SM -.B IFS -are used to split the line into words. -The backslash character (\fB\e\fP) may be used to remove any special -meaning for the next character read and for line continuation. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-a \fIaname\fP -The words are assigned to sequential indices -of the array variable -.IR aname , -starting at 0. -.I aname -is unset before any new values are assigned. -Other \fIname\fP arguments are ignored. -.TP -.B \-d \fIdelim\fP -The first character of \fIdelim\fP is used to terminate the input line, -rather than newline. -.TP -.B \-e -If the standard input -is coming from a terminal, -.B readline -(see -.SM -.B READLINE -above) is used to obtain the line. -.TP -.B \-n \fInchars\fP -\fBread\fP returns after reading \fInchars\fP characters rather than -waiting for a complete line of input. -.TP -.B \-p \fIprompt\fP -Display \fIprompt\fP on standard error, without a -trailing newline, before attempting to read any input. The prompt -is displayed only if input is coming from a terminal. -.TP -.B \-r -Backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. -.TP -.B \-s -Silent mode. If input is coming from a terminal, characters are -not echoed. -.TP -.B \-t \fItimeout\fP -Cause \fBread\fP to time out and return failure if a complete line of -input is not read within \fItimeout\fP seconds. -This option has no effect if \fBread\fP is not reading input from the -terminal or a pipe. -.TP -.B \-u \fIfd\FP -Read input from file descriptor \fIfd\fP. -.PD -.PP -If no -.I names -are supplied, the line read is assigned to the variable -.SM -.BR REPLY . -The return code is zero, unless end-of-file is encountered, \fBread\fP -times out, or an invalid file descriptor is supplied as the argument to -\fB\-u\fP. -.RE -.TP -\fBreadonly\fP [\fB\-apf\fP] [\fIname\fP[=\fIword\fP] ...] -.PD -The given -\fInames\fP are marked readonly; the values of these -.I names -may not be changed by subsequent assignment. -If the -.B \-f -option is supplied, the functions corresponding to the -\fInames\fP are so -marked. -The -.B \-a -option restricts the variables to arrays. -If no -.I name -arguments are given, or if the -.B \-p -option is supplied, a list of all readonly names is printed. -The -.B \-p -option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -The return status is 0 unless an invalid option is encountered, -one of the -.I names -is not a valid 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. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes after the function or script. -.TP -\fBset\fP [\fB\-\-abefhkmnptuvxBCHP\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...] -Without options, the name and value of each shell variable are displayed -in a format that can be reused as input. -The output is sorted according to the current locale. -When options are specified, they set or unset shell attributes. -Any arguments remaining after the options are processed are treated -as values for the positional parameters and are assigned, in order, to -.BR $1 , -.BR $2 , -.B ... -.BR $\fIn\fP . -Options, if specified, have the following meanings: -.RS -.PD 0 -.TP 8 -.B \-a -Automatically mark variables and functions which are modified or -created for export to the environment of subsequent commands. -.TP 8 -.B \-b -Report the status of terminated background jobs -immediately, rather than before the next primary prompt. This is -effective only when job control is enabled. -.TP 8 -.B \-e -Exit immediately if a \fIsimple command\fP (see -.SM -.B SHELL GRAMMAR -above) exits with a non-zero status. -The shell does not exit if the -command that fails is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test in 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 ! . -A trap on \fBERR\fP, if set, is executed before the shell exits. -.TP 8 -.B \-f -Disable pathname expansion. -.TP 8 -.B \-h -Remember the location of commands as they are looked up for execution. -This is enabled by default. -.TP 8 -.B \-k -All arguments in the form of assignment statements -are placed in the environment for a command, not just -those that precede the command name. -.TP 8 -.B \-m -Monitor mode. Job control is enabled. This option 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 by -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 -Same as -.BR \-B . -.TP 8 -.B emacs -Use an emacs-style command line editing interface. This is enabled -by default when the shell is interactive, unless the shell is started -with the -.B \-\-noediting -option. -.TP 8 -.B errtrace -Same as -.BR \-E . -.TP 8 -.B functrace -Same as -.BR \-T . -.TP 8 -.B errexit -Same as -.BR \-e . -.TP 8 -.B hashall -Same as -.BR \-h . -.TP 8 -.B histexpand -Same as -.BR \-H . -.TP 8 -.B history -Enable command history, as described above under -.SM -.BR HISTORY . -This option is on by default in interactive shells. -.TP 8 -.B ignoreeof -The effect is as if the shell command -.if t \f(CWIGNOREEOF=10\fP -.if n ``IGNOREEOF=10'' -had been executed -(see -.B Shell Variables -above). -.TP 8 -.B keyword -Same as -.BR \-k . -.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 . -.B nolog -Currently ignored. -.TP 8 -.B notify -Same as -.BR \-b . -.TP 8 -.B nounset -Same as -.BR \-u . -.TP 8 -.B onecmd -Same as -.BR \-t . -.TP 8 -.B physical -Same as -.BR \-P . -.TP 8 -.B pipefail -If set, the return value of a pipeline is the value of the last -(rightmost) command to exit with a non-zero status, or zero if all -commands in the pipeline exit successfully. -This option is disabled by default. -.TP 8 -.B posix -Change the behavior of -.B bash -where the default operation differs -from the POSIX 1003.2 standard to match the standard (\fI`posix mode\fP). -.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 . -.sp .5 -.PP -If -.B \-o -is supplied with no \fIoption\-name\fP, the values of the current options are -printed. -If -.B +o -is supplied with no \fIoption\-name\fP, a series of -.B set -commands to recreate the current option settings is displayed on -the standard output. -.RE -.TP 8 -.B \-p -Turn on -.I privileged -mode. In this mode, the -.SM -.B $ENV -and -.SM -.B $BASH_ENV -files are not processed, shell functions are not inherited from the -environment, and the -.SM -.B SHELLOPTS -variable, if it appears in the environment, is ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at startup, the effective user id is -not reset. -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 \fIsimple command\fP, -\fBfor\fP command, \fBcase\fP command, \fBselect\fP command, or -arithmetic \fBfor\fP command, display the expanded value of -.SM -.BR PS4 , -followed by the command and its expanded arguments -or associated word list. -.TP 8 -.B \-B -The shell performs brace expansion (see -.B Brace Expansion -above). This is on by default. -.TP 8 -.B \-C -If set, -.B bash -does not overwrite an existing file with the -.BR > , -.BR >& , -and -.B <> -redirection operators. This may be overridden when -creating output files by using the redirection operator -.B >| -instead of -.BR > . -.TP 8 -.B \-E -If set, any trap on \fBERR\fP is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The \fBERR\fP trap is normally not inherited in such cases. -.TP 8 -.B \-H -Enable -.B ! -style history substitution. This option is on by -default when the shell is interactive. -.TP 8 -.B \-P -If set, the shell does not follow symbolic links when executing -commands such as -.B cd -that change the current working directory. It uses the -physical directory structure instead. By default, -.B bash -follows the logical chain of directories when performing commands -which change the current directory. -.TP 8 -.B \-T -If set, any trap on \fBDEBUG\fP is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The \fBDEBUG\fP trap is normally not inherited in such cases. -.TP 8 -.B \-\- -If no arguments follow this option, then the positional parameters are -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 options are off by default unless otherwise noted. -Using + rather than \- causes these options to be turned off. -The options can also be specified as arguments to an invocation of -the shell. -The current set of options may be found in -.BR $\- . -The return status is always true unless an invalid 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. -.I n -must be a non-negative number less than or equal to \fB$#\fP. -If -.I n -is 0, no parameters are changed. -If -.I n -is not given, it is assumed to be 1. -If -.I n -is greater than \fB$#\fP, the positional parameters are not changed. -The return status is greater than zero if -.I n -is greater than -.B $# -or less than zero; otherwise 0. -.TP -\fBshopt\fP [\fB\-pqsu\fP] [\fB\-o\fP] [\fIoptname\fP ...] -Toggle the values of variables controlling optional shell behavior. -With no options, or with the -.B \-p -option, a list of all settable options is displayed, with -an indication of whether or not each is set. -The \fB\-p\fP option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: -.RS -.PD 0 -.TP -.B \-s -Enable (set) each \fIoptname\fP. -.TP -.B \-u -Disable (unset) each \fIoptname\fP. -.TP -.B \-q -Suppresses normal output (quiet mode); the return status indicates -whether the \fIoptname\fP is set or unset. -If multiple \fIoptname\fP arguments are given with -.BR \-q , -the return status is zero if all \fIoptnames\fP are enabled; non-zero -otherwise. -.TP -.B \-o -Restricts the values of \fIoptname\fP to be those defined for the -.B \-o -option to the -.B set -builtin. -.PD -.PP -If either -.B \-s -or -.B \-u -is used with no \fIoptname\fP arguments, the display is limited to -those options which are set or unset, respectively. -Unless otherwise noted, the \fBshopt\fP options are disabled (unset) -by default. -.PP -The return status when listing options is zero if all \fIoptnames\fP -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an \fIoptname\fP is not a valid shell -option. -.PP -The list of \fBshopt\fP options is: -.if t .sp .5v -.if n .sp 1v -.PD 0 -.TP 8 -.B cdable_vars -If set, an argument to the -.B cd -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. -.TP 8 -.B cdspell -If set, minor errors in the spelling of a directory component in a -.B cd -command will be corrected. -The errors checked for are transposed characters, -a missing character, and one character too many. -If a correction is found, the corrected file name is printed, -and the command proceeds. -This option is only used by interactive shells. -.TP 8 -.B checkhash -If set, \fBbash\fP checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. -.TP 8 -.B checkwinsize -If set, \fBbash\fP checks the window size after each command -and, if necessary, updates the values of -.SM -.B LINES -and -.SM -.BR COLUMNS . -.TP 8 -.B cmdhist -If set, -.B bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. -.TP 8 -.B dotglob -If set, -.B bash -includes filenames beginning with a `.' in the results of pathname -expansion. -.TP 8 -.B execfail -If set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the -.B exec -builtin command. An interactive shell does not exit if -.B exec -fails. -.TP 8 -.B expand_aliases -If set, aliases are expanded as described above under -.SM -.BR ALIASES . -This option is enabled by default for interactive shells. -.TP 8 -.B extdebug -If set, behavior intended for use by debuggers is enabled: -.RS -.TP -.B 1. -The \fB\-F\fP option to the \fBdeclare\fP builtin displays the source -file name and line number corresponding to each function name supplied -as an argument. -.TP -.B 2. -If the command run by the \fBDEBUG\fP trap returns a non-zero value, the -next command is skipped and not executed. -.TP -.B 3. -If the command run by the \fBDEBUG\fP trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the \fB.\fP or \fBsource\fP builtins), a call to -\fBreturn\fP is simulated. -.RE -.TP 8 -.B extglob -If set, the extended pattern matching features described above under -\fBPathname Expansion\fP are enabled. -.TP 8 -.B extquote -If set, \fB$\fP'\fIstring\fP' and \fB$\fP"\fIstring\fP" quoting is -performed within \fB${\fP\fIparameter\fP\fB}\fP expansions -enclosed in double quotes. This option is enabled by default. -.TP 8 -.B failglob -If set, patterns which fail to match filenames during pathname expansion -result in an expansion error. -.TP 8 -.B force_fignore -If set, the suffixes specified by the \fBFIGNORE\fP shell variable -cause words to be ignored when performing word completion even if -the ignored words are the only possible completions. -See -.SM -\fBSHELL VARIABLES\fP -above for a description of \fBFIGNORE\fP. -This option is enabled by default. -.TP 8 -.B gnu_errfmt -If set, shell error messages are written in the standard GNU error -message format. -.TP 8 -.B histappend -If set, the history list is appended to the file named by the value -of the -.B HISTFILE -variable when the shell exits, rather than overwriting the file. -.TP 8 -.B histreedit -If set, and -.B readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. -.TP 8 -.B histverify -If set, and -.B readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the \fBreadline\fP editing buffer, allowing further modification. -.TP 8 -.B hostcomplete -If set, and -.B readline -is being used, \fBbash\fP will attempt to perform hostname completion when a -word containing a \fB@\fP is being completed (see -.B Completing -under -.SM -.B READLINE -above). -This is enabled by default. -.TP 8 -.B huponexit -If set, \fBbash\fP will send -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.TP 8 -.B interactive_comments -If set, allow a word beginning with -.B # -to cause that word and all remaining characters on that -line to be ignored in an interactive shell (see -.SM -.B COMMENTS -above). This option is enabled by default. -.TP 8 -.B lithist -If set, and the -.B cmdhist -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. -.TP 8 -.B login_shell -The shell sets this option if it is started as a login shell (see -.SM -.B "INVOCATION" -above). -The value may not be changed. -.TP 8 -.B mailwarn -If set, and a file that \fBbash\fP is checking for mail has been -accessed since the last time it was checked, the message ``The mail in -\fImailfile\fP has been read'' is displayed. -.TP 8 -.B no_empty_cmd_completion -If set, and -.B readline -is being used, -.B bash -will not attempt to search the \fBPATH\fP for possible completions when -completion is attempted on an empty line. -.TP 8 -.B nocaseglob -If set, -.B bash -matches filenames in a case\-insensitive fashion when performing pathname -expansion (see -.B Pathname Expansion -above). -.TP 8 -.B nullglob -If set, -.B bash -allows patterns which match no -files (see -.B Pathname Expansion -above) -to expand to a null string, rather than themselves. -.TP 8 -.B progcomp -If set, the programmable completion facilities (see -\fBProgrammable Completion\fP above) are enabled. -This option is enabled by default. -.TP 8 -.B promptvars -If set, prompt strings undergo -parameter expansion, command substitution, arithmetic -expansion, and quote removal after being expanded as described in -.SM -.B PROMPTING -above. This option is enabled by default. -.TP 8 -.B restricted_shell -The shell sets this option if it is started in restricted mode (see -.SM -.B "RESTRICTED SHELL" -below). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. -.TP 8 -.B shift_verbose -If set, the -.B shift -builtin prints an error message when the shift count exceeds the -number of positional parameters. -.TP 8 -.B sourcepath -If set, the -\fBsource\fP (\fB.\fP) builtin uses the value of -.SM -.B PATH -to find the directory containing the file supplied as an argument. -This option is enabled by default. -.TP 8 -.B xpg_echo -If set, the \fBecho\fP builtin expands backslash-escape sequences -by default. -.RE -.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 -\fBtest\fP \fIexpr\fP -.PD 0 -.TP -\fB[\fP \fIexpr\fP \fB]\fP -Return a status of 0 or 1 depending on -the evaluation of the conditional expression -.IR expr . -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described above under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence. -.RS -.PD 0 -.TP -.B ! \fIexpr\fP -True if -.I expr -is false. -.TP -.B ( \fIexpr\fP ) -Returns the value of \fIexpr\fP. -This may be used to override the normal precedence of operators. -.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. -.PD -.PP -\fBtest\fP and \fB[\fP evaluate conditional -expressions using a set of rules based on the number of arguments. -.if t .sp 0.5 -.if n .sp 1 -.PD 0 -.TP -0 arguments -The expression is false. -.TP -1 argument -The expression is true if and only if the argument is not null. -.TP -2 arguments -If the first argument is \fB!\fP, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the expression is true if the unary test is true. -If the first argument is not a valid unary conditional operator, the expression -is false. -.TP -3 arguments -If the second argument is one of the binary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the result of the expression is the result of the binary test using -the first and third arguments as operands. -If the first argument is \fB!\fP, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly \fB(\fP and the third argument is -exactly \fB)\fP, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -in this case. -.TP -4 arguments -If the first argument is \fB!\fP, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. -.TP -5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -.RE -.PD -.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\-lp\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 (and there is a single \fIsigspec\fP) or -.BR \- , -each specified signal is -reset to its original disposition (the value it had -upon entrance to the shell). -If -.I arg -is the null string the signal specified by each -.I sigspec -is ignored by the shell and by the commands it invokes. -If -.I arg -is not present and -.B \-p -has been supplied, then the trap commands associated with each -.I sigspec -are displayed. -If no arguments are supplied or if only -.B \-p -is given, -.B trap -prints the list of commands associated with each signal. -The -.B \-l -option causes the shell to print a list of signal names and -their corresponding numbers. -Each -.I sigspec -is either -a signal name defined in <\fIsignal.h\fP>, or a signal number. -Signal names are case insensitive and the SIG prefix is optional. -If a -.I sigspec -is -.SM -.B EXIT -(0) the command -.I arg -is executed on exit from the shell. -If a -.I sigspec -is -.SM -.BR DEBUG , -the command -.I arg -is executed before every \fIsimple command\fP, \fIfor\fP command, -\fIcase\fP command, \fIselect\fP command, every arithmetic \fIfor\fP -command, and before the first command executes in a shell function (see -.SM -.B SHELL GRAMMAR -above). -Refer to the description of the \fBextglob\fP option to the -\fBshopt\fP builtin for details of its effect on the \fBDEBUG\fP trap. -If a -.I sigspec -is -.SM -.BR ERR , -the command -.I arg -is executed whenever a simple command has a non\-zero exit status, -subject to the following conditions. -The -.SM -.B ERR -trap is not executed if the failed -command is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test in 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 ! . -These are the same conditions obeyed by the \fBerrexit\fP option. -If a -.I sigspec -is -.SM -.BR RETURN , -the command -.I arg -is executed each time a shell function or a script executed with the -\fB.\fP or \fBsource\fP builtins finishes executing. -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 any -.I sigspec -is invalid; otherwise -.B trap -returns true. -.TP -\fBtype\fP [\fB\-aftpP\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 \-t -option is used, -.B type -prints a string 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 -.I name -is not found, then nothing is printed, and an exit status of false -is returned. -If the -.B \-p -option 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 -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -The -.B \-P -option forces a -.SM -.B PATH -search for each \fIname\fP, even if -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -If a command is hashed, -.B \-p -and -.B \-P -print the hashed value, not necessarily the file that appears -first in -.SM -.BR PATH . -If the -.B \-a -option 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 \-p -option is not also used. -The table of hashed commands is not consulted -when using -.BR \-a . -The -.B \-f -option suppresses shell function lookup, as with the \fBcommand\fP builtin. -.B type -returns true if any of the arguments are found, false if -none are found. -.TP -\fBulimit\fP [\fB\-SHacdflmnpstuv\fP [\fIlimit\fP]] -Provides control over the resources available to the shell and to -processes started by it, on systems that allow such control. -The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is -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 \fB\-H\fP nor \fB\-S\fP is specified, both the soft and hard -limits are set. -The value of -.I limit -can be a number in the unit specified for the resource -or one of the special values -.BR hard , -.BR soft , -or -.BR unlimited , -which stand for the current hard limit, the current soft limit, and -no limit, respectively. -If -.I limit -is omitted, the current value of the soft limit of the resource is -printed, unless the \fB\-H\fP option is given. When more than one -resource is specified, the limit name and unit are printed before the value. -Other options are interpreted as follows: -.RS -.PD 0 -.TP -.B \-a -All current limits are reported -.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 \-l -The maximum size that may be locked into memory -.TP -.B \-m -The maximum resident set size -.TP -.B \-n -The maximum number of open file descriptors (most systems do not -allow this value to be set) -.TP -.B \-p -The pipe size in 512-byte blocks (this may not be set) -.TP -.B \-s -The maximum stack size -.TP -.B \-t -The maximum amount of cpu time in seconds -.TP -.B \-u -The maximum number of processes available to a single user -.TP -.B \-v -The maximum amount of virtual memory available to the shell -.PD -.PP -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 invalid option or argument is supplied, -or an error occurs while setting a new limit. -.RE -.TP -\fBumask\fP [\fB\-p\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, 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. -If the -.B \-p -option is supplied, and -.I mode -is omitted, the output is in a form that may be reused as input. -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 each \fIname\fP 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 function. -If no options are supplied, or the -.B \-v -option is given, each -.I name -refers to a shell variable. -Read-only variables may not be unset. -If -.B \-f -is specifed, -each -.I name -refers to a shell function, and the function definition -is removed. -Each unset variable or function is removed from the environment -passed to subsequent commands. -If any of -.SM -.BR RANDOM , -.SM -.BR SECONDS , -.SM -.BR LINENO , -.SM -.BR HISTCMD , -.SM -.BR FUNCNAME , -.SM -.BR GROUPS , -or -.SM -.B DIRSTACK -are unset, they lose their special properties, even if they are -subsequently reset. The exit status is true unless a -.I name -is readonly. -.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-existent process or job, the return status is -127. Otherwise, the return status is the exit status of the last -process or job waited for. -.\" bash_builtins -.if \n(zZ=1 .ig zZ -.SH "RESTRICTED SHELL" -.\" rbash.1 -.zY -.PP -If -.B bash -is started with the name -.BR rbash , -or the -.B \-r -option is supplied at invocation, -the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -It behaves identically to -.B bash -with the exception that the following are disallowed or not performed: -.IP \(bu -changing directories with \fBcd\fP -.IP \(bu -setting or unsetting the values of -.BR SHELL , -.BR PATH , -.BR ENV , -or -.B BASH_ENV -.IP \(bu -specifying command names containing -.B / -.IP \(bu -specifying a file name containing a -.B / -as an argument to the -.B . -builtin command -.IP \(bu -Specifying a filename containing a slash as an argument to the -.B \-p -option to the -.B hash -builtin command -.IP \(bu -importing function definitions from the shell environment at startup -.IP \(bu -parsing the value of \fBSHELLOPTS\fP from the shell environment at startup -.IP \(bu -redirecting output using the >, >|, <>, >&, &>, and >> redirection operators -.IP \(bu -using the -.B exec -builtin command to replace the shell with another command -.IP \(bu -adding or deleting builtin commands with the -.B \-f -and -.B \-d -options to the -.B enable -builtin command -.IP \(bu -Using the \fBenable\fP builtin command to enable disabled shell builtins -.IP \(bu -specifying the -.B \-p -option to the -.B command -builtin command -.IP \(bu -turning off restricted mode with -\fBset +r\fP or \fBset +o restricted\fP. -.PP -These restrictions are enforced after any startup files are read. -.PP -.ie \n(zY=1 When a command that is found to be a shell script is executed, -.el \{ When a command that is found to be a shell script is executed -(see -.SM -.B "COMMAND EXECUTION" -above), -\} -.B rbash -turns off any restrictions in the shell spawned to execute the -script. -.\" end of rbash.1 -.if \n(zY=1 .ig zY -.SH "SEE ALSO" -.PD 0 -.TP -\fIBash Reference Manual\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 -\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 ~/.bash_logout -The individual login shell cleanup file, executed when a login shell exits -.TP -.FN ~/.inputrc -Individual \fIreadline\fP initialization file -.PD -.SH AUTHORS -Brian Fox, Free Software Foundation -.br -bfox@gnu.org -.PP -Chet Ramey, Case Western Reserve University -.br -chet@po.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 -.BR bash . -The latest version is always available from -\fIftp://ftp.gnu.org/pub/bash/\fP. -.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 encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to \fIbug-bash@gnu.org\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@po.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. -.PP -Shell builtin commands and functions are not stoppable/restartable. -.PP -Compound commands and command sequences of the form `a ; b ; c' -are not handled gracefully when process suspension is attempted. -When a process is stopped, the shell immediately executes the next -command in the sequence. -It suffices to place the sequence of commands between -parentheses to force it into a subshell, which may be stopped as -a unit. -.PP -Commands inside of \fB$(\fP...\fB)\fP command substitution are not -parsed until substitution is attempted. This will delay error -reporting until some time after the command is entered. For example, -unmatched parentheses, even inside shell comments, will result in -error messages while the construct is being read. -.PP -Array variables may not (yet) be exported. -.zZ -.zY diff --git a/doc/bashref.texi.orig b/doc/bashref.texi.orig deleted file mode 100644 index fdce9e3c7..000000000 --- a/doc/bashref.texi.orig +++ /dev/null @@ -1,7105 +0,0 @@ -\input texinfo.tex @c -*- texinfo -*- -@c %**start of header -@setfilename bashref.info -@settitle Bash Reference Manual -@c %**end of header - -@setchapternewpage odd - -@include version.texi - -@copying -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}). - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Copyright @copyright{} 1988-2003 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. - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.1 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with the Front-Cover texts being ``A GNU Manual,'' -and with the Back-Cover Texts as in (a) below. A copy of the license is -included in the section entitled ``GNU Free Documentation License.'' - -(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify -this GNU Manual, like GNU software. Copies published by the Free -Software Foundation raise funds for GNU development.'' -@end quotation -@end copying - -@defcodeindex bt -@defcodeindex rw -@set BashFeatures - -@dircategory Basics -@direntry -* Bash: (bash). The GNU Bourne-Again SHell. -@end direntry - -@finalout - -@titlepage -@title Bash Reference Manual -@subtitle Reference Documentation for Bash -@subtitle Edition @value{EDITION}, for @code{Bash} Version @value{VERSION}. -@subtitle @value{UPDATED-MONTH} -@author Chet Ramey, Case Western Reserve University -@author Brian Fox, Free Software Foundation - -@page -@vskip 0pt plus 1filll -@insertcopying - -@sp 1 -Published by the Free Software Foundation @* -59 Temple Place, Suite 330, @* -Boston, MA 02111-1307 @* -USA @* - -@end titlepage - -@contents - -@ifnottex -@node Top, Introduction, (dir), (dir) -@top Bash Features - -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}).. - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Bash contains features that appear in other popular shells, and some -features that only appear in Bash. Some of the shells that Bash has -borrowed concepts from are the Bourne Shell (@file{sh}), the Korn Shell -(@file{ksh}), and the C-shell (@file{csh} and its successor, -@file{tcsh}). The following menu breaks the features up into -categories based upon which one of these other shells inspired the -feature. - -This manual is meant as a brief introduction to features found in -Bash. The Bash manual page should be used as the definitive -reference on shell behavior. - -@menu -* Introduction:: An introduction to the shell. - -* Definitions:: Some definitions used in the rest of this - manual. - -* Basic Shell Features:: The shell "building blocks". - -* Shell Builtin Commands:: Commands that are a part of the shell. - -* Shell Variables:: Variables used or set by Bash. - -* Bash Features:: Features found only in Bash. - -* Job Control:: A chapter describing what job control is - and how Bash allows you to use it. - -* Using History Interactively:: Chapter dealing with history expansion - rules. - -* Command Line Editing:: Chapter describing the command line - editing features. - -* Installing Bash:: How to build and install Bash on your system. - -* Reporting Bugs:: How to report bugs in Bash. - -* Major Differences From The Bourne Shell:: A terse list of the differences - between Bash and historical - versions of /bin/sh. - -* Copying This Manual:: Copying this manual. - -* Builtin Index:: Index of Bash builtin commands. - -* Reserved Word Index:: Index of Bash reserved words. - -* Variable Index:: Quick reference helps you find the - variable you want. - -* Function Index:: Index of bindable Readline functions. - -* Concept Index:: General index for concepts described in - this manual. -@end menu -@end ifnottex - -@node Introduction -@chapter Introduction -@menu -* What is Bash?:: A short description of Bash. - -* What is a shell?:: A brief introduction to shells. -@end menu - -@node What is Bash? -@section What is Bash? - -Bash is the shell, or command language interpreter, -for the @sc{gnu} operating system. -The name is an acronym for the @samp{Bourne-Again SHell}, -a pun on Stephen Bourne, the author of the direct ancestor of -the current Unix shell @code{/bin/sh}, -which appeared in the Seventh Edition Bell Labs Research version -of Unix. - -Bash is largely compatible with @code{sh} and incorporates useful -features from the Korn shell @code{ksh} and the C shell @code{csh}. -It is intended to be a conformant implementation of the @sc{ieee} -@sc{posix} Shell and Tools specification (@sc{ieee} Working Group 1003.2). -It offers functional improvements over @code{sh} for both interactive and -programming use. - -While the @sc{gnu} operating system provides other shells, including -a version of @code{csh}, Bash is the default shell. -Like other @sc{gnu} software, Bash is quite portable. It currently runs -on nearly every version of Unix and a few other operating systems @minus{} -independently-supported ports exist for @sc{ms-dos}, @sc{os/2}, -Windows @sc{95/98}, and Windows @sc{nt}. - -@node What is a shell? -@section What is a shell? - -At its base, a shell is simply a macro processor that executes -commands. A Unix shell is both a command interpreter, which -provides the user interface to the rich set of @sc{gnu} utilities, -and a programming language, allowing these utilitites to be -combined. Files containing commands can be created, and become -commands themselves. These new commands have the same status as -system commands in directories such as @file{/bin}, allowing users -or groups to establish custom environments. - -A shell allows execution of @sc{gnu} commands, both synchronously and -asynchronously. -The shell waits for synchronous commands to complete before accepting -more input; asynchronous commands continue to execute in parallel -with the shell while it reads and executes additional commands. -The @dfn{redirection} constructs permit -fine-grained control of the input and output of those commands. -Moreover, the shell allows control over the contents of commands' -environments. -Shells may be used interactively or non-interactively: they accept -input typed from the keyboard or from a file. - -Shells also provide a small set of built-in -commands (@dfn{builtins}) implementing functionality impossible -or inconvenient to obtain via separate utilities. -For example, @code{cd}, @code{break}, @code{continue}, and -@code{exec}) cannot be implemented outside of the shell because -they directly manipulate the shell itself. -The @code{history}, @code{getopts}, @code{kill}, or @code{pwd} -builtins, among others, could be implemented in separate utilities, -but they are more convenient to use as builtin commands. -All of the shell builtins are described in -subsequent sections. - -While executing commands is essential, most of the power (and -complexity) of shells is due to their embedded programming -languages. Like any high-level language, the shell provides -variables, flow control constructs, quoting, and functions. - -Shells offer features geared specifically for -interactive use rather than to augment the programming language. -These interactive features include job control, command line -editing, history and aliases. Each of these features is -described in this manual. - -@node Definitions -@chapter Definitions -These definitions are used throughout the remainder of this manual. - -@table @code - -@item POSIX -@cindex POSIX -A family of open system standards based on Unix. Bash -is concerned with @sc{posix} 1003.2, the Shell and Tools Standard. - -@item blank -A space or tab character. - -@item builtin -@cindex builtin -A command that is implemented internally by the shell itself, rather -than by an executable program somewhere in the file system. - -@item control operator -@cindex control operator -A @code{word} that performs a control function. It is a @code{newline} -or one of the following: -@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;}, -@samp{|}, @samp{(}, or @samp{)}. - -@item exit status -@cindex exit status -The value returned by a command to its caller. The value is restricted -to eight bits, so the maximum value is 255. - -@item field -@cindex field -A unit of text that is the result of one of the shell expansions. After -expansion, when executing a command, the resulting fields are used as -the command name and arguments. - -@item filename -@cindex filename -A string of characters used to identify a file. - -@item job -@cindex job -A set of processes comprising a pipeline, and any processes descended -from it, that are all in the same process group. - -@item job control -@cindex job control -A mechanism by which users can selectively stop (suspend) and restart -(resume) execution of processes. - -@item metacharacter -@cindex metacharacter -A character that, when unquoted, separates words. A metacharacter is -a @code{blank} or one of the following characters: -@samp{|}, @samp{&}, @samp{;}, @samp{(}, @samp{)}, @samp{<}, or -@samp{>}. - -@item name -@cindex name -@cindex identifier -A @code{word} consisting solely of letters, numbers, and underscores, -and beginning with a letter or underscore. @code{Name}s are used as -shell variable and function names. -Also referred to as an @code{identifier}. - -@item operator -@cindex operator, shell -A @code{control operator} or a @code{redirection operator}. -@xref{Redirections}, for a list of redirection operators. - -@item process group -@cindex process group -A collection of related processes each having the same process -group @sc{id}. - -@item process group ID -@cindex process group ID -A unique identifer that represents a @code{process group} -during its lifetime. - -@item reserved word -@cindex reserved word -A @code{word} that has a special meaning to the shell. Most reserved -words introduce shell flow control constructs, such as @code{for} and -@code{while}. - -@item return status -@cindex return status -A synonym for @code{exit status}. - -@item signal -@cindex signal -A mechanism by which a process may be notified by the kernel -of an event occurring in the system. - -@item special builtin -@cindex special builtin -A shell builtin command that has been classified as special by the -@sc{posix} 1003.2 standard. - -@item token -@cindex token -A sequence of characters considered a single unit by the shell. It is -either a @code{word} or an @code{operator}. - -@item word -@cindex word -A @code{token} that is not an @code{operator}. -@end table - -@node Basic Shell Features -@chapter Basic Shell Features -@cindex Bourne shell - -Bash is an acronym for @samp{Bourne-Again SHell}. -The Bourne shell is -the traditional Unix shell originally written by Stephen Bourne. -All of the Bourne shell builtin commands are available in Bash, -and the rules for evaluation and quoting are taken from the @sc{posix} -1003.2 specification for the `standard' Unix shell. - -This chapter briefly summarizes the shell's `building blocks': -commands, control structures, shell functions, shell @i{parameters}, -shell expansions, -@i{redirections}, which are a way to direct input and output from -and to named files, and how the shell executes commands. - -@menu -* Shell Syntax:: What your input means to the shell. -* Shell Commands:: The types of commands you can use. -* Shell Functions:: Grouping commands by name. -* Shell Parameters:: How the shell stores values. -* Shell Expansions:: How Bash expands parameters and the various - expansions available. -* Redirections:: A way to control where input and output go. -* Executing Commands:: What happens when you run a command. -* Shell Scripts:: Executing files of shell commands. -@end menu - -@node Shell Syntax -@section Shell Syntax -@menu -* Shell Operation:: The basic operation of the shell. - -* Quoting:: How to remove the special meaning from characters. - -* Comments:: How to specify comments. -@end menu - -When the shell reads input, it proceeds through a -sequence of operations. If the input indicates the beginning of a -comment, the shell ignores the comment symbol (@samp{#}), and the rest -of that line. - -Otherwise, roughly speaking, the shell reads its input and -divides the input into words and operators, employing the quoting rules -to select which meanings to assign various words and characters. - -The shell then parses these tokens into commands and other constructs, -removes the special meaning of certain words or characters, expands -others, redirects input and output as needed, executes the specified -command, waits for the command's exit status, and makes that exit status -available for further inspection or processing. - -@node Shell Operation -@subsection Shell Operation - -The following is a brief description of the shell's operation when it -reads and executes a command. Basically, the shell does the -following: - -@enumerate -@item -Reads its input from a file (@pxref{Shell Scripts}), from a string -supplied as an argument to the @option{-c} invocation option -(@pxref{Invoking Bash}), or from the user's terminal. - -@item -Breaks the input into words and operators, obeying the quoting rules -described in @ref{Quoting}. These tokens are separated by -@code{metacharacters}. Alias expansion is performed by this step -(@pxref{Aliases}). - -@item -Parses the tokens into simple and compound commands -(@pxref{Shell Commands}). - -@item -Performs the various shell expansions (@pxref{Shell Expansions}), breaking -the expanded tokens into lists of filenames (@pxref{Filename Expansion}) -and commands and arguments. - -@item -Performs any necessary redirections (@pxref{Redirections}) and removes -the redirection operators and their operands from the argument list. - -@item -Executes the command (@pxref{Executing Commands}). - -@item -Optionally waits for the command to complete and collects its exit -status (@pxref{Exit Status}). - -@end enumerate - -@node Quoting -@subsection Quoting -@cindex quoting -@menu -* Escape Character:: How to remove the special meaning from a single - character. -* Single Quotes:: How to inhibit all interpretation of a sequence - of characters. -* Double Quotes:: How to suppress most of the interpretation of a - sequence of characters. -* ANSI-C Quoting:: How to expand ANSI-C sequences in quoted strings. - -* Locale Translation:: How to translate strings into different languages. -@end menu - -Quoting is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -disable special treatment for special characters, to prevent -reserved words from being recognized as such, and to prevent -parameter expansion. - -Each of the shell metacharacters (@pxref{Definitions}) -has special meaning to the shell and must be quoted if it is to -represent itself. -When the command history expansion facilities are being used, the -@var{history expansion} character, usually @samp{!}, must be quoted -to prevent history expansion. @xref{Bash History Facilities}, for -more details concerning history expansion. - -There are three quoting mechanisms: the -@var{escape character}, single quotes, and double quotes. - -@node Escape Character -@subsubsection Escape Character -A non-quoted backslash @samp{\} is the Bash escape character. -It preserves the literal value of the next character that follows, -with the exception of @code{newline}. If a @code{\newline} pair -appears, and the backslash itself is not quoted, the @code{\newline} -is treated as a line continuation (that is, it is removed from -the input stream and effectively ignored). - -@node Single Quotes -@subsubsection Single Quotes - -Enclosing characters in single quotes (@samp{'}) preserves the literal value -of each character within the quotes. A single quote may not occur -between single quotes, even when preceded by a backslash. - -@node Double Quotes -@subsubsection Double Quotes - -Enclosing characters in double quotes (@samp{"}) preserves the literal value -of all characters within the quotes, with the exception of -@samp{$}, @samp{`}, and @samp{\}. -The characters @samp{$} and @samp{`} -retain their special meaning within double quotes (@pxref{Shell Expansions}). -The backslash retains its special meaning only when followed by one of -the following characters: -@samp{$}, @samp{`}, @samp{"}, @samp{\}, or @code{newline}. -Within double quotes, backslashes that are followed by one of these -characters are removed. Backslashes preceding characters without a -special meaning are left unmodified. -A double quote may be quoted within double quotes by preceding it with -a backslash. -When command history is being used, the double quote may not be used to -quote the history expansion character. - -The special parameters @samp{*} and @samp{@@} have special meaning -when in double quotes (@pxref{Shell Parameter Expansion}). - -@node ANSI-C Quoting -@subsubsection ANSI-C Quoting -@cindex quoting, ANSI - -Words of the form @code{$'@var{string}'} are treated specially. The -word expands to @var{string}, with backslash-escaped characters replaced -as specified by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: - -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \e -an escape character (not ANSI C) -@item \f -form feed -@item \n -newline -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \' -single quote -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@item \c@var{x} -a control-@var{x} character -@end table - -@noindent -The expanded result is single-quoted, as if the dollar sign had not -been present. - -@node Locale Translation -@subsubsection Locale-Specific Translation -@cindex localization -@cindex internationalization -@cindex native languages -@cindex translation, native languages - -A double-quoted string preceded by a dollar sign (@samp{$}) will cause -the string to be translated according to the current locale. -If the current locale is @code{C} or @code{POSIX}, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. - -@vindex LC_MESSAGES -@vindex TEXTDOMAIN -@vindex TEXTDOMAINDIR -Some systems use the message catalog selected by the @env{LC_MESSAGES} -shell variable. Others create the name of the message catalog from the -value of the @env{TEXTDOMAIN} shell variable, possibly adding a -suffix of @samp{.mo}. If you use the @env{TEXTDOMAIN} variable, you -may need to set the @env{TEXTDOMAINDIR} variable to the location of -the message catalog files. Still others use both variables in this -fashion: -@env{TEXTDOMAINDIR}/@env{LC_MESSAGES}/LC_MESSAGES/@env{TEXTDOMAIN}.mo. - -@node Comments -@subsection Comments -@cindex comments, shell - -In a non-interactive shell, or an interactive shell in which the -@code{interactive_comments} option to the @code{shopt} -builtin is enabled (@pxref{Bash Builtins}), -a word beginning with @samp{#} -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the @code{interactive_comments} -option enabled does not allow comments. The @code{interactive_comments} -option is on by default in interactive shells. -@xref{Interactive Shells}, for a description of what makes -a shell interactive. - -@node Shell Commands -@section Shell Commands -@cindex commands, shell - -A simple shell command such as @code{echo a b c} consists of the command -itself followed by arguments, separated by spaces. - -More complex shell commands are composed of simple commands arranged together -in a variety of ways: in a pipeline in which the output of one command -becomes the input of a second, in a loop or conditional construct, or in -some other grouping. - -@menu -* Simple Commands:: The most common type of command. -* Pipelines:: Connecting the input and output of several - commands. -* Lists:: How to execute commands sequentially. -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Command Grouping:: Ways to group commands. -@end menu - -@node Simple Commands -@subsection Simple Commands -@cindex commands, simple - -A simple command is the kind of command encountered most often. -It's just a sequence of words separated by @code{blank}s, terminated -by one of the shell's control operators (@pxref{Definitions}). The -first word generally specifies a command to be executed, with the -rest of the words being that command's arguments. - -The return status (@pxref{Exit Status}) of a simple command is -its exit status as provided -by the @sc{posix} 1003.1 @code{waitpid} function, or 128+@var{n} if -the command was terminated by signal @var{n}. - -@node Pipelines -@subsection Pipelines -@cindex pipeline -@cindex commands, pipelines - -A @code{pipeline} is a sequence of simple commands separated by -@samp{|}. - -@rwindex time -@rwindex ! -@cindex command timing -The format for a pipeline is -@example -[@code{time} [@code{-p}]] [@code{!}] @var{command1} [@code{|} @var{command2} @dots{}] -@end example - -@noindent -The output of each command in the pipeline is connected via a pipe -to the input of the next command. -That is, each command reads the previous command's output. - -The reserved word @code{time} causes timing statistics -to be printed for the pipeline once it finishes. -The statistics currently consist of elapsed (wall-clock) time and -user and system time consumed by the command's execution. -The @option{-p} option changes the output format to that specified -by @sc{posix}. -The @env{TIMEFORMAT} variable may be set to a format string that -specifies how the timing information should be displayed. -@xref{Bash Variables}, for a description of the available formats. -The use of @code{time} as a reserved word permits the timing of -shell builtins, shell functions, and pipelines. An external -@code{time} command cannot time these easily. - -If the pipeline is not executed asynchronously (@pxref{Lists}), the -shell waits for all commands in the pipeline to complete. - -Each command in a pipeline is executed in its own subshell -(@pxref{Command Execution Environment}). The exit -status of a pipeline is the exit status of the last command in the -pipeline. If the reserved word @samp{!} precedes the pipeline, the -exit status is the logical negation of the exit status of the last command. - -@node Lists -@subsection Lists of Commands -@cindex commands, lists - -A @code{list} is a sequence of one or more pipelines separated by one -of the operators @samp{;}, @samp{&}, @samp{&&}, or @samp{||}, -and optionally terminated by one of @samp{;}, @samp{&}, or a -@code{newline}. - -Of these list operators, @samp{&&} and @samp{||} -have equal precedence, followed by @samp{;} and @samp{&}, -which have equal precedence. - -A sequence of one or more newlines may appear in a @code{list} -to delimit commands, equivalent to a semicolon. - -If a command is terminated by the control operator @samp{&}, -the shell executes the command asynchronously in a subshell. -This is known as executing the command in the @var{background}. -The shell does not wait for the command to finish, and the return -status is 0 (true). -When job control is not active (@pxref{Job Control}), -the standard input for asynchronous commands, in the absence of any -explicit redirections, is redirected from @code{/dev/null}. - -Commands separated by a @samp{;} are executed sequentially; the shell -waits for each command to terminate in turn. The return status is the -exit status of the last command executed. - -The control operators @samp{&&} and @samp{||} -denote @sc{and} lists and @sc{or} lists, respectively. -An @sc{and} list has the form -@example -@var{command1} && @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns an exit status of zero. - -An @sc{or} list has the form -@example -@var{command1} || @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns a non-zero exit status. - -The return status of -@sc{and} and @sc{or} lists is the exit status of the last command -executed in the list. - -@node Looping Constructs -@subsection Looping Constructs -@cindex commands, looping - -Bash supports the following looping constructs. - -Note that wherever a @samp{;} appears in the description of a -command's syntax, it may be replaced with one or more newlines. - -@table @code -@item until -@rwindex until -@rwindex do -@rwindex done -The syntax of the @code{until} command is: -@example -until @var{test-commands}; do @var{consequent-commands}; done -@end example -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status which is not zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item while -@rwindex while -The syntax of the @code{while} command is: -@example -while @var{test-commands}; do @var{consequent-commands}; done -@end example - -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status of zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item for -@rwindex for -The syntax of the @code{for} command is: - -@example -for @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example -Expand @var{words}, and execute @var{commands} once for each member -in the resultant list, with @var{name} bound to the current member. -If @samp{in @var{words}} is not present, the @code{for} command -executes the @var{commands} once for each positional parameter that is -set, as if @samp{in "$@@"} had been specified -(@pxref{Special Parameters}). -The return status is the exit status of the last command that executes. -If there are no items in the expansion of @var{words}, no commands are -executed, and the return status is zero. - -An alternate form of the @code{for} command is also supported: - -@example -for (( @var{expr1} ; @var{expr2} ; @var{expr3} )) ; do @var{commands} ; done -@end example -First, the arithmetic expression @var{expr1} is evaluated according -to the rules described below (@pxref{Shell Arithmetic}). -The arithmetic expression @var{expr2} is then evaluated repeatedly -until it evaluates to zero. -Each time @var{expr2} evaluates to a non-zero value, @var{commands} are -executed and the arithmetic expression @var{expr3} is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in @var{list} -that is executed, or false if any of the expressions is invalid. - -@end table - -The @code{break} and @code{continue} builtins (@pxref{Bourne Shell Builtins}) -may be used to control loop execution. - -@node Conditional Constructs -@subsection Conditional Constructs -@cindex commands, conditional - -@table @code -@item if -@rwindex if -@rwindex then -@rwindex else -@rwindex elif -@rwindex fi -The syntax of the @code{if} command is: - -@example -if @var{test-commands}; then - @var{consequent-commands}; -[elif @var{more-test-commands}; then - @var{more-consequents};] -[else @var{alternate-consequents};] -fi -@end example - -The @var{test-commands} list is executed, and if its return status is zero, -the @var{consequent-commands} list is executed. -If @var{test-commands} returns a non-zero status, each @code{elif} list -is executed in turn, and if its exit status is zero, -the corresponding @var{more-consequents} is executed and the -command completes. -If @samp{else @var{alternate-consequents}} is present, and -the final command in the final @code{if} or @code{elif} clause -has a non-zero exit status, then @var{alternate-consequents} is executed. -The return status is the exit status of the last command executed, or -zero if no condition tested true. - -@item case -@rwindex case -@rwindex in -@rwindex esac -The syntax of the @code{case} command is: - -@example -@code{case @var{word} in [ [(] @var{pattern} [| @var{pattern}]@dots{}) @var{command-list} ;;]@dots{} esac} -@end example - -@code{case} will selectively execute the @var{command-list} corresponding to -the first @var{pattern} that matches @var{word}. -The @samp{|} is used to separate multiple patterns, and the @samp{)} -operator terminates a pattern list. -A list of patterns and an associated command-list is known -as a @var{clause}. Each clause must be terminated with @samp{;;}. -The @var{word} undergoes tilde expansion, parameter expansion, command -substitution, arithmetic expansion, and quote removal before matching is -attempted. Each @var{pattern} undergoes tilde expansion, parameter -expansion, command substitution, and arithmetic expansion. - -There may be an arbitrary number of @code{case} clauses, each terminated -by a @samp{;;}. The first pattern that matches determines the -command-list that is executed. - -Here is an example using @code{case} in a script that could be used to -describe one interesting feature of an animal: - -@example -echo -n "Enter the name of an animal: " -read ANIMAL -echo -n "The $ANIMAL has " -case $ANIMAL in - horse | dog | cat) echo -n "four";; - man | kangaroo ) echo -n "two";; - *) echo -n "an unknown number of";; -esac -echo " legs." -@end example - -@noindent -The return status is zero if no @var{pattern} is matched. Otherwise, the -return status is the exit status of the @var{command-list} executed. - -@item select -@rwindex select - -The @code{select} construct allows the easy generation of menus. -It has almost the same syntax as the @code{for} command: - -@example -select @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example - -The list of words following @code{in} is expanded, generating a list -of items. The set of expanded words is printed on the standard -error output stream, each preceded by a number. If the -@samp{in @var{words}} is omitted, the positional parameters are printed, -as if @samp{in "$@@"} had been specifed. -The @env{PS3} prompt is then displayed and a line is read from the -standard input. -If the line consists of a number corresponding to one of the displayed -words, then the value of @var{name} is set to that word. -If the line is empty, the words and prompt are displayed again. -If @code{EOF} is read, the @code{select} command completes. -Any other value read causes @var{name} to be set to null. -The line read is saved in the variable @env{REPLY}. - -The @var{commands} are executed after each selection until a -@code{break} command is executed, at which -point the @code{select} command completes. - -Here is an example that allows the user to pick a filename from the -current directory, and displays the name and index of the file -selected. - -@example -select fname in *; -do - echo you picked $fname \($REPLY\) - break; -done -@end example - -@item ((@dots{})) -@example -(( @var{expression} )) -@end example - -The arithmetic @var{expression} is evaluated according to the rules -described below (@pxref{Shell Arithmetic}). -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -@example -let "@var{expression}" -@end example -@noindent -@xref{Bash Builtins}, for a full description of the @code{let} builtin. - -@item [[@dots{}]] -@rwindex [[ -@rwindex ]] -@example -[[ @var{expression} ]] -@end example - -Return a status of 0 or 1 depending on the evaluation of -the conditional expression @var{expression}. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. -Word splitting and filename expansion are not performed on the words -between the @samp{[[} and @samp{]]}; tilde expansion, parameter and -variable expansion, arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as @samp{-f} must be unquoted to be recognized -as primaries. - -When the @samp{==} and @samp{!=} operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below in @ref{Pattern Matching}. -The return value is 0 if the string matches or does not match -the pattern, respectively, and 1 otherwise. -Any part of the pattern may be quoted to force it to be matched as a -string. - -Expressions may be combined using the following operators, listed -in decreasing order of precedence: - -@table @code -@item ( @var{expression} ) -Returns the value of @var{expression}. -This may be used to override the normal precedence of operators. - -@item ! @var{expression} -True if @var{expression} is false. - -@item @var{expression1} && @var{expression2} -True if both @var{expression1} and @var{expression2} are true. - -@item @var{expression1} || @var{expression2} -True if either @var{expression1} or @var{expression2} is true. -@end table -@noindent -The @code{&&} and @code{||} operators do not evaluate @var{expression2} if the -value of @var{expression1} is sufficient to determine the return -value of the entire conditional expression. - -@end table - -@node Command Grouping -@subsection Grouping Commands -@cindex commands, grouping - -Bash provides two ways to group a list of commands to be executed -as a unit. When commands are grouped, redirections may be applied -to the entire command list. For example, the output of all the -commands in the list may be redirected to a single stream. - -@table @code -@item () -@example -( @var{list} ) -@end example - -Placing a list of commands between parentheses causes a subshell -to be created, and each of the commands in @var{list} to be executed -in that subshell. Since the @var{list} is executed in a subshell, -variable assignments do not remain in effect after the subshell completes. - -@item @{@} -@rwindex @{ -@rwindex @} -@example -@{ @var{list}; @} -@end example - -Placing a list of commands between curly braces causes the list to -be executed in the current shell context. No subshell is created. -The semicolon (or newline) following @var{list} is required. -@end table - -In addition to the creation of a subshell, there is a subtle difference -between these two constructs due to historical reasons. The braces -are @code{reserved words}, so they must be separated from the @var{list} -by @code{blank}s. The parentheses are @code{operators}, and are -recognized as separate tokens by the shell even if they are not separated -from the @var{list} by whitespace. - -The exit status of both of these constructs is the exit status of -@var{list}. - -@node Shell Functions -@section Shell Functions -@cindex shell function -@cindex functions, shell - -Shell functions are a way to group commands for later execution -using a single name for the group. They are executed just like -a "regular" command. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -Shell functions are executed in the current -shell context; no new process is created to interpret them. - -Functions are declared using this syntax: -@rwindex function -@example -[ @code{function} ] @var{name} () @{ @var{command-list}; @} -@end example - -This defines a shell function named @var{name}. The reserved -word @code{function} is optional. -If the @code{function} reserved -word is supplied, the parentheses are optional. -The @var{body} of the function is the @var{command-list} between @{ and @}. -This list is executed whenever @var{name} is specified as the -name of a command. The exit status of a function is -the exit status of the last command executed in the body. - -Note that for historical reasons, the curly braces that surround -the body of the function must be separated from the body by -@code{blank}s or newlines. -This is because the braces are reserved words and are only recognized -as such when they are separated by whitespace. -Also, the @var{command-list} must be terminated by a semicolon, -a @samp{&}, or a newline. - -When a function is executed, the arguments to the -function become the positional parameters -during its execution (@pxref{Positional Parameters}). -The special parameter @samp{#} that expands to the number of -positional parameters is updated to reflect the change. -Positional parameter @code{0} is unchanged. -The first element of the @env{FUNCNAME} variable is set to the -name of the function while the function is executing. -All other aspects of the shell execution -environment are identical between a function and its caller -with the exception that the @env{DEBUG} trap -below) is not inherited unless the function has been given the -@code{trace} attribute using the @code{declare} builtin or -the @code{-o functrace} option has been enabled with -the @code{set} builtin, -(in which case all functions inherit the @code{DEBUG} trap). -@xref{Bourne Shell Builtins}, for the description of the -@code{trap} builtin. - -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. -Any command associated with the @code{RETURN} trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter @samp{#} -are restored to the values they had prior to the function's -execution. If a numeric argument is given to @code{return}, -that is the function's return status; otherwise the function's -return status is the exit status of the last command executed -before the @code{return}. - -Variables local to the function may be declared with the -@code{local} builtin. These variables are visible only to -the function and the commands it invokes. - -Function names and definitions may be listed with the -@option{-f} option to the @code{declare} or @code{typeset} -builtin commands (@pxref{Bash Builtins}). -The @option{-F} option to @code{declare} or @code{typeset} -will list the function names only -(and optionally the source file and line number, if the @code{extdebug} -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -@option{-f} option to the @code{export} builtin -(@pxref{Bourne Shell Builtins}). -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. - -Functions may be recursive. No limit is placed on the number of -recursive calls. - -@node Shell Parameters -@section Shell Parameters -@cindex parameters -@cindex variable, shell -@cindex shell variable - -@menu -* Positional Parameters:: The shell's command-line arguments. -* Special Parameters:: Parameters denoted by special characters. -@end menu - -A @var{parameter} is an entity that stores values. -It can be a @code{name}, a number, or one of the special characters -listed below. -A @var{variable} is a parameter denoted by a @code{name}. -A variable has a @var{value} and zero or more @var{attributes}. -Attributes are assigned using the @code{declare} builtin command -(see the description of the @code{declare} builtin in @ref{Bash Builtins}). - -A parameter is set if it has been assigned a value. The null string is -a valid value. Once a variable is set, it may be unset only by using -the @code{unset} builtin command. - -A variable may be assigned to by a statement of the form -@example -@var{name}=[@var{value}] -@end example -@noindent -If @var{value} -is not given, the variable is assigned the null string. All -@var{value}s undergo tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote -removal (detailed below). If the variable has its @code{integer} -attribute set, then @var{value} -is evaluated as an arithmetic expression even if the @code{$((@dots{}))} -expansion is not used (@pxref{Arithmetic Expansion}). -Word splitting is not performed, with the exception -of @code{"$@@"} as explained below. -Filename expansion is not performed. -Assignment statements may also appear as arguments to the -@code{declare}, @code{typeset}, @code{export}, @code{readonly}, -and @code{local} builtin commands. - -@node Positional Parameters -@subsection Positional Parameters -@cindex parameters, positional - -A @var{positional parameter} is a parameter denoted by one or more -digits, other than the single digit @code{0}. Positional parameters are -assigned from the shell's arguments when it is invoked, -and may be reassigned using the @code{set} builtin command. -Positional parameter @code{N} may be referenced as @code{$@{N@}}, or -as @code{$N} when @code{N} consists of a single digit. -Positional parameters may not be assigned to with assignment statements. -The @code{set} and @code{shift} builtins are used to set and -unset them (@pxref{Shell Builtin Commands}). -The positional parameters are -temporarily replaced when a shell function is executed -(@pxref{Shell Functions}). - -When a positional parameter consisting of more than a single -digit is expanded, it must be enclosed in braces. - -@node Special Parameters -@subsection Special Parameters -@cindex parameters, special - -The shell treats several parameters specially. These parameters may -only be referenced; assignment to them is not allowed. - -@vtable @code - -@item * -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, it expands to a single word -with the value of each parameter separated by the first character -of the @env{IFS} -special variable. That is, @code{"$*"} is equivalent -to @code{"$1@var{c}$2@var{c}@dots{}"}, where @var{c} -is the first character of the value of the @code{IFS} -variable. -If @env{IFS} is unset, the parameters are separated by spaces. -If @env{IFS} is null, the parameters are joined without intervening -separators. - - -@item @@ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, @code{"$@@"} is equivalent to -@code{"$1" "$2" @dots{}}. -When there are no positional parameters, @code{"$@@"} and -@code{$@@} -expand to nothing (i.e., they are removed). - -@item # -Expands to the number of positional parameters in decimal. - -@item ? -Expands to the exit status of the most recently executed foreground -pipeline. - -@item - -(A hyphen.) Expands to the current option flags as specified upon -invocation, by the @code{set} -builtin command, or those set by the shell itself -(such as the @option{-i} option). - -@item $ -Expands to the process @sc{id} of the shell. In a @code{()} subshell, it -expands to the process @sc{id} of the invoking shell, not the subshell. - -@item ! -Expands to the process @sc{id} of the most recently executed background -(asynchronous) command. - -@item 0 -Expands to the name of the shell or shell script. This is set at -shell initialization. If Bash is invoked with a file of commands -(@pxref{Shell Scripts}), @code{$0} is set to the name of that file. -If Bash is started with the @option{-c} option (@pxref{Invoking Bash}), -then @code{$0} is set to the first argument after the string to be -executed, if one is present. Otherwise, it is set -to the filename used to invoke Bash, as given by argument zero. - -@item _ -(An underscore.) -At shell startup, set to the absolute filename of the shell or shell -script being executed as passed in the argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname of each command executed and placed in -the environment exported to that command. -When checking mail, this parameter holds the name of the mail file. -@end vtable - -@node Shell Expansions -@section Shell Expansions -@cindex expansion - -Expansion is performed on the command line after it has been split into -@code{token}s. There are seven kinds of expansion performed: -@itemize @bullet -@item brace expansion -@item tilde expansion -@item parameter and variable expansion -@item command substitution -@item arithmetic expansion -@item word splitting -@item filename expansion -@end itemize - -@menu -* Brace Expansion:: Expansion of expressions within braces. -* Tilde Expansion:: Expansion of the ~ character. -* Shell Parameter Expansion:: How Bash expands variables to their values. -* Command Substitution:: Using the output of a command as an argument. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Process Substitution:: A way to write and read to and from a - command. -* Word Splitting:: How the results of expansion are split into separate - arguments. -* Filename Expansion:: A shorthand for specifying filenames matching patterns. -* Quote Removal:: How and when quote characters are removed from - words. -@end menu - -The order of expansions is: brace expansion, tilde expansion, -parameter, variable, and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and filename -expansion. - -On systems that can support it, there is an additional expansion -available: @var{process substitution}. This is performed at the -same time as parameter, variable, and arithmetic expansion and -command substitution. - -Only brace expansion, word splitting, and filename expansion -can change the number of words of the expansion; other expansions -expand a single word to a single word. -The only exceptions to this are the expansions of -@code{"$@@"} (@pxref{Special Parameters}) and @code{"$@{@var{name}[@@]@}"} -(@pxref{Arrays}). - -After all expansions, @code{quote removal} (@pxref{Quote Removal}) -is performed. - -@node Brace Expansion -@subsection Brace Expansion -@cindex brace expansion -@cindex expansion, brace - -Brace expansion is a mechanism by which arbitrary strings may be generated. -This mechanism is similar to -@var{filename expansion} (@pxref{Filename Expansion}), -but the file names generated need not exist. -Patterns to be brace expanded take the form of an optional @var{preamble}, -followed by either a series of comma-separated strings or a sequnce expression -between a pair of braces, -followed by an optional @var{postscript}. -The preamble is prefixed to each string contained within the braces, and -the postscript is then appended to each resulting string, expanding left -to right. - -Brace expansions may be nested. -The results of each expanded string are not sorted; left to right order -is preserved. -For example, -@example -bash$ echo a@{d,c,b@}e -ade ace abe -@end example - -A sequence expression takes the form @code{@{@var{x}..@var{y}@}}, -where @var{x} and @var{y} are either integers or single characters. -When integers are supplied, the expression expands to each number between -@var{x} and @var{y}, inclusive. -When characters are supplied, the expression expands to each character -lexicographically between @var{x} and @var{y}, inclusive. Note that -both @var{x} and @var{y} must be of the same type. - -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. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. - -A @{ or @samp{,} may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -@example -mkdir /usr/local/src/bash/@{old,new,dist,bugs@} -@end example -or -@example -chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} -@end example - -@node Tilde Expansion -@subsection Tilde Expansion -@cindex tilde expansion -@cindex expansion, tilde - -If a word begins with an unquoted tilde character (@samp{~}), all of the -characters up to the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a @var{tilde-prefix}. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible @var{login name}. -If this login name is the null string, the tilde is replaced with the -value of the @env{HOME} shell variable. -If @env{HOME} is unset, the home directory of the user executing the -shell is substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. - -If the tilde-prefix is @samp{~+}, the value of -the shell variable @env{PWD} replaces the tilde-prefix. -If the tilde-prefix is @samp{~-}, the value of the shell variable -@env{OLDPWD}, if it is set, is substituted. - -If the characters following the tilde in the tilde-prefix consist of a -number @var{N}, optionally prefixed by a @samp{+} or a @samp{-}, -the tilde-prefix is replaced with the -corresponding element from the directory stack, as it would be displayed -by the @code{dirs} builtin invoked with the characters following tilde -in the tilde-prefix as an argument (@pxref{The Directory Stack}). -If the tilde-prefix, sans the tilde, consists of a number without a -leading @samp{+} or @samp{-}, @samp{+} is assumed. - -If the login name is invalid, or the tilde expansion fails, the word is -left unchanged. - -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a @samp{:} or @samp{=}. -In these cases, tilde expansion is also performed. -Consequently, one may use file names with tildes in assignments to -@env{PATH}, @env{MAILPATH}, and @env{CDPATH}, -and the shell assigns the expanded value. - -The following table shows how Bash treats unquoted tilde-prefixes: - -@table @code -@item ~ -The value of @code{$HOME} -@item ~/foo -@file{$HOME/foo} - -@item ~fred/foo -The subdirectory @code{foo} of the home directory of the user -@code{fred} - -@item ~+/foo -@file{$PWD/foo} - -@item ~-/foo -@file{$@{OLDPWD-'~-'@}/foo} - -@item ~@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~+@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~-@var{N} -The string that would be displayed by @samp{dirs -@var{N}} - -@end table - -@node Shell Parameter Expansion -@subsection Shell Parameter Expansion -@cindex parameter expansion -@cindex expansion, parameter - -The @samp{$} character introduces parameter expansion, -command substitution, or arithmetic expansion. The parameter name -or symbol to be expanded may be enclosed in braces, which -are optional but serve to protect the variable to be expanded from -characters immediately following it which could be -interpreted as part of the name. - -When braces are used, the matching ending brace is the first @samp{@}} -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or parameter -expansion. - -The basic form of parameter expansion is $@{@var{parameter}@}. -The value of @var{parameter} is substituted. The braces are required -when @var{parameter} -is a positional parameter with more than one digit, -or when @var{parameter} -is followed by a character that is not to be -interpreted as part of its name. - -If the first character of @var{parameter} is an exclamation point, -a level of variable indirection is introduced. -Bash uses the value of the variable formed from the rest of -@var{parameter} as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of @var{parameter} itself. -This is known as @code{indirect expansion}. -The exceptions to this are the expansions of $@{!@var{prefix*}@} -and $@{!@var{name}[@@]@} -described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. - -In each of the cases below, @var{word} is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. - -When not performing substring expansion, Bash tests for a parameter -that is unset or null; omitting the colon results in a test only for a -parameter that is unset. Put another way, if the colon is included, -the operator tests for both existence and that the value is not null; -if the colon is omitted, the operator tests only for existence. - -@table @code - -@item $@{@var{parameter}:@minus{}@var{word}@} -If @var{parameter} is unset or null, the expansion of -@var{word} is substituted. Otherwise, the value of -@var{parameter} is substituted. - -@item $@{@var{parameter}:=@var{word}@} -If @var{parameter} -is unset or null, the expansion of @var{word} -is assigned to @var{parameter}. -The value of @var{parameter} -is then substituted. Positional parameters and special parameters may -not be assigned to in this way. - -@item $@{@var{parameter}:?@var{word}@} -If @var{parameter} -is null or unset, the expansion of @var{word} (or a message -to that effect if @var{word} -is not present) is written to the standard error and the shell, if it -is not interactive, exits. Otherwise, the value of @var{parameter} is -substituted. - -@item $@{@var{parameter}:+@var{word}@} -If @var{parameter} -is null or unset, nothing is substituted, otherwise the expansion of -@var{word} is substituted. - -@item $@{@var{parameter}:@var{offset}@} -@itemx $@{@var{parameter}:@var{offset}:@var{length}@} -Expands to up to @var{length} characters of @var{parameter} -starting at the character specified by @var{offset}. -If @var{length} is omitted, expands to the substring of -@var{parameter} starting at the character specified by @var{offset}. -@var{length} and @var{offset} are arithmetic expressions -(@pxref{Shell Arithmetic}). -This is referred to as Substring Expansion. - -@var{length} must evaluate to a number greater than or equal to zero. -If @var{offset} evaluates to a number less than zero, the value -is used as an offset from the end of the value of @var{parameter}. -If @var{parameter} is @samp{@@}, the result is @var{length} positional -parameters beginning at @var{offset}. -If @var{parameter} is an array name indexed by @samp{@@} or @samp{*}, -the result is the @var{length} -members of the array beginning with @code{$@{@var{parameter}[@var{offset}]@}}. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1. - -@item $@{!@var{prefix}*@} -@itemx $@{!@var{prefix}@@@} -Expands to the names of variables whose names begin with @var{prefix}, -separated by the first character of the @env{IFS} special variable. - -@item $@{!@var{name}[@@]@} -@itemx $@{!@var{name}[*]@} -If @var{name} is an array variable, expands to the list of array indices -(keys) assigned in @var{name}. -If @var{name} is not an array, expands to 0 if @var{name} is set and null -otherwise. -When @samp{@@} is used and the expansion appears within double quotes, each -key expands to a separate word. - -@item $@{#@var{parameter}@} -The length in characters of the expanded value of @var{parameter} is -substituted. -If @var{parameter} is @samp{*} or @samp{@@}, the value substituted -is the number of positional parameters. -If @var{parameter} is an array name subscripted by @samp{*} or @samp{@@}, -the value substituted is the number of elements in the array. - -@item $@{@var{parameter}#@var{word}@} -@itemx $@{@var{parameter}##@var{word}@} -The @var{word} -is expanded to produce a pattern just as in filename -expansion (@pxref{Filename Expansion}). If the pattern matches -the beginning of the expanded value of @var{parameter}, -then the result of the expansion is the expanded value of @var{parameter} -with the shortest matching pattern (the @samp{#} case) or the -longest matching pattern (the @samp{##} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} is an array variable subscripted with -@samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}%@var{word}@} -@itemx $@{@var{parameter}%%@var{word}@} -The @var{word} is expanded to produce a pattern just as in -filename expansion. -If the pattern matches a trailing portion of the expanded value of -@var{parameter}, then the result of the expansion is the value of -@var{parameter} with the shortest matching pattern (the @samp{%} case) -or the longest matching pattern (the @samp{%%} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}/@var{pattern}/@var{string}@} -@itemx $@{@var{parameter}//@var{pattern}/@var{string}@} - -The @var{pattern} is expanded to produce a pattern just as in -filename expansion. -@var{Parameter} is expanded and the longest match of @var{pattern} -against its value is replaced with @var{string}. -In the first form, only the first match is replaced. -The second form causes all matches of @var{pattern} to be -replaced with @var{string}. -If @var{pattern} begins with @samp{#}, it must match at the beginning -of the expanded value of @var{parameter}. -If @var{pattern} begins with @samp{%}, it must match at the end -of the expanded value of @var{parameter}. -If @var{string} is null, matches of @var{pattern} are deleted -and the @code{/} following @var{pattern} may be omitted. -If @var{parameter} is @samp{@@} or @samp{*}, -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@end table - -@node Command Substitution -@subsection Command Substitution -@cindex command substitution - -Command substitution allows the output of a command to replace -the command itself. -Command substitution occurs when a command is enclosed as follows: -@example -$(@var{command}) -@end example -@noindent -or -@example -`@var{command}` -@end example - -@noindent -Bash performs the expansion by executing @var{command} and -replacing the command substitution with the standard output of the -command, with any trailing newlines deleted. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution @code{$(cat @var{file})} can be -replaced by the equivalent but faster @code{$(< @var{file})}. - -When the old-style backquote form of substitution is used, -backslash retains its literal meaning except when followed by -@samp{$}, @samp{`}, or @samp{\}. -The first backquote not preceded by a backslash terminates the -command substitution. -When using the @code{$(@var{command})} form, all characters between -the parentheses make up the command; none are treated specially. - -Command substitutions may be nested. To nest when using the backquoted -form, escape the inner backquotes with backslashes. - -If the substitution appears within double quotes, word splitting and -filename expansion are not performed on the results. - -@node Arithmetic Expansion -@subsection Arithmetic Expansion -@cindex expansion, arithmetic -@cindex arithmetic expansion - -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. The format for arithmetic expansion is: - -@example -$(( @var{expression} )) -@end example - -The expression is treated as if it were within double quotes, but -a double quote inside the parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, command -substitution, and quote removal. -Arithmetic expansions may be nested. - -The evaluation is performed according to the rules listed below -(@pxref{Shell Arithmetic}). -If the expression is invalid, Bash prints a message indicating -failure to the standard error and no substitution occurs. - -@node Process Substitution -@subsection Process Substitution -@cindex process substitution - -Process substitution is supported on systems that support named -pipes (@sc{fifo}s) or the @file{/dev/fd} method of naming open files. -It takes the form of -@example -<(@var{list}) -@end example -@noindent -or -@example ->(@var{list}) -@end example -@noindent -The process @var{list} is run with its input or output connected to a -@sc{fifo} or some file in @file{/dev/fd}. The name of this file is -passed as an argument to the current command as the result of the -expansion. If the @code{>(@var{list})} form is used, writing to -the file will provide input for @var{list}. If the -@code{<(@var{list})} form is used, the file passed as an -argument should be read to obtain the output of @var{list}. -Note that no space may appear between the @code{<} or @code{>} -and the left parenthesis, otherwise the construct would be interpreted -as a redirection. - -When available, process substitution is performed simultaneously with -parameter and variable expansion, command substitution, and arithmetic -expansion. - -@node Word Splitting -@subsection Word Splitting -@cindex word splitting - -The shell scans the results of parameter expansion, command substitution, -and arithmetic expansion that did not occur within double quotes for -word splitting. - -The shell treats each character of @env{$IFS} -as a delimiter, and splits the results of the other -expansions into words on these characters. If -@env{IFS} is unset, or its value is exactly @code{}, -the default, then any sequence of @env{IFS} -characters serves to delimit words. If @env{IFS} -has a value other than the default, then sequences of -the whitespace characters @code{space} and @code{tab} -are ignored at the beginning and end of the -word, as long as the whitespace character is in the -value of @env{IFS} (an @env{IFS} whitespace character). -Any character in @env{IFS} that is not @env{IFS} -whitespace, along with any adjacent @env{IFS} -whitespace characters, delimits a field. A sequence of @env{IFS} -whitespace characters is also treated as a delimiter. -If the value of @env{IFS} is null, no word splitting occurs. - -Explicit null arguments (@code{""} or @code{''}) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. - -Note that if no expansion occurs, no splitting -is performed. - -@node Filename Expansion -@subsection Filename Expansion -@menu -* Pattern Matching:: How the shell matches patterns. -@end menu -@cindex expansion, filename -@cindex expansion, pathname -@cindex filename expansion -@cindex pathname expansion - -After word splitting, unless the @option{-f} option has been set -(@pxref{The Set Builtin}), Bash scans each word for the characters -@samp{*}, @samp{?}, and @samp{[}. -If one of these characters appears, then the word is -regarded as a @var{pattern}, -and replaced with an alphabetically sorted list of -file names matching the pattern. If no matching file names are found, -and the shell option @code{nullglob} is disabled, the word is left -unchanged. -If the @code{nullglob} option is set, and no matches are found, the word -is removed. -If the shell option @code{nocaseglob} is enabled, the match is performed -without regard to the case of alphabetic characters. - -When a pattern is used for filename generation, the character @samp{.} -at the start of a filename or immediately following a slash -must be matched explicitly, unless the shell option @code{dotglob} is set. -When matching a file name, the slash character must always be -matched explicitly. -In other cases, the @samp{.} character is not treated specially. - -See the description of @code{shopt} in @ref{Bash Builtins}, -for a description of the @code{nocaseglob}, @code{nullglob}, -and @code{dotglob} options. - -The @env{GLOBIGNORE} -shell variable may be used to restrict the set of filenames matching a -pattern. If @env{GLOBIGNORE} -is set, each matching filename that also matches one of the patterns in -@env{GLOBIGNORE} is removed from the list of matches. The filenames -@file{.} and @file{..} -are always ignored when @env{GLOBIGNORE} -is set and not null. -However, setting @env{GLOBIGNORE} to a non-null value has the effect of -enabling the @code{dotglob} -shell option, so all other filenames beginning with a -@samp{.} will match. -To get the old behavior of ignoring filenames beginning with a -@samp{.}, make @samp{.*} one of the patterns in @env{GLOBIGNORE}. -The @code{dotglob} option is disabled when @env{GLOBIGNORE} -is unset. - -@node Pattern Matching -@subsubsection Pattern Matching -@cindex pattern matching -@cindex matching, pattern - -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. -The @sc{nul} character may not occur in a pattern. -A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if they are to be matched -literally. - -The special pattern characters have the following meanings: -@table @code -@item * -Matches any string, including the null string. -@item ? -Matches any single character. -@item [@dots{}] -Matches any one of the enclosed characters. A pair of characters -separated by a hyphen denotes a @var{range expression}; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -@samp{[} is a @samp{!} or a @samp{^} -then any character not enclosed is matched. A @samp{@minus{}} -may be matched by including it as the first or last character -in the set. A @samp{]} may be matched by including it as the first -character in the set. -The sorting order of characters in range expressions is determined by -the current locale and the value of the @env{LC_COLLATE} shell variable, -if set. - -For example, in the default C locale, @samp{[a-dx-z]} is equivalent to -@samp{[abcdxyz]}. Many locales sort characters in dictionary order, and in -these locales @samp{[a-dx-z]} is typically not equivalent to @samp{[abcdxyz]}; -it might be equivalent to @samp{[aBbCcDdxXyYz]}, for example. To obtain -the traditional interpretation of ranges in bracket expressions, you can -force the use of the C locale by setting the @env{LC_COLLATE} or -@env{LC_ALL} environment variable to the value @samp{C}. - -Within @samp{[} and @samp{]}, @var{character classes} can be specified -using the syntax -@code{[:}@var{class}@code{:]}, where @var{class} is one of the -following classes defined in the @sc{posix} 1003.2 standard: -@example -alnum alpha ascii blank cntrl digit graph lower -print punct space upper word xdigit -@end example -@noindent -A character class matches any character belonging to that class. -The @code{word} character class matches letters, digits, and the character -@samp{_}. - -Within @samp{[} and @samp{]}, an @var{equivalence class} can be -specified using the syntax @code{[=}@var{c}@code{=]}, which -matches all characters with the same collation weight (as defined -by the current locale) as the character @var{c}. - -Within @samp{[} and @samp{]}, the syntax @code{[.}@var{symbol}@code{.]} -matches the collating symbol @var{symbol}. -@end table - -If the @code{extglob} shell option is enabled using the @code{shopt} -builtin, several extended pattern matching operators are recognized. -In the following description, a @var{pattern-list} is a list of one -or more patterns separated by a @samp{|}. -Composite patterns may be formed using one or more of the following -sub-patterns: - -@table @code -@item ?(@var{pattern-list}) -Matches zero or one occurrence of the given patterns. - -@item *(@var{pattern-list}) -Matches zero or more occurrences of the given patterns. - -@item +(@var{pattern-list}) -Matches one or more occurrences of the given patterns. - -@item @@(@var{pattern-list}) -Matches exactly one of the given patterns. - -@item !(@var{pattern-list}) -Matches anything except one of the given patterns. -@end table - -@node Quote Removal -@subsection Quote Removal - -After the preceding expansions, all unquoted occurrences of the -characters @samp{\}, @samp{'}, and @samp{"} that did not -result from one of the above expansions are removed. - -@node Redirections -@section Redirections -@cindex redirection - -Before a command is executed, its input and output -may be @var{redirected} -using a special notation interpreted by the shell. -Redirection may also be used to open and close files for the -current shell execution environment. The following redirection -operators may precede or appear anywhere within a -simple command or may follow a command. -Redirections are processed in the order they appear, from -left to right. - -In the following descriptions, if the file descriptor number is -omitted, and the first character of the redirection operator is -@samp{<}, the redirection refers to the standard input (file -descriptor 0). If the first character of the redirection operator -is @samp{>}, the redirection refers to the standard output (file -descriptor 1). - -The word following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to brace expansion, -tilde expansion, parameter expansion, command substitution, arithmetic -expansion, quote removal, filename expansion, and word splitting. -If it expands to more than one word, Bash reports an error. - -Note that the order of redirections is significant. For example, -the command -@example -ls > @var{dirlist} 2>&1 -@end example -@noindent -directs both standard output (file descriptor 1) and standard error -(file descriptor 2) to the file @var{dirlist}, while the command -@example -ls 2>&1 > @var{dirlist} -@end example -@noindent -directs only the standard output to file @var{dirlist}, -because the standard error was duplicated as standard output -before the standard output was redirected to @var{dirlist}. - -Bash handles several filenames specially when they are used in -redirections, as described in the following table: - -@table @code -@item /dev/fd/@var{fd} -If @var{fd} is a valid integer, file descriptor @var{fd} is duplicated. - -@item /dev/stdin -File descriptor 0 is duplicated. - -@item /dev/stdout -File descriptor 1 is duplicated. - -@item /dev/stderr -File descriptor 2 is duplicated. - -@item /dev/tcp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open a TCP -connection to the corresponding socket. - -@item /dev/udp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open a UDP -connection to the corresponding socket. - -@end table - -A failure to open or create a file causes the redirection to fail. - -@subsection Redirecting Input -Redirection of input causes the file whose name results from -the expansion of @var{word} -to be opened for reading on file descriptor @code{n}, -or the standard input (file descriptor 0) if @code{n} -is not specified. - -The general format for redirecting input is: -@example -[@var{n}]<@var{word} -@end example - -@subsection Redirecting Output -Redirection of output causes the file whose name results from -the expansion of @var{word} -to be opened for writing on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created; -if it does exist it is truncated to zero size. - -The general format for redirecting output is: -@example -[@var{n}]>[|]@var{word} -@end example - -If the redirection operator is @samp{>}, and the @code{noclobber} -option to the @code{set} builtin has been enabled, the redirection -will fail if the file whose name results from the expansion of -@var{word} exists and is a regular file. -If the redirection operator is @samp{>|}, or the redirection operator is -@samp{>} and the @code{noclobber} option is not enabled, the redirection -is attempted even if the file named by @var{word} exists. - -@subsection Appending Redirected Output -Redirection of output in this fashion -causes the file whose name results from -the expansion of @var{word} -to be opened for appending on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created. - -The general format for appending output is: -@example -[@var{n}]>>@var{word} -@end example - -@subsection Redirecting Standard Output and Standard Error -Bash allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be redirected to the file whose name is the -expansion of @var{word} with this construct. - -There are two formats for redirecting standard output and -standard error: -@example -&>@var{word} -@end example -@noindent -and -@example ->&@var{word} -@end example -@noindent -Of the two forms, the first is preferred. -This is semantically equivalent to -@example ->@var{word} 2>&1 -@end example - -@subsection Here Documents -This type of redirection instructs the shell to read input from the -current source until a line containing only @var{word} -(with no trailing blanks) is seen. All of -the lines read up to that point are then used as the standard -input for a command. - -The format of here-documents is: -@example -<<[@minus{}]@var{word} - @var{here-document} -@var{delimiter} -@end example - -No parameter expansion, command substitution, arithmetic expansion, -or filename expansion is performed on -@var{word}. If any characters in @var{word} are quoted, the -@var{delimiter} is the result of quote removal on @var{word}, -and the lines in the here-document are not expanded. -If @var{word} is unquoted, -all lines of the here-document are subjected to parameter expansion, -command substitution, and arithmetic expansion. In the latter -case, the character sequence @code{\newline} is ignored, and @samp{\} -must be used to quote the characters -@samp{\}, @samp{$}, and @samp{`}. - -If the redirection operator is @samp{<<-}, -then all leading tab characters are stripped from input lines and the -line containing @var{delimiter}. -This allows here-documents within shell scripts to be indented in a -natural fashion. - -@subsection Here Strings -A variant of here documents, the format is: -@example -<<< @var{word} -@end example - -The @var{word} is expanded and supplied to the command on its standard -input. - -@subsection Duplicating File Descriptors -The redirection operator -@example -[@var{n}]<&@var{word} -@end example -@noindent -is used to duplicate input file descriptors. -If @var{word} -expands to one or more digits, the file descriptor denoted by @var{n} -is made to be a copy of that file descriptor. -If the digits in @var{word} do not specify a file descriptor open for -input, a redirection error occurs. -If @var{word} -evaluates to @samp{-}, file descriptor @var{n} is closed. If -@var{n} is not specified, the standard input (file descriptor 0) is used. - -The operator -@example -[@var{n}]>&@var{word} -@end example -@noindent -is used similarly to duplicate output file descriptors. If -@var{n} is not specified, the standard output (file descriptor 1) is used. -If the digits in @var{word} do not specify a file descriptor open for -output, a redirection error occurs. -As a special case, if @var{n} is omitted, and @var{word} does not -expand to one or more digits, the standard output and standard -error are redirected as described previously. - -@subsection Moving File Descriptors -The redirection operator -@example -[@var{n}]<&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard input (file descriptor 0) if @var{n} is not specified. -@var{digit} is closed after being duplicated to @var{n}. - -Similarly, the redirection operator -@example -[@var{n}]>&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} is not specified. - -@subsection Opening File Descriptors for Reading and Writing -The redirection operator -@example -[@var{n}]<>@var{word} -@end example -@noindent -causes the file whose name is the expansion of @var{word} -to be opened for both reading and writing on file descriptor -@var{n}, or on file descriptor 0 if @var{n} -is not specified. If the file does not exist, it is created. - -@node Executing Commands -@section Executing Commands - -@menu -* Simple Command Expansion:: How Bash expands simple commands before - executing them. - -* Command Search and Execution:: How Bash finds commands and runs them. - -* Command Execution Environment:: The environment in which Bash - executes commands that are not - shell builtins. - -* Environment:: The environment given to a command. - -* Exit Status:: The status returned by commands and how Bash - interprets it. - -* Signals:: What happens when Bash or a command it runs - receives a signal. - -@end menu - -@node Simple Command Expansion -@subsection Simple Command Expansion -@cindex command expansion - -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. - -@enumerate -@item -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. - -@item -The words that are not variable assignments or redirections are -expanded (@pxref{Shell Expansions}). -If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. - -@item -Redirections are performed as described above (@pxref{Redirections}). - -@item -The text after the @samp{=} in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -@end enumerate - -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. - -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. - -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. - -@node Command Search and Execution -@subsection Command Search and Execution -@cindex command execution -@cindex command search - -After a command has been split into words, if it results in a -simple command and an optional list of arguments, the following -actions are taken. - -@enumerate -@item -If the command name contains no slashes, the shell attempts to -locate it. If there exists a shell function by that name, that -function is invoked as described in @ref{Shell Functions}. - -@item -If the name does not match a function, the shell searches for -it in the list of shell builtins. If a match is found, that -builtin is invoked. - -@item -If the name is neither a shell function nor a builtin, -and contains no slashes, Bash searches each element of -@env{$PATH} for a directory containing an executable file -by that name. Bash uses a hash table to remember the full -pathnames of executable files to avoid multiple @env{PATH} searches -(see the description of @code{hash} in @ref{Bourne Shell Builtins}). -A full search of the directories in @env{$PATH} -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell prints an error -message and returns an exit status of 127. - -@item -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in -a separate execution environment. -Argument 0 is set to the name given, and the remaining arguments -to the command are set to the arguments supplied, if any. - -@item -If this execution fails because the file is not in executable -format, and the file is not a directory, it is assumed to be a -@var{shell script} and the shell executes it as described in -@ref{Shell Scripts}. - -@item -If the command was not begun asynchronously, the shell waits for -the command to complete and collects its exit status. - -@end enumerate - -@node Command Execution Environment -@subsection Command Execution Environment -@cindex execution environment - -The shell has an @var{execution environment}, which consists of the -following: - -@itemize @bullet -@item -open files inherited by the shell at invocation, as modified by -redirections supplied to the @code{exec} builtin - -@item -the current working directory as set by @code{cd}, @code{pushd}, or -@code{popd}, or inherited by the shell at invocation - -@item -the file creation mode mask as set by @code{umask} or inherited from -the shell's parent - -@item -current traps set by @code{trap} - -@item -shell parameters that are set by variable assignment or with @code{set} -or inherited from the shell's parent in the environment - -@item -shell functions defined during execution or inherited from the shell's -parent in the environment - -@item -options enabled at invocation (either by default or with command-line -arguments) or by @code{set} - -@item -options enabled by @code{shopt} - -@item -shell aliases defined with @code{alias} (@pxref{Aliases}) - -@item -various process @sc{id}s, including those of background jobs -(@pxref{Lists}), the value of @code{$$}, and the value of -@env{$PPID} - -@end itemize - -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. - -@itemize @bullet -@item -the shell's open files, plus any modifications and additions specified -by redirections to the command - -@item -the current working directory - -@item -the file creation mode mask - -@item -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment (@pxref{Environment}) - -@item -traps caught by the shell are reset to the values inherited from the -shell's parent, and traps ignored by the shell are ignored - -@end itemize - -A command invoked in this separate environment cannot affect the -shell's execution environment. - -Command substitution and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed -in a subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. - -If a command is followed by a @samp{&} and job control is not active, the -default standard input for the command is the empty file @file{/dev/null}. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. - -@node Environment -@subsection Environment -@cindex environment - -When a program is invoked it is given an array of strings -called the @var{environment}. -This is a list of name-value pairs, of the form @code{name=value}. - -Bash provides several ways to manipulate the environment. -On invocation, the shell scans its own environment and -creates a parameter for each name found, automatically marking -it for @var{export} -to child processes. Executed commands inherit the environment. -The @code{export} and @samp{declare -x} -commands allow parameters and functions to be added to and -deleted from the environment. If the value of a parameter -in the environment is modified, the new value becomes part -of the environment, replacing the old. The environment -inherited by any executed command consists of the shell's -initial environment, whose values may be modified in the shell, -less any pairs removed by the @code{unset} and @samp{export -n} -commands, plus any additions via the @code{export} and -@samp{declare -x} commands. - -The environment for any simple command -or function may be augmented temporarily by prefixing it with -parameter assignments, as described in @ref{Shell Parameters}. -These assignment statements affect only the environment seen -by that command. - -If the @option{-k} option is set (@pxref{The Set Builtin}), then all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. - -When Bash invokes an external command, the variable @samp{$_} -is set to the full path name of the command and passed to that -command in its environment. - -@node Exit Status -@subsection Exit Status -@cindex exit status - -For the shell's purposes, a command which exits with a -zero exit status has succeeded. -A non-zero exit status indicates failure. -This seemingly counter-intuitive scheme is used so there -is one well-defined way to indicate success and a variety of -ways to indicate various failure modes. -When a command terminates on a fatal signal whose number is @var{N}, -Bash uses the value 128+@var{N} as the exit status. - -If a command is not found, the child process created to -execute it returns a status of 127. If a command is found -but is not executable, the return status is 126. - -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. - -The exit status is used by the Bash conditional commands -(@pxref{Conditional Constructs}) and some of the list -constructs (@pxref{Lists}). - -All of the Bash builtins return an exit status of zero if they succeed -and a non-zero status on failure, so they may be used by the -conditional and list constructs. -All builtins return an exit status of 2 to indicate incorrect usage. - -@node Signals -@subsection Signals -@cindex signal handling - -When Bash is interactive, in the absence of any traps, it ignores -@code{SIGTERM} (so that @samp{kill 0} does not kill an interactive shell), -and @code{SIGINT} -is caught and handled (so that the @code{wait} builtin is interruptible). -When Bash receives a @code{SIGINT}, it breaks out of any executing loops. -In all cases, Bash ignores @code{SIGQUIT}. -If job control is in effect (@pxref{Job Control}), Bash -ignores @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -Commands started by Bash have signal handlers set to the -values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore @code{SIGINT} and @code{SIGQUIT} as well. -Commands run as a result of -command substitution ignore the keyboard-generated job control signals -@code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -The shell exits by default upon receipt of a @code{SIGHUP}. -Before exiting, an interactive shell resends the @code{SIGHUP} to -all jobs, running or stopped. -Stopped jobs are sent @code{SIGCONT} to ensure that they receive -the @code{SIGHUP}. -To prevent the shell from sending the @code{SIGHUP} signal to a -particular job, it should be removed -from the jobs table with the @code{disown} -builtin (@pxref{Job Control Builtins}) or marked -to not receive @code{SIGHUP} using @code{disown -h}. - -If the @code{huponexit} shell option has been set with @code{shopt} -(@pxref{Bash Builtins}), Bash sends a @code{SIGHUP} to all jobs when -an interactive login shell exits. - -When Bash receives a signal for which a trap has been set while waiting -for a command to complete, the trap will not be executed until the -command completes. -When Bash is waiting for an asynchronous -command via the @code{wait} builtin, the reception of a signal for -which a trap has been set will cause the @code{wait} builtin to return -immediately with an exit status greater than 128, immediately after -which the trap is executed. - -@node Shell Scripts -@section Shell Scripts -@cindex shell script - -A shell script is a text file containing shell commands. When such -a file is used as the first non-option argument when invoking Bash, -and neither the @option{-c} nor @option{-s} option is supplied -(@pxref{Invoking Bash}), -Bash reads and executes commands from the file, then exits. This -mode of operation creates a non-interactive shell. The shell first -searches for the file in the current directory, and looks in the -directories in @env{$PATH} if not found there. - -When Bash runs -a shell script, it sets the special parameter @code{0} to the name -of the file, rather than the name of the shell, and the positional -parameters are set to the remaining arguments, if any are given. -If no additional arguments are supplied, the positional parameters -are unset. - -A shell script may be made executable by using the @code{chmod} command -to turn on the execute bit. When Bash finds such a file while -searching the @env{$PATH} for a command, it spawns a subshell to -execute it. In other words, executing -@example -filename @var{arguments} -@end example -@noindent -is equivalent to executing -@example -bash filename @var{arguments} -@end example - -@noindent -if @code{filename} is an executable shell script. -This subshell reinitializes itself, so that the effect is as if a -new shell had been invoked to interpret the script, with the -exception that the locations of commands remembered by the parent -(see the description of @code{hash} in @ref{Bourne Shell Builtins}) -are retained by the child. - -Most versions of Unix make this a part of the operating system's command -execution mechanism. If the first line of a script begins with -the two characters @samp{#!}, the remainder of the line specifies -an interpreter for the program. -Thus, you can specify Bash, @code{awk}, Perl, or some other -interpreter and write the rest of the script file in that language. - -The arguments to the interpreter -consist of a single optional argument following the interpreter -name on the first line of the script file, followed by the name of -the script file, followed by the rest of the arguments. Bash -will perform this action on operating systems that do not handle it -themselves. Note that some older versions of Unix limit the interpreter -name and argument to a maximum of 32 characters. - -Bash scripts often begin with @code{#! /bin/bash} (assuming that -Bash has been installed in @file{/bin}), since this ensures that -Bash will be used to interpret the script, even if it is executed -under another shell. - -@node Shell Builtin Commands -@chapter Shell Builtin Commands - -@menu -* Bourne Shell Builtins:: Builtin commands inherited from the Bourne - Shell. -* Bash Builtins:: Table of builtins specific to Bash. -* The Set Builtin:: This builtin is so overloaded it - deserves its own section. -* Special Builtins:: Builtin commands classified specially by - POSIX.2. -@end menu - -Builtin commands are contained within the shell itself. -When the name of a builtin command is used as the first word of -a simple command (@pxref{Simple Commands}), the shell executes -the command directly, without invoking another program. -Builtin commands are necessary to implement functionality impossible -or inconvenient to obtain with separate utilities. - -This section briefly the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -Several builtin commands are described in other chapters: builtin -commands which provide the Bash interface to the job control -facilities (@pxref{Job Control Builtins}), the directory stack -(@pxref{Directory Stack Builtins}), the command history -(@pxref{Bash History Builtins}), and the programmable completion -facilities (@pxref{Programmable Completion Builtins}). - -Many of the builtins have been extended by @sc{posix} or Bash. - -@node Bourne Shell Builtins -@section Bourne Shell Builtins - -The following shell builtin commands are inherited from the Bourne Shell. -These commands are implemented as specified by the @sc{posix} 1003.2 standard. - -@table @code -@item : @r{(a colon)} -@btindex : -@example -: [@var{arguments}] -@end example -Do nothing beyond expanding @var{arguments} and performing redirections. -The return status is zero. - -@item . @r{(a period)} -@btindex . -@example -. @var{filename} [@var{arguments}] -@end example -Read and execute commands from the @var{filename} argument in the -current shell context. If @var{filename} does not contain a slash, -the @env{PATH} variable is used to find @var{filename}. -When Bash is not in @sc{posix} mode, the current directory is searched -if @var{filename} is not found in @env{$PATH}. -If any @var{arguments} are supplied, they become the positional -parameters when @var{filename} is executed. Otherwise the positional -parameters are unchanged. -The return status is the exit status of the last command executed, or -zero if no commands are executed. If @var{filename} is not found, or -cannot be read, the return status is non-zero. -This builtin is equivalent to @code{source}. - -@item break -@btindex break -@example -break [@var{n}] -@end example -Exit from a @code{for}, @code{while}, @code{until}, or @code{select} loop. -If @var{n} is supplied, the @var{n}th enclosing loop is exited. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item cd -@btindex cd -@example -cd [-L|-P] [@var{directory}] -@end example -Change the current working directory to @var{directory}. If @var{directory} -is not given, the value of the @env{HOME} shell variable is used. If the -shell variable @env{CDPATH} exists, it is used as a search path. If -@var{directory} begins with a slash, @env{CDPATH} is not used. -The @option{-P} option means -to not follow symbolic links; symbolic links are followed by default -or with the @option{-L} option. -If @var{directory} is @samp{-}, it is equivalent to @env{$OLDPWD}. -The return status is zero if the directory is successfully changed, -non-zero otherwise. - -@item continue -@btindex continue -@example -continue [@var{n}] -@end example -Resume the next iteration of an enclosing @code{for}, @code{while}, -@code{until}, or @code{select} loop. -If @var{n} is supplied, the execution of the @var{n}th enclosing loop -is resumed. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item eval -@btindex eval -@example -eval [@var{arguments}] -@end example -The arguments are concatenated together into a single command, which is -then read and executed, and its exit status returned as the exit status -of @code{eval}. -If there are no arguments or only empty arguments, the return status is -zero. - -@item exec -@btindex exec -@example -exec [-cl] [-a @var{name}] [@var{command} [@var{arguments}]] -@end example -If @var{command} -is supplied, it replaces the shell without creating a new process. -If the @option{-l} option is supplied, the shell places a dash at the -beginning of the zeroth arg passed to @var{command}. -This is what the @code{login} program does. -The @option{-c} option causes @var{command} to be executed with an empty -environment. -If @option{-a} is supplied, the shell passes @var{name} as the zeroth -argument to @var{command}. -If no @var{command} is specified, redirections may be used to affect -the current shell environment. If there are no redirection errors, the -return status is zero; otherwise the return status is non-zero. - -@item exit -@btindex exit -@example -exit [@var{n}] -@end example -Exit the shell, returning a status of @var{n} to the shell's parent. -If @var{n} is omitted, the exit status is that of the last command executed. -Any trap on @code{EXIT} is executed before the shell terminates. - -@item export -@btindex export -@example -export [-fn] [-p] [@var{name}[=@var{value}]] -@end example -Mark each @var{name} to be passed to child processes -in the environment. If the @option{-f} option is supplied, the @var{name}s -refer to shell functions; otherwise the names refer to shell variables. -The @option{-n} option means to no longer mark each @var{name} for export. -If no @var{names} are supplied, or if the @option{-p} option is given, a -list of exported names is displayed. -The @option{-p} option displays output in a form that may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. - -The return status is zero unless an invalid option is supplied, one of -the names is not a valid shell variable name, or @option{-f} is supplied -with a name that is not a shell function. - -@item getopts -@btindex getopts -@example -getopts @var{optstring} @var{name} [@var{args}] -@end example -@code{getopts} is used by shell scripts to parse positional parameters. -@var{optstring} contains the option characters to be recognized; if a -character is followed by a colon, the option is expected to have an -argument, which should be separated from it by white space. -The colon (@samp{:}) and question mark (@samp{?}) may not be -used as option characters. -Each time it is invoked, @code{getopts} -places the next option in the shell variable @var{name}, initializing -@var{name} if it does not exist, -and the index of the next argument to be processed into the -variable @env{OPTIND}. -@env{OPTIND} is initialized to 1 each time the shell or a shell script -is invoked. -When an option requires an argument, -@code{getopts} places that argument into the variable @env{OPTARG}. -The shell does not reset @env{OPTIND} automatically; it must be manually -reset between multiple calls to @code{getopts} within the same shell -invocation if a new set of parameters is to be used. - -When the end of options is encountered, @code{getopts} exits with a -return value greater than zero. -@env{OPTIND} is set to the index of the first non-option argument, -and @code{name} is set to @samp{?}. - -@code{getopts} -normally parses the positional parameters, but if more arguments are -given in @var{args}, @code{getopts} parses those instead. - -@code{getopts} can report errors in two ways. If the first character of -@var{optstring} is a colon, @var{silent} -error reporting is used. In normal operation diagnostic messages -are printed when invalid options or missing option arguments are -encountered. -If the variable @env{OPTERR} -is set to 0, no error messages will be displayed, even if the first -character of @code{optstring} is not a colon. - -If an invalid option is seen, -@code{getopts} places @samp{?} into @var{name} and, if not silent, -prints an error message and unsets @env{OPTARG}. -If @code{getopts} is silent, the option character found is placed in -@env{OPTARG} and no diagnostic message is printed. - -If a required argument is not found, and @code{getopts} -is not silent, a question mark (@samp{?}) is placed in @var{name}, -@code{OPTARG} is unset, and a diagnostic message is printed. -If @code{getopts} is silent, then a colon (@samp{:}) is placed in -@var{name} and @env{OPTARG} is set to the option character found. - -@item hash -@btindex hash -@example -hash [-'r] [-p @var{filename}] [-dt] [@var{name}] -@end example -Remember the full pathnames of commands specified as @var{name} arguments, -so they need not be searched for on subsequent invocations. -The commands are found by searching through the directories listed in -@env{$PATH}. -The @option{-p} option inhibits the path search, and @var{filename} is -used as the location of @var{name}. -The @option{-r} option causes the shell to forget all remembered locations. -The @option{-d} option causes the shell to forget the remembered location -of each @var{name}. -If the @option{-t} option is supplied, the full pathname to which each -@var{name} corresponds is printed. If multiple @var{name} arguments are -supplied with @option{-t} the @var{name} is printed before the hashed -full pathname. -The @option{-l} option causes output to be displayed in a format -that may be reused as input. -If no arguments are given, or if only @option{-l} is supplied, -information about remembered commands is printed. -The return status is zero unless a @var{name} is not found or an invalid -option is supplied. - -@item pwd -@btindex pwd -@example -pwd [-LP] -@end example -Print the absolute pathname of the current working directory. -If the @option{-P} option is supplied, the pathname printed will not -contain symbolic links. -If the @option{-L} option is supplied, the pathname printed may contain -symbolic links. -The return status is zero unless an error is encountered while -determining the name of the current directory or an invalid option -is supplied. - -@item readonly -@btindex readonly -@example -readonly [-apf] [@var{name}[=@var{value}]] @dots{} -@end example -Mark each @var{name} as readonly. -The values of these names may not be changed by subsequent assignment. -If the @option{-f} option is supplied, each @var{name} refers to a shell -function. -The @option{-a} option means each @var{name} refers to an array variable. -If no @var{name} arguments are given, or if the @option{-p} -option is supplied, a list of all readonly names is printed. -The @option{-p} option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. -The return status is zero unless an invalid option is supplied, one of -the @var{name} arguments is not a valid shell variable or function name, -or the @option{-f} option is supplied with a name that is not a shell function. - -@item return -@btindex return -@example -return [@var{n}] -@end example -Cause a shell function to exit with the return value @var{n}. -If @var{n} is not supplied, the return value is the exit status of the -last command executed in the function. -This may also be used to terminate execution of a script being executed -with the @code{.} (or @code{source}) builtin, returning either @var{n} or -the exit status of the last command executed within the script as the exit -status of the script. -Any command associated with the @code{RETURN} trap is executed -before execution resumes after the function or script. -The return status is non-zero if @code{return} is used outside a function -and not during the execution of a script by @code{.} or @code{source}. - -@item shift -@btindex shift -@example -shift [@var{n}] -@end example -Shift the positional parameters to the left by @var{n}. -The positional parameters from @var{n}+1 @dots{} @code{$#} are -renamed to @code{$1} @dots{} @code{$#}-@var{n}+1. -Parameters represented by the numbers @code{$#} to @var{n}+1 are unset. -@var{n} must be a non-negative number less than or equal to @code{$#}. -If @var{n} is zero or greater than @code{$#}, the positional parameters -are not changed. -If @var{n} is not supplied, it is assumed to be 1. -The return status is zero unless @var{n} is greater than @code{$#} or -less than zero, non-zero otherwise. - -@item test -@itemx [ -@btindex test -@btindex [ -Evaluate a conditional expression @var{expr}. -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. - -When the @code{[} form is used, the last argument to the command must -be a @code{]}. - -Expressions may be combined using the following operators, listed in -decreasing order of precedence. - -@table @code -@item ! @var{expr} -True if @var{expr} is false. - -@item ( @var{expr} ) -Returns the value of @var{expr}. -This may be used to override the normal precedence of operators. - -@item @var{expr1} -a @var{expr2} -True if both @var{expr1} and @var{expr2} are true. - -@item @var{expr1} -o @var{expr2} -True if either @var{expr1} or @var{expr2} is true. -@end table - -The @code{test} and @code{[} builtins evaluate conditional -expressions using a set of rules based on the number of arguments. - -@table @asis -@item 0 arguments -The expression is false. - -@item 1 argument -The expression is true if and only if the argument is not null. - -@item 2 arguments -If the first argument is @samp{!}, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators -(@pxref{Bash Conditional Expressions}), the expression -is true if the unary test is true. -If the first argument is not a valid unary operator, the expression is -false. - -@item 3 arguments -If the second argument is one of the binary conditional -operators (@pxref{Bash Conditional Expressions}), the -result of the expression is the result of the binary test using the -first and third arguments as operands. -If the first argument is @samp{!}, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly @samp{(} and the third argument is -exactly @samp{)}, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -The @samp{-a} and @samp{-o} operators are considered binary operators -in this case. - -@item 4 arguments -If the first argument is @samp{!}, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. - -@item 5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -@end table - -@item times -@btindex times -@example -times -@end example -Print out the user and system times used by the shell and its children. -The return status is zero. - -@item trap -@btindex trap -@example -trap [-lp] [@var{arg}] [@var{sigspec} @dots{}] -@end example -The commands in @var{arg} are to be read and executed when the -shell receives signal @var{sigspec}. If @var{arg} is absent or -equal to @samp{-}, all specified signals are reset to the values -they had when the shell was started. -If @var{arg} is the null string, then the signal specified by -each @var{sigspec} is ignored by the shell and commands it invokes. -If @var{arg} is not present and @option{-p} has been supplied, -the shell displays the trap commands associated with each @var{sigspec}. -If no arguments are supplied, or -only @option{-p} is given, @code{trap} prints the list of commands -associated with each signal number in a form that may be reused as -shell input. -The @option{-l} option causes the shell to print a list of signal names -and their corresponding numbers. - -Each @var{sigspec} is either a signal name such as @code{SIGINT} (with -or without the @code{SIG} prefix) or a signal number. -If a @var{sigspec} -is @code{0} or @code{EXIT}, @var{arg} is executed when the shell exits. -If a @var{sigspec} is @code{DEBUG}, the command @var{arg} is executed -before every simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -Refer to the description of the @code{extglob} option to the -@code{shopt} builtin (@pxref{Bash Builtins}) for details of its -effect on the @code{DEBUG} trap. -If a @var{sigspec} is @code{ERR}, the command @var{arg} -is executed whenever a simple command has a non-zero exit status. -The @code{ERR} trap is not executed if the failed command is part of the -command list immediately following an @code{until} or @code{while} keyword, -part of the test in an @code{if} statement, -part of a @code{&&} or @code{||} list, or if the command's return -status is being inverted using @code{!}. -If a @var{sigspec} is @code{RETURN}, the command @var{arg} is executed -each time a shell function or a script executed with the @code{.} or -@code{source} builtins finishes executing. - -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 zero unless a @var{sigspec} does not specify a -valid signal. - -@item umask -@btindex umask -@example -umask [-p] [-S] [@var{mode}] -@end example -Set the shell process's file creation mask to @var{mode}. If -@var{mode} begins with a digit, it is interpreted as an octal number; -if not, it is interpreted as a symbolic mode mask similar -to that accepted by the @code{chmod} command. If @var{mode} is -omitted, the current value of the mask is printed. If the @option{-S} -option is supplied without a @var{mode} argument, the mask is printed -in a symbolic format. -If the @option{-p} option is supplied, and @var{mode} -is omitted, the output is in a form that may be reused as input. -The return status is zero if the mode is successfully changed or if -no @var{mode} argument is supplied, and non-zero otherwise. - -Note that when the mode is interpreted as an octal number, each number -of the umask is subtracted from @code{7}. Thus, a umask of @code{022} -results in permissions of @code{755}. - -@item unset -@btindex unset -@example -unset [-fv] [@var{name}] -@end example -Each variable or function @var{name} is removed. -If no options are supplied, or the @option{-v} option is given, each -@var{name} refers to a shell variable. -If the @option{-f} option is given, the @var{name}s refer to shell -functions, and the function definition is removed. -Readonly variables and functions may not be unset. -The return status is zero unless a @var{name} is readonly. -@end table - -@node Bash Builtins -@section Bash Builtin Commands - -This section describes builtin commands which are unique to -or have been extended in Bash. -Some of these commands are specified in the @sc{posix} 1003.2 standard. - -@table @code - -@item alias -@btindex alias -@example -alias [@code{-p}] [@var{name}[=@var{value}] @dots{}] -@end example - -Without arguments or with the @option{-p} option, @code{alias} prints -the list of aliases on the standard output in a form that allows -them to be reused as input. -If arguments are supplied, an alias is defined for each @var{name} -whose @var{value} is given. If no @var{value} is given, the name -and value of the alias is printed. -Aliases are described in @ref{Aliases}. - -@item bind -@btindex bind -@example -bind [-m @var{keymap}] [-lpsvPSV] -bind [-m @var{keymap}] [-q @var{function}] [-u @var{function}] [-r @var{keyseq}] -bind [-m @var{keymap}] -f @var{filename} -bind [-m @var{keymap}] -x @var{keyseq:shell-command} -bind [-m @var{keymap}] @var{keyseq:function-name} -bind @var{readline-command} -@end example - -Display current Readline (@pxref{Command Line Editing}) -key and function bindings, -bind a key sequence to a Readline function or macro, -or set a Readline variable. -Each non-option argument is a command as it would appear in a -a Readline initialization file (@pxref{Readline Init File}), -but each binding or command must be passed as a separate argument; e.g., -@samp{"\C-x\C-r":re-read-init-file}. -Options, if supplied, have the following meanings: - -@table @code -@item -m @var{keymap} -Use @var{keymap} as the keymap to be affected by -the subsequent bindings. Acceptable @var{keymap} -names are -@code{emacs}, -@code{emacs-standard}, -@code{emacs-meta}, -@code{emacs-ctlx}, -@code{vi}, -@code{vi-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 -p -Display Readline function names and bindings in such a way that they -can be used as input or in a Readline initialization file. - -@item -P -List current Readline function names and bindings. - -@item -v -Display Readline variable names and values in such a way that they -can be used as input or in a Readline initialization file. - -@item -V -List current Readline variable names and values. - -@item -s -Display Readline key sequences bound to macros and the strings they output -in such a way that they can be used as input or in a Readline -initialization file. - -@item -S -Display Readline key sequences bound to macros and the strings they output. - -@item -f @var{filename} -Read key bindings from @var{filename}. - -@item -q @var{function} -Query about which keys invoke the named @var{function}. - -@item -u @var{function} -Unbind all keys bound to the named @var{function}. - -@item -r @var{keyseq} -Remove any current binding for @var{keyseq}. - -@item -x @var{keyseq:shell-command} -Cause @var{shell-command} to be executed whenever @var{keyseq} is -entered. - -@end table - -@noindent -The return status is zero unless an invalid option is supplied or an -error occurs. - -@item builtin -@btindex builtin -@example -builtin [@var{shell-builtin} [@var{args}]] -@end example -Run a shell builtin, passing it @var{args}, and return its exit status. -This is useful when defining a shell function with the same -name as a shell builtin, retaining the functionality of the builtin within -the function. -The return status is non-zero if @var{shell-builtin} is not a shell -builtin command. - -@item caller -@btindex caller -@example -caller [@var{expr}] -@end example -Returns the context of any active subroutine call (a shell function or -a script executed with the @code{.} or @code{source} builtins. - -Without @var{expr}, @code{caller} displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as @var{expr}, @code{caller} -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. - -The return value is 0 unless the shell is not executing a subroutine -call or @var{expr} does not correspond to a valid position in the -call stack. - -@item command -@btindex command -@example -command [-pVv] @var{command} [@var{arguments} @dots{}] -@end example -Runs @var{command} with @var{arguments} ignoring any shell function -named @var{command}. -Only shell builtin commands or commands found by searching the -@env{PATH} are executed. -If there is a shell function named @code{ls}, running @samp{command ls} -within the function will execute the external command @code{ls} -instead of calling the function recursively. -The @option{-p} option means to use a default value for @env{PATH} -that is guaranteed to find all of the standard utilities. -The return status in this case is 127 if @var{command} cannot be -found or an error occurred, and the exit status of @var{command} -otherwise. - -If either the @option{-V} or @option{-v} option is supplied, a -description of @var{command} is printed. The @option{-v} option -causes a single word indicating the command or file name used to -invoke @var{command} to be displayed; the @option{-V} option produces -a more verbose description. In this case, the return status is -zero if @var{command} is found, and non-zero if not. - -@item declare -@btindex declare -@example -declare [-afFirtx] [-p] [@var{name}[=@var{value}] @dots{}] -@end example - -Declare variables and give them attributes. If no @var{name}s -are given, then display the values of variables instead. - -The @option{-p} option will display the attributes and values of each -@var{name}. -When @option{-p} is used, additional options are ignored. -The @option{-F} option inhibits the display of function definitions; -only the function name and attributes are printed. -If the @code{extdebug} shell option is enabled using @code{shopt} -(@pxref{Bash Builtins}), the source file name and line number where -the function is defined are displayed as well. -@option{-F} implies @option{-f}. -The following options can be used to restrict output to variables with -the specified attributes or to give variables attributes: - -@table @code -@item -a -Each @var{name} is an array variable (@pxref{Arrays}). - -@item -f -Use function names only. - -@item -i -The variable is to be treated as -an integer; arithmetic evaluation (@pxref{Shell Arithmetic}) is -performed when the variable is assigned a value. - -@item -r -Make @var{name}s readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. - -@item -t -Give each @var{name} the @code{trace} attribute. -Traced functions inherit the @code{DEBUG} trap from the calling shell. -The trace attribute has no special meaning for variables. - -@item -x -Mark each @var{name} for export to subsequent commands via -the environment. -@end table - -Using @samp{+} instead of @samp{-} turns off the attribute instead. -When used in a function, @code{declare} makes each @var{name} local, -as with the @code{local} command. If a variable name is followed by -=@var{value}, the value of the variable is set to @var{value}. - -The return status is zero unless an invalid option is encountered, -an attempt is made to define a function using @samp{-f foo=bar}, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (@pxref{Arrays}), -one of the @var{names} is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with @option{-f}. - -@item echo -@btindex echo -@example -echo [-neE] [@var{arg} @dots{}] -@end example -Output the @var{arg}s, separated by spaces, terminated with a -newline. -The return status is always 0. -If @option{-n} is specified, the trailing newline is suppressed. -If the @option{-e} option is given, interpretation of the following -backslash-escaped characters is enabled. -The @option{-E} option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The @code{xpg_echo} shell option may be used to -dynamically determine whether or not @code{echo} expands these -escape characters by default. -@code{echo} interprets the following escape sequences: -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \c -suppress trailing newline -@item \e -escape -@item \f -form feed -@item \n -new line -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \0@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(zero to three octal digits) -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three octal digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@end table - -@item enable -@btindex enable -@example -enable [-n] [-p] [-f @var{filename}] [-ads] [@var{name} @dots{}] -@end example -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -If @option{-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 @env{$PATH} instead of the shell builtin version, type -@samp{enable -n test}. - -If the @option{-p} option is supplied, or no @var{name} arguments appear, -a list of shell builtins is printed. With no other arguments, the list -consists of all enabled shell builtins. -The @option{-a} option means to list -each builtin with an indication of whether or not it is enabled. - -The @option{-f} option means to load the new builtin command @var{name} -from shared object @var{filename}, on systems that support dynamic loading. -The @option{-d} option will delete a builtin loaded with @option{-f}. - -If there are no options, a list of the shell builtins is displayed. -The @option{-s} option restricts @code{enable} to the @sc{posix} special -builtins. If @option{-s} is used with @option{-f}, the new builtin becomes -a special builtin (@pxref{Special Builtins}). - -The return status is zero unless a @var{name} is not a shell builtin -or there is an error loading a new builtin from a shared object. - -@item help -@btindex help -@example -help [-s] [@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. -The @option{-s} option restricts the information displayed to a short -usage synopsis. -The return status is zero unless no command matches @var{pattern}. - -@item let -@btindex let -@example -let @var{expression} [@var{expression}] -@end example -The @code{let} builtin allows arithmetic to be performed on shell -variables. Each @var{expression} is evaluated according to the -rules given below in @ref{Shell Arithmetic}. If the -last @var{expression} evaluates to 0, @code{let} returns 1; -otherwise 0 is returned. - -@item local -@btindex local -@example -local [@var{option}] @var{name}[=@var{value}] @dots{} -@end example -For each argument, a local variable named @var{name} is created, -and assigned @var{value}. -The @var{option} can be any of the options accepted by @code{declare}. -@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. The return status is zero unless @code{local} is used outside -a function, an invalid @var{name} is supplied, or @var{name} is a -readonly variable. - -@item logout -@btindex logout -@example -logout [@var{n}] -@end example -Exit a login shell, returning a status of @var{n} to the shell's -parent. - -@item printf -@btindex printf -@example -@code{printf} @var{format} [@var{arguments}] -@end example -Write the formatted @var{arguments} to the standard output under the -control of the @var{format}. -The @var{format} is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -@var{argument}. -In addition to the standard @code{printf(1)} formats, @samp{%b} causes -@code{printf} to expand backslash escape sequences in the corresponding -@var{argument}, and @samp{%q} causes @code{printf} to output the -corresponding @var{argument} in a format that can be reused as shell input. - -The @var{format} is reused as necessary to consume all of the @var{arguments}. -If the @var{format} requires more @var{arguments} than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. - -@item read -@btindex read -@example -read [-ers] [-a @var{aname}] [-d @var{delim}] [-n @var{nchars}] [-p @var{prompt}] [-t @var{timeout}] [-u @var{fd}] [@var{name} @dots{}] -@end example -One line is read from the standard input, or from the file descriptor -@var{fd} supplied as an argument to the @option{-u} option, and the first word -is assigned to the first @var{name}, the second word to the second @var{name}, -and so on, with leftover words and their intervening separators assigned -to the last @var{name}. -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in the value of the @env{IFS} variable -are used to split the line into words. -The backslash character @samp{\} may be used to remove any special -meaning for the next character read and for line continuation. -If no names are supplied, the line read is assigned to the -variable @env{REPLY}. -The return code is zero, unless end-of-file is encountered, @code{read} -times out, or an invalid file descriptor is supplied as the argument to -@option{-u}. -Options, if supplied, have the following meanings: - -@table @code -@item -a @var{aname} -The words are assigned to sequential indices of the array variable -@var{aname}, starting at 0. -All elements are removed from @var{aname} before the assignment. -Other @var{name} arguments are ignored. - -@item -d @var{delim} -The first character of @var{delim} is used to terminate the input line, -rather than newline. - -@item -e -Readline (@pxref{Command Line Editing}) is used to obtain the line. - -@item -n @var{nchars} -@code{read} returns after reading @var{nchars} characters rather than -waiting for a complete line of input. - -@item -p @var{prompt} -Display @var{prompt}, without a trailing newline, before attempting -to read any input. -The prompt is displayed only if input is coming from a terminal. - -@item -r -If this option is given, backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. - -@item -s -Silent mode. If input is coming from a terminal, characters are -not echoed. - -@item -t @var{timeout} -Cause @code{read} to time out and return failure if a complete line of -input is not read within @var{timeout} seconds. -This option has no effect if @code{read} is not reading input from the -terminal or a pipe. - -@item -u @var{fd} -Read input from file descriptor @var{fd}. - -@end table - -@item shopt -@btindex shopt -@example -shopt [-pqsu] [-o] [@var{optname} @dots{}] -@end example -Toggle the values of variables controlling optional shell behavior. -With no options, or with the @option{-p} option, a list of all settable -options is displayed, with an indication of whether or not each is set. -The @option{-p} option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: - -@table @code -@item -s -Enable (set) each @var{optname}. - -@item -u -Disable (unset) each @var{optname}. - -@item -q -Suppresses normal output; the return status -indicates whether the @var{optname} is set or unset. -If multiple @var{optname} arguments are given with @option{-q}, -the return status is zero if all @var{optnames} are enabled; -non-zero otherwise. - -@item -o -Restricts the values of -@var{optname} to be those defined for the @option{-o} option to the -@code{set} builtin (@pxref{The Set Builtin}). -@end table - -If either @option{-s} or @option{-u} -is used with no @var{optname} arguments, the display is limited to -those options which are set or unset, respectively. - -Unless otherwise noted, the @code{shopt} options are disabled (off) -by default. - -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an @var{optname} is not a valid shell -option. - -The list of @code{shopt} options is: -@table @code -@item cdable_vars -If this is set, an argument to the @code{cd} -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. - -@item cdspell -If set, minor errors in the spelling of a directory component in a -@code{cd} command will be corrected. -The errors checked for are transposed characters, -a missing character, and a character too many. -If a correction is found, the corrected path is printed, -and the command proceeds. -This option is only used by interactive shells. - -@item checkhash -If this is set, Bash checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. - -@item checkwinsize -If set, Bash checks the window size after each command -and, if necessary, updates the values of -@env{LINES} and @env{COLUMNS}. - -@item cmdhist -If set, Bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. - -@item dotglob -If set, Bash includes filenames beginning with a `.' in -the results of filename expansion. - -@item execfail -If this is set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the @code{exec} -builtin command. An interactive shell does not exit if @code{exec} -fails. - -@item expand_aliases -If set, aliases are expanded as described below under Aliases, -@ref{Aliases}. -This option is enabled by default for interactive shells. - -@item extdebug -If set, behavior intended for use by debuggers is enabled: - -@enumerate -@item -The @option{-F} option to the @code{declare} builtin (@pxref{Bash Builtins}) -displays the source file name and line number corresponding to each function -name supplied as an argument. - -@item -If the command run by the @code{DEBUG} trap returns a non-zero value, the -next command is skipped and not executed. - -@item -If the command run by the @code{DEBUG} trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the @code{.} or @code{source} builtins), a call to -@code{return} is simulated. -@end enumerate - -@item extglob -If set, the extended pattern matching features described above -(@pxref{Pattern Matching}) are enabled. - -@item extquote -If set, @code{$'@var{string}'} and @code{$"@var{string}"} quoting is -performed within @code{$@{@var{parameter}@}} expansions -enclosed in double quotes. This option is enabled by default. - -@item histappend -If set, the history list is appended to the file named by the value -of the @env{HISTFILE} -variable when the shell exits, rather than overwriting the file. - -@item histreedit -If set, and Readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. - -@item histverify -If set, and Readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the Readline editing buffer, allowing further modification. - -@item hostcomplete -If set, and Readline is being used, Bash will attempt to perform -hostname completion when a word containing a @samp{@@} is being -completed (@pxref{Commands For Completion}). This option is enabled -by default. - -@item huponexit -If set, Bash will send @code{SIGHUP} to all jobs when an interactive -login shell exits (@pxref{Signals}). - -@item interactive_comments -Allow a word beginning with @samp{#} -to cause that word and all remaining characters on that -line to be ignored in an interactive shell. -This option is enabled by default. - -@item lithist -If enabled, and the @code{cmdhist} -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. - -@item login_shell -The shell sets this option if it is started as a login shell -(@pxref{Invoking Bash}). -The value may not be changed. - -@item mailwarn -If set, and a file that Bash is checking for mail has been -accessed since the last time it was checked, the message -@code{"The mail in @var{mailfile} has been read"} is displayed. - -@item no_empty_cmd_completion -If set, and Readline is being used, Bash will not attempt to search -the @env{PATH} for possible completions when completion is attempted -on an empty line. - -@item nocaseglob -If set, Bash matches filenames in a case-insensitive fashion when -performing filename expansion. - -@item nullglob -If set, Bash allows filename patterns which match no -files to expand to a null string, rather than themselves. - -@item progcomp -If set, the programmable completion facilities -(@pxref{Programmable Completion}) are enabled. -This option is enabled by default. - -@item promptvars -If set, prompt strings undergo variable and parameter expansion after -being expanded (@pxref{Printing a Prompt}). -This option is enabled by default. - -@item restricted_shell -The shell sets this option if it is started in restricted mode -(@pxref{The Restricted Shell}). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. - -@item shift_verbose -If this is set, the @code{shift} -builtin prints an error message when the shift count exceeds the -number of positional parameters. - -@item sourcepath -If set, the @code{source} builtin uses the value of @env{PATH} -to find the directory containing the file supplied as an argument. -This option is enabled by default. - -@item xpg_echo -If set, the @code{echo} builtin expands backslash-escape sequences -by default. - -@end table - -@noindent -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. -When setting or unsetting options, the return status is zero unless an -@var{optname} is not a valid shell option. - -@item source -@btindex source -@example -source @var{filename} -@end example -A synonym for @code{.} (@pxref{Bourne Shell Builtins}). - -@item type -@btindex type -@example -type [-afptP] [@var{name} @dots{}] -@end example -For each @var{name}, indicate how it would be interpreted if used as a -command name. - -If the @option{-t} option is used, @code{type} prints a single word -which is one of @samp{alias}, @samp{function}, @samp{builtin}, -@samp{file} or @samp{keyword}, -if @var{name} is an alias, shell function, shell builtin, -disk file, or shell reserved word, respectively. -If the @var{name} is not found, then nothing is printed, and -@code{type} returns a failure status. - -If the @option{-p} option is used, @code{type} either returns the name -of the disk file that would be executed, or nothing if @option{-t} -would not return @samp{file}. - -The @option{-P} option forces a path search for each @var{name}, even if -@option{-t} would not return @samp{file}. - -If a command is hashed, @option{-p} and @option{-P} print the hashed value, -not necessarily the file that appears first in @code{$PATH}. - -If the @option{-a} option is used, @code{type} returns all of the places -that contain an executable named @var{file}. -This includes aliases and functions, if and only if the @option{-p} option -is not also used. - -If the @option{-f} option is used, @code{type} does not attempt to find -shell functions, as with the @code{command} builtin. - -The return status is zero if any of the @var{names} are found, non-zero -if none are found. - -@item typeset -@btindex typeset -@example -typeset [-afFrxi] [-p] [@var{name}[=@var{value}] @dots{}] -@end example -The @code{typeset} command is supplied for compatibility with the Korn -shell; however, it has been deprecated in favor of the @code{declare} -builtin command. - -@item ulimit -@btindex ulimit -@example -ulimit [-acdflmnpstuvSH] [@var{limit}] -@end example -@code{ulimit} provides control over the resources available to processes -started by the shell, on systems that allow such control. If an -option is given, it is interpreted as follows: -@table @code -@item -S -Change and report the soft limit associated with a resource. - -@item -H -Change and report the hard limit associated with a resource. - -@item -a -All current limits are reported. - -@item -c -The maximum size of core files created. - -@item -d -The maximum size of a process's data segment. - -@item -f -The maximum size of files created by the shell. - -@item -l -The maximum size that may be locked into memory. - -@item -m -The maximum resident set size. - -@item -n -The maximum number of open file descriptors. - -@item -p -The pipe buffer size. - -@item -s -The maximum stack size. - -@item -t -The maximum amount of cpu time in seconds. - -@item -u -The maximum number of processes available to a single user. - -@item -v -The maximum amount of virtual memory available to the process. - -@end table - -If @var{limit} is given, it is the new value of the specified resource; -the special @var{limit} values @code{hard}, @code{soft}, and -@code{unlimited} stand for the current hard limit, the current soft limit, -and no limit, respectively. -Otherwise, the current value of the soft limit for the specified resource -is printed, unless the @option{-H} option is supplied. -When setting new limits, if neither @option{-H} nor @option{-S} is supplied, -both the hard and soft limits are set. -If no option is given, then @option{-f} is assumed. Values are in 1024-byte -increments, except for @option{-t}, which is in seconds, @option{-p}, -which is in units of 512-byte blocks, and @option{-n} and @option{-u}, which -are unscaled values. - -The return status is zero unless an invalid option or argument is supplied, -or an error occurs while setting a new limit. - -@item unalias -@btindex unalias -@example -unalias [-a] [@var{name} @dots{} ] -@end example - -Remove each @var{name} from the list of aliases. If @option{-a} is -supplied, all aliases are removed. -Aliases are described in @ref{Aliases}. - -@end table - -@node The Set Builtin -@section The Set Builtin - -This builtin is so complicated that it deserves its own section. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCHP] [-o @var{option}] [@var{argument} @dots{}] -@end example - -If no options or arguments are supplied, @code{set} displays the names -and values of all shell variables and functions, sorted according to the -current locale, in a format that may be reused as input. - -When options are supplied, they set or unset shell attributes. -Options, if specified, have the following meanings: - -@table @code -@item -a -Mark variables and function which are modified or created for export -to the environment of subsequent commands. - -@item -b -Cause the status of terminated background jobs to be reported -immediately, rather than before printing the next primary prompt. - -@item -e -Exit immediately if a simple command (@pxref{Simple Commands}) exits -with a non-zero status, unless the command that fails is part of the -command list immediately following a @code{while} or @code{until} -keyword, part of the test in an @code{if} statement, -part of a @code{&&} or @code{||} list, or if the command's return -status is being inverted using @code{!}. -A trap on @code{ERR}, if set, is executed before the shell exits. - -@item -f -Disable file name generation (globbing). - -@item -h -Locate and remember (hash) commands as they are looked up for execution. -This option is enabled by default. - -@item -k -All arguments in the form of assignment statements are placed -in the environment for a command, not just those that precede -the command name. - -@item -m -Job control is enabled (@pxref{Job Control}). - -@item -n -Read commands but do not execute them; this may be used to check a -script for syntax errors. -This option is ignored by interactive shells. - -@item -o @var{option-name} - -Set the option corresponding to @var{option-name}: - -@table @code -@item allexport -Same as @code{-a}. - -@item braceexpand -Same as @code{-B}. - -@item emacs -Use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). - -@item errexit -Same as @code{-e}. - -@item errtrace -Same as @code{-E}. - -@item functrace -Same as @code{-T}. - -@item hashall -Same as @code{-h}. - -@item histexpand -Same as @code{-H}. - -@item history -Enable command history, as described in @ref{Bash History Facilities}. -This option is on by default in interactive shells. - -@item ignoreeof -An interactive shell will not exit upon reading EOF. - -@item keyword -Same as @code{-k}. - -@item monitor -Same as @code{-m}. - -@item noclobber -Same as @code{-C}. - -@item noexec -Same as @code{-n}. - -@item noglob -Same as @code{-f}. - -@item nolog -Currently ignored. - -@item notify -Same as @code{-b}. - -@item nounset -Same as @code{-u}. - -@item onecmd -Same as @code{-t}. - -@item physical -Same as @code{-P}. - -@item posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} 1003.2 standard to match the standard -(@pxref{Bash POSIX Mode}). -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 @env{$BASH_ENV} and @env{$ENV} files are not -processed, shell functions are not inherited from the environment, -and the @env{SHELLOPTS} variable, if it appears in the environment, -is ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the @code{-p} option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the @code{-p} option is supplied at startup, the effective user id is -not reset. -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 performing parameter expansion. -An error message will be written to the standard error, and a non-interactive -shell will exit. - -@item -v -Print shell input lines as they are read. - -@item -x -Print a trace of simple commands, \fBfor\fP commands, \fBcase\fP -commands, \fBselect\fP commands, and arithmetic \fBfor\fP commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -the command and its expanded arguments. - -@item -B -The shell will perform brace expansion (@pxref{Brace Expansion}). -This option is on by default. - -@item -C -Prevent output redirection using @samp{>}, @samp{>&}, and @samp{<>} -from overwriting existing files. - -@item -E -If set, any trap on @code{ERR} is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The @code{ERR} trap is normally not inherited in such cases. - -@item -H -Enable @samp{!} style history substitution (@pxref{History Interaction}). -This option is on by default for interactive shells. - -@item -P -If set, do not follow symbolic links when performing commands such as -@code{cd} which change the current directory. The physical directory -is used instead. By default, Bash follows -the logical chain of directories when performing commands -which change the current directory. - -For example, if @file{/usr/sys} is a symbolic link to @file{/usr/local/sys} -then: -@example -$ cd /usr/sys; echo $PWD -/usr/sys -$ cd ..; pwd -/usr -@end example - -@noindent -If @code{set -P} is on, then: -@example -$ cd /usr/sys; echo $PWD -/usr/local/sys -$ cd ..; pwd -/usr/local -@end example - -@item -T -If set, any trap on @code{DEBUG} is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The @code{DEBUG} trap is normally not inherited in such cases. - -@item -- -If no arguments follow this option, then the positional parameters are -unset. Otherwise, the positional parameters are set to the -@var{arguments}, even if some of them begin with a @samp{-}. - -@item - -Signal the end of options, cause all remaining @var{arguments} -to be assigned to the positional parameters. The @option{-x} -and @option{-v} options are turned off. -If there are no arguments, the positional parameters remain unchanged. -@end table - -Using @samp{+} rather than @samp{-} causes these options to be -turned off. The options can also be used upon invocation of the -shell. The current set of options may be found in @code{$-}. - -The remaining N @var{arguments} are positional parameters and are -assigned, in order, to @code{$1}, @code{$2}, @dots{} @code{$N}. -The special parameter @code{#} is set to N. - -The return status is always zero unless an invalid option is supplied. -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} 1003.2 standard has classified -several builtin commands as @emph{special}. -When Bash is executing in @sc{posix} mode, the special builtins -differ from other builtin commands in three respects: - -@enumerate -@item -Special builtins are found before shell functions during command lookup. - -@item -If a special builtin returns an error status, a non-interactive shell exits. - -@item -Assignment statements preceding the command stay in effect in the shell -environment after the command completes. -@end enumerate - -When Bash is not executing in @sc{posix} mode, these builtins behave no -differently than the rest of the Bash builtin commands. -The Bash @sc{posix} mode is described in @ref{Bash POSIX Mode}. - -These are the @sc{posix} special builtins: -@example -@w{break : . continue eval exec exit export readonly return set} -@w{shift trap unset} -@end example - -@node Shell Variables -@chapter Shell Variables - -@menu -* Bourne Shell Variables:: Variables which Bash uses in the same way - as the Bourne Shell. -* Bash Variables:: List of variables that exist in Bash. -@end menu - -This chapter describes the shell variables that Bash uses. -Bash automatically assigns default values to a number of variables. - -@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 CDPATH -A colon-separated list of directories used as a search path for -the @code{cd} builtin command. - -@item HOME -The current user's home directory; the default for the @code{cd} builtin -command. -The value of this variable is also used by tilde expansion -(@pxref{Tilde Expansion}). - -@item IFS -A list of characters that separate fields; used when the shell splits -words as part of expansion. - -@item MAIL -If this parameter is set to a filename and the @env{MAILPATH} variable -is not set, Bash informs the user of the arrival of mail in -the specified file. - -@item MAILPATH -A colon-separated list of filenames which the shell periodically checks -for new mail. -Each list entry can specify the message that is printed when new mail -arrives in the mail file by separating the file name from the message with -a @samp{?}. -When used in the text of the message, @code{$_} expands to the name of -the current mail file. - -@item OPTARG -The value of the last option argument processed by the @code{getopts} builtin. - -@item OPTIND -The index of the last option argument processed by the @code{getopts} builtin. - -@item PATH -A colon-separated list of directories in which the shell looks for -commands. -A zero-length (null) directory name in the value of @code{PATH} indicates the -current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. - - -@item PS1 -The primary prompt string. The default value is @samp{\s-\v\$ }. -@xref{Printing a Prompt}, for the complete list of escape -sequences that are expanded before @env{PS1} is displayed. - -@item PS2 -The secondary prompt string. The default value is @samp{> }. - -@end vtable - -@node Bash Variables -@section Bash Variables - -These variables are set or used by Bash, but other shells -do not normally treat them specially. - -A few variables used by Bash are described in different chapters: -variables for controlling the job control facilities -(@pxref{Job Control Variables}). - -@vtable @code - -@item BASH -The full pathname used to execute the current instance of Bash. - -@item BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current bash execution call stack. The number of -parameters to the current subroutine (shell function or script executed -with @code{.} or @code{source}) is at the top of the stack. When a -subroutine is executed, the number of parameters passed is pushed onto -@code{BASH_ARGC}. - -@item BASH_ARGV -An array variable containing all of the parameters in the current bash -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto @code{BASH_ARGV}. - -@item BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. - -@item BASH_ENV -If this variable is set when Bash is invoked to execute a shell -script, its value is expanded and used as the name of a startup file -to read before executing the script. @xref{Bash Startup Files}. - -@item BASH_EXECUTION_STRING -The command argument to the @option{-c} invocation option. - -@item BASH_LINENO -An array variable whose members are the line numbers in source files -corresponding to each member of @var{FUNCNAME}. -@code{$@{BASH_LINENO[$i]@}} is the line number in the source file where -@code{$@{FUNCNAME[$i + 1]@}} was called. -The corresponding source file name is @code{$@{BASH_SOURCE[$i + 1]@}}. -Use @code{LINENO} to obtain the current line number. - -@item BASH_SOURCE -An array variable whose members are the source filenames corresponding -to the elements in the @code{FUNCNAME} array variable. - -@item BASH_SUBSHELL -Incremented by one each time a subshell or subshell environment is spawned. -The initial value is 0. - -@item BASH_VERSINFO -A readonly array variable (@pxref{Arrays}) -whose members hold version information for this instance of Bash. -The values assigned to the array members are as follows: - -@table @code - -@item BASH_VERSINFO[0] -The major version number (the @var{release}). - -@item BASH_VERSINFO[1] -The minor version number (the @var{version}). - -@item BASH_VERSINFO[2] -The patch level. - -@item BASH_VERSINFO[3] -The build version. - -@item BASH_VERSINFO[4] -The release status (e.g., @var{beta1}). - -@item BASH_VERSINFO[5] -The value of @env{MACHTYPE}. - -@end table - -@item BASH_VERSION -The version number of the current instance of Bash. - -@item COLUMNS -Used by the @code{select} builtin command to determine the terminal width -when printing selection lists. Automatically set upon receipt of a -@code{SIGWINCH}. - -@item COMP_CWORD -An index into @env{$@{COMP_WORDS@}} of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to @code{$@{#COMP_LINE@}}. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_WORDBREAKS -The set of characters that the Readline library treats as word -separators when performing word completion. -If @code{COMP_WORDBREAKS} is unset, it loses its special properties, -even if it is subsequently reset. - -@item COMP_WORDS -An array variable consisting of the individual -words in the current command line. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMPREPLY -An array variable from which Bash reads the possible completions -generated by a shell function invoked by the programmable completion -facility (@pxref{Programmable Completion}). - -@item DIRSTACK -An array variable containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -@code{dirs} builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the @code{pushd} and @code{popd} -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If @env{DIRSTACK} is unset, it loses its special properties, even if -it is subsequently reset. - -@item EMACS -If Bash finds this variable in the environment when the shell -starts with value @samp{t}, it assumes that the shell is running in an -emacs shell buffer and disables line editing. - -@item EUID -The numeric effective user id of the current user. This variable -is readonly. - -@item FCEDIT -The editor used as a default by the @option{-e} option to the @code{fc} -builtin command. - -@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 -@env{FIGNORE} -is excluded from the list of matched file names. A sample -value is @samp{.o:~} - -@item FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element is "main". -This variable exists only when a shell function is executing. -Assignments to @env{FUNCNAME} have no effect and return an error status. -If @env{FUNCNAME} is unset, it loses its special properties, even if -it is subsequently reset. - -@item GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by filename expansion. -If a filename matched by a filename expansion pattern also matches one -of the patterns in @env{GLOBIGNORE}, it is removed from the list -of matches. - -@item GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to @env{GROUPS} have no effect and return an error status. -If @env{GROUPS} is unset, it loses its special properties, even if it is -subsequently reset. - -@item histchars -Up to three characters which control history expansion, quick -substitution, and tokenization (@pxref{History Interaction}). -The first character is the -@var{history expansion} character, 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 indicates that 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 @env{HISTCMD} is unset, it loses its special properties, -even if it is subsequently reset. - -@item HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes @samp{ignorespace}, lines which begin -with a space character are not saved in the history list. -A value of @samp{ignoredups} causes lines which match the previous -history entry to not be saved. -A value of @samp{ignoreboth} is shorthand for -@samp{ignorespace} and @samp{ignoredups}. -A value of @samp{erasedups} causes all previous lines matching the -current line to be removed from the history list before that line -is saved. -Any value not in the above list is ignored. -If @env{HISTCONTROL} is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of @env{HISTIGNORE}. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTCONTROL}. - -@item HISTFILE -The name of the file to which the command history is saved. The -default value is @file{~/.bash_history}. - -@item HISTFILESIZE -The maximum number of lines contained in the history file. When this -variable is assigned a value, the history file is truncated, if -necessary, to contain no more than that number of lines. -The history file is also truncated to this size after -writing it when an interactive shell exits. -The default value is 500. - -@item HISTIGNORE -A colon-separated list of patterns used to decide which command -lines should be saved on the history list. Each pattern is -anchored at the beginning of the line and must match the complete -line (no implicit @samp{*} is appended). Each pattern is tested -against the line after the checks specified by @env{HISTCONTROL} -are applied. In addition to the normal shell pattern matching -characters, @samp{&} matches the previous history line. @samp{&} -may be escaped using a backslash; the backslash is removed -before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTIGNORE}. - -@env{HISTIGNORE} subsumes the function of @env{HISTCONTROL}. A -pattern of @samp{&} is identical to @code{ignoredups}, and a -pattern of @samp{[ ]*} is identical to @code{ignorespace}. -Combining these two patterns, separating them with a colon, -provides the functionality of @code{ignoreboth}. - -@item HISTSIZE -The maximum number of commands to remember on the history list. -The default value is 500. - -@item HOSTFILE -Contains the name of a file in the same format as @file{/etc/hosts} that -should be read when the shell needs to complete a hostname. -The list of possible hostname completions may be changed while the shell -is running; -the next time hostname completion is attempted after the -value is changed, Bash adds the contents of the new file to the -existing list. -If @env{HOSTFILE} is set, but has no value, Bash attempts to read -@file{/etc/hosts} to obtain the list of possible hostname completions. -When @env{HOSTFILE} is unset, the hostname list is cleared. - -@item HOSTNAME -The name of the current host. - -@item HOSTTYPE -A string describing the machine Bash is running on. - -@item IGNOREEOF -Controls the action of the shell on receipt of an @code{EOF} character -as the sole input. If set, the value denotes the number -of consecutive @code{EOF} characters that can be read as the -first character on an input line -before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. -If the variable does not exist, then @code{EOF} signifies the end of -input to the shell. This is only in effect for interactive shells. - -@item INPUTRC -The name of the Readline initialization file, overriding the default -of @file{~/.inputrc}. - -@item LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with @code{LC_}. - -@item LC_ALL -This variable overrides the value of @env{LANG} and any other -@code{LC_} variable specifying a locale category. - -@item LC_COLLATE -This variable determines the collation order used when sorting the -results of filename expansion, and -determines the behavior of range expressions, equivalence classes, -and collating sequences within filename expansion and pattern matching -(@pxref{Filename Expansion}). - -@item LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within filename expansion and pattern -matching (@pxref{Filename Expansion}). - -@item LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a @samp{$} (@pxref{Locale Translation}). - -@item LC_NUMERIC -This variable determines the locale category used for number formatting. - -@item LINENO -The line number in the script or shell function currently executing. - -@item LINES -Used by the @code{select} builtin command to determine the column length -for printing selection lists. Automatically set upon receipt of a -@code{SIGWINCH}. - -@item MACHTYPE -A string that fully describes the system type on which Bash -is executing, in the standard @sc{gnu} @var{cpu-company-system} format. - -@item MAILCHECK -How often (in seconds) that the shell should check for mail in the -files specified in the @env{MAILPATH} or @env{MAIL} variables. -The default is 60 seconds. When it is time to check -for mail, the shell does so before displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. - -@item OLDPWD -The previous working directory as set by the @code{cd} builtin. - -@item OPTERR -If set to the value 1, Bash displays error messages -generated by the @code{getopts} builtin command. - -@item OSTYPE -A string describing the operating system Bash is running on. - -@item PIPESTATUS -An array variable (@pxref{Arrays}) -containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). - -@item POSIXLY_CORRECT -If this variable is in the environment when @code{bash} starts, the shell -enters @sc{posix} mode (@pxref{Bash POSIX Mode}) before reading the -startup files, as if the @option{--posix} invocation option had been supplied. -If it is set while the shell is running, @code{bash} enables @sc{posix} mode, -as if the command -@example -@code{set -o posix} -@end example -@noindent -had been executed. - -@item PPID -The process @sc{id} of the shell's parent process. This variable -is readonly. - -@item PROMPT_COMMAND -If set, the value is interpreted as a command to execute -before the printing of each primary prompt (@env{$PS1}). - -@item PS3 -The value of this variable is used as the prompt for the -@code{select} command. If this variable is not set, the -@code{select} command prompts with @samp{#? } - -@item PS4 -The value is the prompt printed before the command line is echoed -when the @option{-x} option is set (@pxref{The Set Builtin}). -The first character of @env{PS4} is replicated multiple times, as -necessary, to indicate multiple levels of indirection. -The default is @samp{+ }. - -@item PWD -The current working directory as set by the @code{cd} builtin. - -@item RANDOM -Each time this parameter is referenced, a random integer -between 0 and 32767 is generated. Assigning a value to this -variable seeds the random number generator. - -@item REPLY -The default variable for the @code{read} builtin. - -@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 SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the @option{-o} option to the -@code{set} builtin command (@pxref{The Set Builtin}). -The options appearing in @env{SHELLOPTS} are those reported -as @samp{on} by @samp{set -o}. -If this variable is in the environment when Bash -starts up, each shell option in the list will be enabled before -reading any startup files. This variable is readonly. - -@item SHLVL -Incremented by one each time a new instance of Bash is started. This is -intended to be a count of how deeply your Bash shells are nested. - -@item TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the @code{time} -reserved word should be displayed. -The @samp{%} character introduces an -escape sequence that is expanded to a time value or other -information. -The escape sequences and their meanings are as -follows; the braces denote optional portions. - -@table @code - -@item %% -A literal @samp{%}. - -@item %[@var{p}][l]R -The elapsed time in seconds. - -@item %[@var{p}][l]U -The number of CPU seconds spent in user mode. - -@item %[@var{p}][l]S -The number of CPU seconds spent in system mode. - -@item %P -The CPU percentage, computed as (%U + %S) / %R. -@end table - -The optional @var{p} is a digit specifying the precision, the number of -fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; values -of @var{p} greater than 3 are changed to 3. -If @var{p} is not specified, the value 3 is used. - -The optional @code{l} specifies a longer format, including minutes, of -the form @var{MM}m@var{SS}.@var{FF}s. -The value of @var{p} determines whether or not the fraction is included. - -If this variable is not set, Bash acts as if it had the value -@example -@code{$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'} -@end example -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. - -@item TMOUT -If set to a value greater than zero, @code{TMOUT} is treated as the -default timeout for the @code{read} builtin (@pxref{Bash Builtins}). -The @code{select} command (@pxref{Conditional Constructs}) terminates -if input does not arrive after @code{TMOUT} seconds when input is coming -from a terminal. - -In an interative shell, the value is interpreted as -the number of seconds to wait for input after issuing the primary -prompt when the shell is interactive. -Bash terminates after that number of seconds if input does -not arrive. - -@item UID -The numeric real user id of the current user. This variable is readonly. - -@end vtable - -@node Bash Features -@chapter Bash Features - -This section describes features unique to Bash. - -@menu -* Invoking Bash:: Command line options that you can give - to Bash. -* Bash Startup Files:: When and how Bash executes scripts. -* Interactive Shells:: What an interactive shell is. -* Bash Conditional Expressions:: Primitives used in composing expressions for - the @code{test} builtin. -* Shell Arithmetic:: Arithmetic on shell variables. -* Aliases:: Substituting one command for another. -* Arrays:: Array Variables. -* The Directory Stack:: History of visited directories. -* Printing a Prompt:: Controlling the PS1 string. -* The Restricted Shell:: A more controlled mode of shell execution. -* Bash POSIX Mode:: Making Bash behave more closely to what - the POSIX standard specifies. -@end menu - -@node Invoking Bash -@section Invoking Bash - -@example -bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] -c @var{string} [@var{argument} @dots{}] -bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -@end example - -In addition to the single-character shell command-line options -(@pxref{The Set Builtin}), there are several multi-character -options that you can use. These options must appear on the command -line before the single-character options to be recognized. - -@table @code -@item --debugger -Arrange for the debugger profile to be executed before the shell -starts. Turns on extended debugging mode (see @ref{Bash Builtins} -for a description of the @code{extdebug} option to the @code{shopt} -builtin) and shell function tracing -(see @ref{The Set Builtin} for a description of the @code{-o functrace} -option). - -@item --dump-po-strings -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput -in the @sc{gnu} @code{gettext} PO (portable object) file format. -Equivalent to @option{-D} except for the output format. - -@item --dump-strings -Equivalent to @option{-D}. - -@item --help -Display a usage message on standard output and exit sucessfully. - -@item --init-file @var{filename} -@itemx --rcfile @var{filename} -Execute commands from @var{filename} (instead of @file{~/.bashrc}) -in an interactive shell. - -@item --login -Equivalent to @option{-l}. - -@item --noediting -Do not use the @sc{gnu} Readline library (@pxref{Command Line Editing}) -to read command lines when the shell is interactive. - -@item --noprofile -Don't load the system-wide startup file @file{/etc/profile} -or any of the personal initialization files -@file{~/.bash_profile}, @file{~/.bash_login}, or @file{~/.profile} -when Bash is invoked as a login shell. - -@item --norc -Don't read the @file{~/.bashrc} initialization file in an -interactive shell. This is on by default if the shell is -invoked as @code{sh}. - -@item --posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} 1003.2 standard to match the standard. This -is intended to make Bash behave as a strict superset of that -standard. @xref{Bash POSIX Mode}, for a description of the Bash -@sc{posix} mode. - -@item --restricted -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item --verbose -Equivalent to @option{-v}. Print shell input lines as they're read. - -@item --version -Show version information for this instance of -Bash on the standard output and exit successfully. - -@end table - -There are several single-character options that may be supplied at -invocation which are not available with the @code{set} builtin. - -@table @code -@item -c @var{string} -Read and execute commands from @var{string} after processing the -options, then exit. Any remaining arguments are assigned to the -positional parameters, starting with @code{$0}. - -@item -i -Force the shell to run interactively. Interactive shells are -described in @ref{Interactive Shells}. - -@item -l -Make this shell act as if it had been directly invoked by login. -When the shell is interactive, this is equivalent to starting a -login shell with @samp{exec -l bash}. -When the shell is not interactive, the login shell startup files will -be executed. -@samp{exec bash -l} or @samp{exec bash --login} -will replace the current shell with a Bash login shell. -@xref{Bash Startup Files}, for a description of the special behavior -of a login shell. - -@item -r -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item -s -If this option is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. - -@item -D -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput. -These are the strings that -are subject to language translation when the current locale -is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). -This implies the @option{-n} option; no commands will be executed. - -@item [-+]O [@var{shopt_option}] -@var{shopt_option} is one of the shell options accepted by the -@code{shopt} builtin (@pxref{Shell Builtin Commands}). -If @var{shopt_option} is present, @option{-O} sets the value of that option; -@option{+O} unsets it. -If @var{shopt_option} is not supplied, the names and values of the shell -options accepted by @code{shopt} are printed on the standard output. -If the invocation option is @option{+O}, the output is displayed in a format -that may be reused as input. - -@item -- -A @code{--} signals the end of options and disables further option -processing. -Any arguments after the @code{--} are treated as filenames and arguments. - -@end table - -@cindex login shell -A @emph{login} shell is one whose first character of argument zero is -@samp{-}, or one invoked with the @option{--login} option. - -@cindex interactive shell -An @emph{interactive} shell is one started without non-option arguments, -unless @option{-s} is specified, -without specifying the @option{-c} option, and whose input and output are both -connected to terminals (as determined by @code{isatty(3)}), or one -started with the @option{-i} option. @xref{Interactive Shells}, for more -information. - -If arguments remain after option processing, and neither the -@option{-c} nor the @option{-s} -option has been supplied, the first argument is assumed to -be the name of a file containing shell commands (@pxref{Shell Scripts}). -When Bash is invoked in this fashion, @code{$0} -is set to the name of the file, and the positional parameters -are set to the remaining arguments. -Bash reads and executes commands from this file, then exits. -Bash's exit status is the exit status of the last command executed -in the script. If no commands are executed, the exit status is 0. - -@node Bash Startup Files -@section Bash Startup Files -@cindex startup files - -This section describs how Bash executes its startup files. -If any of the files exist but cannot be read, Bash reports an error. -Tildes are expanded in file names as described above under -Tilde Expansion (@pxref{Tilde Expansion}). - -Interactive shells are described in @ref{Interactive Shells}. - -@subsubheading Invoked as an interactive login shell, or with @option{--login} - -When Bash is invoked as an interactive login shell, or as a -non-interactive shell with the @option{--login} option, it first reads and -executes commands from the file @file{/etc/profile}, if that file exists. -After reading that file, it looks for @file{~/.bash_profile}, -@file{~/.bash_login}, and @file{~/.profile}, in that order, and reads -and executes commands from the first one that exists and is readable. -The @option{--noprofile} option may be used when the shell is started to -inhibit this behavior. - -When a login shell exits, Bash reads and executes commands from -the file @file{~/.bash_logout}, if it exists. - -@subsubheading Invoked as an interactive non-login shell - -When an interactive shell that is not a login shell is started, Bash -reads and executes commands from @file{~/.bashrc}, if that file exists. -This may be inhibited by using the @option{--norc} option. -The @option{--rcfile @var{file}} option will force Bash to read and -execute commands from @var{file} instead of @file{~/.bashrc}. - -So, typically, your @file{~/.bash_profile} contains the line -@example -@code{if [ -f ~/.bashrc ]; then . ~/.bashrc; fi} -@end example -@noindent -after (or before) any login-specific initializations. - -@subsubheading Invoked non-interactively - -When Bash is started non-interactively, to run a shell script, -for example, it looks for the variable @env{BASH_ENV} in the environment, -expands its value if it appears there, and uses the expanded value as -the name of a file to read and execute. Bash behaves as if the -following command were executed: -@example -@code{if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi} -@end example -@noindent -but the value of the @env{PATH} variable is not used to search for the -file name. - -As noted above, if a non-interactive shell is invoked with the -@option{--login} option, Bash attempts to read and execute commands from the -login shell startup files. - -@subsubheading Invoked with name @code{sh} - -If Bash is invoked with the name @code{sh}, it tries to mimic the -startup behavior of historical versions of @code{sh} as closely as -possible, while conforming to the @sc{posix} standard as well. - -When invoked as an interactive login shell, or as a non-interactive -shell with the @option{--login} option, it first attempts to read -and execute commands from @file{/etc/profile} and @file{~/.profile}, in -that order. -The @option{--noprofile} option may be used to inhibit this behavior. -When invoked as an interactive shell with the name @code{sh}, Bash -looks for the variable @env{ENV}, expands its value if it is defined, -and uses the expanded value as the name of a file to read and execute. -Since a shell invoked as @code{sh} does not attempt to read and execute -commands from any other startup files, the @option{--rcfile} option has -no effect. -A non-interactive shell invoked with the name @code{sh} does not attempt -to read any other startup files. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after -the startup files are read. - -@subsubheading Invoked in @sc{posix} mode - -When Bash is started in @sc{posix} mode, as with the -@option{--posix} command line option, it follows the @sc{posix} standard -for startup files. -In this mode, interactive shells expand the @env{ENV} variable -and commands are read and executed from the file whose name is the -expanded value. -No other startup files are read. - -@subsubheading Invoked by remote shell daemon - -Bash attempts to determine when it is being run by the remote shell -daemon, usually @code{rshd}. If Bash determines it is being run by -rshd, it reads and executes commands from @file{~/.bashrc}, if that -file exists and is readable. -It will not do this if invoked as @code{sh}. -The @option{--norc} option may be used to inhibit this behavior, and the -@option{--rcfile} option may be used to force another file to be read, but -@code{rshd} does not generally invoke the shell with those options or -allow them to be specified. - -@subsubheading Invoked with unequal effective and real @sc{uid/gid}s - -If Bash is started with the effective user (group) id not equal to the -real user (group) id, and the @code{-p} option is not supplied, no startup -files are read, shell functions are not inherited from the environment, -the @env{SHELLOPTS} variable, if it appears in the environment, is ignored, -and the effective user id is set to the real user id. -If the @code{-p} option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. - -@node Interactive Shells -@section Interactive Shells -@cindex interactive shell -@cindex shell, interactive - -@menu -* What is an Interactive Shell?:: What determines whether a shell is Interactive. -* Is this Shell Interactive?:: How to tell if a shell is interactive. -* Interactive Shell Behavior:: What changes in a interactive shell? -@end menu - -@node What is an Interactive Shell? -@subsection What is an Interactive Shell? - -An interactive shell -is one started without non-option arguments, unless @option{-s} is -specified, without specifiying the @option{-c} option, and -whose input and output are both -connected to terminals (as determined by @code{isatty(3)}), -or one started with the @option{-i} option. - -An interactive shell generally reads from and writes to a user's -terminal. - -The @option{-s} invocation option may be used to set the positional parameters -when an interactive shell is started. - -@node Is this Shell Interactive? -@subsection Is this Shell Interactive? - -To determine within a startup script whether or not Bash is -running interactively, -test the value of the @samp{-} special parameter. -It contains @code{i} when the shell is interactive. For example: - -@example -case "$-" in -*i*) echo This shell is interactive ;; -*) echo This shell is not interactive ;; -esac -@end example - -Alternatively, startup scripts may examine the variable -@env{PS1}; it is unset in non-interactive shells, and set in -interactive shells. Thus: - -@example -if [ -z "$PS1" ]; then - echo This shell is not interactive -else - echo This shell is interactive -fi -@end example - -@node Interactive Shell Behavior -@subsection Interactive Shell Behavior - -When the shell is running interactively, it changes its behavior in -several ways. - -@enumerate -@item -Startup files are read and executed as described in @ref{Bash Startup Files}. - -@item -Job Control (@pxref{Job Control}) is enabled by default. When job -control is in effect, Bash ignores the keyboard-generated job control -signals @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -@item -Bash expands and displays @env{PS1} before reading the first line -of a command, and expands and displays @env{PS2} before reading the -second and subsequent lines of a multi-line command. - -@item -Bash executes the value of the @env{PROMPT_COMMAND} variable as a command -before printing the primary prompt, @env{$PS1} -(@pxref{Bash Variables}). - -@item -Readline (@pxref{Command Line Editing}) is used to read commands from -the user's terminal. - -@item -Bash inspects the value of the @code{ignoreeof} option to @code{set -o} -instead of exiting immediately when it receives an @code{EOF} on its -standard input when reading a command (@pxref{The Set Builtin}). - -@item -Command history (@pxref{Bash History Facilities}) -and history expansion (@pxref{History Interaction}) -are enabled by default. -Bash will save the command history to the file named by @env{$HISTFILE} -when an interactive shell exits. - -@item -Alias expansion (@pxref{Aliases}) is performed by default. - -@item -In the absence of any traps, Bash ignores @code{SIGTERM} -(@pxref{Signals}). - -@item -In the absence of any traps, @code{SIGINT} is caught and handled -((@pxref{Signals}). -@code{SIGINT} will interrupt some shell builtins. - -@item -An interactive login shell sends a @code{SIGHUP} to all jobs on exit -if the @code{hupoxexit} shell option has been enabled (@pxref{Signals}). - -@item -The @option{-n} invocation option is ignored, and @samp{set -n} has -no effect (@pxref{The Set Builtin}). - -@item -Bash will check for mail periodically, depending on the values of the -@env{MAIL}, @env{MAILPATH}, and @env{MAILCHECK} shell variables -(@pxref{Bash Variables}). - -@item -Expansion errors due to references to unbound shell variables after -@samp{set -u} has been enabled will not cause the shell to exit -(@pxref{The Set Builtin}). - -@item -The shell will not exit on expansion errors caused by @var{var} being unset -or null in @code{$@{@var{var}:?@var{word}@}} expansions -(@pxref{Shell Parameter Expansion}). - -@item -Redirection errors encountered by shell builtins will not cause the -shell to exit. - -@item -When running in @sc{posix} mode, a special builtin returning an error -status will not cause the shell to exit (@pxref{Bash POSIX Mode}). -@item -A failed @code{exec} will not cause the shell to exit -(@pxref{Bourne Shell Builtins}). - -@item -Parser syntax errors will not cause the shell to exit. - -@item -Simple spelling correction for directory arguments to the @code{cd} -builtin is enabled by default (see the description of the @code{cdspell} -option to the @code{shopt} builtin in @ref{Bash Builtins}). - -@item -The shell will check the value of the @env{TMOUT} variable and exit -if a command is not read within the specified number of seconds after -printing @env{$PS1} (@pxref{Bash Variables}). - -@end enumerate - -@node Bash Conditional Expressions -@section Bash Conditional Expressions -@cindex expressions, conditional - -Conditional expressions are used by the @code{[[} compound command -and the @code{test} and @code{[} builtin commands. - -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. -If the @var{file} argument to one of the primaries is of the form -@file{/dev/fd/@var{N}}, then file descriptor @var{N} is checked. -If the @var{file} argument to one of the primaries is one of -@file{/dev/stdin}, @file{/dev/stdout}, or @file{/dev/stderr}, file -descriptor 0, 1, or 2, respectively, is checked. - -@table @code -@item -a @var{file} -True if @var{file} exists. - -@item -b @var{file} -True if @var{file} exists and is a block special file. - -@item -c @var{file} -True if @var{file} exists and is a character special file. - -@item -d @var{file} -True if @var{file} exists and is a directory. - -@item -e @var{file} -True if @var{file} exists. - -@item -f @var{file} -True if @var{file} exists and is a regular file. - -@item -g @var{file} -True if @var{file} exists and its set-group-id bit is set. - -@item -h @var{file} -True if @var{file} exists and is a symbolic link. - -@item -k @var{file} -True if @var{file} exists and its "sticky" bit is set. - -@item -p @var{file} -True if @var{file} exists and is a named pipe (FIFO). - -@item -r @var{file} -True if @var{file} exists and is readable. - -@item -s @var{file} -True if @var{file} exists and has a size greater than zero. - -@item -t @var{fd} -True if file descriptor @var{fd} is open and refers to a terminal. - -@item -u @var{file} -True if @var{file} exists and its set-user-id bit is set. - -@item -w @var{file} -True if @var{file} exists and is writable. - -@item -x @var{file} -True if @var{file} exists and is executable. - -@item -O @var{file} -True if @var{file} exists and is owned by the effective user id. - -@item -G @var{file} -True if @var{file} exists and is owned by the effective group id. - -@item -L @var{file} -True if @var{file} exists and is a symbolic link. - -@item -S @var{file} -True if @var{file} exists and is a socket. - -@item -N @var{file} -True if @var{file} exists and has been modified since it was last read. - -@item @var{file1} -nt @var{file2} -True if @var{file1} is newer (according to modification date) -than @var{file2}, or if @var{file1} exists and @var{file2} does not. - -@item @var{file1} -ot @var{file2} -True if @var{file1} is older than @var{file2}, -or if @var{file2} exists and @var{file1} does not. - -@item @var{file1} -ef @var{file2} -True if @var{file1} and @var{file2} refer to the same device and -inode numbers. - -@item -o @var{optname} -True if shell option @var{optname} is enabled. -The list of options appears in the description of the @option{-o} -option to the @code{set} builtin (@pxref{The Set Builtin}). - -@item -z @var{string} -True if the length of @var{string} is zero. - -@item -n @var{string} -@itemx @var{string} -True if the length of @var{string} is non-zero. - -@item @var{string1} == @var{string2} -True if the strings are equal. -@samp{=} may be used in place of @samp{==} for strict @sc{posix} compliance. - -@item @var{string1} != @var{string2} -True if the strings are not equal. - -@item @var{string1} < @var{string2} -True if @var{string1} sorts before @var{string2} lexicographically -in the current locale. - -@item @var{string1} > @var{string2} -True if @var{string1} sorts after @var{string2} lexicographically -in the current locale. - -@item @var{arg1} OP @var{arg2} -@code{OP} is one of -@samp{-eq}, @samp{-ne}, @samp{-lt}, @samp{-le}, @samp{-gt}, or @samp{-ge}. -These arithmetic binary operators return true if @var{arg1} -is equal to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to @var{arg2}, -respectively. @var{Arg1} and @var{arg2} -may be positive or negative integers. - -@end table - -@node Shell Arithmetic -@section Shell Arithmetic -@cindex arithmetic, shell -@cindex shell arithmetic -@cindex expressions, arithmetic -@cindex evaluation, arithmetic -@cindex arithmetic evaluation - -The shell allows arithmetic expressions to be evaluated, as one of -the shell expansions or by the @code{let} and the @option{-i} option -to the @code{declare} builtins. - -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -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 @var{id}++ @var{id}-- -variable post-increment and post-decrement - -@item ++@var{id} --@var{id} -variable pre-increment and pre-decrement - -@item - + -unary minus and plus - -@item ! ~ -logical and bitwise negation - -@item ** -exponentiation - -@item * / % -multiplication, division, remainder - -@item + - -addition, subtraction - -@item << >> -left and right bitwise shifts - -@item <= >= < > -comparison - -@item == != -equality and inequality - -@item & -bitwise AND - -@item ^ -bitwise exclusive OR - -@item | -bitwise OR - -@item && -logical AND - -@item || -logical OR - -@item expr ? expr : expr -conditional operator - -@item = *= /= %= += -= <<= >>= &= ^= |= -assignment - -@item expr1 , expr2 -comma -@end table - -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -@var{integer} attribute using @samp{declare -i} is assigned a value. -A null value evaluates to 0. -A shell variable need not have its integer attribute turned on -to be used in an expression. - -Constants with a leading 0 are interpreted as octal numbers. -A leading @samp{0x} or @samp{0X} denotes hexadecimal. Otherwise, -numbers take the form [@var{base}@code{#}]@var{n}, where @var{base} -is a decimal number between 2 and 64 representing the arithmetic -base, and @var{n} is a number in that base. If @var{base}@code{#} is -omitted, then base 10 is used. -The digits greater than 9 are represented by the lowercase letters, -the uppercase letters, @samp{@@}, and @samp{_}, in that order. -If @var{base} is less than or equal to 36, lowercase and uppercase -letters may be used interchangably to represent numbers between 10 -and 35. - -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. - -@node Aliases -@section Aliases -@cindex alias expansion - -@var{Aliases} allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of aliases that may be set and unset with -the @code{alias} and @code{unalias} builtin commands. - -The first word of each simple 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 @samp{=}. -The first word of the replacement text is tested for -aliases, but a word that is identical to an alias being expanded -is not expanded a second time. This means that one may alias -@code{ls} to @code{"ls -F"}, -for instance, and Bash does not try to recursively expand the -replacement text. If the last character of the alias value is a -space or tab character, then the next command word following the -alias is also checked for alias expansion. - -Aliases are created and listed with the @code{alias} -command, and removed with the @code{unalias} command. - -There is no mechanism for using arguments in the replacement text, -as in @code{csh}. -If arguments are needed, a shell function should be used -(@pxref{Shell Functions}). - -Aliases are not expanded when the shell is not interactive, -unless the @code{expand_aliases} shell option is set using -@code{shopt} (@pxref{Bash Builtins}). - -The rules concerning the definition and use of aliases are -somewhat confusing. Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -The commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when a 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. - -For almost every purpose, shell functions are preferred over aliases. - -@node Arrays -@section Arrays -@cindex arrays - -Bash provides one-dimensional array variables. Any variable may be used as -an array; the @code{declare} builtin will explicitly declare an array. -There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. Arrays are zero-based. - -An array is created automatically if any variable is assigned to using -the syntax -@example -name[@var{subscript}]=@var{value} -@end example - -@noindent -The @var{subscript} -is treated as an arithmetic expression that must evaluate to a number -greater than or equal to zero. To explicitly declare an array, use -@example -declare -a @var{name} -@end example -@noindent -The syntax -@example -declare -a @var{name}[@var{subscript}] -@end example -@noindent -is also accepted; the @var{subscript} is ignored. Attributes may be -specified for an array variable using the @code{declare} and -@code{readonly} builtins. Each attribute applies to all members of -an array. - -Arrays are assigned to using compound assignments of the form -@example -name=(value@var{1} @dots{} value@var{n}) -@end example -@noindent -where each -@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}. If -the optional subscript is supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. -This syntax is also accepted by the @code{declare} -builtin. Individual array elements may be assigned to using the -@code{name[}@var{subscript}@code{]=}@var{value} syntax introduced above. - -Any element of an array may be referenced using -@code{$@{name[}@var{subscript}@code{]@}}. -The braces are required to avoid -conflicts with the shell's filename expansion operators. If the -@var{subscript} is @samp{@@} or @samp{*}, the word expands to all members -of the array @var{name}. These subscripts differ only when the word -appears within double quotes. If the word is double-quoted, -@code{$@{name[*]@}} expands to a single word with -the value of each array member separated by the first character of the -@env{IFS} variable, and @code{$@{name[@@]@}} expands each element of -@var{name} to a separate word. When there are no array members, -@code{$@{name[@@]@}} expands to nothing. This is analogous to the -expansion of the special parameters @samp{@@} and @samp{*}. -@code{$@{#name[}@var{subscript}@code{]@}} expands to the length of -@code{$@{name[}@var{subscript}@code{]@}}. -If @var{subscript} is @samp{@@} or -@samp{*}, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing element zero. - -The @code{unset} builtin is used to destroy arrays. -@code{unset} @var{name}[@var{subscript}] -destroys the array element at index @var{subscript}. -@code{unset} @var{name}, where @var{name} is an array, removes the -entire array. A subscript of @samp{*} or @samp{@@} also removes the -entire array. - -The @code{declare}, @code{local}, and @code{readonly} -builtins each accept a @option{-a} -option to specify an array. The @code{read} -builtin accepts a @option{-a} -option to assign a list of words read from the standard input -to an array, and can read values from the standard input into -individual array elements. The @code{set} and @code{declare} -builtins display array values in a way that allows them to be -reused as input. - -@node The Directory Stack -@section The Directory Stack -@cindex directory stack - -@menu -* Directory Stack Builtins:: Bash builtin commands to manipulate - the directory stack. -@end menu - -The directory stack is a list of recently-visited directories. The -@code{pushd} builtin adds directories to the stack as it changes -the current directory, and the @code{popd} builtin removes specified -directories from the stack and changes the current directory to -the directory removed. The @code{dirs} builtin displays the contents -of the directory stack. - -The contents of the directory stack are also visible -as the value of the @env{DIRSTACK} shell variable. - -@node Directory Stack Builtins -@subsection Directory Stack Builtins - -@table @code - -@item dirs -@btindex dirs -@example -dirs [+@var{N} | -@var{N}] [-clpv] -@end example -Display the list of currently remembered directories. Directories -are added to the list with the @code{pushd} command; the -@code{popd} command removes directories from the list. -@table @code -@item +@var{N} -Displays the @var{N}th directory (counting from the left of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{N} -Displays the @var{N}th directory (counting from the right of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -c -Clears the directory stack by deleting all of the elements. -@item -l -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -@item -p -Causes @code{dirs} to print the directory stack with one entry per -line. -@item -v -Causes @code{dirs} to print the directory stack with one entry per -line, prefixing each entry with its index in the stack. -@end table - -@item popd -@btindex popd -@example -popd [+@var{N} | -@var{N}] [-n] -@end example - -Remove the top entry from the directory stack, and @code{cd} -to the new top directory. -When no arguments are given, @code{popd} -removes the top directory from the stack and -performs a @code{cd} to the new top directory. The -elements are numbered from 0 starting at the first directory listed with -@code{dirs}; i.e., @code{popd} is equivalent to @code{popd +0}. -@table @code -@item +@var{N} -Removes the @var{N}th directory (counting from the left of the -list printed by @code{dirs}), starting with zero. -@item -@var{N} -Removes the @var{N}th directory (counting from the right of the -list printed by @code{dirs}), starting with zero. -@item -n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -@end table - -@btindex pushd -@item pushd -@example -pushd [@var{dir} | @var{+N} | @var{-N}] [-n] -@end example - -Save the current directory on the top of the directory stack -and then @code{cd} to @var{dir}. -With no arguments, @code{pushd} 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}, starting with zero) 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}, starting with zero) to the top of -the list by rotating the stack. -@item -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@item @var{dir} -Makes the current working directory be the top of the stack, and then -executes the equivalent of `@code{cd} @var{dir}'. -@code{cd}s to @var{dir}. -@end table - -@end table - -@node Printing a Prompt -@section Controlling the Prompt -@cindex prompting - -The value of the variable @env{PROMPT_COMMAND} is examined just before -Bash prints each primary prompt. If @env{PROMPT_COMMAND} is set and -has a non-null value, then the -value is executed just as if it had been typed on the command line. - -In addition, the following table describes the special characters which -can appear in the prompt variables: - -@table @code -@item \a -A bell character. -@item \d -The date, in "Weekday Month Date" format (e.g., "Tue May 26"). -@item \D@{@var{format}@} -The @var{format} is passed to @code{strftime}(3) and the result is inserted -into the prompt string; an empty @var{format} results in a locale-specific -time representation. The braces are required. -@item \e -An escape character. -@item \h -The hostname, up to the first `.'. -@item \H -The hostname. -@item \j -The number of jobs currently managed by the shell. -@item \l -The basename of the shell's terminal device name. -@item \n -A newline. -@item \r -A carriage return. -@item \s -The name of the shell, the basename of @code{$0} (the portion -following the final slash). -@item \t -The time, in 24-hour HH:MM:SS format. -@item \T -The time, in 12-hour HH:MM:SS format. -@item \@@ -The time, in 12-hour am/pm format. -@item \A -The time, in 24-hour HH:MM format. -@item \u -The username of the current user. -@item \v -The version of Bash (e.g., 2.00) -@item \V -The release of Bash, version + patchlevel (e.g., 2.00.0) -@item \w -The current working directory. -@item \W -The basename of @env{$PWD}. -@item \! -The history number of this command. -@item \# -The command number of this command. -@item \$ -If the effective uid is 0, @code{#}, otherwise @code{$}. -@item \@var{nnn} -The character whose ASCII code is the octal value @var{nnn}. -@item \\ -A backslash. -@item \[ -Begin a sequence of non-printing characters. This could be used to -embed a terminal control sequence into the prompt. -@item \] -End a sequence of non-printing characters. -@end table - -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 -(@pxref{Bash History Facilities}), 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 quote removal, subject to the value of the -@code{promptvars} shell option (@pxref{Bash Builtins}). - -@node The Restricted Shell -@section The Restricted Shell -@cindex restricted shell - -If Bash is started with the name @code{rbash}, or the -@option{--restricted} -or -@option{-r} -option is supplied at invocation, the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -A restricted shell behaves identically to @code{bash} -with the exception that the following are disallowed or not performed: - -@itemize @bullet -@item -Changing directories with the @code{cd} builtin. -@item -Setting or unsetting the values of the @env{SHELL}, @env{PATH}, -@env{ENV}, or @env{BASH_ENV} variables. -@item -Specifying command names containing slashes. -@item -Specifying a filename containing a slash as an argument to the @code{.} -builtin command. -@item -Specifying a filename containing a slash as an argument to the @option{-p} -option to the @code{hash} builtin command. -@item -Importing function definitions from the shell environment at startup. -@item -Parsing the value of @env{SHELLOPTS} from the shell environment at startup. -@item -Redirecting output using the @samp{>}, @samp{>|}, @samp{<>}, @samp{>&}, -@samp{&>}, and @samp{>>} redirection operators. -@item -Using the @code{exec} builtin to replace the shell with another command. -@item -Adding or deleting builtin commands with the -@option{-f} and @option{-d} options to the @code{enable} builtin. -@item -Using the @code{enable} builtin command to enable disabled shell builtins. -@item -Specifying the @option{-p} option to the @code{command} builtin. -@item -Turning off restricted mode with @samp{set +r} or @samp{set +o restricted}. -@end itemize - -These restrictions are enforced after any startup files are read. - -When a command that is found to be a shell script is executed -(@pxref{Shell Scripts}), @code{rbash} turns off any restrictions in -the shell spawned to execute the script. - -@node Bash POSIX Mode -@section Bash POSIX Mode -@cindex POSIX Mode - -Starting Bash with the @option{--posix} command-line option or executing -@samp{set -o posix} while Bash is running will cause Bash to conform more -closely to the @sc{posix} 1003.2 standard by changing the behavior to -match that specified by @sc{posix} in areas where the Bash default differs. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after reading the -startup files. - -The following list is what's changed when `@sc{posix} mode' is in effect: - -@enumerate -@item -When a command in the hash table no longer exists, Bash will re-search -@env{$PATH} to find the new location. This is also available with -@samp{shopt -s checkhash}. - -@item -The message printed by the job control code and builtins when a job -exits with a non-zero status is `Done(status)'. - -@item -The message printed by the job control code and builtins when a job -is stopped is `Stopped(@var{signame})', where @var{signame} is, for -example, @code{SIGTSTP}. - -@item -Reserved words may not be aliased. - -@item -The @sc{posix} 1003.2 @env{PS1} and @env{PS2} expansions of @samp{!} to -the history number and @samp{!!} to @samp{!} are enabled, -and parameter expansion is performed on the values of @env{PS1} and -@env{PS2} regardless of the setting of the @code{promptvars} option. - -@item -Interactive comments are enabled by default. (Bash has them on by -default anyway.) - -@item -The @sc{posix} 1003.2 startup files are executed (@env{$ENV}) rather than -the normal Bash files. - -@item -Tilde expansion is only performed on assignments preceding a command -name, rather than on all assignment statements on the line. - -@item -The default history file is @file{~/.sh_history} (this is the -default value of @env{$HISTFILE}). - -@item -The output of @samp{kill -l} prints all the signal names on a single line, -separated by spaces. - -@item -Non-interactive shells exit if @var{filename} in @code{.} @var{filename} -is not found. - -@item -Non-interactive shells exit if a syntax error in an arithmetic expansion -results in an invalid expression. - -@item -Redirection operators do not perform filename expansion on the word -in the redirection unless the shell is interactive. - -@item -Redirection operators do not perform word splitting on the word in the -redirection. - -@item -Function names must be valid shell @code{name}s. That is, they may not -contain characters other than letters, digits, and underscores, and -may not start with a digit. Declaring a function with an invalid name -causes a fatal syntax error in non-interactive shells. - -@item -@sc{posix} 1003.2 `special' builtins are found before shell functions -during command lookup. - -@item -If a @sc{posix} 1003.2 special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the POSIX.2 standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@item -If the @code{cd} builtin finds a directory to change to -using @env{$CDPATH}, the -value it assigns to the @env{PWD} variable does not contain any -symbolic links, as if @samp{cd -P} had been executed. - -@item -If @env{CDPATH} is set, the @code{cd} builtin will not implicitly -append the current directory to it. This means that @code{cd} will -fail if no valid directory name can be constructed from -any of the entries in @env{$CDPATH}, even if the a directory with -the same name as the name given as an argument to @code{cd} exists -in the current directory. - -@item -A non-interactive shell exits with an error status if a variable -assignment error occurs when no command name follows the assignment -statements. -A variable assignment error occurs, for example, when trying to assign -a value to a readonly variable. - -@item -A non-interactive shell exits with an error status if the iteration -variable in a @code{for} statement or the selection variable in a -@code{select} statement is a readonly variable. - -@item -Process substitution is not available. - -@item -Assignment statements preceding @sc{posix} 1003.2 special builtins -persist in the shell environment after the builtin completes. - -@item -Assignment statements preceding shell function calls persist in the -shell environment after the function returns, as if a @sc{posix} -special builtin command had been executed. - -@item -The @code{export} and @code{readonly} builtin commands display their -output in the format required by @sc{posix} 1003.2. - -@item -The @code{trap} builtin displays signal names without the leading -@code{SIG}. - -@item -The @code{.} and @code{source} builtins do not search the current directory -for the filename argument if it is not found by searching @env{PATH}. - -@item -Subshells spawned to execute command substitutions inherit the value of -the @option{-e} option from the parent shell. When not in @sc{posix} mode, -Bash clears the @option{-e} option in such subshells. - -@item -Alias expansion is always enabled, even in non-interactive shells. - -@item -When the @code{set} builtin is invoked without options, it does not display -shell function names and definitions. - -@item -When the @code{set} builtin is invoked without options, it displays -variable values without quotes, unless they contain shell metacharacters, -even if the result contains nonprinting characters. - -@item -When the @code{cd} builtin is invoked in @var{logical} mode, and the pathname -constructed from @code{$PWD} and the directory name supplied as an argument -does not refer to an existing directory, @code{cd} will fail instead of -falling back to @var{physical} mode. -@end enumerate - -There is other @sc{posix} 1003.2 behavior that Bash does not implement. -Specifically: - -@enumerate -@item -Assignment statements affect the execution environment of all -builtins, not just special ones. - -@item -When a subshell is created to execute a shell script with execute permission, -but without a leading @samp{#!}, Bash sets @code{$0} to the full pathname of -the script as found by searching @code{$PATH}, rather than the command as -typed by the user. - -@item -When using @samp{.} to source a shell script found in @code{$PATH}, bash -checks execute permission bits rather than read permission bits, just as -if it were searching for a command. - -@end enumerate - -@node Job Control -@chapter Job Control - -This chapter discusses what job control is, how it works, and how -Bash allows you to access its facilities. - -@menu -* Job Control Basics:: How job control works. -* Job Control Builtins:: Bash builtin commands used to interact - with job control. -* Job Control Variables:: Variables Bash uses to customize job - control. -@end menu - -@node Job Control Basics -@section Job Control Basics -@cindex job control -@cindex foreground -@cindex background -@cindex suspending jobs - -Job control -refers to the ability to selectively stop (suspend) -the execution of processes and continue (resume) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the system's terminal driver and Bash. - -The shell associates a @var{job} with each pipeline. It keeps a -table of currently executing jobs, which may be listed with the -@code{jobs} command. When Bash starts a job -asynchronously, it prints a line that looks -like: -@example -[1] 25647 -@end example -@noindent -indicating that this job is job number 1 and that the process @sc{id} -of the last process in the pipeline associated with this job is -25647. All of the processes in a single pipeline are members of -the same job. Bash uses the @var{job} abstraction as the -basis for job control. - -To facilitate the implementation of the user interface to job -control, the operating system maintains the notion of a current terminal -process group @sc{id}. Members of this process group (processes whose -process group @sc{id} is equal to the current terminal process group -@sc{id}) receive keyboard-generated signals such as @code{SIGINT}. -These processes are said to be in the foreground. Background -processes are those whose process group @sc{id} differs from the -terminal's; such processes are immune to keyboard-generated -signals. Only foreground processes are allowed to read from or -write to the terminal. Background processes which attempt to -read from (write to) the terminal are sent a @code{SIGTTIN} -(@code{SIGTTOU}) signal by the terminal driver, which, unless -caught, suspends the process. - -If the operating system on which Bash is running supports -job control, Bash contains facilities 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 -control 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. The user then manipulates 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}. -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 or started -in the background. 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{-}. - -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. - -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 @option{-b} option to the @code{set} builtin is enabled, -Bash reports such changes immediately (@pxref{The Set Builtin}). -Any trap on @code{SIGCHLD} is executed for each child process -that exits. - -If an attempt to exit Bash is while jobs are stopped, the -shell prints a message warning that there are stopped jobs. -The @code{jobs} command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -Bash does not print another warning, and the stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@table @code - -@item bg -@btindex bg -@example -bg [@var{jobspec}] -@end example -Resume the suspended job @var{jobspec} in the background, as if it -had been started with @samp{&}. -If @var{jobspec} is not supplied, the current job is used. -The return status is zero unless it is run when job control is not -enabled, or, when run with job control enabled, if @var{jobspec} was -not found or @var{jobspec} specifies a job that was started without -job control. - -@item fg -@btindex fg -@example -fg [@var{jobspec}] -@end example -Resume the job @var{jobspec} in the foreground and make it the current job. -If @var{jobspec} is not supplied, the current job is used. -The return status is that of the command placed into the foreground, -or non-zero if run when job control is disabled or, when run with -job control enabled, @var{jobspec} does not specify a valid job or -@var{jobspec} specifies a job that was started without job control. - -@item jobs -@btindex jobs -@example -jobs [-lnprs] [@var{jobspec}] -jobs -x @var{command} [@var{arguments}] -@end example - -The first form lists the active jobs. The options have the -following meanings: - -@table @code -@item -l -List process @sc{id}s in addition to the normal information. - -@item -n -Display information only about jobs that have changed status since -the user was last notified of their status. - -@item -p -List only the process @sc{id} of the job's process group leader. - -@item -r -Restrict output to running jobs. - -@item -s -Restrict output to stopped jobs. -@end table - -If @var{jobspec} is given, -output is restricted to information about that job. -If @var{jobspec} is not supplied, the status of all jobs is -listed. - -If the @option{-x} option is supplied, @code{jobs} replaces any -@var{jobspec} found in @var{command} or @var{arguments} with the -corresponding process group @sc{id}, and executes @var{command}, -passing it @var{argument}s, returning its exit status. - -@item kill -@btindex kill -@example -kill [-s @var{sigspec}] [-n @var{signum}] [-@var{sigspec}] @var{jobspec} or @var{pid} -kill -l [@var{exit_status}] -@end example -Send a signal specified by @var{sigspec} or @var{signum} to the process -named by job specification @var{jobspec} or process @sc{id} @var{pid}. -@var{sigspec} is either a signal name such as @code{SIGINT} (with or without -the @code{SIG} prefix) or a signal number; @var{signum} is a signal number. -If @var{sigspec} and @var{signum} are not present, @code{SIGTERM} is used. -The @option{-l} option lists the signal names. -If any arguments are supplied when @option{-l} is given, the names of the -signals corresponding to the arguments are listed, and the return status -is zero. -@var{exit_status} is a number specifying a signal number or the exit -status of a process terminated by a signal. -The return status is zero if at least one signal was successfully sent, -or non-zero if an error occurs or an invalid option is encountered. - -@item wait -@btindex wait -@example -wait [@var{jobspec} or @var{pid}] -@end example -Wait until the child process specified by process @sc{id} @var{pid} or job -specification @var{jobspec} exits and return the exit status of the last -command waited for. -If a job spec is given, all processes in the job are waited for. -If no arguments are given, all currently active child processes are -waited for, and the return status is zero. -If neither @var{jobspec} nor @var{pid} specifies an active child process -of the shell, the return status is 127. - -@item disown -@btindex disown -@example -disown [-ar] [-h] [@var{jobspec} @dots{}] -@end example -Without options, each @var{jobspec} is removed from the table of -active jobs. -If the @option{-h} option is given, the job is not removed from the table, -but is marked so that @code{SIGHUP} is not sent to the job if the shell -receives a @code{SIGHUP}. -If @var{jobspec} is not present, and neither the @option{-a} nor @option{-r} -option is supplied, the current job is used. -If no @var{jobspec} is supplied, the @option{-a} option means to remove or -mark all jobs; the @option{-r} option without a @var{jobspec} -argument restricts operation to running jobs. - -@item suspend -@btindex suspend -@example -suspend [-f] -@end example -Suspend the execution of this shell until it receives a -@code{SIGCONT} signal. The @option{-f} option means to suspend -even if the shell is a login shell. - -@end table - -When job control is not active, the @code{kill} and @code{wait} -builtins do not accept @var{jobspec} arguments. They must be -supplied process @sc{id}s. - -@node Job Control Variables -@section Job Control Variables - -@vtable @code - -@item auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable exists then single word simple -commands without redirections are treated as candidates for resumption -of an existing job. There is no ambiguity allowed; if there is -more than one job beginning with the string typed, then -the most recently accessed job will be selected. -The name of a stopped job, in this context, is the command line -used to start it. If this variable is set to the value @samp{exact}, -the string supplied must match the name of a stopped job exactly; -if set to @samp{substring}, -the string supplied needs to match a substring of the name of a -stopped job. The @samp{substring} value provides functionality -analogous to the @samp{%?} job @sc{id} (@pxref{Job Control Basics}). -If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the @samp{%} job @sc{id}. - -@end vtable - -@set readline-appendix -@set history-appendix -@cindex Readline, how to use -@include rluser.texi -@cindex History, how to use -@include hsuser.texi -@clear readline-appendix -@clear history-appendix - -@node Installing Bash -@chapter Installing Bash - -This chapter provides basic instructions for installing Bash on -the various supported platforms. The distribution supports the -@sc{gnu} operating systems, nearly every version of Unix, and several -non-Unix systems such as BeOS and Interix. -Other independent ports exist for -@sc{ms-dos}, @sc{os/2}, Windows @sc{95/98}, and Windows @sc{nt}. - -@menu -* Basic Installation:: Installation instructions. - -* Compilers and Options:: How to set special options for various - systems. - -* Compiling For Multiple Architectures:: How to compile Bash for more - than one kind of system from - the same source tree. - -* Installation Names:: How to set the various paths used by the installation. - -* Specifying the System Type:: How to configure Bash for a particular system. - -* Sharing Defaults:: How to share default configuration values among GNU - programs. - -* Operation Controls:: Options recognized by the configuration program. - -* Optional Features:: How to enable and disable optional features when - building Bash. -@end menu - -@node Basic Installation -@section Basic Installation -@cindex installation -@cindex configuration -@cindex Bash installation -@cindex Bash configuration - -These are installation instructions for Bash. - -The simplest way to compile Bash is: - -@enumerate -@item -@code{cd} to the directory containing the source code and type -@samp{./configure} to configure Bash for your system. If you're -using @code{csh} on an old version of System V, you might need to -type @samp{sh ./configure} instead to prevent @code{csh} from trying -to execute @code{configure} itself. - -Running @code{configure} takes some time. -While running, it prints messages telling which features it is -checking for. - -@item -Type @samp{make} to compile Bash and build the @code{bashbug} bug -reporting script. - -@item -Optionally, type @samp{make tests} to run the Bash test suite. - -@item -Type @samp{make install} to install @code{bash} and @code{bashbug}. -This will also install the manual pages and Info file. - -@end enumerate - -The @code{configure} shell script attempts to guess correct -values for various system-dependent variables used during -compilation. It uses those values to create a @file{Makefile} in -each directory of the package (the top directory, the -@file{builtins}, @file{doc}, and @file{support} directories, -each directory under @file{lib}, and several others). It also creates a -@file{config.h} file containing system-dependent definitions. -Finally, it creates a shell script named @code{config.status} that you -can run in the future to recreate the current configuration, a -file @file{config.cache} that saves the results of its tests to -speed up reconfiguring, and a file @file{config.log} containing -compiler output (useful mainly for debugging @code{configure}). -If at some point -@file{config.cache} contains results you don't want to keep, you -may remove or edit it. - -To find out more about the options and arguments that the -@code{configure} script understands, type - -@example -bash-2.04$ ./configure --help -@end example - -@noindent -at the Bash prompt in your Bash source directory. - -If you need to do unusual things to compile Bash, please -try to figure out how @code{configure} could check whether or not -to do them, and mail diffs or instructions to -@email{bash-maintainers@@gnu.org} so they can be -considered for the next release. - -The file @file{configure.in} is used to create @code{configure} -by a program called Autoconf. You only need -@file{configure.in} if you want to change it or regenerate -@code{configure} using a newer version of Autoconf. If -you do this, make sure you are using Autoconf version 2.50 or -newer. - -You can remove the program binaries and object files from the -source code directory by typing @samp{make clean}. To also remove the -files that @code{configure} created (so you can compile Bash for -a different kind of computer), type @samp{make distclean}. - -@node Compilers and Options -@section Compilers and Options - -Some systems require unusual options for compilation or linking -that the @code{configure} script does not know about. You can -give @code{configure} initial values for variables by setting -them in the environment. Using a Bourne-compatible shell, you -can do that on the command line like this: - -@example -CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure -@end example - -On systems that have the @code{env} program, you can do it like this: - -@example -env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure -@end example - -The configuration process uses GCC to build Bash if it -is available. - -@node Compiling For Multiple Architectures -@section Compiling For Multiple Architectures - -You can compile Bash for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of @code{make} that -supports the @code{VPATH} variable, such as GNU @code{make}. -@code{cd} to the -directory where you want the object files and executables to go and run -the @code{configure} script from the source directory. You may need to -supply the @option{--srcdir=PATH} argument to tell @code{configure} where the -source files are. @code{configure} automatically checks for the -source code in the directory that @code{configure} is in and in `..'. - -If you have to use a @code{make} that does not supports the @code{VPATH} -variable, you can compile Bash for one architecture at a -time in the source code directory. After you have installed -Bash for one architecture, use @samp{make distclean} before -reconfiguring for another architecture. - -Alternatively, if your system supports symbolic links, you can use the -@file{support/mkclone} script to create a build tree which has -symbolic links back to each file in the source directory. Here's an -example that creates a build directory in the current directory from a -source directory @file{/usr/gnu/src/bash-2.0}: - -@example -bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . -@end example - -@noindent -The @code{mkclone} script requires Bash, so you must have already built -Bash for at least one architecture before you can create build -directories for other architectures. - -@node Installation Names -@section Installation Names - -By default, @samp{make install} will install into -@file{/usr/local/bin}, @file{/usr/local/man}, etc. You can -specify an installation prefix other than @file{/usr/local} by -giving @code{configure} the option @option{--prefix=@var{PATH}}, -or by specifying a value for the @code{DESTDIR} @samp{make} -variable when running @samp{make install}. - -You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. -If you give @code{configure} the option -@option{--exec-prefix=@var{PATH}}, @samp{make install} will use -@var{PATH} as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - -@node Specifying the System Type -@section Specifying the System Type - -There may be some features @code{configure} can not figure out -automatically, but need to determine by the type of host Bash -will run on. Usually @code{configure} can figure that -out, but if it prints a message saying it can not guess the host -type, give it the @option{--host=TYPE} option. @samp{TYPE} can -either be a short name for the system type, such as @samp{sun4}, -or a canonical name with three fields: @samp{CPU-COMPANY-SYSTEM} -(e.g., @samp{i386-unknown-freebsd4.2}). - -See the file @file{support/config.sub} for the possible -values of each field. - -@node Sharing Defaults -@section Sharing Defaults - -If you want to set default values for @code{configure} scripts to -share, you can create a site shell script called -@code{config.site} that gives default values for variables like -@code{CC}, @code{cache_file}, and @code{prefix}. @code{configure} -looks for @file{PREFIX/share/config.site} if it exists, then -@file{PREFIX/etc/config.site} if it exists. Or, you can set the -@code{CONFIG_SITE} environment variable to the location of the site -script. A warning: the Bash @code{configure} looks for a site script, -but not all @code{configure} scripts do. - -@node Operation Controls -@section Operation Controls - -@code{configure} recognizes the following options to control how it -operates. - -@table @code - -@item --cache-file=@var{file} -Use and save the results of the tests in -@var{file} instead of @file{./config.cache}. Set @var{file} to -@file{/dev/null} to disable caching, for debugging -@code{configure}. - -@item --help -Print a summary of the options to @code{configure}, and exit. - -@item --quiet -@itemx --silent -@itemx -q -Do not print messages saying which checks are being made. - -@item --srcdir=@var{dir} -Look for the Bash source code in directory @var{dir}. Usually -@code{configure} can determine that directory automatically. - -@item --version -Print the version of Autoconf used to generate the @code{configure} -script, and exit. -@end table - -@code{configure} also accepts some other, not widely used, boilerplate -options. @samp{configure --help} prints the complete list. - -@node Optional Features -@section Optional Features - -The Bash @code{configure} has a number of @option{--enable-@var{feature}} -options, where @var{feature} indicates an optional part of Bash. -There are also several @option{--with-@var{package}} options, -where @var{package} is something like @samp{bash-malloc} or @samp{purify}. -To turn off the default use of a package, use -@option{--without-@var{package}}. To configure Bash without a feature -that is enabled by default, use @option{--disable-@var{feature}}. - -Here is a complete list of the @option{--enable-} and -@option{--with-} options that the Bash @code{configure} recognizes. - -@table @code -@item --with-afs -Define if you are using the Andrew File System from Transarc. - -@item --with-bash-malloc -Use the Bash version of -@code{malloc} in @file{lib/malloc/malloc.c}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -derived from the 4.2 @sc{bsd} @code{malloc}. This @code{malloc} is -very fast, but wastes some space on each allocation. -This option is enabled by default. -The @file{NOTES} file contains a list of systems for -which this should be turned off, and @code{configure} disables this -option automatically for a number of systems. - -@item --with-curses -Use the curses library instead of the termcap library. This should -be supplied if your system has an inadequate or incomplete termcap -database. - -@item --with-gnu-malloc -A synonym for @code{--with-bash-malloc}. - -@item --with-installed-readline[=@var{PREFIX}] -Define this to make Bash link with a locally-installed version of Readline -rather than the version in @file{lib/readline}. This works only with -Readline 4.3 and later versions. If @var{PREFIX} is @code{yes} or not -supplied, @code{configure} uses the values of the make variables -@code{includedir} and @code{libdir}, which are subdirectories of @code{prefix} -by default, to find the installed version of Readline if it is not in -the standard system include and library directories. -If @var{PREFIX} is @code{no}, Bash links with the version in -@file{lib/readline}. -If @var{PREFIX} is set to any other value, @code{configure} treats it as -a directory pathname and looks for -the installed version of Readline in subdirectories of that directory -(include files in @var{PREFIX}/@code{include} and the library in -@var{PREFIX}/@code{lib}). - -@item --with-purify -Define this to use the Purify memory allocation checker from Rational -Software. - -@item --enable-minimal-config -This produces a shell with minimal features, close to the historical -Bourne shell. -@end table - -There are several @option{--enable-} options that alter how Bash is -compiled and linked, rather than changing run-time features. - -@table @code -@item --enable-largefile -Enable support for @uref{http://www.sas.com/standards/large_file/x_open.20Mar96.html, -large files} if the operating system requires special compiler options -to build programs which can access large files. This is enabled by -default, if the operating system provides large file support. - -@item --enable-profiling -This builds a Bash binary that produces profiling information to be -processed by @code{gprof} each time it is executed. - -@item --enable-static-link -This causes Bash to be linked statically, if @code{gcc} is being used. -This could be used to build a version to use as root's shell. -@end table - -The @samp{minimal-config} option can be used to disable all of -the following options, but it is processed first, so individual -options may be enabled using @samp{enable-@var{feature}}. - -All of the following options except for @samp{disabled-builtins} and -@samp{xpg-echo-default} are -enabled by default, unless the operating system does not provide the -necessary support. - -@table @code -@item --enable-alias -Allow alias expansion and include the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item --enable-arith-for-command -Include support for the alternate form of the @code{for} command -that behaves like the C language @code{for} statement -(@pxref{Looping Constructs}). - -@item --enable-array-variables -Include support for one-dimensional array shell variables -(@pxref{Arrays}). - -@item --enable-bang-history -Include support for @code{csh}-like history substitution -(@pxref{History Interaction}). - -@item --enable-brace-expansion -Include @code{csh}-like brace expansion -( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ). -See @ref{Brace Expansion}, for a complete description. - -@item --enable-command-timing -Include support for recognizing @code{time} as a reserved word and for -displaying timing statistics for the pipeline following @code{time} -(@pxref{Pipelines}). -This allows pipelines as well as shell builtins and functions to be timed. - -@item --enable-cond-command -Include support for the @code{[[} conditional command -(@pxref{Conditional Constructs}). - -@item --enable-directory-stack -Include support for a @code{csh}-like directory stack and the -@code{pushd}, @code{popd}, and @code{dirs} builtins -(@pxref{The Directory Stack}). - -@item --enable-disabled-builtins -Allow builtin commands to be invoked via @samp{builtin xxx} -even after @code{xxx} has been disabled using @samp{enable -n xxx}. -See @ref{Bash Builtins}, for details of the @code{builtin} and -@code{enable} builtin commands. - -@item --enable-dparen-arithmetic -Include support for the @code{((@dots{}))} command -(@pxref{Conditional Constructs}). - -@item --enable-extended-glob -Include support for the extended pattern matching features described -above under @ref{Pattern Matching}. - -@item --enable-help-builtin -Include the @code{help} builtin, which displays help on shell builtins and -variables (@pxref{Bash Builtins}). - -@item --enable-history -Include command history and the @code{fc} and @code{history} -builtin commands (@pxref{Bash History Facilities}). - -@item --enable-job-control -This enables the job control features (@pxref{Job Control}), -if the operating system supports them. - -@item --enable-multibyte -This enables support for multibyte characters if the operating -system provides the necessary support. - -@item --enable-net-redirections -This enables the special handling of filenames of the form -@code{/dev/tcp/@var{host}/@var{port}} and -@code{/dev/udp/@var{host}/@var{port}} -when used in redirections (@pxref{Redirections}). - -@item --enable-process-substitution -This enables process substitution (@pxref{Process Substitution}) if -the operating system provides the necessary support. - -@item --enable-prompt-string-decoding -Turn on the interpretation of a number of backslash-escaped characters -in the @env{$PS1}, @env{$PS2}, @env{$PS3}, and @env{$PS4} prompt -strings. See @ref{Printing a Prompt}, for a complete list of prompt -string escape sequences. - -@item --enable-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@item --enable-readline -Include support for command-line editing and history with the Bash -version of the Readline library (@pxref{Command Line Editing}). - -@item --enable-restricted -Include support for a @dfn{restricted shell}. If this is enabled, Bash, -when called as @code{rbash}, enters a restricted mode. See -@ref{The Restricted Shell}, for a description of restricted mode. - -@item --enable-select -Include the @code{select} builtin, which allows the generation of simple -menus (@pxref{Conditional Constructs}). - -@item --enable-usg-echo-default -A synonym for @code{--enable-xpg-echo-default}. - -@item --enable-xpg-echo-default -Make the @code{echo} builtin expand backslash-escaped characters by default, -without requiring the @option{-e} option. -This sets the default value of the @code{xpg_echo} shell option to @code{on}, -which makes the Bash @code{echo} behave more like the version specified in -the Single Unix Specification, version 2. -@xref{Bash Builtins}, for a description of the escape sequences that -@code{echo} recognizes. - -@end table - -The file @file{config-top.h} contains C Preprocessor -@samp{#define} statements for options which are not settable from -@code{configure}. -Some of these are not meant to be changed; beware of the consequences if -you do. -Read the comments associated with each definition for more -information about its effect. - -@node Reporting Bugs -@appendix Reporting Bugs - -Please report all bugs you find in Bash. -But first, you should -make sure that it really is a bug, and that it appears in the latest -version of Bash. -The latest version of Bash is always available for FTP from -@uref{ftp://ftp.gnu.org/pub/bash/}. - -Once you have determined that a bug actually exists, use the -@code{bashbug} command to submit a bug report. -If you have a fix, you are encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to @email{bug-bash@@gnu.org} or posted to the Usenet -newsgroup @code{gnu.bash.bug}. - -All bug reports should include: -@itemize @bullet -@item -The version number of Bash. -@item -The hardware and operating system. -@item -The compiler used to compile Bash. -@item -A description of the bug behaviour. -@item -A short script or `recipe' which exercises the bug and may be used -to reproduce it. -@end itemize - -@noindent -@code{bashbug} inserts the first three items automatically into -the template it provides for filing a bug report. - -Please send all reports concerning this manual to -@email{chet@@po.CWRU.Edu}. - -@node Major Differences From The Bourne Shell -@appendix Major Differences From The Bourne Shell - -Bash implements essentially the same grammar, parameter and -variable expansion, redirection, and quoting as the Bourne Shell. -Bash uses the @sc{posix} 1003.2 standard as the specification of -how these features are to be implemented. There are some -differences between the traditional Bourne shell and Bash; this -section quickly details the differences of significance. A -number of these differences are explained in greater depth in -previous sections. -This section uses the version of @code{sh} included in SVR4.2 as -the baseline reference. - -@itemize @bullet - -@item -Bash is @sc{posix}-conformant, even where the @sc{posix} specification -differs from traditional @code{sh} behavior (@pxref{Bash POSIX Mode}). - -@item -Bash has multi-character invocation options (@pxref{Invoking Bash}). - -@item -Bash has command-line editing (@pxref{Command Line Editing}) and -the @code{bind} builtin. - -@item -Bash provides a programmable word completion mechanism -(@pxref{Programmable Completion}), and two builtin commands, -@code{complete} and @code{compgen}, to manipulate it. - -@item -Bash has command history (@pxref{Bash History Facilities}) and the -@code{history} and @code{fc} builtins to manipulate it. - -@item -Bash implements @code{csh}-like history expansion -(@pxref{History Interaction}). - -@item -Bash has one-dimensional array variables (@pxref{Arrays}), and the -appropriate variable expansions and assignment syntax to use them. -Several of the Bash builtins take options to act on arrays. -Bash provides a number of built-in array variables. - -@item -The @code{$'@dots{}'} quoting syntax, which expands ANSI-C -backslash-escaped characters in the text between the single quotes, -is supported (@pxref{ANSI-C Quoting}). - -@item -Bash supports the @code{$"@dots{}"} quoting syntax to do -locale-specific translation of the characters between the double -quotes. The @option{-D}, @option{--dump-strings}, and @option{--dump-po-strings} -invocation options list the translatable strings found in a script -(@pxref{Locale Translation}). - -@item -Bash implements the @code{!} keyword to negate the return value of -a pipeline (@pxref{Pipelines}). -Very useful when an @code{if} statement needs to act only if a test fails. - -@item -Bash has the @code{time} reserved word and command timing (@pxref{Pipelines}). -The display of the timing statistics may be controlled with the -@env{TIMEFORMAT} variable. - -@item -Bash implements the @code{for (( @var{expr1} ; @var{expr2} ; @var{expr3} ))} -arithmetic for command, similar to the C language (@pxref{Looping Constructs}). - -@item -Bash includes the @code{select} compound command, which allows the -generation of simple menus (@pxref{Conditional Constructs}). - -@item -Bash includes the @code{[[} compound command, which makes conditional -testing part of the shell grammar (@pxref{Conditional Constructs}). - -@item -Bash includes brace expansion (@pxref{Brace Expansion}) and tilde -expansion (@pxref{Tilde Expansion}). - -@item -Bash implements command aliases and the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item -Bash provides shell arithmetic, the @code{((} compound command -(@pxref{Conditional Constructs}), -and arithmetic expansion (@pxref{Shell Arithmetic}). - -@item -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. - -@item -Bash includes the @sc{posix} pattern removal @samp{%}, @samp{#}, @samp{%%} -and @samp{##} expansions to remove leading or trailing substrings from -variable values (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{#xx@}}, which returns the length of @code{$@{xx@}}, -is supported (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{var:}@var{offset}@code{[:}@var{length}@code{]@}}, -which expands to the substring of @code{var}'s value of length -@var{length}, beginning at @var{offset}, is present -(@pxref{Shell Parameter Expansion}). - -@item -The expansion -@code{$@{var/[/]}@var{pattern}@code{[/}@var{replacement}@code{]@}}, -which matches @var{pattern} and replaces it with @var{replacement} in -the value of @code{var}, is available (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{!@var{prefix@}*}} expansion, which expands to -the names of all shell variables whose names begin with @var{prefix}, -is available (@pxref{Shell Parameter Expansion}). - -@item -Bash has @var{indirect} variable expansion using @code{$@{!word@}} -(@pxref{Shell Parameter Expansion}). - -@item -Bash can expand positional parameters beyond @code{$9} using -@code{$@{@var{num}@}}. - -@item -The @sc{posix} @code{$()} form of command substitution -is implemented (@pxref{Command Substitution}), -and preferred to the Bourne shell's @code{``} (which -is also implemented for backwards compatibility). - -@item -Bash has process substitution (@pxref{Process Substitution}). - -@item -Bash automatically assigns variables that provide information about the -current user (@env{UID}, @env{EUID}, and @env{GROUPS}), the current host -(@env{HOSTTYPE}, @env{OSTYPE}, @env{MACHTYPE}, and @env{HOSTNAME}), -and the instance of Bash that is running (@env{BASH}, -@env{BASH_VERSION}, and @env{BASH_VERSINFO}). @xref{Bash Variables}, -for details. - -@item -The @env{IFS} variable is used to split only the results of expansion, -not all words (@pxref{Word Splitting}). -This closes a longstanding shell security hole. - -@item -Bash implements the full set of @sc{posix} 1003.2 filename expansion operators, -including @var{character classes}, @var{equivalence classes}, and -@var{collating symbols} (@pxref{Filename Expansion}). - -@item -Bash implements extended pattern matching features when the @code{extglob} -shell option is enabled (@pxref{Pattern Matching}). - -@item -It is possible to have a variable and a function with the same name; -@code{sh} does not separate the two name spaces. - -@item -Bash functions are permitted to have local variables using the -@code{local} builtin, and thus useful recursive functions may be written -(@pxref{Bash Builtins}). - -@item -Variable assignments preceding commands affect only that command, even -builtins and functions (@pxref{Environment}). -In @code{sh}, all variable assignments -preceding commands are global unless the command is executed from the -file system. - -@item -Bash performs filename expansion on filenames specified as operands -to input and output redirection operators (@pxref{Redirections}). - -@item -Bash contains the @samp{<>} redirection operator, allowing a file to be -opened for both reading and writing, and the @samp{&>} redirection -operator, for directing standard output and standard error to the same -file (@pxref{Redirections}). - -@item -Bash treats a number of filenames specially when they are -used in redirection operators (@pxref{Redirections}). - -@item -Bash can open network connections to arbitrary machines and services -with the redirection operators (@pxref{Redirections}). - -@item -The @code{noclobber} option is available to avoid overwriting existing -files with output redirection (@pxref{The Set Builtin}). -The @samp{>|} redirection operator may be used to override @code{noclobber}. - -@item -The Bash @code{cd} and @code{pwd} builtins (@pxref{Bourne Shell Builtins}) -each take @option{-L} and @option{-P} options to switch between logical and -physical modes. - -@item -Bash allows a function to override a builtin with the same name, and provides -access to that builtin's functionality within the function via the -@code{builtin} and @code{command} builtins (@pxref{Bash Builtins}). - -@item -The @code{command} builtin allows selective disabling of functions -when command lookup is performed (@pxref{Bash Builtins}). - -@item -Individual builtins may be enabled or disabled using the @code{enable} -builtin (@pxref{Bash Builtins}). - -@item -The Bash @code{exec} builtin takes additional options that allow users -to control the contents of the environment passed to the executed -command, and what the zeroth argument to the command is to be -(@pxref{Bourne Shell Builtins}). - -@item -Shell functions may be exported to children via the environment -using @code{export -f} (@pxref{Shell Functions}). - -@item -The Bash @code{export}, @code{readonly}, and @code{declare} builtins can -take a @option{-f} option to act on shell functions, a @option{-p} option to -display variables with various attributes set in a format that can be -used as shell input, a @option{-n} option to remove various variable -attributes, and @samp{name=value} arguments to set variable attributes -and values simultaneously. - -@item -The Bash @code{hash} builtin allows a name to be associated with -an arbitrary filename, even when that filename cannot be found by -searching the @env{$PATH}, using @samp{hash -p} -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes a @code{help} builtin for quick reference to shell -facilities (@pxref{Bash Builtins}). - -@item -The @code{printf} builtin is available to display formatted output -(@pxref{Bash Builtins}). - -@item -The Bash @code{read} builtin (@pxref{Bash Builtins}) -will read a line ending in @samp{\} with -the @option{-r} option, and will use the @env{REPLY} variable as a -default if no non-option arguments are supplied. -The Bash @code{read} builtin -also accepts a prompt string with the @option{-p} option and will use -Readline to obtain the line when given the @option{-e} option. -The @code{read} builtin also has additional options to control input: -the @option{-s} option will turn off echoing of input characters as -they are read, the @option{-t} option will allow @code{read} to time out -if input does not arrive within a specified number of seconds, the -@option{-n} option will allow reading only a specified number of -characters rather than a full line, and the @option{-d} option will read -until a particular character rather than newline. - -@item -The @code{return} builtin may be used to abort execution of scripts -executed with the @code{.} or @code{source} builtins -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes the @code{shopt} builtin, for finer control of shell -optional capabilities (@pxref{Bash Builtins}), and allows these options -to be set and unset at shell invocation (@pxref{Invoking Bash}). - -@item -Bash has much more optional behavior controllable with the @code{set} -builtin (@pxref{The Set Builtin}). - -@item -The @code{test} builtin (@pxref{Bourne Shell Builtins}) -is slightly different, as it implements the @sc{posix} algorithm, -which specifies the behavior based on the number of arguments. - -@item -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{DEBUG} pseudo-signal specification, similar to @code{EXIT}. -Commands specified with a @code{DEBUG} trap are executed before every -simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -The @code{DEBUG} trap is not inherited by shell functions unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. -The @code{extdebug} shell option has additional effects on the -@code{DEBUG} trap. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows an -@code{ERR} pseudo-signal specification, similar to @code{EXIT} and @code{DEBUG}. -Commands specified with an @code{ERR} trap are executed after a simple -command fails, with a few exceptions. -The @code{ERR} trap is not inherited by shell functions unless the -@code{-o errtrace} option to the @code{set} builtin is enabled. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{RETURN} pseudo-signal specification, similar to -@code{EXIT} and @code{DEBUG}. -Commands specified with an @code{RETURN} trap are executed before -execution resumes after a shell function or a shell script executed with -@code{.} or @code{source} returns. -The @code{RETURN} trap is not inherited by shell functions. - -@item -The Bash @code{type} builtin is more extensive and gives more information -about the names it finds (@pxref{Bash Builtins}). - -@item -The Bash @code{umask} builtin permits a @option{-p} option to cause -the output to be displayed in the form of a @code{umask} command -that may be reused as input (@pxref{Bourne Shell Builtins}). - -@item -Bash implements a @code{csh}-like directory stack, and provides the -@code{pushd}, @code{popd}, and @code{dirs} builtins to manipulate it -(@pxref{The Directory Stack}). -Bash also makes the directory stack visible as the value of the -@env{DIRSTACK} shell variable. - -@item -Bash interprets special backslash-escaped characters in the prompt -strings when interactive (@pxref{Printing a Prompt}). - -@item -The Bash restricted mode is more useful (@pxref{The Restricted Shell}); -the SVR4.2 shell restricted mode is too limited. - -@item -The @code{disown} builtin can remove a job from the internal shell -job table (@pxref{Job Control Builtins}) or suppress the sending -of @code{SIGHUP} to a job when the shell exits as the result of a -@code{SIGHUP}. - -@item -The SVR4.2 shell has two privilege-related builtins -(@code{mldmode} and @code{priv}) not present in Bash. - -@item -Bash does not have the @code{stop} or @code{newgrp} builtins. - -@item -Bash does not use the @env{SHACCT} variable or perform shell accounting. - -@item -The SVR4.2 @code{sh} uses a @env{TIMEOUT} variable like Bash uses -@env{TMOUT}. - -@end itemize - -@noindent -More features unique to Bash may be found in @ref{Bash Features}. - - -@appendixsec Implementation Differences From The SVR4.2 Shell - -Since Bash is a completely new implementation, it does not suffer from -many of the limitations of the SVR4.2 shell. For instance: - -@itemize @bullet - -@item -Bash does not fork a subshell when redirecting into or out of -a shell control structure such as an @code{if} or @code{while} -statement. - -@item -Bash does not allow unbalanced quotes. The SVR4.2 shell will silently -insert a needed closing quote at @code{EOF} under certain circumstances. -This can be the cause of some hard-to-find errors. - -@item -The SVR4.2 shell uses a baroque memory management scheme based on -trapping @code{SIGSEGV}. If the shell is started from a process with -@code{SIGSEGV} blocked (e.g., by using the @code{system()} C library -function call), it misbehaves badly. - -@item -In a questionable attempt at security, the SVR4.2 shell, -when invoked without the @option{-p} option, will alter its real -and effective @sc{uid} and @sc{gid} if they are less than some -magic threshold value, commonly 100. -This can lead to unexpected results. - -@item -The SVR4.2 shell does not allow users to trap @code{SIGSEGV}, -@code{SIGALRM}, or @code{SIGCHLD}. - -@item -The SVR4.2 shell does not allow the @env{IFS}, @env{MAILCHECK}, -@env{PATH}, @env{PS1}, or @env{PS2} variables to be unset. - -@item -The SVR4.2 shell treats @samp{^} as the undocumented equivalent of -@samp{|}. - -@item -Bash allows multiple option arguments when it is invoked (@code{-x -v}); -the SVR4.2 shell allows only one option argument (@code{-xv}). In -fact, some versions of the shell dump core if the second argument begins -with a @samp{-}. - -@item -The SVR4.2 shell exits a script if any builtin fails; Bash exits -a script only if one of the @sc{posix} 1003.2 special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} 1003.2 standard. - -@item -The SVR4.2 shell behaves differently when invoked as @code{jsh} -(it turns on job control). -@end itemize - -@node Copying This Manual -@appendix Copying This Manual - -@menu -* GNU Free Documentation License:: License for copying this manual. -@end menu - -@include fdl.texi - -@node Builtin Index -@unnumbered Index of Shell Builtin Commands -@printindex bt - -@node Reserved Word Index -@unnumbered Index of Shell Reserved Words -@printindex rw - -@node Variable Index -@unnumbered Parameter and Variable Index -@printindex vr - -@node Function Index -@unnumbered Function Index -@printindex fn - -@node Concept Index -@unnumbered Concept Index -@printindex cp - -@bye diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ deleted file mode 100644 index 615a0a0c3..000000000 --- a/doc/bashref.texi~ +++ /dev/null @@ -1,7267 +0,0 @@ -\input texinfo.tex @c -*- texinfo -*- -@c %**start of header -@setfilename bashref.info -@settitle Bash Reference Manual -@c %**end of header - -@setchapternewpage odd - -@include version.texi - -@copying -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}). - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Copyright @copyright{} 1988-2004 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. - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.1 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with the Front-Cover texts being ``A GNU Manual,'' -and with the Back-Cover Texts as in (a) below. A copy of the license is -included in the section entitled ``GNU Free Documentation License.'' - -(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify -this GNU Manual, like GNU software. Copies published by the Free -Software Foundation raise funds for GNU development.'' -@end quotation -@end copying - -@defcodeindex bt -@defcodeindex rw -@set BashFeatures - -@dircategory Basics -@direntry -* Bash: (bash). The GNU Bourne-Again SHell. -@end direntry - -@finalout - -@titlepage -@title Bash Reference Manual -@subtitle Reference Documentation for Bash -@subtitle Edition @value{EDITION}, for @code{Bash} Version @value{VERSION}. -@subtitle @value{UPDATED-MONTH} -@author Chet Ramey, Case Western Reserve University -@author Brian Fox, Free Software Foundation - -@page -@vskip 0pt plus 1filll -@insertcopying - -@sp 1 -Published by the Free Software Foundation @* -59 Temple Place, Suite 330, @* -Boston, MA 02111-1307 @* -USA @* - -@end titlepage - -@contents - -@ifnottex -@node Top, Introduction, (dir), (dir) -@top Bash Features - -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}).. - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Bash contains features that appear in other popular shells, and some -features that only appear in Bash. Some of the shells that Bash has -borrowed concepts from are the Bourne Shell (@file{sh}), the Korn Shell -(@file{ksh}), and the C-shell (@file{csh} and its successor, -@file{tcsh}). The following menu breaks the features up into -categories based upon which one of these other shells inspired the -feature. - -This manual is meant as a brief introduction to features found in -Bash. The Bash manual page should be used as the definitive -reference on shell behavior. - -@menu -* Introduction:: An introduction to the shell. - -* Definitions:: Some definitions used in the rest of this - manual. - -* Basic Shell Features:: The shell "building blocks". - -* Shell Builtin Commands:: Commands that are a part of the shell. - -* Shell Variables:: Variables used or set by Bash. - -* Bash Features:: Features found only in Bash. - -* Job Control:: A chapter describing what job control is - and how Bash allows you to use it. - -* Using History Interactively:: Chapter dealing with history expansion - rules. - -* Command Line Editing:: Chapter describing the command line - editing features. - -* Installing Bash:: How to build and install Bash on your system. - -* Reporting Bugs:: How to report bugs in Bash. - -* Major Differences From The Bourne Shell:: A terse list of the differences - between Bash and historical - versions of /bin/sh. - -* Copying This Manual:: Copying this manual. - -* Builtin Index:: Index of Bash builtin commands. - -* Reserved Word Index:: Index of Bash reserved words. - -* Variable Index:: Quick reference helps you find the - variable you want. - -* Function Index:: Index of bindable Readline functions. - -* Concept Index:: General index for concepts described in - this manual. -@end menu -@end ifnottex - -@node Introduction -@chapter Introduction -@menu -* What is Bash?:: A short description of Bash. - -* What is a shell?:: A brief introduction to shells. -@end menu - -@node What is Bash? -@section What is Bash? - -Bash is the shell, or command language interpreter, -for the @sc{gnu} operating system. -The name is an acronym for the @samp{Bourne-Again SHell}, -a pun on Stephen Bourne, the author of the direct ancestor of -the current Unix shell @code{sh}, -which appeared in the Seventh Edition Bell Labs Research version -of Unix. - -Bash is largely compatible with @code{sh} and incorporates useful -features from the Korn shell @code{ksh} and the C shell @code{csh}. -It is intended to be a conformant implementation of the @sc{ieee} -@sc{posix} Shell and Tools specification (@sc{ieee} Working Group 1003.2). -It offers functional improvements over @code{sh} for both interactive and -programming use. - -While the @sc{gnu} operating system provides other shells, including -a version of @code{csh}, Bash is the default shell. -Like other @sc{gnu} software, Bash is quite portable. It currently runs -on nearly every version of Unix and a few other operating systems @minus{} -independently-supported ports exist for @sc{ms-dos}, @sc{os/2}, -and Windows platforms. - -@node What is a shell? -@section What is a shell? - -At its base, a shell is simply a macro processor that executes -commands. The term macro processor means functionality where text -and symbols are expanded to create larger expressions. - -A Unix shell is both a command interpreter and a programming -language. As a command interpreter, the shell provides the user -interface to the rich set of @sc{gnu} utilities. The programming -language features allow these utilitites to be combined. -Files containing commands can be created, and become -commands themselves. These new commands have the same status as -system commands in directories such as @file{/bin}, allowing users -or groups to establish custom environments to automate their common -tasks. - -Shells may be used interactively or non-interactively. In -interactive mode, they accept input typed from the keyboard. -When executing non-interactively, shells execute commands read -from a file. - -A shell allows execution of @sc{gnu} commands, both synchronously and -asynchronously. -The shell waits for synchronous commands to complete before accepting -more input; asynchronous commands continue to execute in parallel -with the shell while it reads and executes additional commands. -The @dfn{redirection} constructs permit -fine-grained control of the input and output of those commands. -Moreover, the shell allows control over the contents of commands' -environments. - -Shells also provide a small set of built-in -commands (@dfn{builtins}) implementing functionality impossible -or inconvenient to obtain via separate utilities. -For example, @code{cd}, @code{break}, @code{continue}, and -@code{exec}) cannot be implemented outside of the shell because -they directly manipulate the shell itself. -The @code{history}, @code{getopts}, @code{kill}, or @code{pwd} -builtins, among others, could be implemented in separate utilities, -but they are more convenient to use as builtin commands. -All of the shell builtins are described in -subsequent sections. - -While executing commands is essential, most of the power (and -complexity) of shells is due to their embedded programming -languages. Like any high-level language, the shell provides -variables, flow control constructs, quoting, and functions. - -Shells offer features geared specifically for -interactive use rather than to augment the programming language. -These interactive features include job control, command line -editing, command history and aliases. Each of these features is -described in this manual. - -@node Definitions -@chapter Definitions -These definitions are used throughout the remainder of this manual. - -@table @code - -@item POSIX -@cindex POSIX -A family of open system standards based on Unix. Bash -is concerned with @sc{posix} 1003.2, the Shell and Tools Standard. - -@item blank -A space or tab character. - -@item builtin -@cindex builtin -A command that is implemented internally by the shell itself, rather -than by an executable program somewhere in the file system. - -@item control operator -@cindex control operator -A @code{word} that performs a control function. It is a @code{newline} -or one of the following: -@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;}, -@samp{|}, @samp{(}, or @samp{)}. - -@item exit status -@cindex exit status -The value returned by a command to its caller. The value is restricted -to eight bits, so the maximum value is 255. - -@item field -@cindex field -A unit of text that is the result of one of the shell expansions. After -expansion, when executing a command, the resulting fields are used as -the command name and arguments. - -@item filename -@cindex filename -A string of characters used to identify a file. - -@item job -@cindex job -A set of processes comprising a pipeline, and any processes descended -from it, that are all in the same process group. - -@item job control -@cindex job control -A mechanism by which users can selectively stop (suspend) and restart -(resume) execution of processes. - -@item metacharacter -@cindex metacharacter -A character that, when unquoted, separates words. A metacharacter is -a @code{blank} or one of the following characters: -@samp{|}, @samp{&}, @samp{;}, @samp{(}, @samp{)}, @samp{<}, or -@samp{>}. - -@item name -@cindex name -@cindex identifier -A @code{word} consisting solely of letters, numbers, and underscores, -and beginning with a letter or underscore. @code{Name}s are used as -shell variable and function names. -Also referred to as an @code{identifier}. - -@item operator -@cindex operator, shell -A @code{control operator} or a @code{redirection operator}. -@xref{Redirections}, for a list of redirection operators. - -@item process group -@cindex process group -A collection of related processes each having the same process -group @sc{id}. - -@item process group ID -@cindex process group ID -A unique identifer that represents a @code{process group} -during its lifetime. - -@item reserved word -@cindex reserved word -A @code{word} that has a special meaning to the shell. Most reserved -words introduce shell flow control constructs, such as @code{for} and -@code{while}. - -@item return status -@cindex return status -A synonym for @code{exit status}. - -@item signal -@cindex signal -A mechanism by which a process may be notified by the kernel -of an event occurring in the system. - -@item special builtin -@cindex special builtin -A shell builtin command that has been classified as special by the -@sc{posix} 1003.2 standard. - -@item token -@cindex token -A sequence of characters considered a single unit by the shell. It is -either a @code{word} or an @code{operator}. - -@item word -@cindex word -A @code{token} that is not an @code{operator}. -@end table - -@node Basic Shell Features -@chapter Basic Shell Features -@cindex Bourne shell - -Bash is an acronym for @samp{Bourne-Again SHell}. -The Bourne shell is -the traditional Unix shell originally written by Stephen Bourne. -All of the Bourne shell builtin commands are available in Bash, -The rules for evaluation and quoting are taken from the @sc{posix} -specification for the `standard' Unix shell. - -This chapter briefly summarizes the shell's `building blocks': -commands, control structures, shell functions, shell @i{parameters}, -shell expansions, -@i{redirections}, which are a way to direct input and output from -and to named files, and how the shell executes commands. - -@menu -* Shell Syntax:: What your input means to the shell. -* Shell Commands:: The types of commands you can use. -* Shell Functions:: Grouping commands by name. -* Shell Parameters:: How the shell stores values. -* Shell Expansions:: How Bash expands parameters and the various - expansions available. -* Redirections:: A way to control where input and output go. -* Executing Commands:: What happens when you run a command. -* Shell Scripts:: Executing files of shell commands. -@end menu - -@node Shell Syntax -@section Shell Syntax -@menu -* Shell Operation:: The basic operation of the shell. - -* Quoting:: How to remove the special meaning from characters. - -* Comments:: How to specify comments. -@end menu - -When the shell reads input, it proceeds through a -sequence of operations. If the input indicates the beginning of a -comment, the shell ignores the comment symbol (@samp{#}), and the rest -of that line. - -Otherwise, roughly speaking, the shell reads its input and -divides the input into words and operators, employing the quoting rules -to select which meanings to assign various words and characters. - -The shell then parses these tokens into commands and other constructs, -removes the special meaning of certain words or characters, expands -others, redirects input and output as needed, executes the specified -command, waits for the command's exit status, and makes that exit status -available for further inspection or processing. - -@node Shell Operation -@subsection Shell Operation - -The following is a brief description of the shell's operation when it -reads and executes a command. Basically, the shell does the -following: - -@enumerate -@item -Reads its input from a file (@pxref{Shell Scripts}), from a string -supplied as an argument to the @option{-c} invocation option -(@pxref{Invoking Bash}), or from the user's terminal. - -@item -Breaks the input into words and operators, obeying the quoting rules -described in @ref{Quoting}. These tokens are separated by -@code{metacharacters}. Alias expansion is performed by this step -(@pxref{Aliases}). - -@item -Parses the tokens into simple and compound commands -(@pxref{Shell Commands}). - -@item -Performs the various shell expansions (@pxref{Shell Expansions}), breaking -the expanded tokens into lists of filenames (@pxref{Filename Expansion}) -and commands and arguments. - -@item -Performs any necessary redirections (@pxref{Redirections}) and removes -the redirection operators and their operands from the argument list. - -@item -Executes the command (@pxref{Executing Commands}). - -@item -Optionally waits for the command to complete and collects its exit -status (@pxref{Exit Status}). - -@end enumerate - -@node Quoting -@subsection Quoting -@cindex quoting -@menu -* Escape Character:: How to remove the special meaning from a single - character. -* Single Quotes:: How to inhibit all interpretation of a sequence - of characters. -* Double Quotes:: How to suppress most of the interpretation of a - sequence of characters. -* ANSI-C Quoting:: How to expand ANSI-C sequences in quoted strings. - -* Locale Translation:: How to translate strings into different languages. -@end menu - -Quoting is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -disable special treatment for special characters, to prevent -reserved words from being recognized as such, and to prevent -parameter expansion. - -Each of the shell metacharacters (@pxref{Definitions}) -has special meaning to the shell and must be quoted if it is to -represent itself. -When the command history expansion facilities are being used, the -@var{history expansion} character, usually @samp{!}, must be quoted -to prevent history expansion. @xref{Bash History Facilities}, for -more details concerning history expansion. - -There are three quoting mechanisms: the -@var{escape character}, single quotes, and double quotes. - -@node Escape Character -@subsubsection Escape Character -A non-quoted backslash @samp{\} is the Bash escape character. -It preserves the literal value of the next character that follows, -with the exception of @code{newline}. If a @code{\newline} pair -appears, and the backslash itself is not quoted, the @code{\newline} -is treated as a line continuation (that is, it is removed from -the input stream and effectively ignored). - -@node Single Quotes -@subsubsection Single Quotes - -Enclosing characters in single quotes (@samp{'}) preserves the literal value -of each character within the quotes. A single quote may not occur -between single quotes, even when preceded by a backslash. - -@node Double Quotes -@subsubsection Double Quotes - -Enclosing characters in double quotes (@samp{"}) preserves the literal value -of all characters within the quotes, with the exception of -@samp{$}, @samp{`}, and @samp{\}. -The characters @samp{$} and @samp{`} -retain their special meaning within double quotes (@pxref{Shell Expansions}). -The backslash retains its special meaning only when followed by one of -the following characters: -@samp{$}, @samp{`}, @samp{"}, @samp{\}, or @code{newline}. -Within double quotes, backslashes that are followed by one of these -characters are removed. Backslashes preceding characters without a -special meaning are left unmodified. -A double quote may be quoted within double quotes by preceding it with -a backslash. -When command history is being used, the double quote may not be used to -quote the history expansion character. - -The special parameters @samp{*} and @samp{@@} have special meaning -when in double quotes (@pxref{Shell Parameter Expansion}). - -@node ANSI-C Quoting -@subsubsection ANSI-C Quoting -@cindex quoting, ANSI - -Words of the form @code{$'@var{string}'} are treated specially. The -word expands to @var{string}, with backslash-escaped characters replaced -as specified by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: - -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \e -an escape character (not ANSI C) -@item \f -form feed -@item \n -newline -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \' -single quote -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@item \c@var{x} -a control-@var{x} character -@end table - -@noindent -The expanded result is single-quoted, as if the dollar sign had not -been present. - -@node Locale Translation -@subsubsection Locale-Specific Translation -@cindex localization -@cindex internationalization -@cindex native languages -@cindex translation, native languages - -A double-quoted string preceded by a dollar sign (@samp{$}) will cause -the string to be translated according to the current locale. -If the current locale is @code{C} or @code{POSIX}, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. - -@vindex LC_MESSAGES -@vindex TEXTDOMAIN -@vindex TEXTDOMAINDIR -Some systems use the message catalog selected by the @env{LC_MESSAGES} -shell variable. Others create the name of the message catalog from the -value of the @env{TEXTDOMAIN} shell variable, possibly adding a -suffix of @samp{.mo}. If you use the @env{TEXTDOMAIN} variable, you -may need to set the @env{TEXTDOMAINDIR} variable to the location of -the message catalog files. Still others use both variables in this -fashion: -@env{TEXTDOMAINDIR}/@env{LC_MESSAGES}/LC_MESSAGES/@env{TEXTDOMAIN}.mo. - -@node Comments -@subsection Comments -@cindex comments, shell - -In a non-interactive shell, or an interactive shell in which the -@code{interactive_comments} option to the @code{shopt} -builtin is enabled (@pxref{Bash Builtins}), -a word beginning with @samp{#} -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the @code{interactive_comments} -option enabled does not allow comments. The @code{interactive_comments} -option is on by default in interactive shells. -@xref{Interactive Shells}, for a description of what makes -a shell interactive. - -@node Shell Commands -@section Shell Commands -@cindex commands, shell - -A simple shell command such as @code{echo a b c} consists of the command -itself followed by arguments, separated by spaces. - -More complex shell commands are composed of simple commands arranged together -in a variety of ways: in a pipeline in which the output of one command -becomes the input of a second, in a loop or conditional construct, or in -some other grouping. - -@menu -* Simple Commands:: The most common type of command. -* Pipelines:: Connecting the input and output of several - commands. -* Lists:: How to execute commands sequentially. -* Compound Commands:: Shell commands for control flow. -@end menu - -@node Simple Commands -@subsection Simple Commands -@cindex commands, simple - -A simple command is the kind of command encountered most often. -It's just a sequence of words separated by @code{blank}s, terminated -by one of the shell's control operators (@pxref{Definitions}). The -first word generally specifies a command to be executed, with the -rest of the words being that command's arguments. - -The return status (@pxref{Exit Status}) of a simple command is -its exit status as provided -by the @sc{posix} 1003.1 @code{waitpid} function, or 128+@var{n} if -the command was terminated by signal @var{n}. - -@node Pipelines -@subsection Pipelines -@cindex pipeline -@cindex commands, pipelines - -A @code{pipeline} is a sequence of simple commands separated by -@samp{|}. - -@rwindex time -@rwindex ! -@cindex command timing -The format for a pipeline is -@example -[@code{time} [@code{-p}]] [@code{!}] @var{command1} [@code{|} @var{command2} @dots{}] -@end example - -@noindent -The output of each command in the pipeline is connected via a pipe -to the input of the next command. -That is, each command reads the previous command's output. - -The reserved word @code{time} causes timing statistics -to be printed for the pipeline once it finishes. -The statistics currently consist of elapsed (wall-clock) time and -user and system time consumed by the command's execution. -The @option{-p} option changes the output format to that specified -by @sc{posix}. -The @env{TIMEFORMAT} variable may be set to a format string that -specifies how the timing information should be displayed. -@xref{Bash Variables}, for a description of the available formats. -The use of @code{time} as a reserved word permits the timing of -shell builtins, shell functions, and pipelines. An external -@code{time} command cannot time these easily. - -If the pipeline is not executed asynchronously (@pxref{Lists}), the -shell waits for all commands in the pipeline to complete. - -Each command in a pipeline is executed in its own subshell -(@pxref{Command Execution Environment}). The exit -status of a pipeline is the exit status of the last command in the -pipeline, unless the @code{pipefail} option is enabled -(@pxref{The Set Builtin}). -If @code{pipefail} is enabled, the pipeline's return status is the -value of the last (rightmost) command to exit with a non-zero status, -or zero if all commands exit successfully. -If the reserved word @samp{!} precedes the pipeline, the -exit status is the logical negation of the exit status as described -above. -The shell waits for all commands in the pipeline to terminate before -returning a value. - -@node Lists -@subsection Lists of Commands -@cindex commands, lists - -A @code{list} is a sequence of one or more pipelines separated by one -of the operators @samp{;}, @samp{&}, @samp{&&}, or @samp{||}, -and optionally terminated by one of @samp{;}, @samp{&}, or a -@code{newline}. - -Of these list operators, @samp{&&} and @samp{||} -have equal precedence, followed by @samp{;} and @samp{&}, -which have equal precedence. - -A sequence of one or more newlines may appear in a @code{list} -to delimit commands, equivalent to a semicolon. - -If a command is terminated by the control operator @samp{&}, -the shell executes the command asynchronously in a subshell. -This is known as executing the command in the @var{background}. -The shell does not wait for the command to finish, and the return -status is 0 (true). -When job control is not active (@pxref{Job Control}), -the standard input for asynchronous commands, in the absence of any -explicit redirections, is redirected from @code{/dev/null}. - -Commands separated by a @samp{;} are executed sequentially; the shell -waits for each command to terminate in turn. The return status is the -exit status of the last command executed. - -The control operators @samp{&&} and @samp{||} -denote @sc{and} lists and @sc{or} lists, respectively. -An @sc{and} list has the form -@example -@var{command1} && @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns an exit status of zero. - -An @sc{or} list has the form -@example -@var{command1} || @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns a non-zero exit status. - -The return status of -@sc{and} and @sc{or} lists is the exit status of the last command -executed in the list. - -@node Compound Commands -@subsection Compound Commands -@cindex commands, compound - -@menu -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Command Grouping:: Ways to group commands. -@end menu - -Compound commands are the shell programming constructs. -Each construct begins with a reserved word or control operator and is -terminated by a corresponding reserved word or operator. -Any redirections (@pxref{Redirections}) associated with a compound command -apply to all commands within that compound command unless explicitly overridden. - -Bash provides looping constructs, conditional commands, and mechanisms -to group commands and execute them as a unit. - -@node Looping Constructs -@subsubsection Looping Constructs -@cindex commands, looping - -Bash supports the following looping constructs. - -Note that wherever a @samp{;} appears in the description of a -command's syntax, it may be replaced with one or more newlines. - -@table @code -@item until -@rwindex until -@rwindex do -@rwindex done -The syntax of the @code{until} command is: -@example -until @var{test-commands}; do @var{consequent-commands}; done -@end example -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status which is not zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item while -@rwindex while -The syntax of the @code{while} command is: -@example -while @var{test-commands}; do @var{consequent-commands}; done -@end example - -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status of zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item for -@rwindex for -The syntax of the @code{for} command is: - -@example -for @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example -Expand @var{words}, and execute @var{commands} once for each member -in the resultant list, with @var{name} bound to the current member. -If @samp{in @var{words}} is not present, the @code{for} command -executes the @var{commands} once for each positional parameter that is -set, as if @samp{in "$@@"} had been specified -(@pxref{Special Parameters}). -The return status is the exit status of the last command that executes. -If there are no items in the expansion of @var{words}, no commands are -executed, and the return status is zero. - -An alternate form of the @code{for} command is also supported: - -@example -for (( @var{expr1} ; @var{expr2} ; @var{expr3} )) ; do @var{commands} ; done -@end example -First, the arithmetic expression @var{expr1} is evaluated according -to the rules described below (@pxref{Shell Arithmetic}). -The arithmetic expression @var{expr2} is then evaluated repeatedly -until it evaluates to zero. -Each time @var{expr2} evaluates to a non-zero value, @var{commands} are -executed and the arithmetic expression @var{expr3} is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in @var{list} -that is executed, or false if any of the expressions is invalid. - -@end table - -The @code{break} and @code{continue} builtins (@pxref{Bourne Shell Builtins}) -may be used to control loop execution. - -@node Conditional Constructs -@subsubsection Conditional Constructs -@cindex commands, conditional - -@table @code -@item if -@rwindex if -@rwindex then -@rwindex else -@rwindex elif -@rwindex fi -The syntax of the @code{if} command is: - -@example -if @var{test-commands}; then - @var{consequent-commands}; -[elif @var{more-test-commands}; then - @var{more-consequents};] -[else @var{alternate-consequents};] -fi -@end example - -The @var{test-commands} list is executed, and if its return status is zero, -the @var{consequent-commands} list is executed. -If @var{test-commands} returns a non-zero status, each @code{elif} list -is executed in turn, and if its exit status is zero, -the corresponding @var{more-consequents} is executed and the -command completes. -If @samp{else @var{alternate-consequents}} is present, and -the final command in the final @code{if} or @code{elif} clause -has a non-zero exit status, then @var{alternate-consequents} is executed. -The return status is the exit status of the last command executed, or -zero if no condition tested true. - -@item case -@rwindex case -@rwindex in -@rwindex esac -The syntax of the @code{case} command is: - -@example -@code{case @var{word} in [ [(] @var{pattern} [| @var{pattern}]@dots{}) @var{command-list} ;;]@dots{} esac} -@end example - -@code{case} will selectively execute the @var{command-list} corresponding to -the first @var{pattern} that matches @var{word}. -The @samp{|} is used to separate multiple patterns, and the @samp{)} -operator terminates a pattern list. -A list of patterns and an associated command-list is known -as a @var{clause}. Each clause must be terminated with @samp{;;}. -The @var{word} undergoes tilde expansion, parameter expansion, command -substitution, arithmetic expansion, and quote removal before matching is -attempted. Each @var{pattern} undergoes tilde expansion, parameter -expansion, command substitution, and arithmetic expansion. - -There may be an arbitrary number of @code{case} clauses, each terminated -by a @samp{;;}. The first pattern that matches determines the -command-list that is executed. - -Here is an example using @code{case} in a script that could be used to -describe one interesting feature of an animal: - -@example -echo -n "Enter the name of an animal: " -read ANIMAL -echo -n "The $ANIMAL has " -case $ANIMAL in - horse | dog | cat) echo -n "four";; - man | kangaroo ) echo -n "two";; - *) echo -n "an unknown number of";; -esac -echo " legs." -@end example - -@noindent -The return status is zero if no @var{pattern} is matched. Otherwise, the -return status is the exit status of the @var{command-list} executed. - -@item select -@rwindex select - -The @code{select} construct allows the easy generation of menus. -It has almost the same syntax as the @code{for} command: - -@example -select @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example - -The list of words following @code{in} is expanded, generating a list -of items. The set of expanded words is printed on the standard -error output stream, each preceded by a number. If the -@samp{in @var{words}} is omitted, the positional parameters are printed, -as if @samp{in "$@@"} had been specifed. -The @env{PS3} prompt is then displayed and a line is read from the -standard input. -If the line consists of a number corresponding to one of the displayed -words, then the value of @var{name} is set to that word. -If the line is empty, the words and prompt are displayed again. -If @code{EOF} is read, the @code{select} command completes. -Any other value read causes @var{name} to be set to null. -The line read is saved in the variable @env{REPLY}. - -The @var{commands} are executed after each selection until a -@code{break} command is executed, at which -point the @code{select} command completes. - -Here is an example that allows the user to pick a filename from the -current directory, and displays the name and index of the file -selected. - -@example -select fname in *; -do - echo you picked $fname \($REPLY\) - break; -done -@end example - -@item ((@dots{})) -@example -(( @var{expression} )) -@end example - -The arithmetic @var{expression} is evaluated according to the rules -described below (@pxref{Shell Arithmetic}). -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -@example -let "@var{expression}" -@end example -@noindent -@xref{Bash Builtins}, for a full description of the @code{let} builtin. - -@item [[@dots{}]] -@rwindex [[ -@rwindex ]] -@example -[[ @var{expression} ]] -@end example - -Return a status of 0 or 1 depending on the evaluation of -the conditional expression @var{expression}. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. -Word splitting and filename expansion are not performed on the words -between the @samp{[[} and @samp{]]}; tilde expansion, parameter and -variable expansion, arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as @samp{-f} must be unquoted to be recognized -as primaries. - -When the @samp{==} and @samp{!=} operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below in @ref{Pattern Matching}. -The return value is 0 if the string matches or does not match -the pattern, respectively, and 1 otherwise. -Any part of the pattern may be quoted to force it to be matched as a -string. - -An additional binary operator, @samp{=~}, is available, with the same -precedence as @samp{==} and @samp{!=}. -When it is used, the string to the right of the operator is considered -an extended regular expression and matched accordingly (as in @i{regex}3)). -The return value is 0 if the string matches -the pattern, and 1 otherwise. -If the regular expression is syntactically incorrect, the conditional -expression's return value is 2. -If the shell option @code{nocaseglob} -(see the description of @code{shopt} in @ref{Bash Builtins}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -Substrings matched by parenthesized subexpressions within the regular -expression are saved in the array variable @code{BASH_REMATCH}. -The element of @code{BASH_REMATCH} with index 0 is the portion of the string -matching the entire regular expression. -The element of @code{BASH_REMATCH} with index @var{n} is the portion of the -string matching the @var{n}th parenthesized subexpression. - -Expressions may be combined using the following operators, listed -in decreasing order of precedence: - -@table @code -@item ( @var{expression} ) -Returns the value of @var{expression}. -This may be used to override the normal precedence of operators. - -@item ! @var{expression} -True if @var{expression} is false. - -@item @var{expression1} && @var{expression2} -True if both @var{expression1} and @var{expression2} are true. - -@item @var{expression1} || @var{expression2} -True if either @var{expression1} or @var{expression2} is true. -@end table -@noindent -The @code{&&} and @code{||} operators do not evaluate @var{expression2} if the -value of @var{expression1} is sufficient to determine the return -value of the entire conditional expression. - -@end table - -@node Command Grouping -@subsubsection Grouping Commands -@cindex commands, grouping - -Bash provides two ways to group a list of commands to be executed -as a unit. When commands are grouped, redirections may be applied -to the entire command list. For example, the output of all the -commands in the list may be redirected to a single stream. - -@table @code -@item () -@example -( @var{list} ) -@end example - -Placing a list of commands between parentheses causes a subshell -environment to be created (@pxref{Command Execution Environment}), and each -of the commands in @var{list} to be executed in that subshell. Since the -@var{list} is executed in a subshell, variable assignments do not remain in -effect after the subshell completes. - -@item @{@} -@rwindex @{ -@rwindex @} -@example -@{ @var{list}; @} -@end example - -Placing a list of commands between curly braces causes the list to -be executed in the current shell context. No subshell is created. -The semicolon (or newline) following @var{list} is required. -@end table - -In addition to the creation of a subshell, there is a subtle difference -between these two constructs due to historical reasons. The braces -are @code{reserved words}, so they must be separated from the @var{list} -by @code{blank}s. The parentheses are @code{operators}, and are -recognized as separate tokens by the shell even if they are not separated -from the @var{list} by whitespace. - -The exit status of both of these constructs is the exit status of -@var{list}. - -@node Shell Functions -@section Shell Functions -@cindex shell function -@cindex functions, shell - -Shell functions are a way to group commands for later execution -using a single name for the group. They are executed just like -a "regular" command. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -Shell functions are executed in the current -shell context; no new process is created to interpret them. - -Functions are declared using this syntax: -@rwindex function -@example -[ @code{function} ] @var{name} () @var{compound-command} [ @var{redirections} ] -@end example - -This defines a shell function named @var{name}. The reserved -word @code{function} is optional. -If the @code{function} reserved -word is supplied, the parentheses are optional. -The @var{body} of the function is the compound command -@var{compound-command} (@pxref{Compound Commands}). -That command is usually a @var{list} enclosed between @{ and @}, but -may be any compound command listed above. -@var{compound-command} is executed whenever @var{name} is specified as the -name of a command. -Any redirections (@pxref{Redirections}) associated with the shell function -are performed when the function is executed. - -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -last command executed in the body. - -Note that for historical reasons, in the most common usage the curly braces -that surround the body of the function must be separated from the body by -@code{blank}s or newlines. -This is because the braces are reserved words and are only recognized -as such when they are separated by whitespace. -Also, when using the braces, the @var{list} must be terminated by a semicolon, -a @samp{&}, or a newline. - -When a function is executed, the arguments to the -function become the positional parameters -during its execution (@pxref{Positional Parameters}). -The special parameter @samp{#} that expands to the number of -positional parameters is updated to reflect the change. -Special parameter @code{0} is unchanged. -The first element of the @env{FUNCNAME} variable is set to the -name of the function while the function is executing. -All other aspects of the shell execution -environment are identical between a function and its caller -with the exception that the @env{DEBUG} trap -below) is not inherited unless the function has been given the -@code{trace} attribute using the @code{declare} builtin or -the @code{-o functrace} option has been enabled with -the @code{set} builtin, -(in which case all functions inherit the @code{DEBUG} trap). -@xref{Bourne Shell Builtins}, for the description of the -@code{trap} builtin. - -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. -Any command associated with the @code{RETURN} trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter @samp{#} -are restored to the values they had prior to the function's -execution. If a numeric argument is given to @code{return}, -that is the function's return status; otherwise the function's -return status is the exit status of the last command executed -before the @code{return}. - -Variables local to the function may be declared with the -@code{local} builtin. These variables are visible only to -the function and the commands it invokes. - -Function names and definitions may be listed with the -@option{-f} option to the @code{declare} or @code{typeset} -builtin commands (@pxref{Bash Builtins}). -The @option{-F} option to @code{declare} or @code{typeset} -will list the function names only -(and optionally the source file and line number, if the @code{extdebug} -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -@option{-f} option to the @code{export} builtin -(@pxref{Bourne Shell Builtins}). -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. - -Functions may be recursive. No limit is placed on the number of -recursive calls. - -@node Shell Parameters -@section Shell Parameters -@cindex parameters -@cindex variable, shell -@cindex shell variable - -@menu -* Positional Parameters:: The shell's command-line arguments. -* Special Parameters:: Parameters denoted by special characters. -@end menu - -A @var{parameter} is an entity that stores values. -It can be a @code{name}, a number, or one of the special characters -listed below. -A @var{variable} is a parameter denoted by a @code{name}. -A variable has a @var{value} and zero or more @var{attributes}. -Attributes are assigned using the @code{declare} builtin command -(see the description of the @code{declare} builtin in @ref{Bash Builtins}). - -A parameter is set if it has been assigned a value. The null string is -a valid value. Once a variable is set, it may be unset only by using -the @code{unset} builtin command. - -A variable may be assigned to by a statement of the form -@example -@var{name}=[@var{value}] -@end example -@noindent -If @var{value} -is not given, the variable is assigned the null string. All -@var{value}s undergo tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote -removal (detailed below). If the variable has its @code{integer} -attribute set, then @var{value} -is evaluated as an arithmetic expression even if the @code{$((@dots{}))} -expansion is not used (@pxref{Arithmetic Expansion}). -Word splitting is not performed, with the exception -of @code{"$@@"} as explained below. -Filename expansion is not performed. -Assignment statements may also appear as arguments to the -@code{alias}, -@code{declare}, @code{typeset}, @code{export}, @code{readonly}, -and @code{local} builtin commands. - -@node Positional Parameters -@subsection Positional Parameters -@cindex parameters, positional - -A @var{positional parameter} is a parameter denoted by one or more -digits, other than the single digit @code{0}. Positional parameters are -assigned from the shell's arguments when it is invoked, -and may be reassigned using the @code{set} builtin command. -Positional parameter @code{N} may be referenced as @code{$@{N@}}, or -as @code{$N} when @code{N} consists of a single digit. -Positional parameters may not be assigned to with assignment statements. -The @code{set} and @code{shift} builtins are used to set and -unset them (@pxref{Shell Builtin Commands}). -The positional parameters are -temporarily replaced when a shell function is executed -(@pxref{Shell Functions}). - -When a positional parameter consisting of more than a single -digit is expanded, it must be enclosed in braces. - -@node Special Parameters -@subsection Special Parameters -@cindex parameters, special - -The shell treats several parameters specially. These parameters may -only be referenced; assignment to them is not allowed. - -@vtable @code - -@item * -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, it expands to a single word -with the value of each parameter separated by the first character -of the @env{IFS} -special variable. That is, @code{"$*"} is equivalent -to @code{"$1@var{c}$2@var{c}@dots{}"}, where @var{c} -is the first character of the value of the @code{IFS} -variable. -If @env{IFS} is unset, the parameters are separated by spaces. -If @env{IFS} is null, the parameters are joined without intervening -separators. - - -@item @@ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, @code{"$@@"} is equivalent to -@code{"$1" "$2" @dots{}}. -When there are no positional parameters, @code{"$@@"} and -@code{$@@} -expand to nothing (i.e., they are removed). - -@item # -Expands to the number of positional parameters in decimal. - -@item ? -Expands to the exit status of the most recently executed foreground -pipeline. - -@item - -(A hyphen.) Expands to the current option flags as specified upon -invocation, by the @code{set} -builtin command, or those set by the shell itself -(such as the @option{-i} option). - -@item $ -Expands to the process @sc{id} of the shell. In a @code{()} subshell, it -expands to the process @sc{id} of the invoking shell, not the subshell. - -@item ! -Expands to the process @sc{id} of the most recently executed background -(asynchronous) command. - -@item 0 -Expands to the name of the shell or shell script. This is set at -shell initialization. If Bash is invoked with a file of commands -(@pxref{Shell Scripts}), @code{$0} is set to the name of that file. -If Bash is started with the @option{-c} option (@pxref{Invoking Bash}), -then @code{$0} is set to the first argument after the string to be -executed, if one is present. Otherwise, it is set -to the filename used to invoke Bash, as given by argument zero. - -@item _ -(An underscore.) -At shell startup, set to the absolute filename of the shell or shell -script being executed as passed in the argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname of each command executed and placed in -the environment exported to that command. -When checking mail, this parameter holds the name of the mail file. -@end vtable - -@node Shell Expansions -@section Shell Expansions -@cindex expansion - -Expansion is performed on the command line after it has been split into -@code{token}s. There are seven kinds of expansion performed: -@itemize @bullet -@item brace expansion -@item tilde expansion -@item parameter and variable expansion -@item command substitution -@item arithmetic expansion -@item word splitting -@item filename expansion -@end itemize - -@menu -* Brace Expansion:: Expansion of expressions within braces. -* Tilde Expansion:: Expansion of the ~ character. -* Shell Parameter Expansion:: How Bash expands variables to their values. -* Command Substitution:: Using the output of a command as an argument. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Process Substitution:: A way to write and read to and from a - command. -* Word Splitting:: How the results of expansion are split into separate - arguments. -* Filename Expansion:: A shorthand for specifying filenames matching patterns. -* Quote Removal:: How and when quote characters are removed from - words. -@end menu - -The order of expansions is: brace expansion, tilde expansion, -parameter, variable, and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and filename -expansion. - -On systems that can support it, there is an additional expansion -available: @var{process substitution}. This is performed at the -same time as parameter, variable, and arithmetic expansion and -command substitution. - -Only brace expansion, word splitting, and filename expansion -can change the number of words of the expansion; other expansions -expand a single word to a single word. -The only exceptions to this are the expansions of -@code{"$@@"} (@pxref{Special Parameters}) and @code{"$@{@var{name}[@@]@}"} -(@pxref{Arrays}). - -After all expansions, @code{quote removal} (@pxref{Quote Removal}) -is performed. - -@node Brace Expansion -@subsection Brace Expansion -@cindex brace expansion -@cindex expansion, brace - -Brace expansion is a mechanism by which arbitrary strings may be generated. -This mechanism is similar to -@var{filename expansion} (@pxref{Filename Expansion}), -but the file names generated need not exist. -Patterns to be brace expanded take the form of an optional @var{preamble}, -followed by either a series of comma-separated strings or a sequnce expression -between a pair of braces, -followed by an optional @var{postscript}. -The preamble is prefixed to each string contained within the braces, and -the postscript is then appended to each resulting string, expanding left -to right. - -Brace expansions may be nested. -The results of each expanded string are not sorted; left to right order -is preserved. -For example, -@example -bash$ echo a@{d,c,b@}e -ade ace abe -@end example - -A sequence expression takes the form @code{@{@var{x}..@var{y}@}}, -where @var{x} and @var{y} are either integers or single characters. -When integers are supplied, the expression expands to each number between -@var{x} and @var{y}, inclusive. -When characters are supplied, the expression expands to each character -lexicographically between @var{x} and @var{y}, inclusive. Note that -both @var{x} and @var{y} must be of the same type. - -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. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. - -A @{ or @samp{,} may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -@example -mkdir /usr/local/src/bash/@{old,new,dist,bugs@} -@end example -or -@example -chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} -@end example - -@node Tilde Expansion -@subsection Tilde Expansion -@cindex tilde expansion -@cindex expansion, tilde - -If a word begins with an unquoted tilde character (@samp{~}), all of the -characters up to the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a @var{tilde-prefix}. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible @var{login name}. -If this login name is the null string, the tilde is replaced with the -value of the @env{HOME} shell variable. -If @env{HOME} is unset, the home directory of the user executing the -shell is substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. - -If the tilde-prefix is @samp{~+}, the value of -the shell variable @env{PWD} replaces the tilde-prefix. -If the tilde-prefix is @samp{~-}, the value of the shell variable -@env{OLDPWD}, if it is set, is substituted. - -If the characters following the tilde in the tilde-prefix consist of a -number @var{N}, optionally prefixed by a @samp{+} or a @samp{-}, -the tilde-prefix is replaced with the -corresponding element from the directory stack, as it would be displayed -by the @code{dirs} builtin invoked with the characters following tilde -in the tilde-prefix as an argument (@pxref{The Directory Stack}). -If the tilde-prefix, sans the tilde, consists of a number without a -leading @samp{+} or @samp{-}, @samp{+} is assumed. - -If the login name is invalid, or the tilde expansion fails, the word is -left unchanged. - -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a @samp{:} or @samp{=}. -In these cases, tilde expansion is also performed. -Consequently, one may use file names with tildes in assignments to -@env{PATH}, @env{MAILPATH}, and @env{CDPATH}, -and the shell assigns the expanded value. - -The following table shows how Bash treats unquoted tilde-prefixes: - -@table @code -@item ~ -The value of @code{$HOME} -@item ~/foo -@file{$HOME/foo} - -@item ~fred/foo -The subdirectory @code{foo} of the home directory of the user -@code{fred} - -@item ~+/foo -@file{$PWD/foo} - -@item ~-/foo -@file{$@{OLDPWD-'~-'@}/foo} - -@item ~@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~+@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~-@var{N} -The string that would be displayed by @samp{dirs -@var{N}} - -@end table - -@node Shell Parameter Expansion -@subsection Shell Parameter Expansion -@cindex parameter expansion -@cindex expansion, parameter - -The @samp{$} character introduces parameter expansion, -command substitution, or arithmetic expansion. The parameter name -or symbol to be expanded may be enclosed in braces, which -are optional but serve to protect the variable to be expanded from -characters immediately following it which could be -interpreted as part of the name. - -When braces are used, the matching ending brace is the first @samp{@}} -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or parameter -expansion. - -The basic form of parameter expansion is $@{@var{parameter}@}. -The value of @var{parameter} is substituted. The braces are required -when @var{parameter} -is a positional parameter with more than one digit, -or when @var{parameter} -is followed by a character that is not to be -interpreted as part of its name. - -If the first character of @var{parameter} is an exclamation point, -a level of variable indirection is introduced. -Bash uses the value of the variable formed from the rest of -@var{parameter} as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of @var{parameter} itself. -This is known as @code{indirect expansion}. -The exceptions to this are the expansions of $@{!@var{prefix*}@} -and $@{!@var{name}[@@]@} -described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. - -In each of the cases below, @var{word} is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. - -When not performing substring expansion, Bash tests for a parameter -that is unset or null; omitting the colon results in a test only for a -parameter that is unset. Put another way, if the colon is included, -the operator tests for both existence and that the value is not null; -if the colon is omitted, the operator tests only for existence. - -@table @code - -@item $@{@var{parameter}:@minus{}@var{word}@} -If @var{parameter} is unset or null, the expansion of -@var{word} is substituted. Otherwise, the value of -@var{parameter} is substituted. - -@item $@{@var{parameter}:=@var{word}@} -If @var{parameter} -is unset or null, the expansion of @var{word} -is assigned to @var{parameter}. -The value of @var{parameter} is then substituted. -Positional parameters and special parameters may not be assigned to -in this way. - -@item $@{@var{parameter}:?@var{word}@} -If @var{parameter} -is null or unset, the expansion of @var{word} (or a message -to that effect if @var{word} -is not present) is written to the standard error and the shell, if it -is not interactive, exits. Otherwise, the value of @var{parameter} is -substituted. - -@item $@{@var{parameter}:+@var{word}@} -If @var{parameter} -is null or unset, nothing is substituted, otherwise the expansion of -@var{word} is substituted. - -@item $@{@var{parameter}:@var{offset}@} -@itemx $@{@var{parameter}:@var{offset}:@var{length}@} -Expands to up to @var{length} characters of @var{parameter} -starting at the character specified by @var{offset}. -If @var{length} is omitted, expands to the substring of -@var{parameter} starting at the character specified by @var{offset}. -@var{length} and @var{offset} are arithmetic expressions -(@pxref{Shell Arithmetic}). -This is referred to as Substring Expansion. - -@var{length} must evaluate to a number greater than or equal to zero. -If @var{offset} evaluates to a number less than zero, the value -is used as an offset from the end of the value of @var{parameter}. -If @var{parameter} is @samp{@@}, the result is @var{length} positional -parameters beginning at @var{offset}. -If @var{parameter} is an array name indexed by @samp{@@} or @samp{*}, -the result is the @var{length} -members of the array beginning with @code{$@{@var{parameter}[@var{offset}]@}}. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1. - -@item $@{!@var{prefix}*@} -@itemx $@{!@var{prefix}@@@} -Expands to the names of variables whose names begin with @var{prefix}, -separated by the first character of the @env{IFS} special variable. - -@item $@{!@var{name}[@@]@} -@itemx $@{!@var{name}[*]@} -If @var{name} is an array variable, expands to the list of array indices -(keys) assigned in @var{name}. -If @var{name} is not an array, expands to 0 if @var{name} is set and null -otherwise. -When @samp{@@} is used and the expansion appears within double quotes, each -key expands to a separate word. - -@item $@{#@var{parameter}@} -The length in characters of the expanded value of @var{parameter} is -substituted. -If @var{parameter} is @samp{*} or @samp{@@}, the value substituted -is the number of positional parameters. -If @var{parameter} is an array name subscripted by @samp{*} or @samp{@@}, -the value substituted is the number of elements in the array. - -@item $@{@var{parameter}#@var{word}@} -@itemx $@{@var{parameter}##@var{word}@} -The @var{word} -is expanded to produce a pattern just as in filename -expansion (@pxref{Filename Expansion}). If the pattern matches -the beginning of the expanded value of @var{parameter}, -then the result of the expansion is the expanded value of @var{parameter} -with the shortest matching pattern (the @samp{#} case) or the -longest matching pattern (the @samp{##} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} is an array variable subscripted with -@samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}%@var{word}@} -@itemx $@{@var{parameter}%%@var{word}@} -The @var{word} is expanded to produce a pattern just as in -filename expansion. -If the pattern matches a trailing portion of the expanded value of -@var{parameter}, then the result of the expansion is the value of -@var{parameter} with the shortest matching pattern (the @samp{%} case) -or the longest matching pattern (the @samp{%%} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}/@var{pattern}/@var{string}@} -@itemx $@{@var{parameter}//@var{pattern}/@var{string}@} - -The @var{pattern} is expanded to produce a pattern just as in -filename expansion. -@var{Parameter} is expanded and the longest match of @var{pattern} -against its value is replaced with @var{string}. -In the first form, only the first match is replaced. -The second form causes all matches of @var{pattern} to be -replaced with @var{string}. -If @var{pattern} begins with @samp{#}, it must match at the beginning -of the expanded value of @var{parameter}. -If @var{pattern} begins with @samp{%}, it must match at the end -of the expanded value of @var{parameter}. -If @var{string} is null, matches of @var{pattern} are deleted -and the @code{/} following @var{pattern} may be omitted. -If @var{parameter} is @samp{@@} or @samp{*}, -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@end table - -@node Command Substitution -@subsection Command Substitution -@cindex command substitution - -Command substitution allows the output of a command to replace -the command itself. -Command substitution occurs when a command is enclosed as follows: -@example -$(@var{command}) -@end example -@noindent -or -@example -`@var{command}` -@end example - -@noindent -Bash performs the expansion by executing @var{command} and -replacing the command substitution with the standard output of the -command, with any trailing newlines deleted. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution @code{$(cat @var{file})} can be -replaced by the equivalent but faster @code{$(< @var{file})}. - -When the old-style backquote form of substitution is used, -backslash retains its literal meaning except when followed by -@samp{$}, @samp{`}, or @samp{\}. -The first backquote not preceded by a backslash terminates the -command substitution. -When using the @code{$(@var{command})} form, all characters between -the parentheses make up the command; none are treated specially. - -Command substitutions may be nested. To nest when using the backquoted -form, escape the inner backquotes with backslashes. - -If the substitution appears within double quotes, word splitting and -filename expansion are not performed on the results. - -@node Arithmetic Expansion -@subsection Arithmetic Expansion -@cindex expansion, arithmetic -@cindex arithmetic expansion - -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. The format for arithmetic expansion is: - -@example -$(( @var{expression} )) -@end example - -The expression is treated as if it were within double quotes, but -a double quote inside the parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, command -substitution, and quote removal. -Arithmetic expansions may be nested. - -The evaluation is performed according to the rules listed below -(@pxref{Shell Arithmetic}). -If the expression is invalid, Bash prints a message indicating -failure to the standard error and no substitution occurs. - -@node Process Substitution -@subsection Process Substitution -@cindex process substitution - -Process substitution is supported on systems that support named -pipes (@sc{fifo}s) or the @file{/dev/fd} method of naming open files. -It takes the form of -@example -<(@var{list}) -@end example -@noindent -or -@example ->(@var{list}) -@end example -@noindent -The process @var{list} is run with its input or output connected to a -@sc{fifo} or some file in @file{/dev/fd}. The name of this file is -passed as an argument to the current command as the result of the -expansion. If the @code{>(@var{list})} form is used, writing to -the file will provide input for @var{list}. If the -@code{<(@var{list})} form is used, the file passed as an -argument should be read to obtain the output of @var{list}. -Note that no space may appear between the @code{<} or @code{>} -and the left parenthesis, otherwise the construct would be interpreted -as a redirection. - -When available, process substitution is performed simultaneously with -parameter and variable expansion, command substitution, and arithmetic -expansion. - -@node Word Splitting -@subsection Word Splitting -@cindex word splitting - -The shell scans the results of parameter expansion, command substitution, -and arithmetic expansion that did not occur within double quotes for -word splitting. - -The shell treats each character of @env{$IFS} -as a delimiter, and splits the results of the other -expansions into words on these characters. If -@env{IFS} is unset, or its value is exactly @code{}, -the default, then any sequence of @env{IFS} -characters serves to delimit words. If @env{IFS} -has a value other than the default, then sequences of -the whitespace characters @code{space} and @code{tab} -are ignored at the beginning and end of the -word, as long as the whitespace character is in the -value of @env{IFS} (an @env{IFS} whitespace character). -Any character in @env{IFS} that is not @env{IFS} -whitespace, along with any adjacent @env{IFS} -whitespace characters, delimits a field. A sequence of @env{IFS} -whitespace characters is also treated as a delimiter. -If the value of @env{IFS} is null, no word splitting occurs. - -Explicit null arguments (@code{""} or @code{''}) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. - -Note that if no expansion occurs, no splitting -is performed. - -@node Filename Expansion -@subsection Filename Expansion -@menu -* Pattern Matching:: How the shell matches patterns. -@end menu -@cindex expansion, filename -@cindex expansion, pathname -@cindex filename expansion -@cindex pathname expansion - -After word splitting, unless the @option{-f} option has been set -(@pxref{The Set Builtin}), Bash scans each word for the characters -@samp{*}, @samp{?}, and @samp{[}. -If one of these characters appears, then the word is -regarded as a @var{pattern}, -and replaced with an alphabetically sorted list of -file names matching the pattern. If no matching file names are found, -and the shell option @code{nullglob} is disabled, the word is left -unchanged. -If the @code{nullglob} option is set, and no matches are found, the word -is removed. -If the @code{failglob} shell option is set, and no matches are found, -an error message is printed and the command is not executed. -If the shell option @code{nocaseglob} is enabled, the match is performed -without regard to the case of alphabetic characters. - -When a pattern is used for filename generation, the character @samp{.} -at the start of a filename or immediately following a slash -must be matched explicitly, unless the shell option @code{dotglob} is set. -When matching a file name, the slash character must always be -matched explicitly. -In other cases, the @samp{.} character is not treated specially. - -See the description of @code{shopt} in @ref{Bash Builtins}, -for a description of the @code{nocaseglob}, @code{nullglob}, -@code{failglob}, and @code{dotglob} options. - -The @env{GLOBIGNORE} -shell variable may be used to restrict the set of filenames matching a -pattern. If @env{GLOBIGNORE} -is set, each matching filename that also matches one of the patterns in -@env{GLOBIGNORE} is removed from the list of matches. The filenames -@file{.} and @file{..} -are always ignored when @env{GLOBIGNORE} -is set and not null. -However, setting @env{GLOBIGNORE} to a non-null value has the effect of -enabling the @code{dotglob} -shell option, so all other filenames beginning with a -@samp{.} will match. -To get the old behavior of ignoring filenames beginning with a -@samp{.}, make @samp{.*} one of the patterns in @env{GLOBIGNORE}. -The @code{dotglob} option is disabled when @env{GLOBIGNORE} -is unset. - -@node Pattern Matching -@subsubsection Pattern Matching -@cindex pattern matching -@cindex matching, pattern - -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. -The @sc{nul} character may not occur in a pattern. -A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if they are to be matched -literally. - -The special pattern characters have the following meanings: -@table @code -@item * -Matches any string, including the null string. -@item ? -Matches any single character. -@item [@dots{}] -Matches any one of the enclosed characters. A pair of characters -separated by a hyphen denotes a @var{range expression}; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -@samp{[} is a @samp{!} or a @samp{^} -then any character not enclosed is matched. A @samp{@minus{}} -may be matched by including it as the first or last character -in the set. A @samp{]} may be matched by including it as the first -character in the set. -The sorting order of characters in range expressions is determined by -the current locale and the value of the @env{LC_COLLATE} shell variable, -if set. - -For example, in the default C locale, @samp{[a-dx-z]} is equivalent to -@samp{[abcdxyz]}. Many locales sort characters in dictionary order, and in -these locales @samp{[a-dx-z]} is typically not equivalent to @samp{[abcdxyz]}; -it might be equivalent to @samp{[aBbCcDdxXyYz]}, for example. To obtain -the traditional interpretation of ranges in bracket expressions, you can -force the use of the C locale by setting the @env{LC_COLLATE} or -@env{LC_ALL} environment variable to the value @samp{C}. - -Within @samp{[} and @samp{]}, @var{character classes} can be specified -using the syntax -@code{[:}@var{class}@code{:]}, where @var{class} is one of the -following classes defined in the @sc{posix} 1003.2 standard: -@example -alnum alpha ascii blank cntrl digit graph lower -print punct space upper word xdigit -@end example -@noindent -A character class matches any character belonging to that class. -The @code{word} character class matches letters, digits, and the character -@samp{_}. - -Within @samp{[} and @samp{]}, an @var{equivalence class} can be -specified using the syntax @code{[=}@var{c}@code{=]}, which -matches all characters with the same collation weight (as defined -by the current locale) as the character @var{c}. - -Within @samp{[} and @samp{]}, the syntax @code{[.}@var{symbol}@code{.]} -matches the collating symbol @var{symbol}. -@end table - -If the @code{extglob} shell option is enabled using the @code{shopt} -builtin, several extended pattern matching operators are recognized. -In the following description, a @var{pattern-list} is a list of one -or more patterns separated by a @samp{|}. -Composite patterns may be formed using one or more of the following -sub-patterns: - -@table @code -@item ?(@var{pattern-list}) -Matches zero or one occurrence of the given patterns. - -@item *(@var{pattern-list}) -Matches zero or more occurrences of the given patterns. - -@item +(@var{pattern-list}) -Matches one or more occurrences of the given patterns. - -@item @@(@var{pattern-list}) -Matches exactly one of the given patterns. - -@item !(@var{pattern-list}) -Matches anything except one of the given patterns. -@end table - -@node Quote Removal -@subsection Quote Removal - -After the preceding expansions, all unquoted occurrences of the -characters @samp{\}, @samp{'}, and @samp{"} that did not -result from one of the above expansions are removed. - -@node Redirections -@section Redirections -@cindex redirection - -Before a command is executed, its input and output -may be @var{redirected} -using a special notation interpreted by the shell. -Redirection may also be used to open and close files for the -current shell execution environment. The following redirection -operators may precede or appear anywhere within a -simple command or may follow a command. -Redirections are processed in the order they appear, from -left to right. - -In the following descriptions, if the file descriptor number is -omitted, and the first character of the redirection operator is -@samp{<}, the redirection refers to the standard input (file -descriptor 0). If the first character of the redirection operator -is @samp{>}, the redirection refers to the standard output (file -descriptor 1). - -The word following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to brace expansion, -tilde expansion, parameter expansion, command substitution, arithmetic -expansion, quote removal, filename expansion, and word splitting. -If it expands to more than one word, Bash reports an error. - -Note that the order of redirections is significant. For example, -the command -@example -ls > @var{dirlist} 2>&1 -@end example -@noindent -directs both standard output (file descriptor 1) and standard error -(file descriptor 2) to the file @var{dirlist}, while the command -@example -ls 2>&1 > @var{dirlist} -@end example -@noindent -directs only the standard output to file @var{dirlist}, -because the standard error was duplicated as standard output -before the standard output was redirected to @var{dirlist}. - -Bash handles several filenames specially when they are used in -redirections, as described in the following table: - -@table @code -@item /dev/fd/@var{fd} -If @var{fd} is a valid integer, file descriptor @var{fd} is duplicated. - -@item /dev/stdin -File descriptor 0 is duplicated. - -@item /dev/stdout -File descriptor 1 is duplicated. - -@item /dev/stderr -File descriptor 2 is duplicated. - -@item /dev/tcp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open a TCP -connection to the corresponding socket. - -@item /dev/udp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open a UDP -connection to the corresponding socket. - -@end table - -A failure to open or create a file causes the redirection to fail. - -@subsection Redirecting Input -Redirection of input causes the file whose name results from -the expansion of @var{word} -to be opened for reading on file descriptor @code{n}, -or the standard input (file descriptor 0) if @code{n} -is not specified. - -The general format for redirecting input is: -@example -[@var{n}]<@var{word} -@end example - -@subsection Redirecting Output -Redirection of output causes the file whose name results from -the expansion of @var{word} -to be opened for writing on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created; -if it does exist it is truncated to zero size. - -The general format for redirecting output is: -@example -[@var{n}]>[|]@var{word} -@end example - -If the redirection operator is @samp{>}, and the @code{noclobber} -option to the @code{set} builtin has been enabled, the redirection -will fail if the file whose name results from the expansion of -@var{word} exists and is a regular file. -If the redirection operator is @samp{>|}, or the redirection operator is -@samp{>} and the @code{noclobber} option is not enabled, the redirection -is attempted even if the file named by @var{word} exists. - -@subsection Appending Redirected Output -Redirection of output in this fashion -causes the file whose name results from -the expansion of @var{word} -to be opened for appending on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created. - -The general format for appending output is: -@example -[@var{n}]>>@var{word} -@end example - -@subsection Redirecting Standard Output and Standard Error -Bash allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be redirected to the file whose name is the -expansion of @var{word} with this construct. - -There are two formats for redirecting standard output and -standard error: -@example -&>@var{word} -@end example -@noindent -and -@example ->&@var{word} -@end example -@noindent -Of the two forms, the first is preferred. -This is semantically equivalent to -@example ->@var{word} 2>&1 -@end example - -@subsection Here Documents -This type of redirection instructs the shell to read input from the -current source until a line containing only @var{word} -(with no trailing blanks) is seen. All of -the lines read up to that point are then used as the standard -input for a command. - -The format of here-documents is: -@example -<<[@minus{}]@var{word} - @var{here-document} -@var{delimiter} -@end example - -No parameter expansion, command substitution, arithmetic expansion, -or filename expansion is performed on -@var{word}. If any characters in @var{word} are quoted, the -@var{delimiter} is the result of quote removal on @var{word}, -and the lines in the here-document are not expanded. -If @var{word} is unquoted, -all lines of the here-document are subjected to parameter expansion, -command substitution, and arithmetic expansion. In the latter -case, the character sequence @code{\newline} is ignored, and @samp{\} -must be used to quote the characters -@samp{\}, @samp{$}, and @samp{`}. - -If the redirection operator is @samp{<<-}, -then all leading tab characters are stripped from input lines and the -line containing @var{delimiter}. -This allows here-documents within shell scripts to be indented in a -natural fashion. - -@subsection Here Strings -A variant of here documents, the format is: -@example -<<< @var{word} -@end example - -The @var{word} is expanded and supplied to the command on its standard -input. - -@subsection Duplicating File Descriptors -The redirection operator -@example -[@var{n}]<&@var{word} -@end example -@noindent -is used to duplicate input file descriptors. -If @var{word} -expands to one or more digits, the file descriptor denoted by @var{n} -is made to be a copy of that file descriptor. -If the digits in @var{word} do not specify a file descriptor open for -input, a redirection error occurs. -If @var{word} -evaluates to @samp{-}, file descriptor @var{n} is closed. If -@var{n} is not specified, the standard input (file descriptor 0) is used. - -The operator -@example -[@var{n}]>&@var{word} -@end example -@noindent -is used similarly to duplicate output file descriptors. If -@var{n} is not specified, the standard output (file descriptor 1) is used. -If the digits in @var{word} do not specify a file descriptor open for -output, a redirection error occurs. -As a special case, if @var{n} is omitted, and @var{word} does not -expand to one or more digits, the standard output and standard -error are redirected as described previously. - -@subsection Moving File Descriptors -The redirection operator -@example -[@var{n}]<&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard input (file descriptor 0) if @var{n} is not specified. -@var{digit} is closed after being duplicated to @var{n}. - -Similarly, the redirection operator -@example -[@var{n}]>&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} is not specified. - -@subsection Opening File Descriptors for Reading and Writing -The redirection operator -@example -[@var{n}]<>@var{word} -@end example -@noindent -causes the file whose name is the expansion of @var{word} -to be opened for both reading and writing on file descriptor -@var{n}, or on file descriptor 0 if @var{n} -is not specified. If the file does not exist, it is created. - -@node Executing Commands -@section Executing Commands - -@menu -* Simple Command Expansion:: How Bash expands simple commands before - executing them. - -* Command Search and Execution:: How Bash finds commands and runs them. - -* Command Execution Environment:: The environment in which Bash - executes commands that are not - shell builtins. - -* Environment:: The environment given to a command. - -* Exit Status:: The status returned by commands and how Bash - interprets it. - -* Signals:: What happens when Bash or a command it runs - receives a signal. - -@end menu - -@node Simple Command Expansion -@subsection Simple Command Expansion -@cindex command expansion - -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. - -@enumerate -@item -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. - -@item -The words that are not variable assignments or redirections are -expanded (@pxref{Shell Expansions}). -If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. - -@item -Redirections are performed as described above (@pxref{Redirections}). - -@item -The text after the @samp{=} in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -@end enumerate - -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. - -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. - -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. - -@node Command Search and Execution -@subsection Command Search and Execution -@cindex command execution -@cindex command search - -After a command has been split into words, if it results in a -simple command and an optional list of arguments, the following -actions are taken. - -@enumerate -@item -If the command name contains no slashes, the shell attempts to -locate it. If there exists a shell function by that name, that -function is invoked as described in @ref{Shell Functions}. - -@item -If the name does not match a function, the shell searches for -it in the list of shell builtins. If a match is found, that -builtin is invoked. - -@item -If the name is neither a shell function nor a builtin, -and contains no slashes, Bash searches each element of -@env{$PATH} for a directory containing an executable file -by that name. Bash uses a hash table to remember the full -pathnames of executable files to avoid multiple @env{PATH} searches -(see the description of @code{hash} in @ref{Bourne Shell Builtins}). -A full search of the directories in @env{$PATH} -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell prints an error -message and returns an exit status of 127. - -@item -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in -a separate execution environment. -Argument 0 is set to the name given, and the remaining arguments -to the command are set to the arguments supplied, if any. - -@item -If this execution fails because the file is not in executable -format, and the file is not a directory, it is assumed to be a -@var{shell script} and the shell executes it as described in -@ref{Shell Scripts}. - -@item -If the command was not begun asynchronously, the shell waits for -the command to complete and collects its exit status. - -@end enumerate - -@node Command Execution Environment -@subsection Command Execution Environment -@cindex execution environment - -The shell has an @var{execution environment}, which consists of the -following: - -@itemize @bullet -@item -open files inherited by the shell at invocation, as modified by -redirections supplied to the @code{exec} builtin - -@item -the current working directory as set by @code{cd}, @code{pushd}, or -@code{popd}, or inherited by the shell at invocation - -@item -the file creation mode mask as set by @code{umask} or inherited from -the shell's parent - -@item -current traps set by @code{trap} - -@item -shell parameters that are set by variable assignment or with @code{set} -or inherited from the shell's parent in the environment - -@item -shell functions defined during execution or inherited from the shell's -parent in the environment - -@item -options enabled at invocation (either by default or with command-line -arguments) or by @code{set} - -@item -options enabled by @code{shopt} - -@item -shell aliases defined with @code{alias} (@pxref{Aliases}) - -@item -various process @sc{id}s, including those of background jobs -(@pxref{Lists}), the value of @code{$$}, and the value of -@env{$PPID} - -@end itemize - -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. - -@itemize @bullet -@item -the shell's open files, plus any modifications and additions specified -by redirections to the command - -@item -the current working directory - -@item -the file creation mode mask - -@item -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment (@pxref{Environment}) - -@item -traps caught by the shell are reset to the values inherited from the -shell's parent, and traps ignored by the shell are ignored - -@end itemize - -A command invoked in this separate environment cannot affect the -shell's execution environment. - -Command substitution, commands grouped with parentheses, -and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed -in a subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. - -If a command is followed by a @samp{&} and job control is not active, the -default standard input for the command is the empty file @file{/dev/null}. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. - -@node Environment -@subsection Environment -@cindex environment - -When a program is invoked it is given an array of strings -called the @var{environment}. -This is a list of name-value pairs, of the form @code{name=value}. - -Bash provides several ways to manipulate the environment. -On invocation, the shell scans its own environment and -creates a parameter for each name found, automatically marking -it for @var{export} -to child processes. Executed commands inherit the environment. -The @code{export} and @samp{declare -x} -commands allow parameters and functions to be added to and -deleted from the environment. If the value of a parameter -in the environment is modified, the new value becomes part -of the environment, replacing the old. The environment -inherited by any executed command consists of the shell's -initial environment, whose values may be modified in the shell, -less any pairs removed by the @code{unset} and @samp{export -n} -commands, plus any additions via the @code{export} and -@samp{declare -x} commands. - -The environment for any simple command -or function may be augmented temporarily by prefixing it with -parameter assignments, as described in @ref{Shell Parameters}. -These assignment statements affect only the environment seen -by that command. - -If the @option{-k} option is set (@pxref{The Set Builtin}), then all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. - -When Bash invokes an external command, the variable @samp{$_} -is set to the full path name of the command and passed to that -command in its environment. - -@node Exit Status -@subsection Exit Status -@cindex exit status - -For the shell's purposes, a command which exits with a -zero exit status has succeeded. -A non-zero exit status indicates failure. -This seemingly counter-intuitive scheme is used so there -is one well-defined way to indicate success and a variety of -ways to indicate various failure modes. -When a command terminates on a fatal signal whose number is @var{N}, -Bash uses the value 128+@var{N} as the exit status. - -If a command is not found, the child process created to -execute it returns a status of 127. If a command is found -but is not executable, the return status is 126. - -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. - -The exit status is used by the Bash conditional commands -(@pxref{Conditional Constructs}) and some of the list -constructs (@pxref{Lists}). - -All of the Bash builtins return an exit status of zero if they succeed -and a non-zero status on failure, so they may be used by the -conditional and list constructs. -All builtins return an exit status of 2 to indicate incorrect usage. - -@node Signals -@subsection Signals -@cindex signal handling - -When Bash is interactive, in the absence of any traps, it ignores -@code{SIGTERM} (so that @samp{kill 0} does not kill an interactive shell), -and @code{SIGINT} -is caught and handled (so that the @code{wait} builtin is interruptible). -When Bash receives a @code{SIGINT}, it breaks out of any executing loops. -In all cases, Bash ignores @code{SIGQUIT}. -If job control is in effect (@pxref{Job Control}), Bash -ignores @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -Non-builtin commands started by Bash have signal handlers set to the -values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore @code{SIGINT} and @code{SIGQUIT} in addition to these inherited -handlers. -Commands run as a result of -command substitution ignore the keyboard-generated job control signals -@code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -The shell exits by default upon receipt of a @code{SIGHUP}. -Before exiting, an interactive shell resends the @code{SIGHUP} to -all jobs, running or stopped. -Stopped jobs are sent @code{SIGCONT} to ensure that they receive -the @code{SIGHUP}. -To prevent the shell from sending the @code{SIGHUP} signal to a -particular job, it should be removed -from the jobs table with the @code{disown} -builtin (@pxref{Job Control Builtins}) or marked -to not receive @code{SIGHUP} using @code{disown -h}. - -If the @code{huponexit} shell option has been set with @code{shopt} -(@pxref{Bash Builtins}), Bash sends a @code{SIGHUP} to all jobs when -an interactive login shell exits. - -If Bash is waiting for a command to complete and receives a signal -for which a trap has been set, the trap will not be executed until -the command completes. -When Bash is waiting for an asynchronous -command via the @code{wait} builtin, the reception of a signal for -which a trap has been set will cause the @code{wait} builtin to return -immediately with an exit status greater than 128, immediately after -which the trap is executed. - -@node Shell Scripts -@section Shell Scripts -@cindex shell script - -A shell script is a text file containing shell commands. When such -a file is used as the first non-option argument when invoking Bash, -and neither the @option{-c} nor @option{-s} option is supplied -(@pxref{Invoking Bash}), -Bash reads and executes commands from the file, then exits. This -mode of operation creates a non-interactive shell. The shell first -searches for the file in the current directory, and looks in the -directories in @env{$PATH} if not found there. - -When Bash runs -a shell script, it sets the special parameter @code{0} to the name -of the file, rather than the name of the shell, and the positional -parameters are set to the remaining arguments, if any are given. -If no additional arguments are supplied, the positional parameters -are unset. - -A shell script may be made executable by using the @code{chmod} command -to turn on the execute bit. When Bash finds such a file while -searching the @env{$PATH} for a command, it spawns a subshell to -execute it. In other words, executing -@example -filename @var{arguments} -@end example -@noindent -is equivalent to executing -@example -bash filename @var{arguments} -@end example - -@noindent -if @code{filename} is an executable shell script. -This subshell reinitializes itself, so that the effect is as if a -new shell had been invoked to interpret the script, with the -exception that the locations of commands remembered by the parent -(see the description of @code{hash} in @ref{Bourne Shell Builtins}) -are retained by the child. - -Most versions of Unix make this a part of the operating system's command -execution mechanism. If the first line of a script begins with -the two characters @samp{#!}, the remainder of the line specifies -an interpreter for the program. -Thus, you can specify Bash, @code{awk}, Perl, or some other -interpreter and write the rest of the script file in that language. - -The arguments to the interpreter -consist of a single optional argument following the interpreter -name on the first line of the script file, followed by the name of -the script file, followed by the rest of the arguments. Bash -will perform this action on operating systems that do not handle it -themselves. Note that some older versions of Unix limit the interpreter -name and argument to a maximum of 32 characters. - -Bash scripts often begin with @code{#! /bin/bash} (assuming that -Bash has been installed in @file{/bin}), since this ensures that -Bash will be used to interpret the script, even if it is executed -under another shell. - -@node Shell Builtin Commands -@chapter Shell Builtin Commands - -@menu -* Bourne Shell Builtins:: Builtin commands inherited from the Bourne - Shell. -* Bash Builtins:: Table of builtins specific to Bash. -* The Set Builtin:: This builtin is so overloaded it - deserves its own section. -* Special Builtins:: Builtin commands classified specially by - POSIX.2. -@end menu - -Builtin commands are contained within the shell itself. -When the name of a builtin command is used as the first word of -a simple command (@pxref{Simple Commands}), the shell executes -the command directly, without invoking another program. -Builtin commands are necessary to implement functionality impossible -or inconvenient to obtain with separate utilities. - -This section briefly the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -Several builtin commands are described in other chapters: builtin -commands which provide the Bash interface to the job control -facilities (@pxref{Job Control Builtins}), the directory stack -(@pxref{Directory Stack Builtins}), the command history -(@pxref{Bash History Builtins}), and the programmable completion -facilities (@pxref{Programmable Completion Builtins}). - -Many of the builtins have been extended by @sc{posix} or Bash. - -Unless otherwise noted, each builtin command documented as accepting -options preceded by @samp{-} accepts @samp{--} -to signify the end of the options. - -@node Bourne Shell Builtins -@section Bourne Shell Builtins - -The following shell builtin commands are inherited from the Bourne Shell. -These commands are implemented as specified by the @sc{posix} 1003.2 standard. - -@table @code -@item : @r{(a colon)} -@btindex : -@example -: [@var{arguments}] -@end example -Do nothing beyond expanding @var{arguments} and performing redirections. -The return status is zero. - -@item . @r{(a period)} -@btindex . -@example -. @var{filename} [@var{arguments}] -@end example -Read and execute commands from the @var{filename} argument in the -current shell context. If @var{filename} does not contain a slash, -the @env{PATH} variable is used to find @var{filename}. -When Bash is not in @sc{posix} mode, the current directory is searched -if @var{filename} is not found in @env{$PATH}. -If any @var{arguments} are supplied, they become the positional -parameters when @var{filename} is executed. Otherwise the positional -parameters are unchanged. -The return status is the exit status of the last command executed, or -zero if no commands are executed. If @var{filename} is not found, or -cannot be read, the return status is non-zero. -This builtin is equivalent to @code{source}. - -@item break -@btindex break -@example -break [@var{n}] -@end example -Exit from a @code{for}, @code{while}, @code{until}, or @code{select} loop. -If @var{n} is supplied, the @var{n}th enclosing loop is exited. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item cd -@btindex cd -@example -cd [-L|-P] [@var{directory}] -@end example -Change the current working directory to @var{directory}. -If @var{directory} is not given, the value of the @env{HOME} shell -variable is used. -If the shell variable @env{CDPATH} exists, it is used as a search path. -If @var{directory} begins with a slash, @env{CDPATH} is not used. - -The @option{-P} option means to not follow symbolic links; symbolic -links are followed by default or with the @option{-L} option. -If @var{directory} is @samp{-}, it is equivalent to @env{$OLDPWD}. - -If a non-empty directory name from @env{CDPATH} is used, or if -@samp{-} is the first argument, and the directory change is -successful, the absolute pathname of the new working directory is -written to the standard output. - -The return status is zero if the directory is successfully changed, -non-zero otherwise. - -@item continue -@btindex continue -@example -continue [@var{n}] -@end example -Resume the next iteration of an enclosing @code{for}, @code{while}, -@code{until}, or @code{select} loop. -If @var{n} is supplied, the execution of the @var{n}th enclosing loop -is resumed. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item eval -@btindex eval -@example -eval [@var{arguments}] -@end example -The arguments are concatenated together into a single command, which is -then read and executed, and its exit status returned as the exit status -of @code{eval}. -If there are no arguments or only empty arguments, the return status is -zero. - -@item exec -@btindex exec -@example -exec [-cl] [-a @var{name}] [@var{command} [@var{arguments}]] -@end example -If @var{command} -is supplied, it replaces the shell without creating a new process. -If the @option{-l} option is supplied, the shell places a dash at the -beginning of the zeroth arg passed to @var{command}. -This is what the @code{login} program does. -The @option{-c} option causes @var{command} to be executed with an empty -environment. -If @option{-a} is supplied, the shell passes @var{name} as the zeroth -argument to @var{command}. -If no @var{command} is specified, redirections may be used to affect -the current shell environment. If there are no redirection errors, the -return status is zero; otherwise the return status is non-zero. - -@item exit -@btindex exit -@example -exit [@var{n}] -@end example -Exit the shell, returning a status of @var{n} to the shell's parent. -If @var{n} is omitted, the exit status is that of the last command executed. -Any trap on @code{EXIT} is executed before the shell terminates. - -@item export -@btindex export -@example -export [-fn] [-p] [@var{name}[=@var{value}]] -@end example -Mark each @var{name} to be passed to child processes -in the environment. If the @option{-f} option is supplied, the @var{name}s -refer to shell functions; otherwise the names refer to shell variables. -The @option{-n} option means to no longer mark each @var{name} for export. -If no @var{names} are supplied, or if the @option{-p} option is given, a -list of exported names is displayed. -The @option{-p} option displays output in a form that may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. - -The return status is zero unless an invalid option is supplied, one of -the names is not a valid shell variable name, or @option{-f} is supplied -with a name that is not a shell function. - -@item getopts -@btindex getopts -@example -getopts @var{optstring} @var{name} [@var{args}] -@end example -@code{getopts} is used by shell scripts to parse positional parameters. -@var{optstring} contains the option characters to be recognized; if a -character is followed by a colon, the option is expected to have an -argument, which should be separated from it by white space. -The colon (@samp{:}) and question mark (@samp{?}) may not be -used as option characters. -Each time it is invoked, @code{getopts} -places the next option in the shell variable @var{name}, initializing -@var{name} if it does not exist, -and the index of the next argument to be processed into the -variable @env{OPTIND}. -@env{OPTIND} is initialized to 1 each time the shell or a shell script -is invoked. -When an option requires an argument, -@code{getopts} places that argument into the variable @env{OPTARG}. -The shell does not reset @env{OPTIND} automatically; it must be manually -reset between multiple calls to @code{getopts} within the same shell -invocation if a new set of parameters is to be used. - -When the end of options is encountered, @code{getopts} exits with a -return value greater than zero. -@env{OPTIND} is set to the index of the first non-option argument, -and @code{name} is set to @samp{?}. - -@code{getopts} -normally parses the positional parameters, but if more arguments are -given in @var{args}, @code{getopts} parses those instead. - -@code{getopts} can report errors in two ways. If the first character of -@var{optstring} is a colon, @var{silent} -error reporting is used. In normal operation diagnostic messages -are printed when invalid options or missing option arguments are -encountered. -If the variable @env{OPTERR} -is set to 0, no error messages will be displayed, even if the first -character of @code{optstring} is not a colon. - -If an invalid option is seen, -@code{getopts} places @samp{?} into @var{name} and, if not silent, -prints an error message and unsets @env{OPTARG}. -If @code{getopts} is silent, the option character found is placed in -@env{OPTARG} and no diagnostic message is printed. - -If a required argument is not found, and @code{getopts} -is not silent, a question mark (@samp{?}) is placed in @var{name}, -@code{OPTARG} is unset, and a diagnostic message is printed. -If @code{getopts} is silent, then a colon (@samp{:}) is placed in -@var{name} and @env{OPTARG} is set to the option character found. - -@item hash -@btindex hash -@example -hash [-'r] [-p @var{filename}] [-dt] [@var{name}] -@end example -Remember the full pathnames of commands specified as @var{name} arguments, -so they need not be searched for on subsequent invocations. -The commands are found by searching through the directories listed in -@env{$PATH}. -The @option{-p} option inhibits the path search, and @var{filename} is -used as the location of @var{name}. -The @option{-r} option causes the shell to forget all remembered locations. -The @option{-d} option causes the shell to forget the remembered location -of each @var{name}. -If the @option{-t} option is supplied, the full pathname to which each -@var{name} corresponds is printed. If multiple @var{name} arguments are -supplied with @option{-t} the @var{name} is printed before the hashed -full pathname. -The @option{-l} option causes output to be displayed in a format -that may be reused as input. -If no arguments are given, or if only @option{-l} is supplied, -information about remembered commands is printed. -The return status is zero unless a @var{name} is not found or an invalid -option is supplied. - -@item pwd -@btindex pwd -@example -pwd [-LP] -@end example -Print the absolute pathname of the current working directory. -If the @option{-P} option is supplied, the pathname printed will not -contain symbolic links. -If the @option{-L} option is supplied, the pathname printed may contain -symbolic links. -The return status is zero unless an error is encountered while -determining the name of the current directory or an invalid option -is supplied. - -@item readonly -@btindex readonly -@example -readonly [-apf] [@var{name}[=@var{value}]] @dots{} -@end example -Mark each @var{name} as readonly. -The values of these names may not be changed by subsequent assignment. -If the @option{-f} option is supplied, each @var{name} refers to a shell -function. -The @option{-a} option means each @var{name} refers to an array variable. -If no @var{name} arguments are given, or if the @option{-p} -option is supplied, a list of all readonly names is printed. -The @option{-p} option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. -The return status is zero unless an invalid option is supplied, one of -the @var{name} arguments is not a valid shell variable or function name, -or the @option{-f} option is supplied with a name that is not a shell function. - -@item return -@btindex return -@example -return [@var{n}] -@end example -Cause a shell function to exit with the return value @var{n}. -If @var{n} is not supplied, the return value is the exit status of the -last command executed in the function. -This may also be used to terminate execution of a script being executed -with the @code{.} (or @code{source}) builtin, returning either @var{n} or -the exit status of the last command executed within the script as the exit -status of the script. -Any command associated with the @code{RETURN} trap is executed -before execution resumes after the function or script. -The return status is non-zero if @code{return} is used outside a function -and not during the execution of a script by @code{.} or @code{source}. - -@item shift -@btindex shift -@example -shift [@var{n}] -@end example -Shift the positional parameters to the left by @var{n}. -The positional parameters from @var{n}+1 @dots{} @code{$#} are -renamed to @code{$1} @dots{} @code{$#}-@var{n}+1. -Parameters represented by the numbers @code{$#} to @var{n}+1 are unset. -@var{n} must be a non-negative number less than or equal to @code{$#}. -If @var{n} is zero or greater than @code{$#}, the positional parameters -are not changed. -If @var{n} is not supplied, it is assumed to be 1. -The return status is zero unless @var{n} is greater than @code{$#} or -less than zero, non-zero otherwise. - -@item test -@itemx [ -@btindex test -@btindex [ -Evaluate a conditional expression @var{expr}. -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. - -When the @code{[} form is used, the last argument to the command must -be a @code{]}. - -Expressions may be combined using the following operators, listed in -decreasing order of precedence. - -@table @code -@item ! @var{expr} -True if @var{expr} is false. - -@item ( @var{expr} ) -Returns the value of @var{expr}. -This may be used to override the normal precedence of operators. - -@item @var{expr1} -a @var{expr2} -True if both @var{expr1} and @var{expr2} are true. - -@item @var{expr1} -o @var{expr2} -True if either @var{expr1} or @var{expr2} is true. -@end table - -The @code{test} and @code{[} builtins evaluate conditional -expressions using a set of rules based on the number of arguments. - -@table @asis -@item 0 arguments -The expression is false. - -@item 1 argument -The expression is true if and only if the argument is not null. - -@item 2 arguments -If the first argument is @samp{!}, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators -(@pxref{Bash Conditional Expressions}), the expression -is true if the unary test is true. -If the first argument is not a valid unary operator, the expression is -false. - -@item 3 arguments -If the second argument is one of the binary conditional -operators (@pxref{Bash Conditional Expressions}), the -result of the expression is the result of the binary test using the -first and third arguments as operands. -If the first argument is @samp{!}, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly @samp{(} and the third argument is -exactly @samp{)}, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -The @samp{-a} and @samp{-o} operators are considered binary operators -in this case. - -@item 4 arguments -If the first argument is @samp{!}, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. - -@item 5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -@end table - -@item times -@btindex times -@example -times -@end example -Print out the user and system times used by the shell and its children. -The return status is zero. - -@item trap -@btindex trap -@example -trap [-lp] [@var{arg}] [@var{sigspec} @dots{}] -@end example -The commands in @var{arg} are to be read and executed when the -shell receives signal @var{sigspec}. If @var{arg} is absent (and -there is a single @var{sigspec}) or -equal to @samp{-}, each specified signal's disposition is reset -to the value it had when the shell was started. -If @var{arg} is the null string, then the signal specified by -each @var{sigspec} is ignored by the shell and commands it invokes. -If @var{arg} is not present and @option{-p} has been supplied, -the shell displays the trap commands associated with each @var{sigspec}. -If no arguments are supplied, or -only @option{-p} is given, @code{trap} prints the list of commands -associated with each signal number in a form that may be reused as -shell input. -The @option{-l} option causes the shell to print a list of signal names -and their corresponding numbers. -Each @var{sigspec} is either a signal name or a signal number. -Signal names are case insensitive and the @code{SIG} prefix is optional. -If a @var{sigspec} -is @code{0} or @code{EXIT}, @var{arg} is executed when the shell exits. -If a @var{sigspec} is @code{DEBUG}, the command @var{arg} is executed -before every simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -Refer to the description of the @code{extglob} option to the -@code{shopt} builtin (@pxref{Bash Builtins}) for details of its -effect on the @code{DEBUG} trap. -If a @var{sigspec} is @code{ERR}, the command @var{arg} -is executed whenever a simple command has a non-zero exit status, -subject to the following conditions. -The @code{ERR} trap is not executed if the failed command is part of the -command list immediately following an @code{until} or @code{while} keyword, -part of the test in an @code{if} statement, -part of a @code{&&} or @code{||} list, or if the command's return -status is being inverted using @code{!}. -These are the same conditions obeyed by the @code{errexit} option. -If a @var{sigspec} is @code{RETURN}, the command @var{arg} is executed -each time a shell function or a script executed with the @code{.} or -@code{source} builtins finishes executing. - -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 zero unless a @var{sigspec} does not specify a -valid signal. - -@item umask -@btindex umask -@example -umask [-p] [-S] [@var{mode}] -@end example -Set the shell process's file creation mask to @var{mode}. If -@var{mode} begins with a digit, it is interpreted as an octal number; -if not, it is interpreted as a symbolic mode mask similar -to that accepted by the @code{chmod} command. If @var{mode} is -omitted, the current value of the mask is printed. If the @option{-S} -option is supplied without a @var{mode} argument, the mask is printed -in a symbolic format. -If the @option{-p} option is supplied, and @var{mode} -is omitted, the output is in a form that may be reused as input. -The return status is zero if the mode is successfully changed or if -no @var{mode} argument is supplied, and non-zero otherwise. - -Note that when the mode is interpreted as an octal number, each number -of the umask is subtracted from @code{7}. Thus, a umask of @code{022} -results in permissions of @code{755}. - -@item unset -@btindex unset -@example -unset [-fv] [@var{name}] -@end example -Each variable or function @var{name} is removed. -If no options are supplied, or the @option{-v} option is given, each -@var{name} refers to a shell variable. -If the @option{-f} option is given, the @var{name}s refer to shell -functions, and the function definition is removed. -Readonly variables and functions may not be unset. -The return status is zero unless a @var{name} is readonly. -@end table - -@node Bash Builtins -@section Bash Builtin Commands - -This section describes builtin commands which are unique to -or have been extended in Bash. -Some of these commands are specified in the @sc{posix} 1003.2 standard. - -@table @code - -@item alias -@btindex alias -@example -alias [@code{-p}] [@var{name}[=@var{value}] @dots{}] -@end example - -Without arguments or with the @option{-p} option, @code{alias} prints -the list of aliases on the standard output in a form that allows -them to be reused as input. -If arguments are supplied, an alias is defined for each @var{name} -whose @var{value} is given. If no @var{value} is given, the name -and value of the alias is printed. -Aliases are described in @ref{Aliases}. - -@item bind -@btindex bind -@example -bind [-m @var{keymap}] [-lpsvPSV] -bind [-m @var{keymap}] [-q @var{function}] [-u @var{function}] [-r @var{keyseq}] -bind [-m @var{keymap}] -f @var{filename} -bind [-m @var{keymap}] -x @var{keyseq:shell-command} -bind [-m @var{keymap}] @var{keyseq:function-name} -bind @var{readline-command} -@end example - -Display current Readline (@pxref{Command Line Editing}) -key and function bindings, -bind a key sequence to a Readline function or macro, -or set a Readline variable. -Each non-option argument is a command as it would appear in a -a Readline initialization file (@pxref{Readline Init File}), -but each binding or command must be passed as a separate argument; e.g., -@samp{"\C-x\C-r":re-read-init-file}. -Options, if supplied, have the following meanings: - -@table @code -@item -m @var{keymap} -Use @var{keymap} as the keymap to be affected by -the subsequent bindings. Acceptable @var{keymap} -names are -@code{emacs}, -@code{emacs-standard}, -@code{emacs-meta}, -@code{emacs-ctlx}, -@code{vi}, -@code{vi-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 -p -Display Readline function names and bindings in such a way that they -can be used as input or in a Readline initialization file. - -@item -P -List current Readline function names and bindings. - -@item -v -Display Readline variable names and values in such a way that they -can be used as input or in a Readline initialization file. - -@item -V -List current Readline variable names and values. - -@item -s -Display Readline key sequences bound to macros and the strings they output -in such a way that they can be used as input or in a Readline -initialization file. - -@item -S -Display Readline key sequences bound to macros and the strings they output. - -@item -f @var{filename} -Read key bindings from @var{filename}. - -@item -q @var{function} -Query about which keys invoke the named @var{function}. - -@item -u @var{function} -Unbind all keys bound to the named @var{function}. - -@item -r @var{keyseq} -Remove any current binding for @var{keyseq}. - -@item -x @var{keyseq:shell-command} -Cause @var{shell-command} to be executed whenever @var{keyseq} is -entered. - -@end table - -@noindent -The return status is zero unless an invalid option is supplied or an -error occurs. - -@item builtin -@btindex builtin -@example -builtin [@var{shell-builtin} [@var{args}]] -@end example -Run a shell builtin, passing it @var{args}, and return its exit status. -This is useful when defining a shell function with the same -name as a shell builtin, retaining the functionality of the builtin within -the function. -The return status is non-zero if @var{shell-builtin} is not a shell -builtin command. - -@item caller -@btindex caller -@example -caller [@var{expr}] -@end example -Returns the context of any active subroutine call (a shell function or -a script executed with the @code{.} or @code{source} builtins). - -Without @var{expr}, @code{caller} displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as @var{expr}, @code{caller} -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. - -The return value is 0 unless the shell is not executing a subroutine -call or @var{expr} does not correspond to a valid position in the -call stack. - -@item command -@btindex command -@example -command [-pVv] @var{command} [@var{arguments} @dots{}] -@end example -Runs @var{command} with @var{arguments} ignoring any shell function -named @var{command}. -Only shell builtin commands or commands found by searching the -@env{PATH} are executed. -If there is a shell function named @code{ls}, running @samp{command ls} -within the function will execute the external command @code{ls} -instead of calling the function recursively. -The @option{-p} option means to use a default value for @env{PATH} -that is guaranteed to find all of the standard utilities. -The return status in this case is 127 if @var{command} cannot be -found or an error occurred, and the exit status of @var{command} -otherwise. - -If either the @option{-V} or @option{-v} option is supplied, a -description of @var{command} is printed. The @option{-v} option -causes a single word indicating the command or file name used to -invoke @var{command} to be displayed; the @option{-V} option produces -a more verbose description. In this case, the return status is -zero if @var{command} is found, and non-zero if not. - -@item declare -@btindex declare -@example -declare [-afFirtx] [-p] [@var{name}[=@var{value}] @dots{}] -@end example - -Declare variables and give them attributes. If no @var{name}s -are given, then display the values of variables instead. - -The @option{-p} option will display the attributes and values of each -@var{name}. -When @option{-p} is used, additional options are ignored. -The @option{-F} option inhibits the display of function definitions; -only the function name and attributes are printed. -If the @code{extdebug} shell option is enabled using @code{shopt} -(@pxref{Bash Builtins}), the source file name and line number where -the function is defined are displayed as well. -@option{-F} implies @option{-f}. -The following options can be used to restrict output to variables with -the specified attributes or to give variables attributes: - -@table @code -@item -a -Each @var{name} is an array variable (@pxref{Arrays}). - -@item -f -Use function names only. - -@item -i -The variable is to be treated as -an integer; arithmetic evaluation (@pxref{Shell Arithmetic}) is -performed when the variable is assigned a value. - -@item -r -Make @var{name}s readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. - -@item -t -Give each @var{name} the @code{trace} attribute. -Traced functions inherit the @code{DEBUG} trap from the calling shell. -The trace attribute has no special meaning for variables. - -@item -x -Mark each @var{name} for export to subsequent commands via -the environment. -@end table - -Using @samp{+} instead of @samp{-} turns off the attribute instead. -When used in a function, @code{declare} makes each @var{name} local, -as with the @code{local} command. If a variable name is followed by -=@var{value}, the value of the variable is set to @var{value}. - -The return status is zero unless an invalid option is encountered, -an attempt is made to define a function using @samp{-f foo=bar}, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (@pxref{Arrays}), -one of the @var{names} is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with @option{-f}. - -@item echo -@btindex echo -@example -echo [-neE] [@var{arg} @dots{}] -@end example -Output the @var{arg}s, separated by spaces, terminated with a -newline. -The return status is always 0. -If @option{-n} is specified, the trailing newline is suppressed. -If the @option{-e} option is given, interpretation of the following -backslash-escaped characters is enabled. -The @option{-E} option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The @code{xpg_echo} shell option may be used to -dynamically determine whether or not @code{echo} expands these -escape characters by default. -@code{echo} interprets the following escape sequences: -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \c -suppress trailing newline -@item \e -escape -@item \f -form feed -@item \n -new line -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \0@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(zero to three octal digits) -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three octal digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@end table - -@item enable -@btindex enable -@example -enable [-n] [-p] [-f @var{filename}] [-ads] [@var{name} @dots{}] -@end example -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -If @option{-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 @env{$PATH} instead of the shell builtin version, type -@samp{enable -n test}. - -If the @option{-p} option is supplied, or no @var{name} arguments appear, -a list of shell builtins is printed. With no other arguments, the list -consists of all enabled shell builtins. -The @option{-a} option means to list -each builtin with an indication of whether or not it is enabled. - -The @option{-f} option means to load the new builtin command @var{name} -from shared object @var{filename}, on systems that support dynamic loading. -The @option{-d} option will delete a builtin loaded with @option{-f}. - -If there are no options, a list of the shell builtins is displayed. -The @option{-s} option restricts @code{enable} to the @sc{posix} special -builtins. If @option{-s} is used with @option{-f}, the new builtin becomes -a special builtin (@pxref{Special Builtins}). - -The return status is zero unless a @var{name} is not a shell builtin -or there is an error loading a new builtin from a shared object. - -@item help -@btindex help -@example -help [-s] [@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. -The @option{-s} option restricts the information displayed to a short -usage synopsis. -The return status is zero unless no command matches @var{pattern}. - -@item let -@btindex let -@example -let @var{expression} [@var{expression}] -@end example -The @code{let} builtin allows arithmetic to be performed on shell -variables. Each @var{expression} is evaluated according to the -rules given below in @ref{Shell Arithmetic}. If the -last @var{expression} evaluates to 0, @code{let} returns 1; -otherwise 0 is returned. - -@item local -@btindex local -@example -local [@var{option}] @var{name}[=@var{value}] @dots{} -@end example -For each argument, a local variable named @var{name} is created, -and assigned @var{value}. -The @var{option} can be any of the options accepted by @code{declare}. -@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. The return status is zero unless @code{local} is used outside -a function, an invalid @var{name} is supplied, or @var{name} is a -readonly variable. - -@item logout -@btindex logout -@example -logout [@var{n}] -@end example -Exit a login shell, returning a status of @var{n} to the shell's -parent. - -@item printf -@btindex printf -@example -@code{printf} @var{format} [@var{arguments}] -@end example -Write the formatted @var{arguments} to the standard output under the -control of the @var{format}. -The @var{format} is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -@var{argument}. -In addition to the standard @code{printf(1)} formats, @samp{%b} causes -@code{printf} to expand backslash escape sequences in the corresponding -@var{argument}, -(except that @samp{\c} terminates output, backslashes in -@samp{\'}, @samp{\"}, and @samp{\?} are not removed, and octal escapes -beginning with @samp{\0} may contain up to four digits), -and @samp{%q} causes @code{printf} to output the -corresponding @var{argument} in a format that can be reused as shell input. - -The @var{format} is reused as necessary to consume all of the @var{arguments}. -If the @var{format} requires more @var{arguments} than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. - -@item read -@btindex read -@example -read [-ers] [-a @var{aname}] [-d @var{delim}] [-n @var{nchars}] [-p @var{prompt}] [-t @var{timeout}] [-u @var{fd}] [@var{name} @dots{}] -@end example -One line is read from the standard input, or from the file descriptor -@var{fd} supplied as an argument to the @option{-u} option, and the first word -is assigned to the first @var{name}, the second word to the second @var{name}, -and so on, with leftover words and their intervening separators assigned -to the last @var{name}. -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in the value of the @env{IFS} variable -are used to split the line into words. -The backslash character @samp{\} may be used to remove any special -meaning for the next character read and for line continuation. -If no names are supplied, the line read is assigned to the -variable @env{REPLY}. -The return code is zero, unless end-of-file is encountered, @code{read} -times out, or an invalid file descriptor is supplied as the argument to -@option{-u}. -Options, if supplied, have the following meanings: - -@table @code -@item -a @var{aname} -The words are assigned to sequential indices of the array variable -@var{aname}, starting at 0. -All elements are removed from @var{aname} before the assignment. -Other @var{name} arguments are ignored. - -@item -d @var{delim} -The first character of @var{delim} is used to terminate the input line, -rather than newline. - -@item -e -Readline (@pxref{Command Line Editing}) is used to obtain the line. - -@item -n @var{nchars} -@code{read} returns after reading @var{nchars} characters rather than -waiting for a complete line of input. - -@item -p @var{prompt} -Display @var{prompt}, without a trailing newline, before attempting -to read any input. -The prompt is displayed only if input is coming from a terminal. - -@item -r -If this option is given, backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. - -@item -s -Silent mode. If input is coming from a terminal, characters are -not echoed. - -@item -t @var{timeout} -Cause @code{read} to time out and return failure if a complete line of -input is not read within @var{timeout} seconds. -This option has no effect if @code{read} is not reading input from the -terminal or a pipe. - -@item -u @var{fd} -Read input from file descriptor @var{fd}. - -@end table - -@item shopt -@btindex shopt -@example -shopt [-pqsu] [-o] [@var{optname} @dots{}] -@end example -Toggle the values of variables controlling optional shell behavior. -With no options, or with the @option{-p} option, a list of all settable -options is displayed, with an indication of whether or not each is set. -The @option{-p} option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: - -@table @code -@item -s -Enable (set) each @var{optname}. - -@item -u -Disable (unset) each @var{optname}. - -@item -q -Suppresses normal output; the return status -indicates whether the @var{optname} is set or unset. -If multiple @var{optname} arguments are given with @option{-q}, -the return status is zero if all @var{optnames} are enabled; -non-zero otherwise. - -@item -o -Restricts the values of -@var{optname} to be those defined for the @option{-o} option to the -@code{set} builtin (@pxref{The Set Builtin}). -@end table - -If either @option{-s} or @option{-u} -is used with no @var{optname} arguments, the display is limited to -those options which are set or unset, respectively. - -Unless otherwise noted, the @code{shopt} options are disabled (off) -by default. - -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an @var{optname} is not a valid shell -option. - -The list of @code{shopt} options is: -@table @code -@item cdable_vars -If this is set, an argument to the @code{cd} -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. - -@item cdspell -If set, minor errors in the spelling of a directory component in a -@code{cd} command will be corrected. -The errors checked for are transposed characters, -a missing character, and a character too many. -If a correction is found, the corrected path is printed, -and the command proceeds. -This option is only used by interactive shells. - -@item checkhash -If this is set, Bash checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. - -@item checkwinsize -If set, Bash checks the window size after each command -and, if necessary, updates the values of -@env{LINES} and @env{COLUMNS}. - -@item cmdhist -If set, Bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. - -@item dotglob -If set, Bash includes filenames beginning with a `.' in -the results of filename expansion. - -@item execfail -If this is set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the @code{exec} -builtin command. An interactive shell does not exit if @code{exec} -fails. - -@item expand_aliases -If set, aliases are expanded as described below under Aliases, -@ref{Aliases}. -This option is enabled by default for interactive shells. - -@item extdebug -If set, behavior intended for use by debuggers is enabled: - -@enumerate -@item -The @option{-F} option to the @code{declare} builtin (@pxref{Bash Builtins}) -displays the source file name and line number corresponding to each function -name supplied as an argument. - -@item -If the command run by the @code{DEBUG} trap returns a non-zero value, the -next command is skipped and not executed. - -@item -If the command run by the @code{DEBUG} trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the @code{.} or @code{source} builtins), a call to -@code{return} is simulated. -@end enumerate - -@item extglob -If set, the extended pattern matching features described above -(@pxref{Pattern Matching}) are enabled. - -@item extquote -If set, @code{$'@var{string}'} and @code{$"@var{string}"} quoting is -performed within @code{$@{@var{parameter}@}} expansions -enclosed in double quotes. This option is enabled by default. - -@item failglob -If set, patterns which fail to match filenames during pathname expansion -result in an expansion error. - -@item force_fignore -If set, the suffixes specified by the @env{FIGNORE} shell variable -cause words to be ignored when performing word completion even if -the ignored words are the only possible completions. -@xref{Bash Variables}, for a description of @env{FIGNORE}. -This option is enabled by default. - -@item gnu_errfmt -If set, shell error messages are written in the standard @sc{gnu} error -message format. - -@item histappend -If set, the history list is appended to the file named by the value -of the @env{HISTFILE} -variable when the shell exits, rather than overwriting the file. - -@item histreedit -If set, and Readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. - -@item histverify -If set, and Readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the Readline editing buffer, allowing further modification. - -@item hostcomplete -If set, and Readline is being used, Bash will attempt to perform -hostname completion when a word containing a @samp{@@} is being -completed (@pxref{Commands For Completion}). This option is enabled -by default. - -@item huponexit -If set, Bash will send @code{SIGHUP} to all jobs when an interactive -login shell exits (@pxref{Signals}). - -@item interactive_comments -Allow a word beginning with @samp{#} -to cause that word and all remaining characters on that -line to be ignored in an interactive shell. -This option is enabled by default. - -@item lithist -If enabled, and the @code{cmdhist} -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. - -@item login_shell -The shell sets this option if it is started as a login shell -(@pxref{Invoking Bash}). -The value may not be changed. - -@item mailwarn -If set, and a file that Bash is checking for mail has been -accessed since the last time it was checked, the message -@code{"The mail in @var{mailfile} has been read"} is displayed. - -@item no_empty_cmd_completion -If set, and Readline is being used, Bash will not attempt to search -the @env{PATH} for possible completions when completion is attempted -on an empty line. - -@item nocaseglob -If set, Bash matches filenames in a case-insensitive fashion when -performing filename expansion. - -@item nullglob -If set, Bash allows filename patterns which match no -files to expand to a null string, rather than themselves. - -@item progcomp -If set, the programmable completion facilities -(@pxref{Programmable Completion}) are enabled. -This option is enabled by default. - -@item promptvars -If set, prompt strings undergo -parameter expansion, command substitution, arithmetic -expansion, and quote removal after being expanded -as described below (@pxref{Printing a Prompt}). -This option is enabled by default. - -@item restricted_shell -The shell sets this option if it is started in restricted mode -(@pxref{The Restricted Shell}). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. - -@item shift_verbose -If this is set, the @code{shift} -builtin prints an error message when the shift count exceeds the -number of positional parameters. - -@item sourcepath -If set, the @code{source} builtin uses the value of @env{PATH} -to find the directory containing the file supplied as an argument. -This option is enabled by default. - -@item xpg_echo -If set, the @code{echo} builtin expands backslash-escape sequences -by default. - -@end table - -@noindent -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. -When setting or unsetting options, the return status is zero unless an -@var{optname} is not a valid shell option. - -@item source -@btindex source -@example -source @var{filename} -@end example -A synonym for @code{.} (@pxref{Bourne Shell Builtins}). - -@item type -@btindex type -@example -type [-afptP] [@var{name} @dots{}] -@end example -For each @var{name}, indicate how it would be interpreted if used as a -command name. - -If the @option{-t} option is used, @code{type} prints a single word -which is one of @samp{alias}, @samp{function}, @samp{builtin}, -@samp{file} or @samp{keyword}, -if @var{name} is an alias, shell function, shell builtin, -disk file, or shell reserved word, respectively. -If the @var{name} is not found, then nothing is printed, and -@code{type} returns a failure status. - -If the @option{-p} option is used, @code{type} either returns the name -of the disk file that would be executed, or nothing if @option{-t} -would not return @samp{file}. - -The @option{-P} option forces a path search for each @var{name}, even if -@option{-t} would not return @samp{file}. - -If a command is hashed, @option{-p} and @option{-P} print the hashed value, -not necessarily the file that appears first in @code{$PATH}. - -If the @option{-a} option is used, @code{type} returns all of the places -that contain an executable named @var{file}. -This includes aliases and functions, if and only if the @option{-p} option -is not also used. - -If the @option{-f} option is used, @code{type} does not attempt to find -shell functions, as with the @code{command} builtin. - -The return status is zero if any of the @var{names} are found, non-zero -if none are found. - -@item typeset -@btindex typeset -@example -typeset [-afFrxi] [-p] [@var{name}[=@var{value}] @dots{}] -@end example -The @code{typeset} command is supplied for compatibility with the Korn -shell; however, it has been deprecated in favor of the @code{declare} -builtin command. - -@item ulimit -@btindex ulimit -@example -ulimit [-acdflmnpstuvSH] [@var{limit}] -@end example -@code{ulimit} provides control over the resources available to processes -started by the shell, on systems that allow such control. If an -option is given, it is interpreted as follows: -@table @code -@item -S -Change and report the soft limit associated with a resource. - -@item -H -Change and report the hard limit associated with a resource. - -@item -a -All current limits are reported. - -@item -c -The maximum size of core files created. - -@item -d -The maximum size of a process's data segment. - -@item -f -The maximum size of files created by the shell. - -@item -l -The maximum size that may be locked into memory. - -@item -m -The maximum resident set size. - -@item -n -The maximum number of open file descriptors. - -@item -p -The pipe buffer size. - -@item -s -The maximum stack size. - -@item -t -The maximum amount of cpu time in seconds. - -@item -u -The maximum number of processes available to a single user. - -@item -v -The maximum amount of virtual memory available to the process. - -@end table - -If @var{limit} is given, it is the new value of the specified resource; -the special @var{limit} values @code{hard}, @code{soft}, and -@code{unlimited} stand for the current hard limit, the current soft limit, -and no limit, respectively. -Otherwise, the current value of the soft limit for the specified resource -is printed, unless the @option{-H} option is supplied. -When setting new limits, if neither @option{-H} nor @option{-S} is supplied, -both the hard and soft limits are set. -If no option is given, then @option{-f} is assumed. Values are in 1024-byte -increments, except for @option{-t}, which is in seconds, @option{-p}, -which is in units of 512-byte blocks, and @option{-n} and @option{-u}, which -are unscaled values. - -The return status is zero unless an invalid option or argument is supplied, -or an error occurs while setting a new limit. - -@item unalias -@btindex unalias -@example -unalias [-a] [@var{name} @dots{} ] -@end example - -Remove each @var{name} from the list of aliases. If @option{-a} is -supplied, all aliases are removed. -Aliases are described in @ref{Aliases}. - -@end table - -@node The Set Builtin -@section The Set Builtin - -This builtin is so complicated that it deserves its own section. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCHP] [-o @var{option}] [@var{argument} @dots{}] -@end example - -If no options or arguments are supplied, @code{set} displays the names -and values of all shell variables and functions, sorted according to the -current locale, in a format that may be reused as input. - -When options are supplied, they set or unset shell attributes. -Options, if specified, have the following meanings: - -@table @code -@item -a -Mark variables and function which are modified or created for export -to the environment of subsequent commands. - -@item -b -Cause the status of terminated background jobs to be reported -immediately, rather than before printing the next primary prompt. - -@item -e -Exit immediately if a simple command (@pxref{Simple Commands}) exits -with a non-zero status, unless the command that fails is part of the -command list immediately following a @code{while} or @code{until} -keyword, part of the test in an @code{if} statement, -part of a @code{&&} or @code{||} list, or if the command's return -status is being inverted using @code{!}. -A trap on @code{ERR}, if set, is executed before the shell exits. - -@item -f -Disable file name generation (globbing). - -@item -h -Locate and remember (hash) commands as they are looked up for execution. -This option is enabled by default. - -@item -k -All arguments in the form of assignment statements are placed -in the environment for a command, not just those that precede -the command name. - -@item -m -Job control is enabled (@pxref{Job Control}). - -@item -n -Read commands but do not execute them; this may be used to check a -script for syntax errors. -This option is ignored by interactive shells. - -@item -o @var{option-name} - -Set the option corresponding to @var{option-name}: - -@table @code -@item allexport -Same as @code{-a}. - -@item braceexpand -Same as @code{-B}. - -@item emacs -Use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). - -@item errexit -Same as @code{-e}. - -@item errtrace -Same as @code{-E}. - -@item functrace -Same as @code{-T}. - -@item hashall -Same as @code{-h}. - -@item histexpand -Same as @code{-H}. - -@item history -Enable command history, as described in @ref{Bash History Facilities}. -This option is on by default in interactive shells. - -@item ignoreeof -An interactive shell will not exit upon reading EOF. - -@item keyword -Same as @code{-k}. - -@item monitor -Same as @code{-m}. - -@item noclobber -Same as @code{-C}. - -@item noexec -Same as @code{-n}. - -@item noglob -Same as @code{-f}. - -@item nolog -Currently ignored. - -@item notify -Same as @code{-b}. - -@item nounset -Same as @code{-u}. - -@item onecmd -Same as @code{-t}. - -@item physical -Same as @code{-P}. - -@item pipefail -If set, the return value of a pipeline is the value of the last -(rightmost) command to exit with a non-zero status, or zero if all -commands in the pipeline exit successfully. -This option is disabled by default. - -@item posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} 1003.2 standard to match the standard -(@pxref{Bash POSIX Mode}). -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 @env{$BASH_ENV} and @env{$ENV} files are not -processed, shell functions are not inherited from the environment, -and the @env{SHELLOPTS} variable, if it appears in the environment, -is ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the @code{-p} option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the @code{-p} option is supplied at startup, the effective user id is -not reset. -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 performing parameter expansion. -An error message will be written to the standard error, and a non-interactive -shell will exit. - -@item -v -Print shell input lines as they are read. - -@item -x -Print a trace of simple commands, \fBfor\fP commands, \fBcase\fP -commands, \fBselect\fP commands, and arithmetic \fBfor\fP commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -the command and its expanded arguments. - -@item -B -The shell will perform brace expansion (@pxref{Brace Expansion}). -This option is on by default. - -@item -C -Prevent output redirection using @samp{>}, @samp{>&}, and @samp{<>} -from overwriting existing files. - -@item -E -If set, any trap on @code{ERR} is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The @code{ERR} trap is normally not inherited in such cases. - -@item -H -Enable @samp{!} style history substitution (@pxref{History Interaction}). -This option is on by default for interactive shells. - -@item -P -If set, do not follow symbolic links when performing commands such as -@code{cd} which change the current directory. The physical directory -is used instead. By default, Bash follows -the logical chain of directories when performing commands -which change the current directory. - -For example, if @file{/usr/sys} is a symbolic link to @file{/usr/local/sys} -then: -@example -$ cd /usr/sys; echo $PWD -/usr/sys -$ cd ..; pwd -/usr -@end example - -@noindent -If @code{set -P} is on, then: -@example -$ cd /usr/sys; echo $PWD -/usr/local/sys -$ cd ..; pwd -/usr/local -@end example - -@item -T -If set, any trap on @code{DEBUG} is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The @code{DEBUG} trap is normally not inherited in such cases. - -@item -- -If no arguments follow this option, then the positional parameters are -unset. Otherwise, the positional parameters are set to the -@var{arguments}, even if some of them begin with a @samp{-}. - -@item - -Signal the end of options, cause all remaining @var{arguments} -to be assigned to the positional parameters. The @option{-x} -and @option{-v} options are turned off. -If there are no arguments, the positional parameters remain unchanged. -@end table - -Using @samp{+} rather than @samp{-} causes these options to be -turned off. The options can also be used upon invocation of the -shell. The current set of options may be found in @code{$-}. - -The remaining N @var{arguments} are positional parameters and are -assigned, in order, to @code{$1}, @code{$2}, @dots{} @code{$N}. -The special parameter @code{#} is set to N. - -The return status is always zero unless an invalid option is supplied. -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} 1003.2 standard has classified -several builtin commands as @emph{special}. -When Bash is executing in @sc{posix} mode, the special builtins -differ from other builtin commands in three respects: - -@enumerate -@item -Special builtins are found before shell functions during command lookup. - -@item -If a special builtin returns an error status, a non-interactive shell exits. - -@item -Assignment statements preceding the command stay in effect in the shell -environment after the command completes. -@end enumerate - -When Bash is not executing in @sc{posix} mode, these builtins behave no -differently than the rest of the Bash builtin commands. -The Bash @sc{posix} mode is described in @ref{Bash POSIX Mode}. - -These are the @sc{posix} special builtins: -@example -@w{break : . continue eval exec exit export readonly return set} -@w{shift trap unset} -@end example - -@node Shell Variables -@chapter Shell Variables - -@menu -* Bourne Shell Variables:: Variables which Bash uses in the same way - as the Bourne Shell. -* Bash Variables:: List of variables that exist in Bash. -@end menu - -This chapter describes the shell variables that Bash uses. -Bash automatically assigns default values to a number of variables. - -@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 CDPATH -A colon-separated list of directories used as a search path for -the @code{cd} builtin command. - -@item HOME -The current user's home directory; the default for the @code{cd} builtin -command. -The value of this variable is also used by tilde expansion -(@pxref{Tilde Expansion}). - -@item IFS -A list of characters that separate fields; used when the shell splits -words as part of expansion. - -@item MAIL -If this parameter is set to a filename and the @env{MAILPATH} variable -is not set, Bash informs the user of the arrival of mail in -the specified file. - -@item MAILPATH -A colon-separated list of filenames which the shell periodically checks -for new mail. -Each list entry can specify the message that is printed when new mail -arrives in the mail file by separating the file name from the message with -a @samp{?}. -When used in the text of the message, @code{$_} expands to the name of -the current mail file. - -@item OPTARG -The value of the last option argument processed by the @code{getopts} builtin. - -@item OPTIND -The index of the last option argument processed by the @code{getopts} builtin. - -@item PATH -A colon-separated list of directories in which the shell looks for -commands. -A zero-length (null) directory name in the value of @code{PATH} indicates the -current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. - - -@item PS1 -The primary prompt string. The default value is @samp{\s-\v\$ }. -@xref{Printing a Prompt}, for the complete list of escape -sequences that are expanded before @env{PS1} is displayed. - -@item PS2 -The secondary prompt string. The default value is @samp{> }. - -@end vtable - -@node Bash Variables -@section Bash Variables - -These variables are set or used by Bash, but other shells -do not normally treat them specially. - -A few variables used by Bash are described in different chapters: -variables for controlling the job control facilities -(@pxref{Job Control Variables}). - -@vtable @code - -@item BASH -The full pathname used to execute the current instance of Bash. - -@item BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current bash execution call stack. The number of -parameters to the current subroutine (shell function or script executed -with @code{.} or @code{source}) is at the top of the stack. When a -subroutine is executed, the number of parameters passed is pushed onto -@code{BASH_ARGC}. - -@item BASH_ARGV -An array variable containing all of the parameters in the current bash -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto @code{BASH_ARGV}. - -@item BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. - -@item BASH_ENV -If this variable is set when Bash is invoked to execute a shell -script, its value is expanded and used as the name of a startup file -to read before executing the script. @xref{Bash Startup Files}. - -@item BASH_EXECUTION_STRING -The command argument to the @option{-c} invocation option. - -@item BASH_LINENO -An array variable whose members are the line numbers in source files -corresponding to each member of @var{FUNCNAME}. -@code{$@{BASH_LINENO[$i]@}} is the line number in the source file where -@code{$@{FUNCNAME[$i + 1]@}} was called. -The corresponding source file name is @code{$@{BASH_SOURCE[$i + 1]@}}. -Use @code{LINENO} to obtain the current line number. - -@item BASH_REMATCH -An array variable whose members are assigned by the @samp{=~} binary -operator to the @code{[[} conditional command -(@pxref{Conditional Constructs}). -The element with index 0 is the portion of the string -matching the entire regular expression. -The element with index @var{n} is the portion of the -string matching the @var{n}th parenthesized subexpression. -This variable is read-only. - -@item BASH_SOURCE -An array variable whose members are the source filenames corresponding -to the elements in the @code{FUNCNAME} array variable. - -@item BASH_SUBSHELL -Incremented by one each time a subshell or subshell environment is spawned. -The initial value is 0. - -@item BASH_VERSINFO -A readonly array variable (@pxref{Arrays}) -whose members hold version information for this instance of Bash. -The values assigned to the array members are as follows: - -@table @code - -@item BASH_VERSINFO[0] -The major version number (the @var{release}). - -@item BASH_VERSINFO[1] -The minor version number (the @var{version}). - -@item BASH_VERSINFO[2] -The patch level. - -@item BASH_VERSINFO[3] -The build version. - -@item BASH_VERSINFO[4] -The release status (e.g., @var{beta1}). - -@item BASH_VERSINFO[5] -The value of @env{MACHTYPE}. - -@end table - -@item BASH_VERSION -The version number of the current instance of Bash. - -@item COLUMNS -Used by the @code{select} builtin command to determine the terminal width -when printing selection lists. Automatically set upon receipt of a -@code{SIGWINCH}. - -@item COMP_CWORD -An index into @env{$@{COMP_WORDS@}} of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to @code{$@{#COMP_LINE@}}. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_WORDBREAKS -The set of characters that the Readline library treats as word -separators when performing word completion. -If @code{COMP_WORDBREAKS} is unset, it loses its special properties, -even if it is subsequently reset. - -@item COMP_WORDS -An array variable consisting of the individual -words in the current command line. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMPREPLY -An array variable from which Bash reads the possible completions -generated by a shell function invoked by the programmable completion -facility (@pxref{Programmable Completion}). - -@item DIRSTACK -An array variable containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -@code{dirs} builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the @code{pushd} and @code{popd} -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If @env{DIRSTACK} is unset, it loses its special properties, even if -it is subsequently reset. - -@item EMACS -If Bash finds this variable in the environment when the shell -starts with value @samp{t}, it assumes that the shell is running in an -emacs shell buffer and disables line editing. - -@item EUID -The numeric effective user id of the current user. This variable -is readonly. - -@item FCEDIT -The editor used as a default by the @option{-e} option to the @code{fc} -builtin command. - -@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 -@env{FIGNORE} -is excluded from the list of matched file names. A sample -value is @samp{.o:~} - -@item FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element is "main". -This variable exists only when a shell function is executing. -Assignments to @env{FUNCNAME} have no effect and return an error status. -If @env{FUNCNAME} is unset, it loses its special properties, even if -it is subsequently reset. - -@item GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by filename expansion. -If a filename matched by a filename expansion pattern also matches one -of the patterns in @env{GLOBIGNORE}, it is removed from the list -of matches. - -@item GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to @env{GROUPS} have no effect and return an error status. -If @env{GROUPS} is unset, it loses its special properties, even if it is -subsequently reset. - -@item histchars -Up to three characters which control history expansion, quick -substitution, and tokenization (@pxref{History Interaction}). -The first character is the -@var{history expansion} character, 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 indicates that 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 @env{HISTCMD} is unset, it loses its special properties, -even if it is subsequently reset. - -@item HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes @samp{ignorespace}, lines which begin -with a space character are not saved in the history list. -A value of @samp{ignoredups} causes lines which match the previous -history entry to not be saved. -A value of @samp{ignoreboth} is shorthand for -@samp{ignorespace} and @samp{ignoredups}. -A value of @samp{erasedups} causes all previous lines matching the -current line to be removed from the history list before that line -is saved. -Any value not in the above list is ignored. -If @env{HISTCONTROL} is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of @env{HISTIGNORE}. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTCONTROL}. - -@item HISTFILE -The name of the file to which the command history is saved. The -default value is @file{~/.bash_history}. - -@item HISTFILESIZE -The maximum number of lines contained in the history file. When this -variable is assigned a value, the history file is truncated, if -necessary, to contain no more than that number of lines. -The history file is also truncated to this size after -writing it when an interactive shell exits. -The default value is 500. - -@item HISTIGNORE -A colon-separated list of patterns used to decide which command -lines should be saved on the history list. Each pattern is -anchored at the beginning of the line and must match the complete -line (no implicit @samp{*} is appended). Each pattern is tested -against the line after the checks specified by @env{HISTCONTROL} -are applied. In addition to the normal shell pattern matching -characters, @samp{&} matches the previous history line. @samp{&} -may be escaped using a backslash; the backslash is removed -before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTIGNORE}. - -@env{HISTIGNORE} subsumes the function of @env{HISTCONTROL}. A -pattern of @samp{&} is identical to @code{ignoredups}, and a -pattern of @samp{[ ]*} is identical to @code{ignorespace}. -Combining these two patterns, separating them with a colon, -provides the functionality of @code{ignoreboth}. - -@item HISTSIZE -The maximum number of commands to remember on the history list. -The default value is 500. - -@item HISTTIMEFORMAT -If this variable is set and not null, its value is used as a format string -for @var{strftime} to print the time stamp associated with each history -entry displayed by the @code{history} builtin. -If this variable is set, time stamps are written to the history file so -they may be preserved across shell sessions. - -@item HOSTFILE -Contains the name of a file in the same format as @file{/etc/hosts} that -should be read when the shell needs to complete a hostname. -The list of possible hostname completions may be changed while the shell -is running; -the next time hostname completion is attempted after the -value is changed, Bash adds the contents of the new file to the -existing list. -If @env{HOSTFILE} is set, but has no value, Bash attempts to read -@file{/etc/hosts} to obtain the list of possible hostname completions. -When @env{HOSTFILE} is unset, the hostname list is cleared. - -@item HOSTNAME -The name of the current host. - -@item HOSTTYPE -A string describing the machine Bash is running on. - -@item IGNOREEOF -Controls the action of the shell on receipt of an @code{EOF} character -as the sole input. If set, the value denotes the number -of consecutive @code{EOF} characters that can be read as the -first character on an input line -before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. -If the variable does not exist, then @code{EOF} signifies the end of -input to the shell. This is only in effect for interactive shells. - -@item INPUTRC -The name of the Readline initialization file, overriding the default -of @file{~/.inputrc}. - -@item LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with @code{LC_}. - -@item LC_ALL -This variable overrides the value of @env{LANG} and any other -@code{LC_} variable specifying a locale category. - -@item LC_COLLATE -This variable determines the collation order used when sorting the -results of filename expansion, and -determines the behavior of range expressions, equivalence classes, -and collating sequences within filename expansion and pattern matching -(@pxref{Filename Expansion}). - -@item LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within filename expansion and pattern -matching (@pxref{Filename Expansion}). - -@item LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a @samp{$} (@pxref{Locale Translation}). - -@item LC_NUMERIC -This variable determines the locale category used for number formatting. - -@item LINENO -The line number in the script or shell function currently executing. - -@item LINES -Used by the @code{select} builtin command to determine the column length -for printing selection lists. Automatically set upon receipt of a -@code{SIGWINCH}. - -@item MACHTYPE -A string that fully describes the system type on which Bash -is executing, in the standard @sc{gnu} @var{cpu-company-system} format. - -@item MAILCHECK -How often (in seconds) that the shell should check for mail in the -files specified in the @env{MAILPATH} or @env{MAIL} variables. -The default is 60 seconds. When it is time to check -for mail, the shell does so before displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. - -@item OLDPWD -The previous working directory as set by the @code{cd} builtin. - -@item OPTERR -If set to the value 1, Bash displays error messages -generated by the @code{getopts} builtin command. - -@item OSTYPE -A string describing the operating system Bash is running on. - -@item PIPESTATUS -An array variable (@pxref{Arrays}) -containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). - -@item POSIXLY_CORRECT -If this variable is in the environment when @code{bash} starts, the shell -enters @sc{posix} mode (@pxref{Bash POSIX Mode}) before reading the -startup files, as if the @option{--posix} invocation option had been supplied. -If it is set while the shell is running, @code{bash} enables @sc{posix} mode, -as if the command -@example -@code{set -o posix} -@end example -@noindent -had been executed. - -@item PPID -The process @sc{id} of the shell's parent process. This variable -is readonly. - -@item PROMPT_COMMAND -If set, the value is interpreted as a command to execute -before the printing of each primary prompt (@env{$PS1}). - -@item PS3 -The value of this variable is used as the prompt for the -@code{select} command. If this variable is not set, the -@code{select} command prompts with @samp{#? } - -@item PS4 -The value is the prompt printed before the command line is echoed -when the @option{-x} option is set (@pxref{The Set Builtin}). -The first character of @env{PS4} is replicated multiple times, as -necessary, to indicate multiple levels of indirection. -The default is @samp{+ }. - -@item PWD -The current working directory as set by the @code{cd} builtin. - -@item RANDOM -Each time this parameter is referenced, a random integer -between 0 and 32767 is generated. Assigning a value to this -variable seeds the random number generator. - -@item REPLY -The default variable for the @code{read} builtin. - -@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 SHELL -The full pathname to the shell is kept in this environment variable. -If it is not set when the shell starts, -Bash assigns to it the full pathname of the current user's login shell. - -@item SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the @option{-o} option to the -@code{set} builtin command (@pxref{The Set Builtin}). -The options appearing in @env{SHELLOPTS} are those reported -as @samp{on} by @samp{set -o}. -If this variable is in the environment when Bash -starts up, each shell option in the list will be enabled before -reading any startup files. This variable is readonly. - -@item SHLVL -Incremented by one each time a new instance of Bash is started. This is -intended to be a count of how deeply your Bash shells are nested. - -@item TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the @code{time} -reserved word should be displayed. -The @samp{%} character introduces an -escape sequence that is expanded to a time value or other -information. -The escape sequences and their meanings are as -follows; the braces denote optional portions. - -@table @code - -@item %% -A literal @samp{%}. - -@item %[@var{p}][l]R -The elapsed time in seconds. - -@item %[@var{p}][l]U -The number of CPU seconds spent in user mode. - -@item %[@var{p}][l]S -The number of CPU seconds spent in system mode. - -@item %P -The CPU percentage, computed as (%U + %S) / %R. -@end table - -The optional @var{p} is a digit specifying the precision, the number of -fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; values -of @var{p} greater than 3 are changed to 3. -If @var{p} is not specified, the value 3 is used. - -The optional @code{l} specifies a longer format, including minutes, of -the form @var{MM}m@var{SS}.@var{FF}s. -The value of @var{p} determines whether or not the fraction is included. - -If this variable is not set, Bash acts as if it had the value -@example -@code{$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'} -@end example -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. - -@item TMOUT -If set to a value greater than zero, @code{TMOUT} is treated as the -default timeout for the @code{read} builtin (@pxref{Bash Builtins}). -The @code{select} command (@pxref{Conditional Constructs}) terminates -if input does not arrive after @code{TMOUT} seconds when input is coming -from a terminal. - -In an interative shell, the value is interpreted as -the number of seconds to wait for input after issuing the primary -prompt when the shell is interactive. -Bash terminates after that number of seconds if input does -not arrive. - -@item UID -The numeric real user id of the current user. This variable is readonly. - -@end vtable - -@node Bash Features -@chapter Bash Features - -This section describes features unique to Bash. - -@menu -* Invoking Bash:: Command line options that you can give - to Bash. -* Bash Startup Files:: When and how Bash executes scripts. -* Interactive Shells:: What an interactive shell is. -* Bash Conditional Expressions:: Primitives used in composing expressions for - the @code{test} builtin. -* Shell Arithmetic:: Arithmetic on shell variables. -* Aliases:: Substituting one command for another. -* Arrays:: Array Variables. -* The Directory Stack:: History of visited directories. -* Printing a Prompt:: Controlling the PS1 string. -* The Restricted Shell:: A more controlled mode of shell execution. -* Bash POSIX Mode:: Making Bash behave more closely to what - the POSIX standard specifies. -@end menu - -@node Invoking Bash -@section Invoking Bash - -@example -bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] -c @var{string} [@var{argument} @dots{}] -bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -@end example - -In addition to the single-character shell command-line options -(@pxref{The Set Builtin}), there are several multi-character -options that you can use. These options must appear on the command -line before the single-character options to be recognized. - -@table @code -@item --debugger -Arrange for the debugger profile to be executed before the shell -starts. Turns on extended debugging mode (see @ref{Bash Builtins} -for a description of the @code{extdebug} option to the @code{shopt} -builtin) and shell function tracing -(see @ref{The Set Builtin} for a description of the @code{-o functrace} -option). - -@item --dump-po-strings -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput -in the @sc{gnu} @code{gettext} PO (portable object) file format. -Equivalent to @option{-D} except for the output format. - -@item --dump-strings -Equivalent to @option{-D}. - -@item --help -Display a usage message on standard output and exit sucessfully. - -@item --init-file @var{filename} -@itemx --rcfile @var{filename} -Execute commands from @var{filename} (instead of @file{~/.bashrc}) -in an interactive shell. - -@item --login -Equivalent to @option{-l}. - -@item --noediting -Do not use the @sc{gnu} Readline library (@pxref{Command Line Editing}) -to read command lines when the shell is interactive. - -@item --noprofile -Don't load the system-wide startup file @file{/etc/profile} -or any of the personal initialization files -@file{~/.bash_profile}, @file{~/.bash_login}, or @file{~/.profile} -when Bash is invoked as a login shell. - -@item --norc -Don't read the @file{~/.bashrc} initialization file in an -interactive shell. This is on by default if the shell is -invoked as @code{sh}. - -@item --posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} 1003.2 standard to match the standard. This -is intended to make Bash behave as a strict superset of that -standard. @xref{Bash POSIX Mode}, for a description of the Bash -@sc{posix} mode. - -@item --restricted -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item --verbose -Equivalent to @option{-v}. Print shell input lines as they're read. - -@item --version -Show version information for this instance of -Bash on the standard output and exit successfully. - -@end table - -There are several single-character options that may be supplied at -invocation which are not available with the @code{set} builtin. - -@table @code -@item -c @var{string} -Read and execute commands from @var{string} after processing the -options, then exit. Any remaining arguments are assigned to the -positional parameters, starting with @code{$0}. - -@item -i -Force the shell to run interactively. Interactive shells are -described in @ref{Interactive Shells}. - -@item -l -Make this shell act as if it had been directly invoked by login. -When the shell is interactive, this is equivalent to starting a -login shell with @samp{exec -l bash}. -When the shell is not interactive, the login shell startup files will -be executed. -@samp{exec bash -l} or @samp{exec bash --login} -will replace the current shell with a Bash login shell. -@xref{Bash Startup Files}, for a description of the special behavior -of a login shell. - -@item -r -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item -s -If this option is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. - -@item -D -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput. -These are the strings that -are subject to language translation when the current locale -is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). -This implies the @option{-n} option; no commands will be executed. - -@item [-+]O [@var{shopt_option}] -@var{shopt_option} is one of the shell options accepted by the -@code{shopt} builtin (@pxref{Shell Builtin Commands}). -If @var{shopt_option} is present, @option{-O} sets the value of that option; -@option{+O} unsets it. -If @var{shopt_option} is not supplied, the names and values of the shell -options accepted by @code{shopt} are printed on the standard output. -If the invocation option is @option{+O}, the output is displayed in a format -that may be reused as input. - -@item -- -A @code{--} signals the end of options and disables further option -processing. -Any arguments after the @code{--} are treated as filenames and arguments. - -@end table - -@cindex login shell -A @emph{login} shell is one whose first character of argument zero is -@samp{-}, or one invoked with the @option{--login} option. - -@cindex interactive shell -An @emph{interactive} shell is one started without non-option arguments, -unless @option{-s} is specified, -without specifying the @option{-c} option, and whose input and output are both -connected to terminals (as determined by @code{isatty(3)}), or one -started with the @option{-i} option. @xref{Interactive Shells}, for more -information. - -If arguments remain after option processing, and neither the -@option{-c} nor the @option{-s} -option has been supplied, the first argument is assumed to -be the name of a file containing shell commands (@pxref{Shell Scripts}). -When Bash is invoked in this fashion, @code{$0} -is set to the name of the file, and the positional parameters -are set to the remaining arguments. -Bash reads and executes commands from this file, then exits. -Bash's exit status is the exit status of the last command executed -in the script. If no commands are executed, the exit status is 0. - -@node Bash Startup Files -@section Bash Startup Files -@cindex startup files - -This section describs how Bash executes its startup files. -If any of the files exist but cannot be read, Bash reports an error. -Tildes are expanded in file names as described above under -Tilde Expansion (@pxref{Tilde Expansion}). - -Interactive shells are described in @ref{Interactive Shells}. - -@subsubheading Invoked as an interactive login shell, or with @option{--login} - -When Bash is invoked as an interactive login shell, or as a -non-interactive shell with the @option{--login} option, it first reads and -executes commands from the file @file{/etc/profile}, if that file exists. -After reading that file, it looks for @file{~/.bash_profile}, -@file{~/.bash_login}, and @file{~/.profile}, in that order, and reads -and executes commands from the first one that exists and is readable. -The @option{--noprofile} option may be used when the shell is started to -inhibit this behavior. - -When a login shell exits, Bash reads and executes commands from -the file @file{~/.bash_logout}, if it exists. - -@subsubheading Invoked as an interactive non-login shell - -When an interactive shell that is not a login shell is started, Bash -reads and executes commands from @file{~/.bashrc}, if that file exists. -This may be inhibited by using the @option{--norc} option. -The @option{--rcfile @var{file}} option will force Bash to read and -execute commands from @var{file} instead of @file{~/.bashrc}. - -So, typically, your @file{~/.bash_profile} contains the line -@example -@code{if [ -f ~/.bashrc ]; then . ~/.bashrc; fi} -@end example -@noindent -after (or before) any login-specific initializations. - -@subsubheading Invoked non-interactively - -When Bash is started non-interactively, to run a shell script, -for example, it looks for the variable @env{BASH_ENV} in the environment, -expands its value if it appears there, and uses the expanded value as -the name of a file to read and execute. Bash behaves as if the -following command were executed: -@example -@code{if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi} -@end example -@noindent -but the value of the @env{PATH} variable is not used to search for the -file name. - -As noted above, if a non-interactive shell is invoked with the -@option{--login} option, Bash attempts to read and execute commands from the -login shell startup files. - -@subsubheading Invoked with name @code{sh} - -If Bash is invoked with the name @code{sh}, it tries to mimic the -startup behavior of historical versions of @code{sh} as closely as -possible, while conforming to the @sc{posix} standard as well. - -When invoked as an interactive login shell, or as a non-interactive -shell with the @option{--login} option, it first attempts to read -and execute commands from @file{/etc/profile} and @file{~/.profile}, in -that order. -The @option{--noprofile} option may be used to inhibit this behavior. -When invoked as an interactive shell with the name @code{sh}, Bash -looks for the variable @env{ENV}, expands its value if it is defined, -and uses the expanded value as the name of a file to read and execute. -Since a shell invoked as @code{sh} does not attempt to read and execute -commands from any other startup files, the @option{--rcfile} option has -no effect. -A non-interactive shell invoked with the name @code{sh} does not attempt -to read any other startup files. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after -the startup files are read. - -@subsubheading Invoked in @sc{posix} mode - -When Bash is started in @sc{posix} mode, as with the -@option{--posix} command line option, it follows the @sc{posix} standard -for startup files. -In this mode, interactive shells expand the @env{ENV} variable -and commands are read and executed from the file whose name is the -expanded value. -No other startup files are read. - -@subsubheading Invoked by remote shell daemon - -Bash attempts to determine when it is being run by the remote shell -daemon, usually @code{rshd}. If Bash determines it is being run by -rshd, it reads and executes commands from @file{~/.bashrc}, if that -file exists and is readable. -It will not do this if invoked as @code{sh}. -The @option{--norc} option may be used to inhibit this behavior, and the -@option{--rcfile} option may be used to force another file to be read, but -@code{rshd} does not generally invoke the shell with those options or -allow them to be specified. - -@subsubheading Invoked with unequal effective and real @sc{uid/gid}s - -If Bash is started with the effective user (group) id not equal to the -real user (group) id, and the @code{-p} option is not supplied, no startup -files are read, shell functions are not inherited from the environment, -the @env{SHELLOPTS} variable, if it appears in the environment, is ignored, -and the effective user id is set to the real user id. -If the @code{-p} option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. - -@node Interactive Shells -@section Interactive Shells -@cindex interactive shell -@cindex shell, interactive - -@menu -* What is an Interactive Shell?:: What determines whether a shell is Interactive. -* Is this Shell Interactive?:: How to tell if a shell is interactive. -* Interactive Shell Behavior:: What changes in a interactive shell? -@end menu - -@node What is an Interactive Shell? -@subsection What is an Interactive Shell? - -An interactive shell -is one started without non-option arguments, unless @option{-s} is -specified, without specifiying the @option{-c} option, and -whose input and output are both -connected to terminals (as determined by @code{isatty(3)}), -or one started with the @option{-i} option. - -An interactive shell generally reads from and writes to a user's -terminal. - -The @option{-s} invocation option may be used to set the positional parameters -when an interactive shell is started. - -@node Is this Shell Interactive? -@subsection Is this Shell Interactive? - -To determine within a startup script whether or not Bash is -running interactively, -test the value of the @samp{-} special parameter. -It contains @code{i} when the shell is interactive. For example: - -@example -case "$-" in -*i*) echo This shell is interactive ;; -*) echo This shell is not interactive ;; -esac -@end example - -Alternatively, startup scripts may examine the variable -@env{PS1}; it is unset in non-interactive shells, and set in -interactive shells. Thus: - -@example -if [ -z "$PS1" ]; then - echo This shell is not interactive -else - echo This shell is interactive -fi -@end example - -@node Interactive Shell Behavior -@subsection Interactive Shell Behavior - -When the shell is running interactively, it changes its behavior in -several ways. - -@enumerate -@item -Startup files are read and executed as described in @ref{Bash Startup Files}. - -@item -Job Control (@pxref{Job Control}) is enabled by default. When job -control is in effect, Bash ignores the keyboard-generated job control -signals @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -@item -Bash expands and displays @env{PS1} before reading the first line -of a command, and expands and displays @env{PS2} before reading the -second and subsequent lines of a multi-line command. - -@item -Bash executes the value of the @env{PROMPT_COMMAND} variable as a command -before printing the primary prompt, @env{$PS1} -(@pxref{Bash Variables}). - -@item -Readline (@pxref{Command Line Editing}) is used to read commands from -the user's terminal. - -@item -Bash inspects the value of the @code{ignoreeof} option to @code{set -o} -instead of exiting immediately when it receives an @code{EOF} on its -standard input when reading a command (@pxref{The Set Builtin}). - -@item -Command history (@pxref{Bash History Facilities}) -and history expansion (@pxref{History Interaction}) -are enabled by default. -Bash will save the command history to the file named by @env{$HISTFILE} -when an interactive shell exits. - -@item -Alias expansion (@pxref{Aliases}) is performed by default. - -@item -In the absence of any traps, Bash ignores @code{SIGTERM} -(@pxref{Signals}). - -@item -In the absence of any traps, @code{SIGINT} is caught and handled -((@pxref{Signals}). -@code{SIGINT} will interrupt some shell builtins. - -@item -An interactive login shell sends a @code{SIGHUP} to all jobs on exit -if the @code{hupoxexit} shell option has been enabled (@pxref{Signals}). - -@item -The @option{-n} invocation option is ignored, and @samp{set -n} has -no effect (@pxref{The Set Builtin}). - -@item -Bash will check for mail periodically, depending on the values of the -@env{MAIL}, @env{MAILPATH}, and @env{MAILCHECK} shell variables -(@pxref{Bash Variables}). - -@item -Expansion errors due to references to unbound shell variables after -@samp{set -u} has been enabled will not cause the shell to exit -(@pxref{The Set Builtin}). - -@item -The shell will not exit on expansion errors caused by @var{var} being unset -or null in @code{$@{@var{var}:?@var{word}@}} expansions -(@pxref{Shell Parameter Expansion}). - -@item -Redirection errors encountered by shell builtins will not cause the -shell to exit. - -@item -When running in @sc{posix} mode, a special builtin returning an error -status will not cause the shell to exit (@pxref{Bash POSIX Mode}). -@item -A failed @code{exec} will not cause the shell to exit -(@pxref{Bourne Shell Builtins}). - -@item -Parser syntax errors will not cause the shell to exit. - -@item -Simple spelling correction for directory arguments to the @code{cd} -builtin is enabled by default (see the description of the @code{cdspell} -option to the @code{shopt} builtin in @ref{Bash Builtins}). - -@item -The shell will check the value of the @env{TMOUT} variable and exit -if a command is not read within the specified number of seconds after -printing @env{$PS1} (@pxref{Bash Variables}). - -@end enumerate - -@node Bash Conditional Expressions -@section Bash Conditional Expressions -@cindex expressions, conditional - -Conditional expressions are used by the @code{[[} compound command -and the @code{test} and @code{[} builtin commands. - -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. -If the @var{file} argument to one of the primaries is of the form -@file{/dev/fd/@var{N}}, then file descriptor @var{N} is checked. -If the @var{file} argument to one of the primaries is one of -@file{/dev/stdin}, @file{/dev/stdout}, or @file{/dev/stderr}, file -descriptor 0, 1, or 2, respectively, is checked. - -@table @code -@item -a @var{file} -True if @var{file} exists. - -@item -b @var{file} -True if @var{file} exists and is a block special file. - -@item -c @var{file} -True if @var{file} exists and is a character special file. - -@item -d @var{file} -True if @var{file} exists and is a directory. - -@item -e @var{file} -True if @var{file} exists. - -@item -f @var{file} -True if @var{file} exists and is a regular file. - -@item -g @var{file} -True if @var{file} exists and its set-group-id bit is set. - -@item -h @var{file} -True if @var{file} exists and is a symbolic link. - -@item -k @var{file} -True if @var{file} exists and its "sticky" bit is set. - -@item -p @var{file} -True if @var{file} exists and is a named pipe (FIFO). - -@item -r @var{file} -True if @var{file} exists and is readable. - -@item -s @var{file} -True if @var{file} exists and has a size greater than zero. - -@item -t @var{fd} -True if file descriptor @var{fd} is open and refers to a terminal. - -@item -u @var{file} -True if @var{file} exists and its set-user-id bit is set. - -@item -w @var{file} -True if @var{file} exists and is writable. - -@item -x @var{file} -True if @var{file} exists and is executable. - -@item -O @var{file} -True if @var{file} exists and is owned by the effective user id. - -@item -G @var{file} -True if @var{file} exists and is owned by the effective group id. - -@item -L @var{file} -True if @var{file} exists and is a symbolic link. - -@item -S @var{file} -True if @var{file} exists and is a socket. - -@item -N @var{file} -True if @var{file} exists and has been modified since it was last read. - -@item @var{file1} -nt @var{file2} -True if @var{file1} is newer (according to modification date) -than @var{file2}, or if @var{file1} exists and @var{file2} does not. - -@item @var{file1} -ot @var{file2} -True if @var{file1} is older than @var{file2}, -or if @var{file2} exists and @var{file1} does not. - -@item @var{file1} -ef @var{file2} -True if @var{file1} and @var{file2} refer to the same device and -inode numbers. - -@item -o @var{optname} -True if shell option @var{optname} is enabled. -The list of options appears in the description of the @option{-o} -option to the @code{set} builtin (@pxref{The Set Builtin}). - -@item -z @var{string} -True if the length of @var{string} is zero. - -@item -n @var{string} -@itemx @var{string} -True if the length of @var{string} is non-zero. - -@item @var{string1} == @var{string2} -True if the strings are equal. -@samp{=} may be used in place of @samp{==} for strict @sc{posix} compliance. - -@item @var{string1} != @var{string2} -True if the strings are not equal. - -@item @var{string1} < @var{string2} -True if @var{string1} sorts before @var{string2} lexicographically -in the current locale. - -@item @var{string1} > @var{string2} -True if @var{string1} sorts after @var{string2} lexicographically -in the current locale. - -@item @var{arg1} OP @var{arg2} -@code{OP} is one of -@samp{-eq}, @samp{-ne}, @samp{-lt}, @samp{-le}, @samp{-gt}, or @samp{-ge}. -These arithmetic binary operators return true if @var{arg1} -is equal to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to @var{arg2}, -respectively. @var{Arg1} and @var{arg2} -may be positive or negative integers. - -@end table - -@node Shell Arithmetic -@section Shell Arithmetic -@cindex arithmetic, shell -@cindex shell arithmetic -@cindex expressions, arithmetic -@cindex evaluation, arithmetic -@cindex arithmetic evaluation - -The shell allows arithmetic expressions to be evaluated, as one of -the shell expansions or by the @code{let} and the @option{-i} option -to the @code{declare} builtins. - -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -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 @var{id}++ @var{id}-- -variable post-increment and post-decrement - -@item ++@var{id} --@var{id} -variable pre-increment and pre-decrement - -@item - + -unary minus and plus - -@item ! ~ -logical and bitwise negation - -@item ** -exponentiation - -@item * / % -multiplication, division, remainder - -@item + - -addition, subtraction - -@item << >> -left and right bitwise shifts - -@item <= >= < > -comparison - -@item == != -equality and inequality - -@item & -bitwise AND - -@item ^ -bitwise exclusive OR - -@item | -bitwise OR - -@item && -logical AND - -@item || -logical OR - -@item expr ? expr : expr -conditional operator - -@item = *= /= %= += -= <<= >>= &= ^= |= -assignment - -@item expr1 , expr2 -comma -@end table - -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -@var{integer} attribute using @samp{declare -i} is assigned a value. -A null value evaluates to 0. -A shell variable need not have its integer attribute turned on -to be used in an expression. - -Constants with a leading 0 are interpreted as octal numbers. -A leading @samp{0x} or @samp{0X} denotes hexadecimal. Otherwise, -numbers take the form [@var{base}@code{#}]@var{n}, where @var{base} -is a decimal number between 2 and 64 representing the arithmetic -base, and @var{n} is a number in that base. If @var{base}@code{#} is -omitted, then base 10 is used. -The digits greater than 9 are represented by the lowercase letters, -the uppercase letters, @samp{@@}, and @samp{_}, in that order. -If @var{base} is less than or equal to 36, lowercase and uppercase -letters may be used interchangably to represent numbers between 10 -and 35. - -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. - -@node Aliases -@section Aliases -@cindex alias expansion - -@var{Aliases} allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of aliases that may be set and unset with -the @code{alias} and @code{unalias} builtin commands. - -The first word of each simple command, if unquoted, is checked to see -if it has an alias. -If so, that word is replaced by the text of the alias. -The characters @samp{/}, @samp{$}, @samp{`}, @samp{=} and any of the -shell metacharacters or quoting characters listed above may not appear -in an alias name. -The replacement text may contain any valid -shell input, including shell metacharacters. -The first word of the replacement text is tested for -aliases, but a word that is identical to an alias being expanded -is not expanded a second time. -This means that one may alias @code{ls} to @code{"ls -F"}, -for instance, and Bash does not try to recursively expand the -replacement text. If the last character of the alias value is a -space or tab character, then the next command word following the -alias is also checked for alias expansion. - -Aliases are created and listed with the @code{alias} -command, and removed with the @code{unalias} command. - -There is no mechanism for using arguments in the replacement text, -as in @code{csh}. -If arguments are needed, a shell function should be used -(@pxref{Shell Functions}). - -Aliases are not expanded when the shell is not interactive, -unless the @code{expand_aliases} shell option is set using -@code{shopt} (@pxref{Bash Builtins}). - -The rules concerning the definition and use of aliases are -somewhat confusing. Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -The commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when a 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. - -For almost every purpose, shell functions are preferred over aliases. - -@node Arrays -@section Arrays -@cindex arrays - -Bash provides one-dimensional array variables. Any variable may be used as -an array; the @code{declare} builtin will explicitly declare an array. -There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. Arrays are zero-based. - -An array is created automatically if any variable is assigned to using -the syntax -@example -name[@var{subscript}]=@var{value} -@end example - -@noindent -The @var{subscript} -is treated as an arithmetic expression that must evaluate to a number -greater than or equal to zero. To explicitly declare an array, use -@example -declare -a @var{name} -@end example -@noindent -The syntax -@example -declare -a @var{name}[@var{subscript}] -@end example -@noindent -is also accepted; the @var{subscript} is ignored. Attributes may be -specified for an array variable using the @code{declare} and -@code{readonly} builtins. Each attribute applies to all members of -an array. - -Arrays are assigned to using compound assignments of the form -@example -name=(value@var{1} @dots{} value@var{n}) -@end example -@noindent -where each -@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}. If -the optional subscript is supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. -This syntax is also accepted by the @code{declare} -builtin. Individual array elements may be assigned to using the -@code{name[}@var{subscript}@code{]=}@var{value} syntax introduced above. - -Any element of an array may be referenced using -@code{$@{name[}@var{subscript}@code{]@}}. -The braces are required to avoid -conflicts with the shell's filename expansion operators. If the -@var{subscript} is @samp{@@} or @samp{*}, the word expands to all members -of the array @var{name}. These subscripts differ only when the word -appears within double quotes. If the word is double-quoted, -@code{$@{name[*]@}} expands to a single word with -the value of each array member separated by the first character of the -@env{IFS} variable, and @code{$@{name[@@]@}} expands each element of -@var{name} to a separate word. When there are no array members, -@code{$@{name[@@]@}} expands to nothing. This is analogous to the -expansion of the special parameters @samp{@@} and @samp{*}. -@code{$@{#name[}@var{subscript}@code{]@}} expands to the length of -@code{$@{name[}@var{subscript}@code{]@}}. -If @var{subscript} is @samp{@@} or -@samp{*}, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing element zero. - -The @code{unset} builtin is used to destroy arrays. -@code{unset} @var{name}[@var{subscript}] -destroys the array element at index @var{subscript}. -@code{unset} @var{name}, where @var{name} is an array, removes the -entire array. A subscript of @samp{*} or @samp{@@} also removes the -entire array. - -The @code{declare}, @code{local}, and @code{readonly} -builtins each accept a @option{-a} -option to specify an array. The @code{read} -builtin accepts a @option{-a} -option to assign a list of words read from the standard input -to an array, and can read values from the standard input into -individual array elements. The @code{set} and @code{declare} -builtins display array values in a way that allows them to be -reused as input. - -@node The Directory Stack -@section The Directory Stack -@cindex directory stack - -@menu -* Directory Stack Builtins:: Bash builtin commands to manipulate - the directory stack. -@end menu - -The directory stack is a list of recently-visited directories. The -@code{pushd} builtin adds directories to the stack as it changes -the current directory, and the @code{popd} builtin removes specified -directories from the stack and changes the current directory to -the directory removed. The @code{dirs} builtin displays the contents -of the directory stack. - -The contents of the directory stack are also visible -as the value of the @env{DIRSTACK} shell variable. - -@node Directory Stack Builtins -@subsection Directory Stack Builtins - -@table @code - -@item dirs -@btindex dirs -@example -dirs [+@var{N} | -@var{N}] [-clpv] -@end example -Display the list of currently remembered directories. Directories -are added to the list with the @code{pushd} command; the -@code{popd} command removes directories from the list. -@table @code -@item +@var{N} -Displays the @var{N}th directory (counting from the left of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{N} -Displays the @var{N}th directory (counting from the right of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -c -Clears the directory stack by deleting all of the elements. -@item -l -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -@item -p -Causes @code{dirs} to print the directory stack with one entry per -line. -@item -v -Causes @code{dirs} to print the directory stack with one entry per -line, prefixing each entry with its index in the stack. -@end table - -@item popd -@btindex popd -@example -popd [+@var{N} | -@var{N}] [-n] -@end example - -Remove the top entry from the directory stack, and @code{cd} -to the new top directory. -When no arguments are given, @code{popd} -removes the top directory from the stack and -performs a @code{cd} to the new top directory. The -elements are numbered from 0 starting at the first directory listed with -@code{dirs}; i.e., @code{popd} is equivalent to @code{popd +0}. -@table @code -@item +@var{N} -Removes the @var{N}th directory (counting from the left of the -list printed by @code{dirs}), starting with zero. -@item -@var{N} -Removes the @var{N}th directory (counting from the right of the -list printed by @code{dirs}), starting with zero. -@item -n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -@end table - -@btindex pushd -@item pushd -@example -pushd [@var{dir} | @var{+N} | @var{-N}] [-n] -@end example - -Save the current directory on the top of the directory stack -and then @code{cd} to @var{dir}. -With no arguments, @code{pushd} 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}, starting with zero) 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}, starting with zero) to the top of -the list by rotating the stack. -@item -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@item @var{dir} -Makes the current working directory be the top of the stack, and then -executes the equivalent of `@code{cd} @var{dir}'. -@code{cd}s to @var{dir}. -@end table - -@end table - -@node Printing a Prompt -@section Controlling the Prompt -@cindex prompting - -The value of the variable @env{PROMPT_COMMAND} is examined just before -Bash prints each primary prompt. If @env{PROMPT_COMMAND} is set and -has a non-null value, then the -value is executed just as if it had been typed on the command line. - -In addition, the following table describes the special characters which -can appear in the prompt variables: - -@table @code -@item \a -A bell character. -@item \d -The date, in "Weekday Month Date" format (e.g., "Tue May 26"). -@item \D@{@var{format}@} -The @var{format} is passed to @code{strftime}(3) and the result is inserted -into the prompt string; an empty @var{format} results in a locale-specific -time representation. The braces are required. -@item \e -An escape character. -@item \h -The hostname, up to the first `.'. -@item \H -The hostname. -@item \j -The number of jobs currently managed by the shell. -@item \l -The basename of the shell's terminal device name. -@item \n -A newline. -@item \r -A carriage return. -@item \s -The name of the shell, the basename of @code{$0} (the portion -following the final slash). -@item \t -The time, in 24-hour HH:MM:SS format. -@item \T -The time, in 12-hour HH:MM:SS format. -@item \@@ -The time, in 12-hour am/pm format. -@item \A -The time, in 24-hour HH:MM format. -@item \u -The username of the current user. -@item \v -The version of Bash (e.g., 2.00) -@item \V -The release of Bash, version + patchlevel (e.g., 2.00.0) -@item \w -The current working directory, with @env{$HOME} abbreviated with a tilde. -@item \W -The basename of @env{$PWD}, with @env{$HOME} abbreviated with a tilde. -@item \! -The history number of this command. -@item \# -The command number of this command. -@item \$ -If the effective uid is 0, @code{#}, otherwise @code{$}. -@item \@var{nnn} -The character whose ASCII code is the octal value @var{nnn}. -@item \\ -A backslash. -@item \[ -Begin a sequence of non-printing characters. This could be used to -embed a terminal control sequence into the prompt. -@item \] -End a sequence of non-printing characters. -@end table - -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 -(@pxref{Bash History Facilities}), 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 quote removal, subject to the value of the -@code{promptvars} shell option (@pxref{Bash Builtins}). - -@node The Restricted Shell -@section The Restricted Shell -@cindex restricted shell - -If Bash is started with the name @code{rbash}, or the -@option{--restricted} -or -@option{-r} -option is supplied at invocation, the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -A restricted shell behaves identically to @code{bash} -with the exception that the following are disallowed or not performed: - -@itemize @bullet -@item -Changing directories with the @code{cd} builtin. -@item -Setting or unsetting the values of the @env{SHELL}, @env{PATH}, -@env{ENV}, or @env{BASH_ENV} variables. -@item -Specifying command names containing slashes. -@item -Specifying a filename containing a slash as an argument to the @code{.} -builtin command. -@item -Specifying a filename containing a slash as an argument to the @option{-p} -option to the @code{hash} builtin command. -@item -Importing function definitions from the shell environment at startup. -@item -Parsing the value of @env{SHELLOPTS} from the shell environment at startup. -@item -Redirecting output using the @samp{>}, @samp{>|}, @samp{<>}, @samp{>&}, -@samp{&>}, and @samp{>>} redirection operators. -@item -Using the @code{exec} builtin to replace the shell with another command. -@item -Adding or deleting builtin commands with the -@option{-f} and @option{-d} options to the @code{enable} builtin. -@item -Using the @code{enable} builtin command to enable disabled shell builtins. -@item -Specifying the @option{-p} option to the @code{command} builtin. -@item -Turning off restricted mode with @samp{set +r} or @samp{set +o restricted}. -@end itemize - -These restrictions are enforced after any startup files are read. - -When a command that is found to be a shell script is executed -(@pxref{Shell Scripts}), @code{rbash} turns off any restrictions in -the shell spawned to execute the script. - -@node Bash POSIX Mode -@section Bash POSIX Mode -@cindex POSIX Mode - -Starting Bash with the @option{--posix} command-line option or executing -@samp{set -o posix} while Bash is running will cause Bash to conform more -closely to the @sc{posix} 1003.2 standard by changing the behavior to -match that specified by @sc{posix} in areas where the Bash default differs. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after reading the -startup files. - -The following list is what's changed when `@sc{posix} mode' is in effect: - -@enumerate -@item -When a command in the hash table no longer exists, Bash will re-search -@env{$PATH} to find the new location. This is also available with -@samp{shopt -s checkhash}. - -@item -The message printed by the job control code and builtins when a job -exits with a non-zero status is `Done(status)'. - -@item -The message printed by the job control code and builtins when a job -is stopped is `Stopped(@var{signame})', where @var{signame} is, for -example, @code{SIGTSTP}. - -@item -Reserved words may not be aliased. - -@item -The @sc{posix} 1003.2 @env{PS1} and @env{PS2} expansions of @samp{!} to -the history number and @samp{!!} to @samp{!} are enabled, -and parameter expansion is performed on the values of @env{PS1} and -@env{PS2} regardless of the setting of the @code{promptvars} option. - -@item -The @sc{posix} 1003.2 startup files are executed (@env{$ENV}) rather than -the normal Bash files. - -@item -Tilde expansion is only performed on assignments preceding a command -name, rather than on all assignment statements on the line. - -@item -The default history file is @file{~/.sh_history} (this is the -default value of @env{$HISTFILE}). - -@item -The output of @samp{kill -l} prints all the signal names on a single line, -separated by spaces, without the @samp{SIG} prefix. - -@item -The @code{kill} builtin does not accept signal names with a @samp{SIG} -prefix. - -@item -Non-interactive shells exit if @var{filename} in @code{.} @var{filename} -is not found. - -@item -Non-interactive shells exit if a syntax error in an arithmetic expansion -results in an invalid expression. - -@item -Redirection operators do not perform filename expansion on the word -in the redirection unless the shell is interactive. - -@item -Redirection operators do not perform word splitting on the word in the -redirection. - -@item -Function names must be valid shell @code{name}s. That is, they may not -contain characters other than letters, digits, and underscores, and -may not start with a digit. Declaring a function with an invalid name -causes a fatal syntax error in non-interactive shells. - -@item -@sc{posix} 1003.2 `special' builtins are found before shell functions -during command lookup. - -@item -If a @sc{posix} 1003.2 special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the POSIX.2 standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@item -If the @code{cd} builtin finds a directory to change to -using @env{$CDPATH}, the -value it assigns to the @env{PWD} variable does not contain any -symbolic links, as if @samp{cd -P} had been executed. - -@item -If @env{CDPATH} is set, the @code{cd} builtin will not implicitly -append the current directory to it. This means that @code{cd} will -fail if no valid directory name can be constructed from -any of the entries in @env{$CDPATH}, even if the a directory with -the same name as the name given as an argument to @code{cd} exists -in the current directory. - -@item -A non-interactive shell exits with an error status if a variable -assignment error occurs when no command name follows the assignment -statements. -A variable assignment error occurs, for example, when trying to assign -a value to a readonly variable. - -@item -A non-interactive shell exits with an error status if the iteration -variable in a @code{for} statement or the selection variable in a -@code{select} statement is a readonly variable. - -@item -Process substitution is not available. - -@item -Assignment statements preceding @sc{posix} 1003.2 special builtins -persist in the shell environment after the builtin completes. - -@item -Assignment statements preceding shell function calls persist in the -shell environment after the function returns, as if a @sc{posix} -special builtin command had been executed. - -@item -The @code{export} and @code{readonly} builtin commands display their -output in the format required by @sc{posix} 1003.2. - -@item -The @code{trap} builtin displays signal names without the leading -@code{SIG}. - -@item -The @code{trap} builtin doesn't check the first argument for a possible -signal specification and revert the signal handling to the original -disposition if it is. If users want to reset the handler for a given -signal to the original disposition, they should use @samp{-} as the -first argument. - -@item -The @code{.} and @code{source} builtins do not search the current directory -for the filename argument if it is not found by searching @env{PATH}. - -@item -Subshells spawned to execute command substitutions inherit the value of -the @option{-e} option from the parent shell. When not in @sc{posix} mode, -Bash clears the @option{-e} option in such subshells. - -@item -Alias expansion is always enabled, even in non-interactive shells. - -@item -When the @code{alias} builtin displays alias definitions, it does not -display them with a leading @samp{alias } unless the @option{-p} option -is supplied. - -@item -When the @code{set} builtin is invoked without options, it does not display -shell function names and definitions. - -@item -When the @code{set} builtin is invoked without options, it displays -variable values without quotes, unless they contain shell metacharacters, -even if the result contains nonprinting characters. - -@item -When the @code{cd} builtin is invoked in @var{logical} mode, and the pathname -constructed from @code{$PWD} and the directory name supplied as an argument -does not refer to an existing directory, @code{cd} will fail instead of -falling back to @var{physical} mode. -@end enumerate - -There is other @sc{posix} 1003.2 behavior that Bash does not implement. -Specifically: - -@enumerate -@item -Assignment statements affect the execution environment of all -builtins, not just special ones. - -@item -When a subshell is created to execute a shell script with execute permission, -but without a leading @samp{#!}, Bash sets @code{$0} to the full pathname of -the script as found by searching @code{$PATH}, rather than the command as -typed by the user. - -@item -When using @samp{.} to source a shell script found in @code{$PATH}, bash -checks execute permission bits rather than read permission bits, just as -if it were searching for a command. - -@end enumerate - -@node Job Control -@chapter Job Control - -This chapter discusses what job control is, how it works, and how -Bash allows you to access its facilities. - -@menu -* Job Control Basics:: How job control works. -* Job Control Builtins:: Bash builtin commands used to interact - with job control. -* Job Control Variables:: Variables Bash uses to customize job - control. -@end menu - -@node Job Control Basics -@section Job Control Basics -@cindex job control -@cindex foreground -@cindex background -@cindex suspending jobs - -Job control -refers to the ability to selectively stop (suspend) -the execution of processes and continue (resume) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the system's terminal driver and Bash. - -The shell associates a @var{job} with each pipeline. It keeps a -table of currently executing jobs, which may be listed with the -@code{jobs} command. When Bash starts a job -asynchronously, it prints a line that looks -like: -@example -[1] 25647 -@end example -@noindent -indicating that this job is job number 1 and that the process @sc{id} -of the last process in the pipeline associated with this job is -25647. All of the processes in a single pipeline are members of -the same job. Bash uses the @var{job} abstraction as the -basis for job control. - -To facilitate the implementation of the user interface to job -control, the operating system maintains the notion of a current terminal -process group @sc{id}. Members of this process group (processes whose -process group @sc{id} is equal to the current terminal process group -@sc{id}) receive keyboard-generated signals such as @code{SIGINT}. -These processes are said to be in the foreground. Background -processes are those whose process group @sc{id} differs from the -terminal's; such processes are immune to keyboard-generated -signals. Only foreground processes are allowed to read from or -write to the terminal. Background processes which attempt to -read from (write to) the terminal are sent a @code{SIGTTIN} -(@code{SIGTTOU}) signal by the terminal driver, which, unless -caught, suspends the process. - -If the operating system on which Bash is running supports -job control, Bash contains facilities 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 -control 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. The user then manipulates 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}. -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 or started -in the background. 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{-}. - -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. - -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 @option{-b} option to the @code{set} builtin is enabled, -Bash reports such changes immediately (@pxref{The Set Builtin}). -Any trap on @code{SIGCHLD} is executed for each child process -that exits. - -If an attempt to exit Bash is made while jobs are stopped, the -shell prints a message warning that there are stopped jobs. -The @code{jobs} command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -Bash does not print another warning, and the stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@table @code - -@item bg -@btindex bg -@example -bg [@var{jobspec}] -@end example -Resume the suspended job @var{jobspec} in the background, as if it -had been started with @samp{&}. -If @var{jobspec} is not supplied, the current job is used. -The return status is zero unless it is run when job control is not -enabled, or, when run with job control enabled, if @var{jobspec} was -not found or @var{jobspec} specifies a job that was started without -job control. - -@item fg -@btindex fg -@example -fg [@var{jobspec}] -@end example -Resume the job @var{jobspec} in the foreground and make it the current job. -If @var{jobspec} is not supplied, the current job is used. -The return status is that of the command placed into the foreground, -or non-zero if run when job control is disabled or, when run with -job control enabled, @var{jobspec} does not specify a valid job or -@var{jobspec} specifies a job that was started without job control. - -@item jobs -@btindex jobs -@example -jobs [-lnprs] [@var{jobspec}] -jobs -x @var{command} [@var{arguments}] -@end example - -The first form lists the active jobs. The options have the -following meanings: - -@table @code -@item -l -List process @sc{id}s in addition to the normal information. - -@item -n -Display information only about jobs that have changed status since -the user was last notified of their status. - -@item -p -List only the process @sc{id} of the job's process group leader. - -@item -r -Restrict output to running jobs. - -@item -s -Restrict output to stopped jobs. -@end table - -If @var{jobspec} is given, -output is restricted to information about that job. -If @var{jobspec} is not supplied, the status of all jobs is -listed. - -If the @option{-x} option is supplied, @code{jobs} replaces any -@var{jobspec} found in @var{command} or @var{arguments} with the -corresponding process group @sc{id}, and executes @var{command}, -passing it @var{argument}s, returning its exit status. - -@item kill -@btindex kill -@example -kill [-s @var{sigspec}] [-n @var{signum}] [-@var{sigspec}] @var{jobspec} or @var{pid} -kill -l [@var{exit_status}] -@end example -Send a signal specified by @var{sigspec} or @var{signum} to the process -named by job specification @var{jobspec} or process @sc{id} @var{pid}. -@var{sigspec} is either a case-insensitive signal name such as -@code{SIGINT} (with or without the @code{SIG} prefix) -or a signal number; @var{signum} is a signal number. -If @var{sigspec} and @var{signum} are not present, @code{SIGTERM} is used. -The @option{-l} option lists the signal names. -If any arguments are supplied when @option{-l} is given, the names of the -signals corresponding to the arguments are listed, and the return status -is zero. -@var{exit_status} is a number specifying a signal number or the exit -status of a process terminated by a signal. -The return status is zero if at least one signal was successfully sent, -or non-zero if an error occurs or an invalid option is encountered. - -@item wait -@btindex wait -@example -wait [@var{jobspec} or @var{pid}] -@end example -Wait until the child process specified by process @sc{id} @var{pid} or job -specification @var{jobspec} exits and return the exit status of the last -command waited for. -If a job spec is given, all processes in the job are waited for. -If no arguments are given, all currently active child processes are -waited for, and the return status is zero. -If neither @var{jobspec} nor @var{pid} specifies an active child process -of the shell, the return status is 127. - -@item disown -@btindex disown -@example -disown [-ar] [-h] [@var{jobspec} @dots{}] -@end example -Without options, each @var{jobspec} is removed from the table of -active jobs. -If the @option{-h} option is given, the job is not removed from the table, -but is marked so that @code{SIGHUP} is not sent to the job if the shell -receives a @code{SIGHUP}. -If @var{jobspec} is not present, and neither the @option{-a} nor @option{-r} -option is supplied, the current job is used. -If no @var{jobspec} is supplied, the @option{-a} option means to remove or -mark all jobs; the @option{-r} option without a @var{jobspec} -argument restricts operation to running jobs. - -@item suspend -@btindex suspend -@example -suspend [-f] -@end example -Suspend the execution of this shell until it receives a -@code{SIGCONT} signal. The @option{-f} option means to suspend -even if the shell is a login shell. - -@end table - -When job control is not active, the @code{kill} and @code{wait} -builtins do not accept @var{jobspec} arguments. They must be -supplied process @sc{id}s. - -@node Job Control Variables -@section Job Control Variables - -@vtable @code - -@item auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable exists then single word simple -commands without redirections are treated as candidates for resumption -of an existing job. There is no ambiguity allowed; if there is -more than one job beginning with the string typed, then -the most recently accessed job will be selected. -The name of a stopped job, in this context, is the command line -used to start it. If this variable is set to the value @samp{exact}, -the string supplied must match the name of a stopped job exactly; -if set to @samp{substring}, -the string supplied needs to match a substring of the name of a -stopped job. The @samp{substring} value provides functionality -analogous to the @samp{%?} job @sc{id} (@pxref{Job Control Basics}). -If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the @samp{%} job @sc{id}. - -@end vtable - -@set readline-appendix -@set history-appendix -@cindex Readline, how to use -@include rluser.texi -@cindex History, how to use -@include hsuser.texi -@clear readline-appendix -@clear history-appendix - -@node Installing Bash -@chapter Installing Bash - -This chapter provides basic instructions for installing Bash on -the various supported platforms. The distribution supports the -@sc{gnu} operating systems, nearly every version of Unix, and several -non-Unix systems such as BeOS and Interix. -Other independent ports exist for -@sc{ms-dos}, @sc{os/2}, and Windows platforms. - -@menu -* Basic Installation:: Installation instructions. - -* Compilers and Options:: How to set special options for various - systems. - -* Compiling For Multiple Architectures:: How to compile Bash for more - than one kind of system from - the same source tree. - -* Installation Names:: How to set the various paths used by the installation. - -* Specifying the System Type:: How to configure Bash for a particular system. - -* Sharing Defaults:: How to share default configuration values among GNU - programs. - -* Operation Controls:: Options recognized by the configuration program. - -* Optional Features:: How to enable and disable optional features when - building Bash. -@end menu - -@node Basic Installation -@section Basic Installation -@cindex installation -@cindex configuration -@cindex Bash installation -@cindex Bash configuration - -These are installation instructions for Bash. - -The simplest way to compile Bash is: - -@enumerate -@item -@code{cd} to the directory containing the source code and type -@samp{./configure} to configure Bash for your system. If you're -using @code{csh} on an old version of System V, you might need to -type @samp{sh ./configure} instead to prevent @code{csh} from trying -to execute @code{configure} itself. - -Running @code{configure} takes some time. -While running, it prints messages telling which features it is -checking for. - -@item -Type @samp{make} to compile Bash and build the @code{bashbug} bug -reporting script. - -@item -Optionally, type @samp{make tests} to run the Bash test suite. - -@item -Type @samp{make install} to install @code{bash} and @code{bashbug}. -This will also install the manual pages and Info file. - -@end enumerate - -The @code{configure} shell script attempts to guess correct -values for various system-dependent variables used during -compilation. It uses those values to create a @file{Makefile} in -each directory of the package (the top directory, the -@file{builtins}, @file{doc}, and @file{support} directories, -each directory under @file{lib}, and several others). It also creates a -@file{config.h} file containing system-dependent definitions. -Finally, it creates a shell script named @code{config.status} that you -can run in the future to recreate the current configuration, a -file @file{config.cache} that saves the results of its tests to -speed up reconfiguring, and a file @file{config.log} containing -compiler output (useful mainly for debugging @code{configure}). -If at some point -@file{config.cache} contains results you don't want to keep, you -may remove or edit it. - -To find out more about the options and arguments that the -@code{configure} script understands, type - -@example -bash-2.04$ ./configure --help -@end example - -@noindent -at the Bash prompt in your Bash source directory. - -If you need to do unusual things to compile Bash, please -try to figure out how @code{configure} could check whether or not -to do them, and mail diffs or instructions to -@email{bash-maintainers@@gnu.org} so they can be -considered for the next release. - -The file @file{configure.in} is used to create @code{configure} -by a program called Autoconf. You only need -@file{configure.in} if you want to change it or regenerate -@code{configure} using a newer version of Autoconf. If -you do this, make sure you are using Autoconf version 2.50 or -newer. - -You can remove the program binaries and object files from the -source code directory by typing @samp{make clean}. To also remove the -files that @code{configure} created (so you can compile Bash for -a different kind of computer), type @samp{make distclean}. - -@node Compilers and Options -@section Compilers and Options - -Some systems require unusual options for compilation or linking -that the @code{configure} script does not know about. You can -give @code{configure} initial values for variables by setting -them in the environment. Using a Bourne-compatible shell, you -can do that on the command line like this: - -@example -CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure -@end example - -On systems that have the @code{env} program, you can do it like this: - -@example -env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure -@end example - -The configuration process uses GCC to build Bash if it -is available. - -@node Compiling For Multiple Architectures -@section Compiling For Multiple Architectures - -You can compile Bash for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of @code{make} that -supports the @code{VPATH} variable, such as GNU @code{make}. -@code{cd} to the -directory where you want the object files and executables to go and run -the @code{configure} script from the source directory. You may need to -supply the @option{--srcdir=PATH} argument to tell @code{configure} where the -source files are. @code{configure} automatically checks for the -source code in the directory that @code{configure} is in and in `..'. - -If you have to use a @code{make} that does not supports the @code{VPATH} -variable, you can compile Bash for one architecture at a -time in the source code directory. After you have installed -Bash for one architecture, use @samp{make distclean} before -reconfiguring for another architecture. - -Alternatively, if your system supports symbolic links, you can use the -@file{support/mkclone} script to create a build tree which has -symbolic links back to each file in the source directory. Here's an -example that creates a build directory in the current directory from a -source directory @file{/usr/gnu/src/bash-2.0}: - -@example -bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . -@end example - -@noindent -The @code{mkclone} script requires Bash, so you must have already built -Bash for at least one architecture before you can create build -directories for other architectures. - -@node Installation Names -@section Installation Names - -By default, @samp{make install} will install into -@file{/usr/local/bin}, @file{/usr/local/man}, etc. You can -specify an installation prefix other than @file{/usr/local} by -giving @code{configure} the option @option{--prefix=@var{PATH}}, -or by specifying a value for the @code{DESTDIR} @samp{make} -variable when running @samp{make install}. - -You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. -If you give @code{configure} the option -@option{--exec-prefix=@var{PATH}}, @samp{make install} will use -@var{PATH} as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - -@node Specifying the System Type -@section Specifying the System Type - -There may be some features @code{configure} can not figure out -automatically, but need to determine by the type of host Bash -will run on. Usually @code{configure} can figure that -out, but if it prints a message saying it can not guess the host -type, give it the @option{--host=TYPE} option. @samp{TYPE} can -either be a short name for the system type, such as @samp{sun4}, -or a canonical name with three fields: @samp{CPU-COMPANY-SYSTEM} -(e.g., @samp{i386-unknown-freebsd4.2}). - -See the file @file{support/config.sub} for the possible -values of each field. - -@node Sharing Defaults -@section Sharing Defaults - -If you want to set default values for @code{configure} scripts to -share, you can create a site shell script called -@code{config.site} that gives default values for variables like -@code{CC}, @code{cache_file}, and @code{prefix}. @code{configure} -looks for @file{PREFIX/share/config.site} if it exists, then -@file{PREFIX/etc/config.site} if it exists. Or, you can set the -@code{CONFIG_SITE} environment variable to the location of the site -script. A warning: the Bash @code{configure} looks for a site script, -but not all @code{configure} scripts do. - -@node Operation Controls -@section Operation Controls - -@code{configure} recognizes the following options to control how it -operates. - -@table @code - -@item --cache-file=@var{file} -Use and save the results of the tests in -@var{file} instead of @file{./config.cache}. Set @var{file} to -@file{/dev/null} to disable caching, for debugging -@code{configure}. - -@item --help -Print a summary of the options to @code{configure}, and exit. - -@item --quiet -@itemx --silent -@itemx -q -Do not print messages saying which checks are being made. - -@item --srcdir=@var{dir} -Look for the Bash source code in directory @var{dir}. Usually -@code{configure} can determine that directory automatically. - -@item --version -Print the version of Autoconf used to generate the @code{configure} -script, and exit. -@end table - -@code{configure} also accepts some other, not widely used, boilerplate -options. @samp{configure --help} prints the complete list. - -@node Optional Features -@section Optional Features - -The Bash @code{configure} has a number of @option{--enable-@var{feature}} -options, where @var{feature} indicates an optional part of Bash. -There are also several @option{--with-@var{package}} options, -where @var{package} is something like @samp{bash-malloc} or @samp{purify}. -To turn off the default use of a package, use -@option{--without-@var{package}}. To configure Bash without a feature -that is enabled by default, use @option{--disable-@var{feature}}. - -Here is a complete list of the @option{--enable-} and -@option{--with-} options that the Bash @code{configure} recognizes. - -@table @code -@item --with-afs -Define if you are using the Andrew File System from Transarc. - -@item --with-bash-malloc -Use the Bash version of -@code{malloc} in @file{lib/malloc/malloc.c}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -derived from the 4.2 @sc{bsd} @code{malloc}. This @code{malloc} is -very fast, but wastes some space on each allocation. -This option is enabled by default. -The @file{NOTES} file contains a list of systems for -which this should be turned off, and @code{configure} disables this -option automatically for a number of systems. - -@item --with-curses -Use the curses library instead of the termcap library. This should -be supplied if your system has an inadequate or incomplete termcap -database. - -@item --with-gnu-malloc -A synonym for @code{--with-bash-malloc}. - -@item --with-installed-readline[=@var{PREFIX}] -Define this to make Bash link with a locally-installed version of Readline -rather than the version in @file{lib/readline}. This works only with -Readline 4.3 and later versions. If @var{PREFIX} is @code{yes} or not -supplied, @code{configure} uses the values of the make variables -@code{includedir} and @code{libdir}, which are subdirectories of @code{prefix} -by default, to find the installed version of Readline if it is not in -the standard system include and library directories. -If @var{PREFIX} is @code{no}, Bash links with the version in -@file{lib/readline}. -If @var{PREFIX} is set to any other value, @code{configure} treats it as -a directory pathname and looks for -the installed version of Readline in subdirectories of that directory -(include files in @var{PREFIX}/@code{include} and the library in -@var{PREFIX}/@code{lib}). - -@item --with-purify -Define this to use the Purify memory allocation checker from Rational -Software. - -@item --enable-minimal-config -This produces a shell with minimal features, close to the historical -Bourne shell. -@end table - -There are several @option{--enable-} options that alter how Bash is -compiled and linked, rather than changing run-time features. - -@table @code -@item --enable-largefile -Enable support for @uref{http://www.sas.com/standards/large_file/x_open.20Mar96.html, -large files} if the operating system requires special compiler options -to build programs which can access large files. This is enabled by -default, if the operating system provides large file support. - -@item --enable-profiling -This builds a Bash binary that produces profiling information to be -processed by @code{gprof} each time it is executed. - -@item --enable-static-link -This causes Bash to be linked statically, if @code{gcc} is being used. -This could be used to build a version to use as root's shell. -@end table - -The @samp{minimal-config} option can be used to disable all of -the following options, but it is processed first, so individual -options may be enabled using @samp{enable-@var{feature}}. - -All of the following options except for @samp{disabled-builtins} and -@samp{xpg-echo-default} are -enabled by default, unless the operating system does not provide the -necessary support. - -@table @code -@item --enable-alias -Allow alias expansion and include the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item --enable-arith-for-command -Include support for the alternate form of the @code{for} command -that behaves like the C language @code{for} statement -(@pxref{Looping Constructs}). - -@item --enable-array-variables -Include support for one-dimensional array shell variables -(@pxref{Arrays}). - -@item --enable-bang-history -Include support for @code{csh}-like history substitution -(@pxref{History Interaction}). - -@item --enable-brace-expansion -Include @code{csh}-like brace expansion -( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ). -See @ref{Brace Expansion}, for a complete description. - -@item --enable-command-timing -Include support for recognizing @code{time} as a reserved word and for -displaying timing statistics for the pipeline following @code{time} -(@pxref{Pipelines}). -This allows pipelines as well as shell builtins and functions to be timed. - -@item --enable-cond-command -Include support for the @code{[[} conditional command. -(@pxref{Conditional Constructs}). - -@item --enable-cond-regexp -Include support for matching POSIX regular expressions using the -@samp{=~} binary operator in the @code{[[} conditional command. -(@pxref{Conditional Constructs}). - -@item --enable-directory-stack -Include support for a @code{csh}-like directory stack and the -@code{pushd}, @code{popd}, and @code{dirs} builtins -(@pxref{The Directory Stack}). - -@item --enable-disabled-builtins -Allow builtin commands to be invoked via @samp{builtin xxx} -even after @code{xxx} has been disabled using @samp{enable -n xxx}. -See @ref{Bash Builtins}, for details of the @code{builtin} and -@code{enable} builtin commands. - -@item --enable-dparen-arithmetic -Include support for the @code{((@dots{}))} command -(@pxref{Conditional Constructs}). - -@item --enable-extended-glob -Include support for the extended pattern matching features described -above under @ref{Pattern Matching}. - -@item --enable-help-builtin -Include the @code{help} builtin, which displays help on shell builtins and -variables (@pxref{Bash Builtins}). - -@item --enable-history -Include command history and the @code{fc} and @code{history} -builtin commands (@pxref{Bash History Facilities}). - -@item --enable-job-control -This enables the job control features (@pxref{Job Control}), -if the operating system supports them. - -@item --enable-multibyte -This enables support for multibyte characters if the operating -system provides the necessary support. - -@item --enable-net-redirections -This enables the special handling of filenames of the form -@code{/dev/tcp/@var{host}/@var{port}} and -@code{/dev/udp/@var{host}/@var{port}} -when used in redirections (@pxref{Redirections}). - -@item --enable-process-substitution -This enables process substitution (@pxref{Process Substitution}) if -the operating system provides the necessary support. - -@item --enable-prompt-string-decoding -Turn on the interpretation of a number of backslash-escaped characters -in the @env{$PS1}, @env{$PS2}, @env{$PS3}, and @env{$PS4} prompt -strings. See @ref{Printing a Prompt}, for a complete list of prompt -string escape sequences. - -@item --enable-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@item --enable-readline -Include support for command-line editing and history with the Bash -version of the Readline library (@pxref{Command Line Editing}). - -@item --enable-restricted -Include support for a @dfn{restricted shell}. If this is enabled, Bash, -when called as @code{rbash}, enters a restricted mode. See -@ref{The Restricted Shell}, for a description of restricted mode. - -@item --enable-select -Include the @code{select} builtin, which allows the generation of simple -menus (@pxref{Conditional Constructs}). - -@item --enable-usg-echo-default -A synonym for @code{--enable-xpg-echo-default}. - -@item --enable-xpg-echo-default -Make the @code{echo} builtin expand backslash-escaped characters by default, -without requiring the @option{-e} option. -This sets the default value of the @code{xpg_echo} shell option to @code{on}, -which makes the Bash @code{echo} behave more like the version specified in -the Single Unix Specification, version 2. -@xref{Bash Builtins}, for a description of the escape sequences that -@code{echo} recognizes. - -@end table - -The file @file{config-top.h} contains C Preprocessor -@samp{#define} statements for options which are not settable from -@code{configure}. -Some of these are not meant to be changed; beware of the consequences if -you do. -Read the comments associated with each definition for more -information about its effect. - -@node Reporting Bugs -@appendix Reporting Bugs - -Please report all bugs you find in Bash. -But first, you should -make sure that it really is a bug, and that it appears in the latest -version of Bash. -The latest version of Bash is always available for FTP from -@uref{ftp://ftp.gnu.org/pub/bash/}. - -Once you have determined that a bug actually exists, use the -@code{bashbug} command to submit a bug report. -If you have a fix, you are encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to @email{bug-bash@@gnu.org} or posted to the Usenet -newsgroup @code{gnu.bash.bug}. - -All bug reports should include: -@itemize @bullet -@item -The version number of Bash. -@item -The hardware and operating system. -@item -The compiler used to compile Bash. -@item -A description of the bug behaviour. -@item -A short script or `recipe' which exercises the bug and may be used -to reproduce it. -@end itemize - -@noindent -@code{bashbug} inserts the first three items automatically into -the template it provides for filing a bug report. - -Please send all reports concerning this manual to -@email{chet@@po.CWRU.Edu}. - -@node Major Differences From The Bourne Shell -@appendix Major Differences From The Bourne Shell - -Bash implements essentially the same grammar, parameter and -variable expansion, redirection, and quoting as the Bourne Shell. -Bash uses the @sc{posix} 1003.2 standard as the specification of -how these features are to be implemented. There are some -differences between the traditional Bourne shell and Bash; this -section quickly details the differences of significance. A -number of these differences are explained in greater depth in -previous sections. -This section uses the version of @code{sh} included in SVR4.2 as -the baseline reference. - -@itemize @bullet - -@item -Bash is @sc{posix}-conformant, even where the @sc{posix} specification -differs from traditional @code{sh} behavior (@pxref{Bash POSIX Mode}). - -@item -Bash has multi-character invocation options (@pxref{Invoking Bash}). - -@item -Bash has command-line editing (@pxref{Command Line Editing}) and -the @code{bind} builtin. - -@item -Bash provides a programmable word completion mechanism -(@pxref{Programmable Completion}), and two builtin commands, -@code{complete} and @code{compgen}, to manipulate it. - -@item -Bash has command history (@pxref{Bash History Facilities}) and the -@code{history} and @code{fc} builtins to manipulate it. -The Bash history list maintains timestamp information and uses the -value of the @code{HISTTIMEFORMAT} variable to display it. - -@item -Bash implements @code{csh}-like history expansion -(@pxref{History Interaction}). - -@item -Bash has one-dimensional array variables (@pxref{Arrays}), and the -appropriate variable expansions and assignment syntax to use them. -Several of the Bash builtins take options to act on arrays. -Bash provides a number of built-in array variables. - -@item -The @code{$'@dots{}'} quoting syntax, which expands ANSI-C -backslash-escaped characters in the text between the single quotes, -is supported (@pxref{ANSI-C Quoting}). - -@item -Bash supports the @code{$"@dots{}"} quoting syntax to do -locale-specific translation of the characters between the double -quotes. The @option{-D}, @option{--dump-strings}, and @option{--dump-po-strings} -invocation options list the translatable strings found in a script -(@pxref{Locale Translation}). - -@item -Bash implements the @code{!} keyword to negate the return value of -a pipeline (@pxref{Pipelines}). -Very useful when an @code{if} statement needs to act only if a test fails. - -@item -Bash has the @code{time} reserved word and command timing (@pxref{Pipelines}). -The display of the timing statistics may be controlled with the -@env{TIMEFORMAT} variable. - -@item -Bash implements the @code{for (( @var{expr1} ; @var{expr2} ; @var{expr3} ))} -arithmetic for command, similar to the C language (@pxref{Looping Constructs}). - -@item -Bash includes the @code{select} compound command, which allows the -generation of simple menus (@pxref{Conditional Constructs}). - -@item -Bash includes the @code{[[} compound command, which makes conditional -testing part of the shell grammar (@pxref{Conditional Constructs}). - -@item -Bash includes brace expansion (@pxref{Brace Expansion}) and tilde -expansion (@pxref{Tilde Expansion}). - -@item -Bash implements command aliases and the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item -Bash provides shell arithmetic, the @code{((} compound command -(@pxref{Conditional Constructs}), -and arithmetic expansion (@pxref{Shell Arithmetic}). - -@item -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. - -@item -Bash includes the @sc{posix} pattern removal @samp{%}, @samp{#}, @samp{%%} -and @samp{##} expansions to remove leading or trailing substrings from -variable values (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{#xx@}}, which returns the length of @code{$@{xx@}}, -is supported (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{var:}@var{offset}@code{[:}@var{length}@code{]@}}, -which expands to the substring of @code{var}'s value of length -@var{length}, beginning at @var{offset}, is present -(@pxref{Shell Parameter Expansion}). - -@item -The expansion -@code{$@{var/[/]}@var{pattern}@code{[/}@var{replacement}@code{]@}}, -which matches @var{pattern} and replaces it with @var{replacement} in -the value of @code{var}, is available (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{!@var{prefix@}*}} expansion, which expands to -the names of all shell variables whose names begin with @var{prefix}, -is available (@pxref{Shell Parameter Expansion}). - -@item -Bash has @var{indirect} variable expansion using @code{$@{!word@}} -(@pxref{Shell Parameter Expansion}). - -@item -Bash can expand positional parameters beyond @code{$9} using -@code{$@{@var{num}@}}. - -@item -The @sc{posix} @code{$()} form of command substitution -is implemented (@pxref{Command Substitution}), -and preferred to the Bourne shell's @code{``} (which -is also implemented for backwards compatibility). - -@item -Bash has process substitution (@pxref{Process Substitution}). - -@item -Bash automatically assigns variables that provide information about the -current user (@env{UID}, @env{EUID}, and @env{GROUPS}), the current host -(@env{HOSTTYPE}, @env{OSTYPE}, @env{MACHTYPE}, and @env{HOSTNAME}), -and the instance of Bash that is running (@env{BASH}, -@env{BASH_VERSION}, and @env{BASH_VERSINFO}). @xref{Bash Variables}, -for details. - -@item -The @env{IFS} variable is used to split only the results of expansion, -not all words (@pxref{Word Splitting}). -This closes a longstanding shell security hole. - -@item -Bash implements the full set of @sc{posix} 1003.2 filename expansion operators, -including @var{character classes}, @var{equivalence classes}, and -@var{collating symbols} (@pxref{Filename Expansion}). - -@item -Bash implements extended pattern matching features when the @code{extglob} -shell option is enabled (@pxref{Pattern Matching}). - -@item -It is possible to have a variable and a function with the same name; -@code{sh} does not separate the two name spaces. - -@item -Bash functions are permitted to have local variables using the -@code{local} builtin, and thus useful recursive functions may be written -(@pxref{Bash Builtins}). - -@item -Variable assignments preceding commands affect only that command, even -builtins and functions (@pxref{Environment}). -In @code{sh}, all variable assignments -preceding commands are global unless the command is executed from the -file system. - -@item -Bash performs filename expansion on filenames specified as operands -to input and output redirection operators (@pxref{Redirections}). - -@item -Bash contains the @samp{<>} redirection operator, allowing a file to be -opened for both reading and writing, and the @samp{&>} redirection -operator, for directing standard output and standard error to the same -file (@pxref{Redirections}). - -@item -Bash treats a number of filenames specially when they are -used in redirection operators (@pxref{Redirections}). - -@item -Bash can open network connections to arbitrary machines and services -with the redirection operators (@pxref{Redirections}). - -@item -The @code{noclobber} option is available to avoid overwriting existing -files with output redirection (@pxref{The Set Builtin}). -The @samp{>|} redirection operator may be used to override @code{noclobber}. - -@item -The Bash @code{cd} and @code{pwd} builtins (@pxref{Bourne Shell Builtins}) -each take @option{-L} and @option{-P} options to switch between logical and -physical modes. - -@item -Bash allows a function to override a builtin with the same name, and provides -access to that builtin's functionality within the function via the -@code{builtin} and @code{command} builtins (@pxref{Bash Builtins}). - -@item -The @code{command} builtin allows selective disabling of functions -when command lookup is performed (@pxref{Bash Builtins}). - -@item -Individual builtins may be enabled or disabled using the @code{enable} -builtin (@pxref{Bash Builtins}). - -@item -The Bash @code{exec} builtin takes additional options that allow users -to control the contents of the environment passed to the executed -command, and what the zeroth argument to the command is to be -(@pxref{Bourne Shell Builtins}). - -@item -Shell functions may be exported to children via the environment -using @code{export -f} (@pxref{Shell Functions}). - -@item -The Bash @code{export}, @code{readonly}, and @code{declare} builtins can -take a @option{-f} option to act on shell functions, a @option{-p} option to -display variables with various attributes set in a format that can be -used as shell input, a @option{-n} option to remove various variable -attributes, and @samp{name=value} arguments to set variable attributes -and values simultaneously. - -@item -The Bash @code{hash} builtin allows a name to be associated with -an arbitrary filename, even when that filename cannot be found by -searching the @env{$PATH}, using @samp{hash -p} -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes a @code{help} builtin for quick reference to shell -facilities (@pxref{Bash Builtins}). - -@item -The @code{printf} builtin is available to display formatted output -(@pxref{Bash Builtins}). - -@item -The Bash @code{read} builtin (@pxref{Bash Builtins}) -will read a line ending in @samp{\} with -the @option{-r} option, and will use the @env{REPLY} variable as a -default if no non-option arguments are supplied. -The Bash @code{read} builtin -also accepts a prompt string with the @option{-p} option and will use -Readline to obtain the line when given the @option{-e} option. -The @code{read} builtin also has additional options to control input: -the @option{-s} option will turn off echoing of input characters as -they are read, the @option{-t} option will allow @code{read} to time out -if input does not arrive within a specified number of seconds, the -@option{-n} option will allow reading only a specified number of -characters rather than a full line, and the @option{-d} option will read -until a particular character rather than newline. - -@item -The @code{return} builtin may be used to abort execution of scripts -executed with the @code{.} or @code{source} builtins -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes the @code{shopt} builtin, for finer control of shell -optional capabilities (@pxref{Bash Builtins}), and allows these options -to be set and unset at shell invocation (@pxref{Invoking Bash}). - -@item -Bash has much more optional behavior controllable with the @code{set} -builtin (@pxref{The Set Builtin}). - -@item -The @samp{-x} (@code{xtrace}) option displays commands other than -simple commands when performing an execution trace -(@pxref{The Set Builtin}). - -@item -The @code{test} builtin (@pxref{Bourne Shell Builtins}) -is slightly different, as it implements the @sc{posix} algorithm, -which specifies the behavior based on the number of arguments. - -@item -Bash includes the @code{caller} builtin, which displays the context of -any active subroutine call (a shell function or a script executed with -the @code{.} or @code{source} builtins). This supports the bash -debugger. - -@item -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{DEBUG} pseudo-signal specification, similar to @code{EXIT}. -Commands specified with a @code{DEBUG} trap are executed before every -simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -The @code{DEBUG} trap is not inherited by shell functions unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. -The @code{extdebug} shell option has additional effects on the -@code{DEBUG} trap. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows an -@code{ERR} pseudo-signal specification, similar to @code{EXIT} and @code{DEBUG}. -Commands specified with an @code{ERR} trap are executed after a simple -command fails, with a few exceptions. -The @code{ERR} trap is not inherited by shell functions unless the -@code{-o errtrace} option to the @code{set} builtin is enabled. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{RETURN} pseudo-signal specification, similar to -@code{EXIT} and @code{DEBUG}. -Commands specified with an @code{RETURN} trap are executed before -execution resumes after a shell function or a shell script executed with -@code{.} or @code{source} returns. -The @code{RETURN} trap is not inherited by shell functions. - -@item -The Bash @code{type} builtin is more extensive and gives more information -about the names it finds (@pxref{Bash Builtins}). - -@item -The Bash @code{umask} builtin permits a @option{-p} option to cause -the output to be displayed in the form of a @code{umask} command -that may be reused as input (@pxref{Bourne Shell Builtins}). - -@item -Bash implements a @code{csh}-like directory stack, and provides the -@code{pushd}, @code{popd}, and @code{dirs} builtins to manipulate it -(@pxref{The Directory Stack}). -Bash also makes the directory stack visible as the value of the -@env{DIRSTACK} shell variable. - -@item -Bash interprets special backslash-escaped characters in the prompt -strings when interactive (@pxref{Printing a Prompt}). - -@item -The Bash restricted mode is more useful (@pxref{The Restricted Shell}); -the SVR4.2 shell restricted mode is too limited. - -@item -The @code{disown} builtin can remove a job from the internal shell -job table (@pxref{Job Control Builtins}) or suppress the sending -of @code{SIGHUP} to a job when the shell exits as the result of a -@code{SIGHUP}. - -@item -The SVR4.2 shell has two privilege-related builtins -(@code{mldmode} and @code{priv}) not present in Bash. - -@item -Bash does not have the @code{stop} or @code{newgrp} builtins. - -@item -Bash does not use the @env{SHACCT} variable or perform shell accounting. - -@item -The SVR4.2 @code{sh} uses a @env{TIMEOUT} variable like Bash uses -@env{TMOUT}. - -@end itemize - -@noindent -More features unique to Bash may be found in @ref{Bash Features}. - - -@appendixsec Implementation Differences From The SVR4.2 Shell - -Since Bash is a completely new implementation, it does not suffer from -many of the limitations of the SVR4.2 shell. For instance: - -@itemize @bullet - -@item -Bash does not fork a subshell when redirecting into or out of -a shell control structure such as an @code{if} or @code{while} -statement. - -@item -Bash does not allow unbalanced quotes. The SVR4.2 shell will silently -insert a needed closing quote at @code{EOF} under certain circumstances. -This can be the cause of some hard-to-find errors. - -@item -The SVR4.2 shell uses a baroque memory management scheme based on -trapping @code{SIGSEGV}. If the shell is started from a process with -@code{SIGSEGV} blocked (e.g., by using the @code{system()} C library -function call), it misbehaves badly. - -@item -In a questionable attempt at security, the SVR4.2 shell, -when invoked without the @option{-p} option, will alter its real -and effective @sc{uid} and @sc{gid} if they are less than some -magic threshold value, commonly 100. -This can lead to unexpected results. - -@item -The SVR4.2 shell does not allow users to trap @code{SIGSEGV}, -@code{SIGALRM}, or @code{SIGCHLD}. - -@item -The SVR4.2 shell does not allow the @env{IFS}, @env{MAILCHECK}, -@env{PATH}, @env{PS1}, or @env{PS2} variables to be unset. - -@item -The SVR4.2 shell treats @samp{^} as the undocumented equivalent of -@samp{|}. - -@item -Bash allows multiple option arguments when it is invoked (@code{-x -v}); -the SVR4.2 shell allows only one option argument (@code{-xv}). In -fact, some versions of the shell dump core if the second argument begins -with a @samp{-}. - -@item -The SVR4.2 shell exits a script if any builtin fails; Bash exits -a script only if one of the @sc{posix} 1003.2 special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} 1003.2 standard. - -@item -The SVR4.2 shell behaves differently when invoked as @code{jsh} -(it turns on job control). -@end itemize - -@node Copying This Manual -@appendix Copying This Manual - -@menu -* GNU Free Documentation License:: License for copying this manual. -@end menu - -@include fdl.texi - -@node Builtin Index -@unnumbered Index of Shell Builtin Commands -@printindex bt - -@node Reserved Word Index -@unnumbered Index of Shell Reserved Words -@printindex rw - -@node Variable Index -@unnumbered Parameter and Variable Index -@printindex vr - -@node Function Index -@unnumbered Function Index -@printindex fn - -@node Concept Index -@unnumbered Concept Index -@printindex cp - -@bye diff --git a/doc/version.texi~ b/doc/version.texi~ deleted file mode 100644 index 274798bdf..000000000 --- a/doc/version.texi~ +++ /dev/null @@ -1,10 +0,0 @@ -@ignore -Copyright (C) 1988-2004 Free Software Foundation, Inc. -@end ignore - -@set EDITION 3.0 -@set VERSION 3.0-rc1 -@set UPDATED 27 May 2004 -@set UPDATED-MONTH May 2004 - -@set LASTCHANGE Thu May 27 22:10:33 EDT 2004 diff --git a/examples/scripts/adventure.sh.save1 b/examples/scripts/adventure.sh.save1 deleted file mode 100755 index 4e2239396..000000000 --- a/examples/scripts/adventure.sh.save1 +++ /dev/null @@ -1,549 +0,0 @@ -#!/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/ $//'; } - -# enable history, bang history expansion, and emacs editing -set -o history -set -o histexpand -set -o emacs - -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 - - read -e -p '-advsh> ' verb obj x # prompt is '-advsh> ' - 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/execute_cmd.c~ b/execute_cmd.c~ deleted file mode 100644 index 7a3671502..000000000 --- a/execute_cmd.c~ +++ /dev/null @@ -1,4027 +0,0 @@ -/* execute_command.c -- Execute a COMMAND structure. */ - -/* Copyright (C) 1987-2003 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#include "config.h" - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include -#include "chartypes.h" -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixtime.h" - -#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) -# include -#endif - -#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES) -# include -#endif - -#include - -#if !defined (errno) -extern int errno; -#endif - -#include "bashansi.h" -#include "bashintl.h" - -#include "memalloc.h" -#include "shell.h" -#include /* use <...> so we pick it up from the build directory */ -#include "flags.h" -#include "builtins.h" -#include "hashlib.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "redir.h" -#include "trap.h" -#include "pathexp.h" -#include "hashcmd.h" - -#if defined (COND_COMMAND) -# include "test.h" -#endif - -#include "builtins/common.h" -#include "builtins/builtext.h" /* list of builtins */ - -#include -#include - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int posixly_correct; -extern int breaking, continuing, loop_level; -extern int expand_aliases; -extern int parse_and_execute_level, running_trap; -extern int command_string_index, line_number; -extern int dot_found_in_search; -extern int already_making_children; -extern char *the_printed_command, *shell_name; -extern pid_t last_command_subst_pid; -extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; -extern char **subshell_argv, **subshell_envp; -extern int subshell_argc; -#if 0 -extern char *glob_argv_flags; -#endif - -extern int close __P((int)); - -/* Static functions defined and used in this file. */ -static void close_pipes __P((int, int)); -static void do_piping __P((int, int)); -static void bind_lastarg __P((char *)); -static int shell_control_structure __P((enum command_type)); -static void cleanup_redirects __P((REDIRECT *)); - -#if defined (JOB_CONTROL) -static int restore_signal_mask __P((sigset_t *)); -#endif - -static void async_redirect_stdin __P((void)); - -static int builtin_status __P((int)); - -static int execute_for_command __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -static int print_index_and_element __P((int, int, WORD_LIST *)); -static void indent __P((int, int)); -static void print_select_list __P((WORD_LIST *, int, int, int)); -static char *select_query __P((WORD_LIST *, int, char *, int)); -static int execute_select_command __P((SELECT_COM *)); -#endif -#if defined (DPAREN_ARITHMETIC) -static int execute_arith_command __P((ARITH_COM *)); -#endif -#if defined (COND_COMMAND) -static int execute_cond_node __P((COND_COM *)); -static int execute_cond_command __P((COND_COM *)); -#endif -#if defined (COMMAND_TIMING) -static int mkfmt __P((char *, int, int, time_t, int)); -static void print_formatted_time __P((FILE *, char *, - time_t, int, time_t, int, - time_t, int, int)); -static int time_command __P((COMMAND *, int, int, int, struct fd_bitmap *)); -#endif -#if defined (ARITH_FOR_COMMAND) -static intmax_t eval_arith_for_expr __P((WORD_LIST *, int *)); -static int execute_arith_for_command __P((ARITH_FOR_COM *)); -#endif -static int execute_case_command __P((CASE_COM *)); -static int execute_while_command __P((WHILE_COM *)); -static int execute_until_command __P((WHILE_COM *)); -static int execute_while_or_until __P((WHILE_COM *, int)); -static int execute_if_command __P((IF_COM *)); -static int execute_null_command __P((REDIRECT *, int, int, int, pid_t)); -static void fix_assignment_words __P((WORD_LIST *)); -static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *)); -static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int)); -static int execute_function __P((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int)); -static int execute_builtin_or_function __P((WORD_LIST *, sh_builtin_func_t *, - SHELL_VAR *, - REDIRECT *, struct fd_bitmap *, int)); -static void execute_subshell_builtin_or_function __P((WORD_LIST *, REDIRECT *, - sh_builtin_func_t *, - SHELL_VAR *, - int, int, int, - struct fd_bitmap *, - int)); -static void execute_disk_command __P((WORD_LIST *, REDIRECT *, char *, - int, int, int, struct fd_bitmap *, int)); - -static char *getinterp __P((char *, int, int *)); -static void initialize_subshell __P((void)); -static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_intern_function __P((WORD_DESC *, COMMAND *)); - -/* The line number that the currently executing function starts on. */ -static int function_line_number; - -/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global - so that reader_loop can set it to zero before executing a command. */ -int stdin_redir; - -/* The name of the command that is currently being executed. - `test' needs this, for example. */ -char *this_command_name; - -/* The printed representation of the currently-executing command (same as - the_printed_command), except when a trap is being executed. Useful for - a debugger to know where exactly the program is currently executing. */ -char *the_printed_command_except_trap; - -static COMMAND *currently_executing_command; - -struct stat SB; /* used for debugging */ - -static int special_builtin_failed; - -/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line - number containing the function name. Used by executing_line_number to - report the correct line number. Kind of a hack. */ -static int showing_function_line; - -/* For catching RETURN in a function. */ -int return_catch_flag; -int return_catch_value; -procenv_t return_catch; - -/* The value returned by the last synchronous command. */ -int last_command_exit_value; - -/* Whether or not the last command (corresponding to last_command_exit_value) - was terminated by a signal, and, if so, which one. */ -int last_command_exit_signal; - -/* 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; - -/* Count of nested subshells, like SHLVL. Available via $BASH_SUBSHELL */ -int subshell_level = 0; - -/* Currently-executing shell function. */ -SHELL_VAR *this_shell_function; - -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) - int size; -{ - struct fd_bitmap *ret; - - ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); - - ret->size = size; - - if (size) - { - ret->bitmap = (char *)xmalloc (size); - memset (ret->bitmap, '\0', 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; - } - } -} - -/* Return the line number of the currently executing command. */ -int -executing_line_number () -{ - if (executing && showing_function_line == 0 && - (variable_context == 0 || interactive_shell == 0) && - currently_executing_command) - { -#if defined (COND_COMMAND) - if (currently_executing_command->type == cm_cond) - return currently_executing_command->value.Cond->line; -#endif -#if defined (DPAREN_ARITHMETIC) - else if (currently_executing_command->type == cm_arith) - return currently_executing_command->value.Arith->line; -#endif -#if defined (ARITH_FOR_COMMAND) - else if (currently_executing_command->type == cm_arith_for) - return currently_executing_command->value.ArithFor->line; -#endif - - return line_number; - } - else - return line_number; -} - -/* Execute the command passed in COMMAND. COMMAND is exactly what - read_command () places into GLOBAL_COMMAND. See "command.h" for the - details of the command structure. - - EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible - return values. Executing a command with nothing in it returns - EXECUTION_SUCCESS. */ -int -execute_command (command) - COMMAND *command; -{ - 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) - /* don't unlink fifos if we're in a shell function; wait until the function - returns. */ - if (variable_context == 0) - 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 (ARITH_FOR_COMMAND) - case cm_arith_for: -#endif -#if defined (SELECT_COMMAND) - case cm_select: -#endif -#if defined (DPAREN_ARITHMETIC) - case cm_arith: -#endif -#if defined (COND_COMMAND) - case cm_cond: -#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, RX_ACTIVE); - dispose_redirects (list); -} - -#if 0 -/* Function to unwind_protect the redirections for functions and builtins. */ -static void -cleanup_func_redirects (list) - REDIRECT *list; -{ - do_redirections (list, RX_ACTIVE); -} -#endif - -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 */ - -#ifdef DEBUG -/* 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 %ld open files:", (long)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"); -} -#endif - -static void -async_redirect_stdin () -{ - int fd; - - fd = open ("/dev/null", O_RDONLY); - if (fd > 0) - { - dup2 (fd, 0); - close (fd); - } - else if (fd < 0) - internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno)); -} - -#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) - -/* Execute the command passed in COMMAND, perhaps doing it asynchrounously. - COMMAND is exactly what read_command () places into GLOBAL_COMMAND. - 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. */ -int -execute_command_internal (command, asynchronous, pipe_in, pipe_out, - fds_to_close) - COMMAND *command; - int asynchronous; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int exec_result, invert, ignore_return, was_error_trap; - REDIRECT *my_undo_list, *exec_undo_list; - volatile pid_t last_pid; - volatile int save_line_number; - - if (command == 0 || breaking || continuing || read_but_dont_execute) - return (EXECUTION_SUCCESS); - - run_pending_traps (); - -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = command; - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - - /* If we're inverting the return value and `set -e' has been executed, - we don't want a failing command to inadvertently cause the shell - to exit. */ - if (exit_immediately_on_error && invert) /* XXX */ - command->flags |= CMD_IGNORE_RETURN; /* XXX */ - - exec_result = EXECUTION_SUCCESS; - - /* If a command was being explicitly run in a subshell, or if it is - a shell control-structure, and it has a pipe, then we do the command - in a subshell. */ - if (command->type == cm_subshell && (command->flags & CMD_NO_FORK)) - return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); - - if (command->type == cm_subshell || - (command->flags & (CMD_WANT_SUBSHELL|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) - exit (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); - /* NOTREACHED */ - 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 == 0) - { - last_command_exit_value = wait_for (paren_pid); - - /* If we have to, invert the return value. */ - if (invert) - exec_result = ((last_command_exit_value == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS); - else - exec_result = last_command_exit_value; - - return (last_command_exit_value = exec_result); - } - else - { - DESCRIBE_PID (paren_pid); - - run_pending_traps (); - - return (EXECUTION_SUCCESS); - } - } - } - -#if defined (COMMAND_TIMING) - if (command->flags & CMD_TIME_PIPELINE) - { - if (asynchronous) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); - } - else - { - exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = (COMMAND *)NULL; - } - return (exec_result); - } -#endif /* COMMAND_TIMING */ - - if (shell_control_structure (command->type) && command->redirects) - stdin_redir = stdin_redirects (command->redirects); - - /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input - redirection.) */ - if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 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_simple: - { - save_line_number = line_number; - /* We can't rely on variables retaining their values across a - call to execute_simple_command if a longjmp occurs as the - result of a `return' builtin. This is true for sure with gcc. */ - last_pid = last_made_pid; - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - - if (ignore_return && command->value.Simple) - command->value.Simple->flags |= CMD_IGNORE_RETURN; - if (command->flags & CMD_STDIN_REDIR) - command->value.Simple->flags |= CMD_STDIN_REDIR; - - line_number = command->value.Simple->line; - exec_result = - execute_simple_command (command->value.Simple, pipe_in, pipe_out, - asynchronous, fds_to_close); - line_number = save_line_number; - - /* The temporary environment should be used for only the simple - command immediately following its definition. */ - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Reclaim memory allocated with alloca () on machines which - may be using the alloca emulation code. */ - (void) alloca (0); -#endif /* (ultrix && mips) || C_ALLOCA */ - - /* If we forked to do the command, then we must wait_for () - the child. */ - - /* XXX - this is something to watch out for if there are problems - when the shell is compiled without job control. */ - if (already_making_children && pipe_out == NO_PIPE && - last_pid != last_made_pid) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); - - if (asynchronous) - { - DESCRIBE_PID (last_made_pid); - } - else -#if !defined (JOB_CONTROL) - /* Do not wait for asynchronous processes started from - startup files. */ - if (last_made_pid != last_asynchronous_pid) -#endif - /* When executing a shell function that executes other - commands, this causes the last simple command in - the function to be waited for twice. This also causes - subshells forked to execute builtin commands (e.g., in - pipelines) to be waited for twice. */ - exec_result = wait_for (last_made_pid); -#if defined (RECYCLES_PIDS) - /* LynxOS, for one, recycles pids very quickly -- so quickly - that a new process may have the same pid as the last one - created. This has been reported to fix the problem on that - OS, and a similar problem on Cygwin. */ - if (exec_result == 0) - last_made_pid = NO_PID; -#endif - } - } - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_error_trap (); - } - - if (ignore_return == 0 && invert == 0 && - ((posixly_correct && interactive == 0 && special_builtin_failed) || - (exit_immediately_on_error && (exec_result != EXECUTION_SUCCESS)))) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; - - case cm_for: - if (ignore_return) - command->value.For->flags |= CMD_IGNORE_RETURN; - exec_result = execute_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - if (ignore_return) - command->value.ArithFor->flags |= CMD_IGNORE_RETURN; - exec_result = execute_arith_for_command (command->value.ArithFor); - break; -#endif - -#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_connection: - exec_result = execute_connection (command, asynchronous, - pipe_in, pipe_out, fds_to_close); - break; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - if (ignore_return) - command->value.Arith->flags |= CMD_IGNORE_RETURN; - exec_result = execute_arith_command (command->value.Arith); - break; -#endif - -#if defined (COND_COMMAND) - case cm_cond: - if (ignore_return) - command->value.Cond->flags |= CMD_IGNORE_RETURN; - save_line_number = line_number; - exec_result = execute_cond_command (command->value.Cond); - line_number = save_line_number; - break; -#endif - - case cm_function_def: - exec_result = execute_intern_function (command->value.Function_def->name, - command->value.Function_def->command); - break; - - default: - command_error ("execute_command", CMDERR_BADTYPE, command->type, 0); - } - - if (my_undo_list) - { - do_redirections (my_undo_list, RX_ACTIVE); - 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) - exec_result = (exec_result == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - - last_command_exit_value = exec_result; - run_pending_traps (); -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = (COMMAND *)NULL; - return (last_command_exit_value); -} - -#if defined (COMMAND_TIMING) - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -extern struct timeval *difftimeval __P((struct timeval *, struct timeval *, struct timeval *)); -extern struct timeval *addtimeval __P((struct timeval *, struct timeval *, struct timeval *)); -extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeval *)); -#endif - -#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S" -#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS" - -static int precs[] = { 0, 100, 10, 1 }; - -/* Expand one `%'-prefixed escape sequence from a time format string. */ -static int -mkfmt (buf, prec, lng, sec, sec_fraction) - char *buf; - int prec, lng; - time_t sec; - int sec_fraction; -{ - time_t min; - char abuf[INT_STRLEN_BOUND(time_t) + 1]; - int ind, aind; - - ind = 0; - abuf[sizeof(abuf) - 1] = '\0'; - - /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ - if (lng) - { - min = sec / 60; - sec %= 60; - aind = sizeof(abuf) - 2; - do - abuf[aind--] = (min % 10) + '0'; - while (min /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - buf[ind++] = 'm'; - } - - /* Now add the seconds. */ - aind = sizeof (abuf) - 2; - do - abuf[aind--] = (sec % 10) + '0'; - while (sec /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - - /* We want to add a decimal point and PREC places after it if PREC is - nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 - and 999. */ - if (prec != 0) - { - buf[ind++] = '.'; - for (aind = 1; aind <= prec; aind++) - { - buf[ind++] = (sec_fraction / precs[aind]) + '0'; - sec_fraction %= precs[aind]; - } - } - - if (lng) - buf[ind++] = 's'; - buf[ind] = '\0'; - - return (ind); -} - -/* Interpret the format string FORMAT, interpolating the following escape - sequences: - %[prec][l][RUS] - - where the optional `prec' is a precision, meaning the number of - characters after the decimal point, the optional `l' means to format - using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', - and the last character is one of - - R number of seconds of `real' time - U number of seconds of `user' time - S number of seconds of `system' time - - An occurrence of `%%' in the format string is translated to a `%'. The - result is printed to FP, a pointer to a FILE. The other variables are - the seconds and thousandths of a second of real, user, and system time, - resectively. */ -static void -print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) - FILE *fp; - char *format; - time_t rs; - int rsf; - time_t us; - int usf; - time_t ss; - int ssf, cpu; -{ - int prec, lng, len; - char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")]; - time_t sum; - int sum_frac; - int sindex, ssize; - - len = strlen (format); - ssize = (len + 64) - (len % 64); - str = (char *)xmalloc (ssize); - sindex = 0; - - for (s = format; *s; s++) - { - if (*s != '%' || s[1] == '\0') - { - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == '%') - { - s++; - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == 'P') - { - s++; - if (cpu > 10000) - cpu = 10000; - sum = cpu / 100; - sum_frac = (cpu % 100) * 10; - len = mkfmt (ts, 2, 0, sum, sum_frac); - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - else - { - prec = 3; /* default is three places past the decimal point. */ - lng = 0; /* default is to not use minutes or append `s' */ - s++; - if (DIGIT (*s)) /* `precision' */ - { - prec = *s++ - '0'; - if (prec > 3) prec = 3; - } - if (*s == 'l') /* `length extender' */ - { - lng = 1; - s++; - } - if (*s == 'R' || *s == 'E') - len = mkfmt (ts, prec, lng, rs, rsf); - else if (*s == 'U') - len = mkfmt (ts, prec, lng, us, usf); - else if (*s == 'S') - len = mkfmt (ts, prec, lng, ss, ssf); - else - { - internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s); - free (str); - return; - } - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - } - - str[sindex] = '\0'; - fprintf (fp, "%s\n", str); - fflush (fp); - - free (str); -} - -static int -time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rv, posix_time, old_flags; - time_t rs, us, ss; - int rsf, usf, ssf; - int cpu; - char *time_format; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) - struct timeval real, user, sys; - struct timeval before, after; -# if defined (HAVE_STRUCT_TIMEZONE) - struct timezone dtz; /* posix doesn't define this */ -# endif - struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */ -#else -# if defined (HAVE_TIMES) - clock_t tbefore, tafter, real, user, sys; - struct tms before, after; -# endif -#endif - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&before, &dtz); -# else - gettimeofday (&before, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfb); - getrusage (RUSAGE_CHILDREN, &kidsb); -#else -# if defined (HAVE_TIMES) - tbefore = times (&before); -# endif -#endif - - posix_time = (command->flags & CMD_TIME_POSIX); - - old_flags = command->flags; - command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); - rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); - command->flags = old_flags; - - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&after, &dtz); -# else - gettimeofday (&after, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfa); - getrusage (RUSAGE_CHILDREN, &kidsa); - - difftimeval (&real, &before, &after); - timeval_to_secs (&real, &rs, &rsf); - - addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), - difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); - timeval_to_secs (&user, &us, &usf); - - addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), - difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); - timeval_to_secs (&sys, &ss, &ssf); - - cpu = timeval_to_cpu (&real, &user, &sys); -#else -# if defined (HAVE_TIMES) - tafter = times (&after); - - real = tafter - tbefore; - clock_t_to_secs (real, &rs, &rsf); - - user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); - clock_t_to_secs (user, &us, &usf); - - sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); - clock_t_to_secs (sys, &ss, &ssf); - - cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real; - -# else - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; -# endif -#endif - - if (posix_time) - time_format = POSIX_TIMEFORMAT; - else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) - time_format = BASH_TIMEFORMAT; - - if (time_format && *time_format) - print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); - - return rv; -} -#endif /* COMMAND_TIMING */ - -/* Execute a command that's supposed to be in a subshell. This must be - called after make_child and we must be running in the child process. - The caller will return or exit() immediately with the value this returns. */ -static int -execute_in_subshell (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 user_subshell, return_code, function_value, should_redir_stdin, invert; - int ois; - COMMAND *tcom; - - USE_VAR(user_subshell); - USE_VAR(invert); - USE_VAR(tcom); - USE_VAR(asynchronous); - - subshell_level++; - should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - stdin_redirects (command->redirects) == 0); - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - user_subshell = command->type == cm_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 */ - ois = interactive_shell; - interactive_shell = 0; - /* This test is to prevent alias expansion by interactive shells that - run `(command) &' but to allow scripts that have enabled alias - expansion with `shopt -s expand_alias' to continue to expand - aliases. */ - if (ois != interactive_shell) - expand_aliases = 0; - asynchronous = 0; - } - - /* Subshells are neither login nor interactive. */ - login_shell = interactive = 0; - - subshell_environment = user_subshell ? SUBSHELL_PAREN : SUBSHELL_ASYNC; - - reset_terminating_signals (); /* in sig.c */ - /* Cancel traps, in trap.c. */ - restore_original_signals (); - if (asynchronous) - setup_async_signals (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - -#if defined (JOB_CONTROL) - /* Delete all traces that there were any jobs running. This is - only for subshells. */ - without_job_control (); -#endif /* JOB_CONTROL */ - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - 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) - { - stdin_redir = stdin_redirects (command->redirects); - restore_default_signal (0); - } - - /* If this is an asynchronous command (command &), we want to - redirect the standard input from /dev/null in the absence of - any specific redirection involving stdin. */ - if (should_redir_stdin && stdin_redir == 0) - async_redirect_stdin (); - - /* Do redirections, then dispose of them before recursive call. */ - if (command->redirects) - { - if (do_redirections (command->redirects, RX_ACTIVE) != 0) - exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - - dispose_redirects (command->redirects); - command->redirects = (REDIRECT *)NULL; - } - - tcom = (command->type == cm_subshell) ? command->value.Subshell->command : command; - - /* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */ - if ((command->flags & CMD_IGNORE_RETURN) && tcom != command) - tcom->flags |= CMD_IGNORE_RETURN; - - /* 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 we're timing the command or inverting its return value, however, - we cannot do this optimization. */ - if (user_subshell && (tcom->type == cm_simple || tcom->type == cm_subshell) && - ((tcom->flags & CMD_TIME_PIPELINE) == 0) && - ((tcom->flags & CMD_INVERT_RETURN) == 0)) - { - tcom->flags |= CMD_NO_FORK; - if (tcom->type == cm_simple) - tcom->value.Simple->flags |= CMD_NO_FORK; - } - - invert = (tcom->flags & CMD_INVERT_RETURN) != 0; - tcom->flags &= ~CMD_INVERT_RETURN; - - /* 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 - (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); - - /* If we are asked to, invert the return value. */ - if (invert) - return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - - /* 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 (); - } - - subshell_level--; - return (return_code); - /* NOTREACHED */ -} - -static int -execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; - COMMAND *cmd; - struct fd_bitmap *fd_bitmap; - -#if defined (JOB_CONTROL) - sigset_t set, oset; - BLOCK_CHILD (set, oset); -#endif /* JOB_CONTROL */ - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - prev = pipe_in; - cmd = command; - - while (cmd && cmd->type == cm_connection && - cmd->value.Connection && cmd->value.Connection->connector == '|') - { - /* Make a pipeline between the two commands. */ - if (pipe (fildes) < 0) - { - sys_error ("pipe error"); -#if defined (JOB_CONTROL) - terminate_current_pipeline (); - kill_current_pipeline (); -#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 (); - return (EXECUTION_FAILURE); /* XXX */ - } - - /* Here is a problem: with the new file close-on-exec - code, the read end of the pipe (fildes[0]) stays open - in the first process, so that process will never get a - SIGPIPE. There is no way to signal the first process - that it should close fildes[0] after forking, so it - remains open. No SIGPIPE is ever sent because there - is still a file descriptor open for reading connected - to the pipe. We take care of that here. This passes - around a bitmap of file descriptors that must be - closed after making a child process in execute_simple_command. */ - - /* We need fd_bitmap to be at least as big as fildes[0]. - If fildes[0] is less than fds_to_close->size, then - use fds_to_close->size. */ - new_bitmap_size = (fildes[0] < fds_to_close->size) - ? fds_to_close->size - : fildes[0] + 8; - - fd_bitmap = new_fd_bitmap (new_bitmap_size); - - /* Now copy the old information into the new bitmap. */ - xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); - - /* And mark the pipe file descriptors to be closed. */ - fd_bitmap->bitmap[fildes[0]] = 1; - - /* In case there are pipe or out-of-processes errors, we - want all these file descriptors to be closed when - unwind-protects are run, and the storage used for the - bitmaps freed up. */ - begin_unwind_frame ("pipe-file-descriptors"); - add_unwind_protect (dispose_fd_bitmap, fd_bitmap); - add_unwind_protect (close_fd_bitmap, fd_bitmap); - if (prev >= 0) - add_unwind_protect (close, prev); - dummyfd = fildes[1]; - add_unwind_protect (close, dummyfd); - -#if defined (JOB_CONTROL) - add_unwind_protect (restore_signal_mask, &oset); -#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 - - return (exec_result); -} - -static int -execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - REDIRECT *rp; - COMMAND *tc, *second; - int ignore_return, exec_result; - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - switch (command->value.Connection->connector) - { - /* Do the first command asynchronously. */ - case '&': - tc = command->value.Connection->first; - if (tc == 0) - return (EXECUTION_SUCCESS); - - rp = tc->redirects; - - if (ignore_return) - tc->flags |= CMD_IGNORE_RETURN; - tc->flags |= CMD_AMPERSAND; - - /* If this shell was compiled without job control support, - 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 ((subshell_environment || !job_control) && !stdin_redir) -#else - if (!stdin_redir) -#endif /* JOB_CONTROL */ - tc->flags |= CMD_STDIN_REDIR; - - exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); - - if (tc->flags & CMD_STDIN_REDIR) - tc->flags &= ~CMD_STDIN_REDIR; - - 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; - - /* Just call execute command on both sides. */ - case ';': - if (ignore_return) - { - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - if (command->value.Connection->second) - command->value.Connection->second->flags |= CMD_IGNORE_RETURN; - } - QUIT; - execute_command (command->value.Connection->first); - QUIT; - exec_result = execute_command_internal (command->value.Connection->second, - asynchronous, pipe_in, pipe_out, - fds_to_close); - break; - - case '|': - exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); - 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: - command_error ("execute_connection", CMDERR_BADCONN, command->value.Connection->connector, 0); - jump_to_top_level (DISCARD); - exec_result = EXECUTION_FAILURE; - } - - return exec_result; -} - -#define REAP() \ - do \ - { \ - if (!interactive_shell) \ - reap_dead_jobs (); \ - } \ - while (0) - -/* Execute a FOR command. The syntax is: FOR word_desc IN word_list; - DO command; DONE */ -static int -execute_for_command (for_command) - FOR_COM *for_command; -{ - register WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier; - int retval, save_line_number; -#if 0 - SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ -#endif - - save_line_number = line_number; - if (check_identifier (for_command->name, 1) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_USAGE; - jump_to_top_level (ERREXIT); - } - 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 0 - if (lexical_scoping) - { - old_value = copy_variable (find_variable (identifier)); - if (old_value) - add_unwind_protect (dispose_variable, old_value); - } -#endif - - if (for_command->flags & CMD_IGNORE_RETURN) - for_command->action->flags |= CMD_IGNORE_RETURN; - - for (retval = EXECUTION_SUCCESS; list; list = list->next) - { - QUIT; - - line_number = for_command->line; - - /* Remember what this command looks like, for debugger. */ - command_string_index = 0; - print_for_command_head (for_command); - - if (echo_command_at_execute) - xtrace_print_for_command_head (for_command); - - /* Save this command unless it's a trap command. */ - if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - continue; -#endif - - this_command_name = (char *)NULL; - v = bind_variable (identifier, list->word->word); - if (readonly_p (v) || noassign_p (v)) - { - line_number = save_line_number; - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("for"); - loop_level--; - return (EXECUTION_FAILURE); - } - } - retval = execute_command (for_command->action); - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - } - - loop_level--; - line_number = save_line_number; - -#if 0 - if (lexical_scoping) - { - if (!old_value) - unbind_variable (identifier); - 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 - - dispose_words (releaser); - discard_unwind_frame ("for"); - return (retval); -} - -#if defined (ARITH_FOR_COMMAND) -/* Execute an arithmetic for command. The syntax is - - for (( init ; step ; test )) - do - body - done - - The execution should be exactly equivalent to - - eval \(\( init \)\) - while eval \(\( test \)\) ; do - body; - eval \(\( step \)\) - done -*/ -static intmax_t -eval_arith_for_expr (l, okp) - WORD_LIST *l; - int *okp; -{ - WORD_LIST *new; - intmax_t expresult; - int r; - - new = expand_words_no_vars (l); - if (new) - { - if (echo_command_at_execute) - xtrace_print_arith_cmd (new); - this_command_name = "(("; /* )) for expression error messages */ - - command_string_index = 0; - print_arith_command (new); - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - - r = run_debug_trap (); - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ -#if defined (DEBUGGER) - if (debugging_mode == 0 || r == EXECUTION_SUCCESS) - expresult = evalexp (new->word->word, okp); - else - { - expresult = 0; - if (okp) - *okp = 1; - } -#else - expresult = evalexp (new->word->word, okp); -#endif - dispose_words (new); - } - else - { - expresult = 0; - if (okp) - *okp = 1; - } - return (expresult); -} - -static int -execute_arith_for_command (arith_for_command) - ARITH_FOR_COM *arith_for_command; -{ - intmax_t expresult; - int expok, body_status, arith_lineno, save_lineno; - - body_status = EXECUTION_SUCCESS; - loop_level++; - save_lineno = line_number; - - if (arith_for_command->flags & CMD_IGNORE_RETURN) - arith_for_command->action->flags |= CMD_IGNORE_RETURN; - - this_command_name = "(("; /* )) for expression error messages */ - - /* save the starting line number of the command so we can reset - line_number before executing each expression -- for $LINENO - and the DEBUG trap. */ - line_number = arith_lineno = arith_for_command->line; - if (variable_context && interactive_shell) - line_number -= function_line_number; - - /* Evaluate the initialization expression. */ - expresult = eval_arith_for_expr (arith_for_command->init, &expok); - if (expok == 0) - { - line_number = save_lineno; - return (EXECUTION_FAILURE); - } - - while (1) - { - /* Evaluate the test expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->test, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - REAP (); - if (expresult == 0) - break; - - /* Execute the body of the arithmetic for command. */ - QUIT; - body_status = execute_command (arith_for_command->action); - QUIT; - - /* Handle any `break' or `continue' commands executed by the body. */ - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - - /* Evaluate the step expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->step, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - } - - loop_level--; - line_number = save_lineno; - - return (body_status); -} -#endif - -#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); - for (i = ind, l = list; l && --i; l = l->next) - ; - fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); - return (STRLEN (l->word->word)); -} - -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 = max_elem_len ? COLS / max_elem_len : 1; - 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, or an invalid - number is entered, the loop is executed again. */ -static char * -select_query (list, list_len, prompt, print_menu) - WORD_LIST *list; - int list_len; - char *prompt; - int print_menu; -{ - int max_elem_len, indices_len, len; - intmax_t 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) - { - if (print_menu) - print_select_list (list, list_len, max_elem_len, indices_len); - fprintf (stderr, "%s", prompt); - fflush (stderr); - QUIT; - - if (read_builtin ((WORD_LIST *)NULL) == EXECUTION_FAILURE) - { - putchar ('\n'); - return ((char *)NULL); - } - repl_string = get_string_value ("REPLY"); - if (*repl_string == 0) - { - print_menu = 1; - continue; - } - if (legal_number (repl_string, &reply) == 0) - return ""; - if (reply < 1 || reply > list_len) - return ""; - - for (l = list; 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. */ -static int -execute_select_command (select_command) - SELECT_COM *select_command; -{ - WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier, *ps3_prompt, *selection; - int retval, list_len, show_menu, save_line_number; - - if (check_identifier (select_command->name, 1) == 0) - return (EXECUTION_FAILURE); - - save_line_number = line_number; - line_number = select_command->line; - - command_string_index = 0; - print_select_command_head (select_command); - - if (echo_command_at_execute) - xtrace_print_select_command_head (select_command); - - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - 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); - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } - - begin_unwind_frame ("select"); - add_unwind_protect (dispose_words, releaser); - - if (select_command->flags & CMD_IGNORE_RETURN) - select_command->action->flags |= CMD_IGNORE_RETURN; - - retval = EXECUTION_SUCCESS; - show_menu = 1; - - while (1) - { - line_number = select_command->line; - ps3_prompt = get_string_value ("PS3"); - if (ps3_prompt == 0) - ps3_prompt = "#? "; - - QUIT; - selection = select_query (list, list_len, ps3_prompt, show_menu); - QUIT; - if (selection == 0) - { - /* select_query returns EXECUTION_FAILURE if the read builtin - fails, so we want to return failure in this case. */ - retval = EXECUTION_FAILURE; - break; - } - - v = bind_variable (identifier, selection); - if (readonly_p (v) || noassign_p (v)) - { - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("select"); - loop_level--; - line_number = save_line_number; - return (EXECUTION_FAILURE); - } - } - - retval = execute_command (select_command->action); - - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - -#if defined (KSH_COMPATIBLE_SELECT) - show_menu = 0; - selection = get_string_value ("REPLY"); - if (selection && *selection == '\0') - show_menu = 1; -#endif - } - - loop_level--; - line_number = save_line_number; - - dispose_words (releaser); - discard_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. */ -static int -execute_case_command (case_command) - CASE_COM *case_command; -{ - register WORD_LIST *list; - WORD_LIST *wlist, *es; - PATTERN_LIST *clauses; - char *word, *pattern; - int retval, match, ignore_return, save_line_number; - - save_line_number = line_number; - line_number = case_command->line; - - command_string_index = 0; - print_case_command_head (case_command); - - if (echo_command_at_execute) - xtrace_print_case_command_head (case_command); - - if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap(); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - /* Posix.2 specifies that the WORD is tilde expanded. */ - if (member ('~', case_command->word->word)) - { - word = bash_tilde_expand (case_command->word->word, 0); - free (case_command->word->word); - case_command->word->word = word; - } - - wlist = expand_word_unsplit (case_command->word, 0); - word = wlist ? string_list (wlist) : savestring (""); - dispose_words (wlist); - - retval = EXECUTION_SUCCESS; - ignore_return = case_command->flags & CMD_IGNORE_RETURN; - - begin_unwind_frame ("case"); - add_unwind_protect ((Function *)xfree, word); - -#define EXIT_CASE() goto exit_case_command - - for (clauses = case_command->clauses; clauses; clauses = clauses->next) - { - QUIT; - for (list = clauses->patterns; list; list = list->next) - { - /* Posix.2 specifies to tilde expand each member of the pattern - list. */ - if (member ('~', list->word->word)) - { - pattern = bash_tilde_expand (list->word->word, 0); - free (list->word->word); - list->word->word = pattern; - } - - 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, QGLOB_CVTNULL); - else - { - pattern = (char *)xmalloc (1); - pattern[0] = '\0'; - } - - /* Since the pattern does not undergo quote removal (as per - Posix.2, section 3.9.4.3), the strmatch () call must be able - to recognize backslashes as escape characters. */ - match = strmatch (pattern, word, FNMATCH_EXTFLAG) != FNM_NOMATCH; - free (pattern); - - dispose_words (es); - - if (match) - { - if (clauses->action && ignore_return) - clauses->action->flags |= CMD_IGNORE_RETURN; - retval = execute_command (clauses->action); - EXIT_CASE (); - } - - QUIT; - } - } - -exit_case_command: - free (word); - discard_unwind_frame ("case"); - line_number = save_line_number; - 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. */ -static int -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. */ -static int -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. */ -static int -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 (); - - /* Need to handle `break' in the test when we would break out of the - loop. The job control code will set `breaking' to loop_level - when a job in a loop is stopped with SIGTSTP. If the stopped job - is in the loop test, `breaking' will not be reset unless we do - this, and the shell will cease to execute commands. */ - if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - break; - } - if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - 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. */ -static int -execute_if_command (if_command) - IF_COM *if_command; -{ - int return_value, save_line_number; - - save_line_number = line_number; - if_command->test->flags |= CMD_IGNORE_RETURN; - return_value = execute_command (if_command->test); - line_number = save_line_number; - - 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)); - } -} - -#if defined (DPAREN_ARITHMETIC) -static int -execute_arith_command (arith_command) - ARITH_COM *arith_command; -{ - int expok, save_line_number, retval; - intmax_t expresult; - WORD_LIST *new; - - expresult = 0; - - save_line_number = line_number; - this_command_name = "(("; /* )) */ - line_number = arith_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell) - line_number -= function_line_number; - - command_string_index = 0; - print_arith_command (arith_command->exp); - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - - /* Run the debug trap before each arithmetic command, but do it after we - update the line number information and before we expand the various - words in the expression. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - new = expand_words_no_vars (arith_command->exp); - - /* If we're tracing, make a new word list with `((' at the front and `))' - at the back and print it. */ - if (echo_command_at_execute) - xtrace_print_arith_cmd (new); - - if (new) - { - expresult = evalexp (new->word->word, &expok); - line_number = save_line_number; - dispose_words (new); - } - else - { - expresult = 0; - expok = 1; - } - - if (expok == 0) - return (EXECUTION_FAILURE); - - return (expresult == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif /* DPAREN_ARITHMETIC */ - -#if defined (COND_COMMAND) - -static char *nullstr = ""; - -static int -execute_cond_node (cond) - COND_COM *cond; -{ - int result, invert, patmatch, rmatch, mflags; - char *arg1, *arg2; - - invert = (cond->flags & CMD_INVERT_RETURN); - - if (cond->type == COND_EXPR) - result = execute_cond_node (cond->left); - else if (cond->type == COND_OR) - { - result = execute_cond_node (cond->left); - if (result != EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_AND) - { - result = execute_cond_node (cond->left); - if (result == EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_UNARY) - { - arg1 = cond_expand_word (cond->left->op, 0); - if (arg1 == 0) - arg1 = nullstr; - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL); - result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; - if (arg1 != nullstr) - free (arg1); - } - else if (cond->type == COND_BINARY) - { - patmatch = ((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && - (cond->op->word[0] == '!' || cond->op->word[0] == '=') || - (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); -#if defined (COND_REGEXP) - rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' && - cond->op->word[2] == '\0'); -#endif - - arg1 = cond_expand_word (cond->left->op, 0); - if (arg1 == 0) - arg1 = nullstr; - arg2 = cond_expand_word (cond->right->op, patmatch); - if (arg2 == 0) - arg2 = nullstr; - - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2); - -#if defined (COND_REGEXP) - if (rmatch) - { - mflags = SHMAT_PWARN; -#if defined (ARRAY_VARS) - mflags |= SHMAT_SUBEXP; -#endif - - result = sh_regmatch (arg1, arg2, mflags); - } - else -#endif /* COND_REGEXP */ - result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP) - ? EXECUTION_SUCCESS - : EXECUTION_FAILURE; - if (arg1 != nullstr) - free (arg1); - if (arg2 != nullstr) - free (arg2); - } - else - { - command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0); - jump_to_top_level (DISCARD); - result = EXECUTION_FAILURE; - } - - if (invert) - result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - - return result; -} - -static int -execute_cond_command (cond_command) - COND_COM *cond_command; -{ - int retval, save_line_number; - - retval = EXECUTION_SUCCESS; - save_line_number = line_number; - - this_command_name = "[["; - line_number = cond_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell) - line_number -= function_line_number; - - command_string_index = 0; - print_cond_command (cond_command); - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - - /* Run the debug trap before each conditional command, but do it after we - update the line number information. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - -#if 0 - debug_print_cond_command (cond_command); -#endif - - last_command_exit_value = retval = execute_cond_node (cond_command); - line_number = save_line_number; - return (retval); -} -#endif /* COND_COMMAND */ - -static void -bind_lastarg (arg) - char *arg; -{ - SHELL_VAR *var; - - if (arg == 0) - arg = ""; - var = bind_variable ("_", arg); - VUNSETATTR (var, att_exported); -} - -/* Execute a null command. Fork a subshell if the command uses pipes or is - to be run asynchronously. This handles all the side effects that are - supposed to take place. */ -static int -execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subst_pid) - REDIRECT *redirects; - int pipe_in, pipe_out, async; - pid_t old_last_command_subst_pid; -{ - int r; - - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) - { - /* We have a null command, but we really want a subshell to take - care of it. Just fork, do piping and redirections, and exit. */ - if (make_child ((char *)NULL, async) == 0) - { - /* Cancel traps, in trap.c. */ - restore_original_signals (); /* XXX */ - - do_piping (pipe_in, pipe_out); - - subshell_environment = SUBSHELL_ASYNC; - - if (do_redirections (redirects, RX_ACTIVE) == 0) - exit (EXECUTION_SUCCESS); - else - exit (EXECUTION_FAILURE); - } - else - { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - return (EXECUTION_SUCCESS); - } - } - else - { - /* Even if there aren't any command names, pretend to do the - redirections that are specified. The user expects the side - effects to take place. If the redirections fail, then return - failure. Otherwise, if a command substitution took place while - expanding the command or a redirection, return the value of that - substitution. Otherwise, return EXECUTION_SUCCESS. */ - - r = do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE); - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - - if (r != 0) - return (EXECUTION_FAILURE); - else if (old_last_command_subst_pid != last_command_subst_pid) - return (last_command_exit_value); - else - return (EXECUTION_SUCCESS); - } -} - -/* This is a hack to suppress word splitting for assignment statements - given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */ -static void -fix_assignment_words (words) - WORD_LIST *words; -{ - WORD_LIST *w; - struct builtin *b; - - if (words == 0) - return; - - b = 0; - - for (w = words; w; w = w->next) - if (w->word->flags & W_ASSIGNMENT) - { - if (b == 0) - { - b = builtin_address_internal (words->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP); - } -} - -/* The meaty part of all the executions. We have to start hacking the - real execution of commands here. Fork a process, set things up, - execute the command. */ -static int -execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) - SIMPLE_COM *simple_command; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; -{ - WORD_LIST *words, *lastword; - char *command_line, *lastarg, *temp; - int first_word_quoted, result, builtin_is_special, already_forked, dofork; - pid_t old_last_command_subst_pid, old_last_async_pid; - sh_builtin_func_t *builtin; - SHELL_VAR *func; - - result = EXECUTION_SUCCESS; - special_builtin_failed = builtin_is_special = 0; - command_line = (char *)0; - - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell) - line_number -= function_line_number; - - /* Remember what this command line looks like at invocation. */ - command_string_index = 0; - print_simple_command (simple_command); - - if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - /* Run the debug trap before each simple command, but do it after we - update the line number information. */ - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && result != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - first_word_quoted = - simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0; - - old_last_command_subst_pid = last_command_subst_pid; - old_last_async_pid = last_asynchronous_pid; - - already_forked = dofork = 0; - - /* If we're in a pipeline or run in the background, set DOFORK so we - make the child early, before word expansion. This keeps assignment - statements from affecting the parent shell's environment when they - should not. */ - dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async; - - /* Something like `%2 &' should restart job 2 in the background, not cause - the shell to fork here. */ - if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && - simple_command->words && simple_command->words->word && - simple_command->words->word->word && - (simple_command->words->word->word[0] == '%')) - dofork = 0; - - if (dofork) - { -#if 0 - /* XXX memory leak if expand_words() error causes a jump_to_top_level */ - command_line = savestring (the_printed_command); -#endif - - /* Do this now, because execute_disk_command will do it anyway in the - vast majority of cases. */ - maybe_make_export_env (); - -#if 0 - if (make_child (command_line, async) == 0) -#else - if (make_child (savestring (the_printed_command), async) == 0) -#endif - { - already_forked = 1; - simple_command->flags |= CMD_NO_FORK; - - subshell_environment = (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - ? (SUBSHELL_PIPE|SUBSHELL_FORK) - : (SUBSHELL_ASYNC|SUBSHELL_FORK); - - /* We need to do this before piping to handle some really - pathological cases where one of the pipe file descriptors - is < 2. */ - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - pipe_in = pipe_out = NO_PIPE; - - last_asynchronous_pid = old_last_async_pid; - } - else - { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - command_line = (char *)NULL; /* don't free this. */ - bind_lastarg ((char *)NULL); - return (result); - } - } - - /* 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; - fix_assignment_words (simple_command->words); - words = expand_words (simple_command->words); - current_fds_to_close = (struct fd_bitmap *)NULL; - } - else - words = copy_word_list (simple_command->words); - - /* 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 == 0) - { - this_command_name = 0; - result = execute_null_command (simple_command->redirects, - pipe_in, pipe_out, - already_forked ? 0 : async, - old_last_command_subst_pid); - if (already_forked) - exit (result); - else - { - bind_lastarg ((char *)NULL); - set_pipestatus_from_exit (result); - return (result); - } - } - - lastarg = (char *)NULL; - - begin_unwind_frame ("simple-command"); - - if (echo_command_at_execute) - xtrace_print_word_list (words, 1); - - builtin = (sh_builtin_func_t *)NULL; - func = (SHELL_VAR *)NULL; - if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0) - { - /* Posix.2 says special builtins are found before functions. We - don't set builtin_is_special anywhere other than here, because - this path is followed only when the `command' builtin is *not* - being used, and we don't want to exit the shell if a special - builtin executed with `command builtin' fails. `command' is not - a special builtin. */ - if (posixly_correct) - { - builtin = find_special_builtin (words->word->word); - if (builtin) - builtin_is_special = 1; - } - if (builtin == 0) - func = find_function (words->word->word); - } - - /* In POSIX mode, assignment errors in the temporary environment cause a - non-interactive shell to exit. */ - if (builtin_is_special && interactive_shell == 0 && tempenv_assign_error) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (ERREXIT); - } - - 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] == '%' && already_forked == 0) - { - this_command_name = async ? "bg" : "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. */ - if (job_control && already_forked == 0 && async == 0 && - !first_word_quoted && - !words->next && - words->word->word[0] && - !simple_command->redirects && - pipe_in == NO_PIPE && - pipe_out == NO_PIPE && - (temp = get_string_value ("auto_resume"))) - { - int job, jflags, started_status; - - jflags = JM_STOPPED|JM_FIRSTMATCH; - if (STREQ (temp, "exact")) - jflags |= JM_EXACT; - else if (STREQ (temp, "substring")) - jflags |= JM_SUBSTRING; - else - jflags |= JM_PREFIX; - job = get_job_by_name (words->word->word, jflags); - if (job != NO_JOB) - { - run_unwind_frame ("simple-command"); - this_command_name = "fg"; - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address ("fg"); - - started_status = start_job (job, 1); - return ((started_status < 0) ? EXECUTION_FAILURE : started_status); - } - } -#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. - We have already found special builtins by this time, so we do not - set builtin_is_special. If this is a function or builtin, and we - have pipes, then fork a subshell in here. Otherwise, just execute - the command directly. */ - if (func == 0 && builtin == 0) - builtin = find_shell_builtin (this_command_name); - - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin; - - if (builtin || func) - { - if (already_forked) - { - /* reset_terminating_signals (); */ /* XXX */ - /* Cancel traps, in trap.c. */ - restore_original_signals (); - - if (async) - { - if ((simple_command->flags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (simple_command->redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - subshell_level++; - execute_subshell_builtin_or_function - (words, simple_command->redirects, builtin, func, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); - subshell_level--; - } - else - { - result = execute_builtin_or_function - (words, builtin, func, simple_command->redirects, fds_to_close, - simple_command->flags); - if (builtin) - { - if (result > EX_SHERRBASE) - { - result = builtin_status (result); - if (builtin_is_special) - special_builtin_failed = 1; - } - /* In POSIX mode, if there are assignment statements preceding - a special builtin, they persist after the builtin - completes. */ - if (posixly_correct && builtin_is_special && temporary_env) - merge_temporary_env (); - } - else /* function */ - { - if (result == EX_USAGE) - result = EX_BADUSAGE; - else if (result > EX_SHERRBASE) - result = EXECUTION_FAILURE; - } - - set_pipestatus_from_exit (result); - - goto return_result; - } - } - - if (command_line == 0) - command_line = savestring (the_printed_command); - - execute_disk_command (words, simple_command->redirects, command_line, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); - - return_result: - bind_lastarg (lastarg); - FREE (command_line); - dispose_words (words); - discard_unwind_frame ("simple-command"); - this_command_name = (char *)NULL; /* points to freed memory now */ - return (result); -} - -/* Translate the special builtin exit statuses. We don't really need a - function for this; it's a placeholder for future work. */ -static int -builtin_status (result) - int result; -{ - int r; - - switch (result) - { - case EX_USAGE: - r = EX_BADUSAGE; - break; - case EX_REDIRFAIL: - case EX_BADSYNTAX: - case EX_BADASSIGN: - case EX_EXPFAIL: - r = EXECUTION_FAILURE; - break; - default: - r = EXECUTION_SUCCESS; - break; - } - return (r); -} - -static int -execute_builtin (builtin, words, flags, subshell) - sh_builtin_func_t *builtin; - WORD_LIST *words; - int flags, subshell; -{ - int old_e_flag, result, eval_unwind; - int isbltinenv; - - old_e_flag = exit_immediately_on_error; - /* The eval builtin calls parse_and_execute, which does not know about - the setting of flags, and always calls the execution functions with - flags that will exit the shell on an error if -e is set. If the - 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; - eval_unwind = 1; - } - else - eval_unwind = 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' and `eval' builtins. */ - isbltinenv = (builtin == source_builtin || builtin == eval_builtin); - if (isbltinenv) - { - if (subshell == 0) - begin_unwind_frame ("builtin_env"); - - if (temporary_env) - { - push_scope (VC_BLTNENV, temporary_env); - if (subshell == 0) - add_unwind_protect (pop_scope, "1"); - temporary_env = (HASH_TABLE *)NULL; - } - } - - /* `return' does a longjmp() back to a saved environment in execute_function. - If a variable assignment list preceded the command, and the shell is - running in POSIX mode, we need to merge that into the shell_variables - table, since `return' is a POSIX special builtin. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) - { - begin_unwind_frame ("return_temp_env"); - add_unwind_protect (merge_temporary_env, (char *)NULL); - } - - result = ((*builtin) (words->next)); - - /* This shouldn't happen, but in case `return' comes back instead of - longjmp'ing, we need to unwind. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) - discard_unwind_frame ("return_temp_env"); - - if (subshell == 0 && isbltinenv) - run_unwind_frame ("builtin_env"); - - if (eval_unwind) - { - exit_immediately_on_error += old_e_flag; - discard_unwind_frame ("eval_builtin"); - } - - return (result); -} - -static int -execute_function (var, words, flags, fds_to_close, async, subshell) - SHELL_VAR *var; - WORD_LIST *words; - int flags; - struct fd_bitmap *fds_to_close; - int async, subshell; -{ - int return_val, result; - COMMAND *tc, *fc, *save_current; - char *debug_trap, *error_trap, *return_trap; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; -#endif - FUNCTION_DEF *shell_fn; - char *sfile, *t; - static int funcnest = 0; - - USE_VAR(fc); - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); -#endif - - tc = (COMMAND *)copy_command (function_cell (var)); - if (tc && (flags & CMD_IGNORE_RETURN)) - tc->flags |= CMD_IGNORE_RETURN; - - if (subshell == 0) - { - begin_unwind_frame ("function_calling"); - push_context (var->name, subshell, temporary_env); - add_unwind_protect (pop_context, (char *)NULL); - unwind_protect_int (line_number); - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - add_unwind_protect (dispose_command, (char *)tc); - unwind_protect_pointer (this_shell_function); - unwind_protect_int (loop_level); - } - else - push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */ - - temporary_env = (HASH_TABLE *)NULL; - - this_shell_function = var; - make_funcname_visible (1); - - debug_trap = TRAP_STRING(DEBUG_TRAP); - error_trap = TRAP_STRING(ERROR_TRAP); - return_trap = TRAP_STRING(RETURN_TRAP); - - /* The order of the unwind protects for debug_trap, error_trap and - return_trap is important here! unwind-protect commands are run - in reverse order of registration. If this causes problems, take - out the xfree unwind-protect calls and live with the small memory leak. */ - - /* function_trace_mode != 0 means that all functions inherit the DEBUG trap. - if the function has the trace attribute set, it inherits the DEBUG trap */ - if (debug_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) - { - if (subshell == 0) - { - debug_trap = savestring (debug_trap); - add_unwind_protect (xfree, debug_trap); - add_unwind_protect (set_debug_trap, debug_trap); - } - restore_default_signal (DEBUG_TRAP); - } - - /* error_trace_mode != 0 means that functions inherit the ERR trap. */ - if (error_trap && error_trace_mode == 0) - { - if (subshell == 0) - { - error_trap = savestring (error_trap); - add_unwind_protect (xfree, error_trap); - add_unwind_protect (set_error_trap, error_trap); - } - restore_default_signal (ERROR_TRAP); - } - - if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) - { - if (subshell == 0) - { - return_trap = savestring (return_trap); - add_unwind_protect (xfree, return_trap); - add_unwind_protect (set_return_trap, return_trap); - } - restore_default_signal (RETURN_TRAP); - } - - funcnest++; -#if defined (ARRAY_VARS) - /* This is quite similar to the code in shell.c and elsewhere. */ - shell_fn = find_function_def (this_shell_function->name); - sfile = shell_fn ? shell_fn->source_file : ""; - array_push (funcname_a, this_shell_function->name); - - array_push (bash_source_a, sfile); - t = itos (executing_line_number ()); - array_push (bash_lineno_a, t); - free (t); -#endif - - /* The temporary environment for a function is supposed to apply to - all commands executed within the function body. */ - - remember_args (words->next, 1); - - /* Update BASH_ARGV and BASH_ARGC */ - if (debugging_mode) - push_args (words->next); - - /* Number of the line on which the function body starts. */ - line_number = function_line_number = tc->line; - - if (subshell) - { -#if defined (JOB_CONTROL) - stop_pipeline (async, (COMMAND *)NULL); -#endif - fc = (tc->type == cm_group) ? tc->value.Group->command : tc; - - if (fc && (flags & CMD_IGNORE_RETURN)) - fc->flags |= CMD_IGNORE_RETURN; - } - else - fc = tc; - - return_catch_flag++; - return_val = setjmp (return_catch); - - if (return_val) - result = return_catch_value; - else - { - /* Run the debug trap here so we can trap at the start of a function's - execution rather than the execution of the body's first command. */ - showing_function_line = 1; - save_current = currently_executing_command; - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode == 0 || result == EXECUTION_SUCCESS) - { - showing_function_line = 0; - currently_executing_command = save_current; - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - - /* Run the RETURN trap in the function's context */ - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; - } -#else - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); -#endif - showing_function_line = 0; - } - - /* Restore BASH_ARGC and BASH_ARGV */ - if (debugging_mode) - pop_args (); - - if (subshell == 0) - run_unwind_frame ("function_calling"); - - funcnest--; -#if defined (ARRAY_VARS) - array_pop (bash_source_a); - array_pop (funcname_a); - array_pop (bash_lineno_a); -#endif - - if (variable_context == 0 || this_shell_function == 0) - make_funcname_visible (0); - - return (result); -} - -/* A convenience routine for use by other parts of the shell to execute - a particular shell function. */ -int -execute_shell_function (var, words) - SHELL_VAR *var; - WORD_LIST *words; -{ - int ret; - struct fd_bitmap *bitmap; - - bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); - begin_unwind_frame ("execute-shell-function"); - add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); - - ret = execute_function (var, words, 0, bitmap, 0, 0); - - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("execute-shell-function"); - - return ret; -} - -/* 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; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result, r; -#if defined (JOB_CONTROL) - int jobs_hack; - - jobs_hack = (builtin == jobs_builtin) && - ((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE); -#endif - - /* A subshell is neither a login shell nor interactive. */ - login_shell = interactive = 0; - - subshell_environment = SUBSHELL_ASYNC; - - maybe_make_export_env (); /* XXX - is this needed? */ - -#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 (jobs_hack) - kill_current_pipeline (); - else - without_job_control (); - - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - - if (do_redirections (redirects, RX_ACTIVE) != 0) - exit (EXECUTION_FAILURE); - - if (builtin) - { - /* 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 - { - r = execute_builtin (builtin, words, flags, 1); - if (r == EX_USAGE) - r = EX_BADUSAGE; - exit (r); - } - } - else - exit (execute_function (var, words, flags, fds_to_close, async, 1)); -} - -/* 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; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - REDIRECT *redirects; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result; - REDIRECT *saved_undo_list; - sh_builtin_func_t *saved_this_shell_builtin; - - if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - dispose_exec_redirects (); - return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */ - } - - saved_this_shell_builtin = this_shell_builtin; - 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_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); - - /* We do this before undoing the effects of any redirections. */ - if (ferror (stdout)) - clearerr (stdout); - - /* If we are executing the `command' builtin, but this_shell_builtin is - set to `exec_builtin', we know that we have something like - `command exec [redirection]', since otherwise `exec' would have - overwritten the shell and we wouldn't get here. In this case, we - want to behave as if the `command' builtin had not been specified - and preserve the redirections. */ - if (builtin == command_builtin && this_shell_builtin == exec_builtin) - { - if (saved_undo_list) - dispose_redirects (saved_undo_list); - redirection_undo_list = exec_redirection_undo_list; - saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL; - discard_unwind_frame ("saved_redirects"); - } - - if (saved_undo_list) - { - redirection_undo_list = saved_undo_list; - discard_unwind_frame ("saved redirects"); - } - - if (redirection_undo_list) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } - - return (result); -} - -void -setup_async_signals () -{ -#if defined (__BEOS__) - set_signal_handler (SIGHUP, SIG_IGN); /* they want csh-like behavior */ -#endif - -#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. - - NOTE: callers expect this to fork or exit(). */ -static void -execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, - async, fds_to_close, cmdflags) - WORD_LIST *words; - REDIRECT *redirects; - char *command_line; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int cmdflags; -{ - char *pathname, *command, **args; - int nofork; - pid_t pid; - - nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */ - pathname = words->word->word; - -#if defined (RESTRICTED_SHELL) - command = (char *)NULL; - if (restricted && xstrchr (pathname, '/')) - { - internal_error (_("%s: restricted: cannot specify `/' in command names"), - pathname); - last_command_exit_value = EXECUTION_FAILURE; - - /* If we're not going to fork below, we must already be in a child - process or a context in which it's safe to call exit(2). */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - exit (last_command_exit_value); - else - goto parent_return; - } -#endif /* RESTRICTED_SHELL */ - - command = search_for_command (pathname); - - if (command) - { - maybe_make_export_env (); - put_command_name_into_env (command); - } - - /* We have to make the child before we check for the non-existence - 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; - -#if 0 - /* This has been disabled for the time being. */ -#if !defined (ARG_MAX) || ARG_MAX >= 10240 - if (posixly_correct == 0) - put_gnu_argv_flags_into_env ((long)getpid (), glob_argv_flags); -#endif -#endif - - /* 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) - { - if ((cmdflags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - /* 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); - - do_piping (pipe_in, pipe_out); - - old_interactive = interactive; - if (async) - interactive = 0; - - subshell_environment = SUBSHELL_FORK; - - if (redirects && (do_redirections (redirects, RX_ACTIVE) != 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 == 0) - { - internal_error (_("%s: command not found"), pathname); - exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ - } - - /* Execve expects the command name to be in args[0]. So we - leave it there, in the same format that the user used to - type it in. */ - args = strvec_from_word_list (words, 0, 0, (int *)NULL); - exit (shell_execve (command, args, export_env)); - } - else - { -parent_return: - /* 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); - } -} - -/* CPP defines to decide whether a particular index into the #! line - corresponds to a valid interpreter name or argument character, or - whitespace. The MSDOS define is to allow \r to be treated the same - as \n. */ - -#if !defined (MSDOS) -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#else /* MSDOS */ -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#endif /* MSDOS */ - -static char * -getinterp (sample, sample_len, endp) - char *sample; - int sample_len, *endp; -{ - register int i; - char *execname; - int start; - - /* Find the name of the interpreter to exec. */ - for (i = 2; i < sample_len && whitespace (sample[i]); i++) - ; - - for (start = i; STRINGCHAR(i); i++) - ; - - execname = substring (sample, start, i); - - if (endp) - *endp = i; - return execname; -} - -#if !defined (HAVE_HASH_BANG_EXEC) -/* If the operating system on which we're running does not handle - the #! executable format, then help out. SAMPLE is the text read - from the file, SAMPLE_LEN characters. COMMAND is the name of - 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) - char *sample; - int sample_len; - char *command; - char **args, **env; -{ - char *execname, *firstarg; - int i, start, size_increment, larry; - - /* Find the name of the interpreter to exec. */ - execname = getinterp (sample, sample_len, &i); - size_increment = 1; - - /* Now the argument, if any. */ - for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++) - ; - - /* If there is more text on the line, then it is an argument for the - interpreter. */ - - if (STRINGCHAR(i)) - { - for (start = i; STRINGCHAR(i); i++) - ; - firstarg = substring ((char *)sample, start, i); - size_increment = 2; - } - - larry = strvec_len (args) + size_increment; - args = strvec_resize (args, larry + 1); - - 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)); -} -#undef STRINGCHAR -#undef WHITECHAR - -#endif /* !HAVE_HASH_BANG_EXEC */ - -static void -initialize_subshell () -{ -#if defined (ALIAS) - /* Forget about any aliases that we knew of. We are in a subshell. */ - delete_all_aliases (); -#endif /* ALIAS */ - -#if defined (HISTORY) - /* Forget about the history lines we have read. This is a non-interactive - subshell. */ - history_lines_this_session = 0; -#endif - -#if defined (JOB_CONTROL) - /* Forget about the way job control was working. We are in a subshell. */ - without_job_control (); - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - /* Reset the values of the shell flags and options. */ - reset_shell_flags (); - reset_shell_options (); - reset_shopt_options (); - - /* Zero out builtin_env, since this could be a shell script run from a - sourced file with a temporary environment supplied to the `source/.' - builtin. Such variables are not supposed to be exported (empirical - testing with sh and ksh). Just throw it away; don't worry about a - memory leak. */ - if (vc_isbltnenv (shell_variables)) - shell_variables = shell_variables->down; - - clear_unwind_protect_list (0); - - /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = 0; - - /* If we're not interactive, close the file descriptor from which we're - reading the current shell script. */ - if (interactive_shell == 0) - unset_bash_input (0); -} - -#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) -# define SETOSTYPE(x) __setostype(x) -#else -# define SETOSTYPE(x) -#endif - -#define READ_SAMPLE_BUF(file, buf, len) \ - do \ - { \ - fd = open(file, O_RDONLY); \ - if (fd >= 0) \ - { \ - len = read (fd, buf, 80); \ - close (fd); \ - } \ - else \ - len = -1; \ - } \ - while (0) - -/* Call execve (), handling interpreting shell scripts, and handling - exec failures. */ -int -shell_execve (command, args, env) - char *command; - char **args, **env; -{ - struct stat finfo; - int larray, i, fd; - char sample[80]; - int sample_len; - - SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ - execve (command, args, env); - i = errno; /* error from execve() */ - SETOSTYPE (1); - - /* If we get to this point, then start checking out the file. - Maybe it is something we can hack ourselves. */ - if (i != ENOEXEC) - { - if ((stat (command, &finfo) == 0) && (S_ISDIR (finfo.st_mode))) - internal_error (_("%s: is a directory"), command); - else if (executable_file (command) == 0) - { - errno = i; - file_error (command); - } - else - { - /* The file has the execute bits set, but the kernel refuses to - run it for some reason. See why. */ -#if defined (HAVE_HASH_BANG_EXEC) - READ_SAMPLE_BUF (command, sample, sample_len); - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - { - char *interp; - - interp = getinterp (sample, sample_len, (int *)NULL); - errno = i; - sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : ""); - FREE (interp); - return (EX_NOEXEC); - } -#endif - errno = i; - file_error (command); - } - return ((i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); /* XXX Posix.2 says that exit status is 126 */ - } - - /* 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 contents of the first line (or up to 80 characters) are in the - ASCII set. If it's a text file, execute the contents as shell commands, - otherwise return 126 (EX_BINARY_FILE). */ - READ_SAMPLE_BUF (command, sample, sample_len); - - 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) - { -#if !defined (HAVE_HASH_BANG_EXEC) - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - return (execute_shell_script (sample, sample_len, command, args, env)); - else -#endif - if (check_binary_file (sample, sample_len)) - { - internal_error (_("%s: cannot execute binary file"), command); - return (EX_BINARY_FILE); - } - } - - /* We have committed to attempting to execute the contents of this file - as shell commands. */ - - initialize_subshell (); - - set_sigint_handler (); - - /* Insert the name of this shell into the argument list. */ - larray = strvec_len (args) + 1; - args = strvec_resize (args, larray + 1); - - 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 defined (RESTRICTED_SHELL) - if (restricted) - change_flag ('r', FLAG_OFF); -#endif - - if (subshell_argv) - { - /* Can't free subshell_argv[0]; that is shell_name. */ - for (i = 1; i < subshell_argc; i++) - free (subshell_argv[i]); - free (subshell_argv); - } - - dispose_command (currently_executing_command); /* XXX */ - currently_executing_command = (COMMAND *)NULL; - - subshell_argc = larray; - subshell_argv = args; - subshell_envp = env; - - unbind_args (); /* remove the positional parameters */ - - longjmp (subshell_top_level, 1); - /*NOTREACHED*/ -} - -static int -execute_intern_function (name, function) - WORD_DESC *name; - COMMAND *function; -{ - SHELL_VAR *var; - - if (check_identifier (name, posixly_correct) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_USAGE; - jump_to_top_level (ERREXIT); - } - return (EXECUTION_FAILURE); - } - - var = find_function (name->word); - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - internal_error (_("%s: readonly function"), var->name); - return (EXECUTION_FAILURE); - } - - bind_function (name->word, function); - return (EXECUTION_SUCCESS); -} - -#if defined (INCLUDE_UNUSED) -#if defined (PROCESS_SUBSTITUTION) -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 */ -#endif - -static void -close_pipes (in, out) - int in, out; -{ - if (in >= 0) - close (in); - if (out >= 0) - close (out); -} - -static void -dup_error (oldd, newd) - int oldd, newd; -{ - sys_error (_("cannot duplicate fd %d to fd %d"), oldd, newd); -} - -/* 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) - dup_error (pipe_in, 0); - if (pipe_in > 0) - close (pipe_in); - } - if (pipe_out != NO_PIPE) - { - if (pipe_out != REDIRECT_BOTH) - { - if (dup2 (pipe_out, 1) < 0) - dup_error (pipe_out, 1); - if (pipe_out == 0 || pipe_out > 1) - close (pipe_out); - } - else - { - if (dup2 (1, 2) < 0) - dup_error (1, 2); - } - } -} diff --git a/expr.c.save1 b/expr.c.save1 deleted file mode 100644 index 147cf55fc..000000000 --- a/expr.c.save1 +++ /dev/null @@ -1,1243 +0,0 @@ -/* expr.c -- arithmetic expression evaluation. */ - -/* Copyright (C) 1990-2003 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* - All arithmetic is done as intmax_t 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. - - "id++", "id--" [post-increment and post-decrement] - "++id", "--id" [pre-increment and pre-decrement] - "-", "+" [(unary operators)] - "!", "~" - "**" [(exponentiation)] - "*", "/", "%" - "+", "-" - "<<", ">>" - "<=", ">=", "<", ">" - "==", "!=" - "&" - "^" - "|" - "&&" - "||" - "expr ? expr : expr" - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" - , [comma] - - (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 "config.h" - -#include -#include "bashansi.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "chartypes.h" -#include "bashintl.h" - -#include "shell.h" - -/* Because of the $((...)) construct, expressions may include newlines. - Here is a macro which accepts newlines, tabs and spaces as whitespace. */ -#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) - -/* 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. */ -#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 COND 12 /* exp1 ? exp2 : exp3 */ -#define POWER 13 /* exp1**exp2 */ -#define PREINC 14 /* ++var */ -#define PREDEC 15 /* --var */ -#define POSTINC 16 /* var++ */ -#define POSTDEC 17 /* var-- */ -#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 '|' /* Bitwise OR. */ -#define BXOR '^' /* Bitwise eXclusive OR. */ -#define BNOT '~' /* Bitwise NOT; Two's complement. */ -#define QUES '?' -#define COL ':' -#define COMMA ',' - -/* This should be the function corresponding to the operator with the - highest precedence. */ -#define EXP_HIGHEST expcomma - -static char *expression; /* The current expression */ -static char *tp; /* token lexical position */ -static char *lasttp; /* pointer to last token position */ -static int curtok; /* the current token */ -static int lasttok; /* the previous token */ -static int assigntok; /* the OP in OP= */ -static char *tokstr; /* current token string */ -static intmax_t tokval; /* current token value */ -static int noeval; /* set to 1 if no assignment to be done */ -static procenv_t evalbuf; - -static void readtok __P((void)); /* lexical analyzer */ - -static intmax_t expr_streval __P((char *, int)); -static intmax_t strlong __P((char *)); -static void evalerror __P((char *)); - -static void pushexp __P((void)); -static void popexp __P((void)); -static void expr_unwind __P((void)); -static void expr_bind_variable __P((char *, char *)); - -static intmax_t subexpr __P((char *)); - -static intmax_t expcomma __P((void)); -static intmax_t expassign __P((void)); -static intmax_t expcond __P((void)); -static intmax_t explor __P((void)); -static intmax_t expland __P((void)); -static intmax_t expbor __P((void)); -static intmax_t expbxor __P((void)); -static intmax_t expband __P((void)); -static intmax_t exp5 __P((void)); -static intmax_t exp4 __P((void)); -static intmax_t expshift __P((void)); -static intmax_t exp3 __P((void)); -static intmax_t exp2 __P((void)); -static intmax_t exppower __P((void)); -static intmax_t exp1 __P((void)); -static intmax_t exp0 __P((void)); - -/* A structure defining a single expression context. */ -typedef struct { - int curtok, lasttok; - char *expression, *tp, *lasttp; - intmax_t tokval; - char *tokstr; - int noeval; -} EXPR_CONTEXT; - -#ifdef INCLUDE_UNUSED -/* Not used yet. */ -typedef struct { - char *tokstr; - intmax_t tokval; -} LVALUE; -#endif - -/* Global var which contains the stack of expression contexts. */ -static EXPR_CONTEXT **expr_stack; -static int expr_depth; /* Location in the stack. */ -static int expr_stack_size; /* Number of slots already allocated. */ - -extern char *this_command_name; -extern int unbound_vars_is_error; - -#if defined (ARRAY_VARS) -extern char *bash_badsub_errmsg; -#endif - -#define SAVETOK(X) \ - do { \ - (X)->curtok = curtok; \ - (X)->lasttok = lasttok; \ - (X)->tp = tp; \ - (X)->lasttp = lasttp; \ - (X)->tokval = tokval; \ - (X)->tokstr = tokstr; \ - (X)->noeval = noeval; \ - } while (0) - -#define RESTORETOK(X) \ - do { \ - curtok = (X)->curtok; \ - lasttok = (X)->lasttok; \ - tp = (X)->tp; \ - lasttp = (X)->lasttp; \ - tokval = (X)->tokval; \ - tokstr = (X)->tokstr; \ - noeval = (X)->noeval; \ - } while (0) - -/* Push and save away the contents of the globals describing the - current expression context. */ -static void -pushexp () -{ - EXPR_CONTEXT *context; - - if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) - evalerror (_("expression recursion level exceeded")); - - if (expr_depth >= expr_stack_size) - { - expr_stack_size += EXPR_STACK_GROW_SIZE; - expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); - } - - context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); - - context->expression = expression; - SAVETOK(context); - - 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]; - - expression = context->expression; - RESTORETOK (context); - - free (context); -} - -static void -expr_unwind () -{ - while (--expr_depth > 0) - { - if (expr_stack[expr_depth]->tokstr) - free (expr_stack[expr_depth]->tokstr); - - if (expr_stack[expr_depth]->expression) - free (expr_stack[expr_depth]->expression); - - free (expr_stack[expr_depth]); - } - free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ -} - -static void -expr_bind_variable (lhs, rhs) - char *lhs, *rhs; -{ - (void)bind_int_variable (lhs, rhs); - stupidly_hack_special_variables (lhs); -} - -/* Evaluate EXPR, and return the arithmetic result. If VALIDP is - non-null, a zero is stored into the location to which it points - if the expression is invalid, non-zero otherwise. If a non-zero - value is returned in *VALIDP, the return value of evalexp() may - be used. - - 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. */ -intmax_t -evalexp (expr, validp) - char *expr; - int *validp; -{ - intmax_t val; - int c; - procenv_t oevalbuf; - - val = 0; - - FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); - - c = setjmp (evalbuf); - - if (c) - { - FREE (tokstr); - FREE (expression); - tokstr = expression = (char *)NULL; - - expr_unwind (); - - if (validp) - *validp = 0; - return (0); - } - - val = subexpr (expr); - - if (validp) - *validp = 1; - - FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); - - return (val); -} - -static intmax_t -subexpr (expr) - char *expr; -{ - intmax_t val; - char *p; - - for (p = expr; p && *p && cr_whitespace (*p); p++) - ; - - if (p == NULL || *p == '\0') - return (0); - - pushexp (); - curtok = lasttok = 0; - expression = savestring (expr); - tp = expression; - - tokstr = (char *)NULL; - tokval = 0; - - readtok (); - - val = EXP_HIGHEST (); - - if (curtok != 0) - evalerror (_("syntax error in expression")); - - FREE (tokstr); - FREE (expression); - - popexp (); - - return val; -} - -static intmax_t -expcomma () -{ - register intmax_t value; - - value = expassign (); - while (curtok == COMMA) - { - readtok (); - value = expassign (); - } - - return value; -} - -static intmax_t -expassign () -{ - register intmax_t value; - char *lhs, *rhs; - - value = expcond (); - if (curtok == EQ || curtok == OP_ASSIGN) - { - int special, op; - intmax_t lvalue; - - special = curtok == OP_ASSIGN; - - if (lasttok != STR) - evalerror (_("attempted assignment 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: - if (value == 0) - evalerror (_("division by 0")); - lvalue /= value; - break; - case MOD: - if (value == 0) - evalerror (_("division by 0")); - 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; - case BXOR: - lvalue ^= value; - break; - default: - free (lhs); - evalerror (_("bug: bad expassign token")); - break; - } - value = lvalue; - } - - rhs = itos (value); - if (noeval == 0) - expr_bind_variable (lhs, rhs); - free (rhs); - free (lhs); - FREE (tokstr); - tokstr = (char *)NULL; /* For freeing on errors. */ - } - return (value); -} - -/* Conditional expression (expr?expr:expr) */ -static intmax_t -expcond () -{ - intmax_t cval, val1, val2, rval; - int set_noeval; - - set_noeval = 0; - rval = cval = explor (); - if (curtok == QUES) /* found conditional expr */ - { - readtok (); - if (curtok == 0 || curtok == COL) - evalerror (_("expression expected")); - if (cval == 0) - { - set_noeval = 1; - noeval++; - } - - val1 = EXP_HIGHEST (); - - if (set_noeval) - noeval--; - if (curtok != COL) - evalerror (_("`:' expected for conditional expression")); - readtok (); - if (curtok == 0) - evalerror (_("expression expected")); - set_noeval = 0; - if (cval) - { - set_noeval = 1; - noeval++; - } - val2 = explor (); - if (set_noeval) - noeval--; - rval = cval ? val1 : val2; - lasttok = COND; - } - return rval; -} - -/* Logical OR. */ -static intmax_t -explor () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expland (); - - while (curtok == LOR) - { - set_noeval = 0; - if (val1 != 0) - { - noeval++; - set_noeval = 1; - } - readtok (); - val2 = expland (); - if (set_noeval) - noeval--; - val1 = val1 || val2; - lasttok = LOR; - } - - return (val1); -} - -/* Logical AND. */ -static intmax_t -expland () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expbor (); - - while (curtok == LAND) - { - set_noeval = 0; - if (val1 == 0) - { - set_noeval = 1; - noeval++; - } - readtok (); - val2 = expbor (); - if (set_noeval) - noeval--; - val1 = val1 && val2; - lasttok = LAND; - } - - return (val1); -} - -/* Bitwise OR. */ -static intmax_t -expbor () -{ - register intmax_t val1, val2; - - val1 = expbxor (); - - while (curtok == BOR) - { - readtok (); - val2 = expbxor (); - val1 = val1 | val2; - } - - return (val1); -} - -/* Bitwise XOR. */ -static intmax_t -expbxor () -{ - register intmax_t val1, val2; - - val1 = expband (); - - while (curtok == BXOR) - { - readtok (); - val2 = expband (); - val1 = val1 ^ val2; - } - - return (val1); -} - -/* Bitwise AND. */ -static intmax_t -expband () -{ - register intmax_t val1, val2; - - val1 = exp5 (); - - while (curtok == BAND) - { - readtok (); - val2 = exp5 (); - val1 = val1 & val2; - } - - return (val1); -} - -static intmax_t -exp5 () -{ - register intmax_t 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 intmax_t -exp4 () -{ - register intmax_t 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 /* (op == GT) */ - val1 = val1 > val2; - } - return (val1); -} - -/* Left and right shifts. */ -static intmax_t -expshift () -{ - register intmax_t 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 intmax_t -exp3 () -{ - register intmax_t 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 intmax_t -exp2 () -{ - register intmax_t val1, val2; - - val1 = exppower (); - - while ((curtok == MUL) || - (curtok == DIV) || - (curtok == MOD)) - { - int op = curtok; - - readtok (); - - val2 = exppower (); - - 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 intmax_t -exppower () -{ - register intmax_t val1, val2, c; - - val1 = exp1 (); - while (curtok == POWER) - { - readtok (); - val2 = exp1 (); - if (val2 == 0) - return (1); - if (val2 < 0) - evalerror (_("exponent less than 0")); - for (c = 1; val2--; c *= val1) - ; - val1 = c; - } - return (val1); -} - -static intmax_t -exp1 () -{ - register intmax_t val; - - if (curtok == NOT) - { - readtok (); - val = !exp1 (); - } - else if (curtok == BNOT) - { - readtok (); - val = ~exp1 (); - } - else - val = exp0 (); - - return (val); -} - -static intmax_t -exp0 () -{ - register intmax_t val = 0, v2; - char *vincdec; - int stok; - - /* XXX - might need additional logic here to decide whether or not - pre-increment or pre-decrement is legal at this point. */ - if (curtok == PREINC || curtok == PREDEC) - { - stok = lasttok = curtok; - readtok (); - if (curtok != STR) - /* readtok() catches this */ - evalerror (_("identifier expected after pre-increment or pre-decrement")); - - v2 = tokval + ((stok == PREINC) ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - expr_bind_variable (tokstr, vincdec); - free (vincdec); - val = v2; - - curtok = NUM; /* make sure --x=7 is flagged as an error */ - readtok (); - } - else if (curtok == MINUS) - { - readtok (); - val = - exp0 (); - } - else if (curtok == PLUS) - { - readtok (); - val = exp0 (); - } - else if (curtok == LPAR) - { - readtok (); - val = EXP_HIGHEST (); - - if (curtok != RPAR) /* ( */ - evalerror (_("missing `)'")); - - /* Skip over closing paren. */ - readtok (); - } - else if ((curtok == NUM) || (curtok == STR)) - { - val = tokval; - if (curtok == STR && (*tp == '+' || *tp == '-') && tp[1] == *tp && - (tp[2] == '\0' || (ISALNUM ((unsigned char)tp[2]) == 0))) - { - /* post-increment or post-decrement */ - v2 = val + ((*tp == '+') ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - expr_bind_variable (tokstr, vincdec); - free (vincdec); - tp += 2; - curtok = NUM; /* make sure x++=7 is flagged as an error */ - } - - readtok (); - } - else - evalerror (_("syntax error: operand expected")); - - return (val); -} - -static intmax_t -expr_streval (tok, e) - char *tok; - int e; -{ - SHELL_VAR *v; - char *value; - intmax_t tval; - - /* [[[[[ */ -#if defined (ARRAY_VARS) - v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok); -#else - v = find_variable (tok); -#endif - - if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) - { -#if defined (ARRAY_VARS) - value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok; -#else - value = tok; -#endif - - err_unboundvar (value); - -#if defined (ARRAY_VARS) - if (e == ']') - FREE (value); /* array_variable_name returns new memory */ -#endif - - if (interactive_shell) - { - expr_unwind (); - jump_to_top_level (DISCARD); - } - else - jump_to_top_level (FORCE_EOF); - } - -#if defined (ARRAY_VARS) - /* Second argument of 0 to get_array_value means that we don't allow - references like array[@]. In this case, get_array_value is just - like get_variable_value in that it does not return newly-allocated - memory or quote the results. */ - value = (e == ']') ? get_array_value (tok, 0, (int *)NULL) : get_variable_value (v); -#else - value = get_variable_value (v); -#endif - - tval = (value && *value) ? subexpr (value) : 0; - - return (tval); -} - -/* 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; - register unsigned char c, c1; - register int e; - - /* Skip leading whitespace. */ - cp = tp; - c = e = 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 (legal_variable_starter (c)) - { - /* variable names not preceded with a dollar sign are shell variables. */ - char *savecp; - EXPR_CONTEXT ec; - int peektok; - - while (legal_variable_char (c)) - c = *cp++; - - c = *--cp; - -#if defined (ARRAY_VARS) - if (c == '[') - { - e = skipsubscript (cp, 0); - if (cp[e] == ']') - { - cp += e + 1; - c = *cp; - e = ']'; - } - else - evalerror (bash_badsub_errmsg); - } -#endif /* ARRAY_VARS */ - - *cp = '\0'; - FREE (tokstr); - tokstr = savestring (tp); - *cp = c; - - SAVETOK (&ec); - tokstr = (char *)NULL; /* keep it from being freed */ - tp = savecp = cp; - noeval = 1; - readtok (); - peektok = curtok; - if (peektok == STR) /* free new tokstr before old one is restored */ - FREE (tokstr); - RESTORETOK (&ec); - cp = savecp; - - /* The tests for PREINC and PREDEC aren't strictly correct, but they - preserve old behavior if a construct like --x=9 is given. */ - if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) - tokval = expr_streval (tokstr, e); - else - tokval = 0; - - lasttok = curtok; - curtok = STR; - } - else if (DIGIT(c)) - { - while (ISALNUM (c) || c == '#' || 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 ((c == '*') && (c1 == '*')) - c = POWER; - else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) - c = PREDEC; - else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) - c = PREINC; - 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; - for (t = expression; whitespace (*t); t++) - ; - internal_error ("%s%s%s: %s (error token is \"%s\")", - name ? name : "", name ? ": " : "", t, - msg, (lasttp && *lasttp) ? lasttp : ""); - longjmp (evalbuf, 1); -} - -/* Convert a string to an intmax_t integer, with an arbitrary base. - 0nnn -> base 8 - 0[Xx]nn -> base 16 - Anything else: [base#]number (this is implemented to match ksh93) - - Base may be >=2 and <=64. If base is <= 36, the numbers are drawn - from [0-9][a-zA-Z], and lowercase and uppercase letters may be used - interchangably. If base is > 36 and <= 64, the numbers are drawn - from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 -- - you get the picture). */ - -static intmax_t -strlong (num) - char *num; -{ - register char *s; - register unsigned char c; - int base, foundbase; - intmax_t val; - - s = num; - - base = 10; - foundbase = 0; - if (*s == '0') - { - s++; - - if (*s == '\0') - return 0; - - /* Base 16? */ - if (*s == 'x' || *s == 'X') - { - base = 16; - s++; - } - else - base = 8; - foundbase++; - } - - val = 0; - for (c = *s++; c; c = *s++) - { - if (c == '#') - { - if (foundbase) - evalerror (_("invalid number")); - - /* Illegal base specifications raise an evaluation error. */ - if (val < 2 || val > 64) - evalerror (_("invalid arithmetic base")); - - base = val; - val = 0; - foundbase++; - } - else if (ISALNUM(c) || (c == '_') || (c == '@')) - { - if (DIGIT(c)) - c = TODIGIT(c); - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - ((base <= 36) ? 10 : 36); - else if (c == '@') - c = 62; - else if (c == '_') - c = 63; - - if (c >= base) - evalerror (_("value too great for base")); - - val = (val * base) + c; - } - else - break; - } - return (val); -} - -#if defined (EXPR_TEST) -void * -xmalloc (n) - int n; -{ - return (malloc (n)); -} - -void * -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; } - -procenv_t top_level; - -main (argc, argv) - int argc; - char **argv; -{ - register int i; - intmax_t v; - int expok; - - if (setjmp (top_level)) - exit (0); - - for (i = 1; i < argc; i++) - { - v = evalexp (argv[i], &expok); - if (expok == 0) - fprintf (stderr, "%s: expression error\n", argv[i]); - else - 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) - intmax_t n; -{ - return ("42"); -} - -#endif /* EXPR_TEST */ diff --git a/expr.c.save2 b/expr.c.save2 deleted file mode 100644 index 00896b718..000000000 --- a/expr.c.save2 +++ /dev/null @@ -1,1268 +0,0 @@ -/* expr.c -- arithmetic expression evaluation. */ - -/* Copyright (C) 1990-2003 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* - All arithmetic is done as intmax_t 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. - - "id++", "id--" [post-increment and post-decrement] - "++id", "--id" [pre-increment and pre-decrement] - "-", "+" [(unary operators)] - "!", "~" - "**" [(exponentiation)] - "*", "/", "%" - "+", "-" - "<<", ">>" - "<=", ">=", "<", ">" - "==", "!=" - "&" - "^" - "|" - "&&" - "||" - "expr ? expr : expr" - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" - , [comma] - - (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 "config.h" - -#include -#include "bashansi.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "chartypes.h" -#include "bashintl.h" - -#include "shell.h" - -/* Because of the $((...)) construct, expressions may include newlines. - Here is a macro which accepts newlines, tabs and spaces as whitespace. */ -#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) - -/* 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. */ -#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 COND 12 /* exp1 ? exp2 : exp3 */ -#define POWER 13 /* exp1**exp2 */ -#define PREINC 14 /* ++var */ -#define PREDEC 15 /* --var */ -#define POSTINC 16 /* var++ */ -#define POSTDEC 17 /* var-- */ -#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 '|' /* Bitwise OR. */ -#define BXOR '^' /* Bitwise eXclusive OR. */ -#define BNOT '~' /* Bitwise NOT; Two's complement. */ -#define QUES '?' -#define COL ':' -#define COMMA ',' - -/* This should be the function corresponding to the operator with the - highest precedence. */ -#define EXP_HIGHEST expcomma - -static char *expression; /* The current expression */ -static char *tp; /* token lexical position */ -static char *lasttp; /* pointer to last token position */ -static int curtok; /* the current token */ -static int lasttok; /* the previous token */ -static int assigntok; /* the OP in OP= */ -static char *tokstr; /* current token string */ -static intmax_t tokval; /* current token value */ -static int noeval; /* set to 1 if no assignment to be done */ -static procenv_t evalbuf; - -static void readtok __P((void)); /* lexical analyzer */ - -static intmax_t expr_streval __P((char *, int)); -static intmax_t strlong __P((char *)); -static void evalerror __P((char *)); - -static void pushexp __P((void)); -static void popexp __P((void)); -static void expr_unwind __P((void)); -static void expr_bind_variable __P((char *, char *)); - -static intmax_t subexpr __P((char *)); - -static intmax_t expcomma __P((void)); -static intmax_t expassign __P((void)); -static intmax_t expcond __P((void)); -static intmax_t explor __P((void)); -static intmax_t expland __P((void)); -static intmax_t expbor __P((void)); -static intmax_t expbxor __P((void)); -static intmax_t expband __P((void)); -static intmax_t exp5 __P((void)); -static intmax_t exp4 __P((void)); -static intmax_t expshift __P((void)); -static intmax_t exp3 __P((void)); -static intmax_t exp2 __P((void)); -static intmax_t exppower __P((void)); -static intmax_t exp1 __P((void)); -static intmax_t exp0 __P((void)); - -/* A structure defining a single expression context. */ -typedef struct { - int curtok, lasttok; - char *expression, *tp, *lasttp; - intmax_t tokval; - char *tokstr; - int noeval; -} EXPR_CONTEXT; - -#ifdef INCLUDE_UNUSED -/* Not used yet. */ -typedef struct { - char *tokstr; - intmax_t tokval; -} LVALUE; -#endif - -/* Global var which contains the stack of expression contexts. */ -static EXPR_CONTEXT **expr_stack; -static int expr_depth; /* Location in the stack. */ -static int expr_stack_size; /* Number of slots already allocated. */ - -extern char *this_command_name; -extern int unbound_vars_is_error; - -#if defined (ARRAY_VARS) -extern char *bash_badsub_errmsg; -#endif - -#define SAVETOK(X) \ - do { \ - (X)->curtok = curtok; \ - (X)->lasttok = lasttok; \ - (X)->tp = tp; \ - (X)->lasttp = lasttp; \ - (X)->tokval = tokval; \ - (X)->tokstr = tokstr; \ - (X)->noeval = noeval; \ - } while (0) - -#define RESTORETOK(X) \ - do { \ - curtok = (X)->curtok; \ - lasttok = (X)->lasttok; \ - tp = (X)->tp; \ - lasttp = (X)->lasttp; \ - tokval = (X)->tokval; \ - tokstr = (X)->tokstr; \ - noeval = (X)->noeval; \ - } while (0) - -/* Push and save away the contents of the globals describing the - current expression context. */ -static void -pushexp () -{ - EXPR_CONTEXT *context; - - if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) - evalerror (_("expression recursion level exceeded")); - - if (expr_depth >= expr_stack_size) - { - expr_stack_size += EXPR_STACK_GROW_SIZE; - expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); - } - - context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); - - context->expression = expression; - SAVETOK(context); - - 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]; - - expression = context->expression; - RESTORETOK (context); - - free (context); -} - -static void -expr_unwind () -{ - while (--expr_depth > 0) - { - if (expr_stack[expr_depth]->tokstr) - free (expr_stack[expr_depth]->tokstr); - - if (expr_stack[expr_depth]->expression) - free (expr_stack[expr_depth]->expression); - - free (expr_stack[expr_depth]); - } - free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ -} - -static void -expr_bind_variable (lhs, rhs) - char *lhs, *rhs; -{ - (void)bind_int_variable (lhs, rhs); - stupidly_hack_special_variables (lhs); -} - -/* Evaluate EXPR, and return the arithmetic result. If VALIDP is - non-null, a zero is stored into the location to which it points - if the expression is invalid, non-zero otherwise. If a non-zero - value is returned in *VALIDP, the return value of evalexp() may - be used. - - 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. */ -intmax_t -evalexp (expr, validp) - char *expr; - int *validp; -{ - intmax_t val; - int c; - procenv_t oevalbuf; - - val = 0; - - FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); - - c = setjmp (evalbuf); - - if (c) - { - FREE (tokstr); - FREE (expression); - tokstr = expression = (char *)NULL; - - expr_unwind (); - - if (validp) - *validp = 0; - return (0); - } - - val = subexpr (expr); - - if (validp) - *validp = 1; - - FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); - - return (val); -} - -static intmax_t -subexpr (expr) - char *expr; -{ - intmax_t val; - char *p; - - for (p = expr; p && *p && cr_whitespace (*p); p++) - ; - - if (p == NULL || *p == '\0') - return (0); - - pushexp (); - curtok = lasttok = 0; - expression = savestring (expr); - tp = expression; - - tokstr = (char *)NULL; - tokval = 0; - - readtok (); - - val = EXP_HIGHEST (); - - if (curtok != 0) - evalerror (_("syntax error in expression")); - - FREE (tokstr); - FREE (expression); - - popexp (); - - return val; -} - -static intmax_t -expcomma () -{ - register intmax_t value; - - value = expassign (); - while (curtok == COMMA) - { - readtok (); - value = expassign (); - } - - return value; -} - -static intmax_t -expassign () -{ - register intmax_t value; - char *lhs, *rhs; - - value = expcond (); - if (curtok == EQ || curtok == OP_ASSIGN) - { - int special, op; - intmax_t lvalue; - - special = curtok == OP_ASSIGN; - - if (lasttok != STR) - evalerror (_("attempted assignment 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: - if (value == 0) - evalerror (_("division by 0")); - lvalue /= value; - break; - case MOD: - if (value == 0) - evalerror (_("division by 0")); - 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; - case BXOR: - lvalue ^= value; - break; - default: - free (lhs); - evalerror (_("bug: bad expassign token")); - break; - } - value = lvalue; - } - - rhs = itos (value); - if (noeval == 0) - expr_bind_variable (lhs, rhs); - free (rhs); - free (lhs); - FREE (tokstr); - tokstr = (char *)NULL; /* For freeing on errors. */ - } - return (value); -} - -/* Conditional expression (expr?expr:expr) */ -static intmax_t -expcond () -{ - intmax_t cval, val1, val2, rval; - int set_noeval; - - set_noeval = 0; - rval = cval = explor (); - if (curtok == QUES) /* found conditional expr */ - { - readtok (); - if (curtok == 0 || curtok == COL) - evalerror (_("expression expected")); - if (cval == 0) - { - set_noeval = 1; - noeval++; - } - - val1 = EXP_HIGHEST (); - - if (set_noeval) - noeval--; - if (curtok != COL) - evalerror (_("`:' expected for conditional expression")); - readtok (); - if (curtok == 0) - evalerror (_("expression expected")); - set_noeval = 0; - if (cval) - { - set_noeval = 1; - noeval++; - } - val2 = explor (); - if (set_noeval) - noeval--; - rval = cval ? val1 : val2; - lasttok = COND; - } - return rval; -} - -/* Logical OR. */ -static intmax_t -explor () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expland (); - - while (curtok == LOR) - { - set_noeval = 0; - if (val1 != 0) - { - noeval++; - set_noeval = 1; - } - readtok (); - val2 = expland (); - if (set_noeval) - noeval--; - val1 = val1 || val2; - lasttok = LOR; - } - - return (val1); -} - -/* Logical AND. */ -static intmax_t -expland () -{ - register intmax_t val1, val2; - int set_noeval; - - val1 = expbor (); - - while (curtok == LAND) - { - set_noeval = 0; - if (val1 == 0) - { - set_noeval = 1; - noeval++; - } - readtok (); - val2 = expbor (); - if (set_noeval) - noeval--; - val1 = val1 && val2; - lasttok = LAND; - } - - return (val1); -} - -/* Bitwise OR. */ -static intmax_t -expbor () -{ - register intmax_t val1, val2; - - val1 = expbxor (); - - while (curtok == BOR) - { - readtok (); - val2 = expbxor (); - val1 = val1 | val2; - } - - return (val1); -} - -/* Bitwise XOR. */ -static intmax_t -expbxor () -{ - register intmax_t val1, val2; - - val1 = expband (); - - while (curtok == BXOR) - { - readtok (); - val2 = expband (); - val1 = val1 ^ val2; - } - - return (val1); -} - -/* Bitwise AND. */ -static intmax_t -expband () -{ - register intmax_t val1, val2; - - val1 = exp5 (); - - while (curtok == BAND) - { - readtok (); - val2 = exp5 (); - val1 = val1 & val2; - } - - return (val1); -} - -static intmax_t -exp5 () -{ - register intmax_t 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 intmax_t -exp4 () -{ - register intmax_t 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 /* (op == GT) */ - val1 = val1 > val2; - } - return (val1); -} - -/* Left and right shifts. */ -static intmax_t -expshift () -{ - register intmax_t 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 intmax_t -exp3 () -{ - register intmax_t 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 intmax_t -exp2 () -{ - register intmax_t val1, val2; - - val1 = exppower (); - - while ((curtok == MUL) || - (curtok == DIV) || - (curtok == MOD)) - { - int op = curtok; - - readtok (); - - val2 = exppower (); - - 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 intmax_t -exppower () -{ - register intmax_t val1, val2, c; - - val1 = exp1 (); - while (curtok == POWER) - { - readtok (); - val2 = exp1 (); - if (val2 == 0) - return (1); - if (val2 < 0) - evalerror (_("exponent less than 0")); - for (c = 1; val2--; c *= val1) - ; - val1 = c; - } - return (val1); -} - -static intmax_t -exp1 () -{ - register intmax_t val; - - if (curtok == NOT) - { - readtok (); - val = !exp1 (); - } - else if (curtok == BNOT) - { - readtok (); - val = ~exp1 (); - } - else - val = exp0 (); - - return (val); -} - -static intmax_t -exp0 () -{ - register intmax_t val = 0, v2; - char *vincdec; - int stok; - EXPR_CONTEXT ec; - - /* XXX - might need additional logic here to decide whether or not - pre-increment or pre-decrement is legal at this point. */ - if (curtok == PREINC || curtok == PREDEC) - { - stok = lasttok = curtok; - readtok (); - if (curtok != STR) - /* readtok() catches this */ - evalerror (_("identifier expected after pre-increment or pre-decrement")); - - v2 = tokval + ((stok == PREINC) ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - expr_bind_variable (tokstr, vincdec); - free (vincdec); - val = v2; - - curtok = NUM; /* make sure --x=7 is flagged as an error */ - readtok (); - } - else if (curtok == MINUS) - { - readtok (); - val = - exp0 (); - } - else if (curtok == PLUS) - { - readtok (); - val = exp0 (); - } - else if (curtok == LPAR) - { - readtok (); - val = EXP_HIGHEST (); - - if (curtok != RPAR) /* ( */ - evalerror (_("missing `)'")); - - /* Skip over closing paren. */ - readtok (); - } - else if ((curtok == NUM) || (curtok == STR)) - { - val = tokval; - if (curtok == STR) - { - SAVETOK (&ec); - tokstr = (char *)NULL; /* keep it from being freed */ - noeval = 1; - readtok (); - stok = curtok; - - /* post-increment or post-decrement */ - if (stok == POSTINC || stok == POSTDEC) - { - /* restore certain portions of EC */ - tokstr = ec.tokstr; - noeval = ec.noeval; - lasttok = STR; /* ec.curtok */ - - v2 = val + ((stok == POSTINC) ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - expr_bind_variable (tokstr, vincdec); - free (vincdec); - curtok = NUM; /* make sure x++=7 is flagged as an error */ - } - else - { - if (stok == STR) /* free new tokstr before old one is restored */ - FREE (tokstr); - RESTORETOK (&ec); - } - - } - - readtok (); - } - else - evalerror (_("syntax error: operand expected")); - - return (val); -} - -static intmax_t -expr_streval (tok, e) - char *tok; - int e; -{ - SHELL_VAR *v; - char *value; - intmax_t tval; - - /* [[[[[ */ -#if defined (ARRAY_VARS) - v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok); -#else - v = find_variable (tok); -#endif - - if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) - { -#if defined (ARRAY_VARS) - value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok; -#else - value = tok; -#endif - - err_unboundvar (value); - -#if defined (ARRAY_VARS) - if (e == ']') - FREE (value); /* array_variable_name returns new memory */ -#endif - - if (interactive_shell) - { - expr_unwind (); - jump_to_top_level (DISCARD); - } - else - jump_to_top_level (FORCE_EOF); - } - -#if defined (ARRAY_VARS) - /* Second argument of 0 to get_array_value means that we don't allow - references like array[@]. In this case, get_array_value is just - like get_variable_value in that it does not return newly-allocated - memory or quote the results. */ - value = (e == ']') ? get_array_value (tok, 0, (int *)NULL) : get_variable_value (v); -#else - value = get_variable_value (v); -#endif - - tval = (value && *value) ? subexpr (value) : 0; - - return (tval); -} - -/* 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; - register unsigned char c, c1; - register int e; - - /* Skip leading whitespace. */ - cp = tp; - c = e = 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 (legal_variable_starter (c)) - { - /* variable names not preceded with a dollar sign are shell variables. */ - char *savecp; - EXPR_CONTEXT ec; - int peektok; - - while (legal_variable_char (c)) - c = *cp++; - - c = *--cp; - -#if defined (ARRAY_VARS) - if (c == '[') - { - e = skipsubscript (cp, 0); - if (cp[e] == ']') - { - cp += e + 1; - c = *cp; - e = ']'; - } - else - evalerror (bash_badsub_errmsg); - } -#endif /* ARRAY_VARS */ - - *cp = '\0'; - FREE (tokstr); - tokstr = savestring (tp); - *cp = c; - - SAVETOK (&ec); - tokstr = (char *)NULL; /* keep it from being freed */ - tp = savecp = cp; - noeval = 1; - curtok = STR; - readtok (); - peektok = curtok; - if (peektok == STR) /* free new tokstr before old one is restored */ - FREE (tokstr); - RESTORETOK (&ec); - cp = savecp; - - /* The tests for PREINC and PREDEC aren't strictly correct, but they - preserve old behavior if a construct like --x=9 is given. */ - if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) - tokval = expr_streval (tokstr, e); - else - tokval = 0; - - lasttok = curtok; - curtok = STR; - } - else if (DIGIT(c)) - { - while (ISALNUM (c) || c == '#' || 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 ((c == '*') && (c1 == '*')) - c = POWER; - else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) - c = PREDEC; - else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) - c = PREINC; - else if ((c == '-') && (c1 == '-') && (curtok == STR)) - c = POSTDEC; - else if ((c == '+') && (c1 == '+') && (curtok == STR)) - c = POSTINC; - 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; - for (t = expression; whitespace (*t); t++) - ; - internal_error ("%s%s%s: %s (error token is \"%s\")", - name ? name : "", name ? ": " : "", t, - msg, (lasttp && *lasttp) ? lasttp : ""); - longjmp (evalbuf, 1); -} - -/* Convert a string to an intmax_t integer, with an arbitrary base. - 0nnn -> base 8 - 0[Xx]nn -> base 16 - Anything else: [base#]number (this is implemented to match ksh93) - - Base may be >=2 and <=64. If base is <= 36, the numbers are drawn - from [0-9][a-zA-Z], and lowercase and uppercase letters may be used - interchangably. If base is > 36 and <= 64, the numbers are drawn - from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 -- - you get the picture). */ - -static intmax_t -strlong (num) - char *num; -{ - register char *s; - register unsigned char c; - int base, foundbase; - intmax_t val; - - s = num; - - base = 10; - foundbase = 0; - if (*s == '0') - { - s++; - - if (*s == '\0') - return 0; - - /* Base 16? */ - if (*s == 'x' || *s == 'X') - { - base = 16; - s++; - } - else - base = 8; - foundbase++; - } - - val = 0; - for (c = *s++; c; c = *s++) - { - if (c == '#') - { - if (foundbase) - evalerror (_("invalid number")); - - /* Illegal base specifications raise an evaluation error. */ - if (val < 2 || val > 64) - evalerror (_("invalid arithmetic base")); - - base = val; - val = 0; - foundbase++; - } - else if (ISALNUM(c) || (c == '_') || (c == '@')) - { - if (DIGIT(c)) - c = TODIGIT(c); - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - ((base <= 36) ? 10 : 36); - else if (c == '@') - c = 62; - else if (c == '_') - c = 63; - - if (c >= base) - evalerror (_("value too great for base")); - - val = (val * base) + c; - } - else - break; - } - return (val); -} - -#if defined (EXPR_TEST) -void * -xmalloc (n) - int n; -{ - return (malloc (n)); -} - -void * -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; } - -procenv_t top_level; - -main (argc, argv) - int argc; - char **argv; -{ - register int i; - intmax_t v; - int expok; - - if (setjmp (top_level)) - exit (0); - - for (i = 1; i < argc; i++) - { - v = evalexp (argv[i], &expok); - if (expok == 0) - fprintf (stderr, "%s: expression error\n", argv[i]); - else - 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) - intmax_t n; -{ - return ("42"); -} - -#endif /* EXPR_TEST */ diff --git a/externs.h~ b/externs.h~ deleted file mode 100644 index a015d782e..000000000 --- a/externs.h~ +++ /dev/null @@ -1,375 +0,0 @@ -/* externs.h -- extern function declarations which do not appear in their - own header file. */ - -/* Copyright (C) 1993-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* Make sure that this is included *after* config.h! */ - -#if !defined (_EXTERNS_H_) -# define _EXTERNS_H_ - -#include "stdc.h" - -/* Functions from expr.c. */ -extern intmax_t evalexp __P((char *, int *)); - -/* Functions from print_cmd.c. */ -extern char *make_command_string __P((COMMAND *)); -extern char *named_function_string __P((char *, COMMAND *, int)); - -extern void print_command __P((COMMAND *)); -extern void print_simple_command __P((SIMPLE_COM *)); -extern void print_word_list __P((WORD_LIST *, char *)); - -/* debugger support */ -extern void print_for_command_head __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -extern void print_select_command_head __P((SELECT_COM *)); -#endif -extern void print_case_command_head __P((CASE_COM *)); -#if defined (DPAREN_ARITHMETIC) -extern void print_arith_command __P((WORD_LIST *)); -#endif -#if defined (COND_COMMAND) -extern void print_cond_command __P((COND_COM *)); -#endif - -/* set -x support */ -extern char *indirection_level_string __P((void)); -extern void xtrace_print_assignment __P((char *, char *, int, int)); -extern void xtrace_print_word_list __P((WORD_LIST *, int)); -extern void xtrace_print_for_command_head __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -extern void xtrace_print_select_command_head __P((SELECT_COM *)); -#endif -extern void xtrace_print_case_command_head __P((CASE_COM *)); -#if defined (DPAREN_ARITHMETIC) -extern void xtrace_print_arith_cmd __P((WORD_LIST *)); -#endif -#if defined (COND_COMMAND) -extern void xtrace_print_cond_term __P((int, int, WORD_DESC *, char *, char *)); -#endif - -/* Functions from shell.c. */ -extern void exit_shell __P((int)) __attribute__((__noreturn__)); -extern void sh_exit __P((int)) __attribute__((__noreturn__)); -extern void disable_priv_mode __P((void)); -extern void unbind_args __P((void)); - -#if defined (RESTRICTED_SHELL) -extern int shell_is_restricted __P((char *)); -extern int maybe_make_restricted __P((char *)); -#endif - -extern void unset_bash_input __P((int)); -extern void get_current_user_info __P((void)); - -/* Functions from eval.c. */ -extern int reader_loop __P((void)); -extern int parse_command __P((void)); -extern int read_command __P((void)); - -/* Functions from braces.c. */ -#if defined (BRACE_EXPANSION) -extern char **brace_expand __P((char *)); -#endif - -/* Miscellaneous functions from parse.y */ -extern int yyparse __P((void)); -extern int return_EOF __P((void)); -extern void reset_parser __P((void)); -extern WORD_LIST *parse_string_to_word_list __P((char *, int, const char *)); - -extern void free_pushed_string_input __P((void)); - -extern char *decode_prompt_string __P((char *)); - -extern int get_current_prompt_level __P((void)); -extern void set_current_prompt_level __P((int)); - -#if defined (HISTORY) -extern char *history_delimiting_chars __P((void)); -#endif - -/* Declarations for functions defined in locale.c */ -extern void set_default_locale __P((void)); -extern void set_default_locale_vars __P((void)); -extern int set_locale_var __P((char *, char *)); -extern int set_lang __P((char *, char *)); -extern char *get_locale_var __P((char *)); -extern char *localetrans __P((char *, int, int *)); -extern char *mk_msgstr __P((char *, int *)); -extern char *localeexpand __P((char *, int, int, int, int *)); - -/* Declarations for functions defined in list.c. */ -extern void list_walk __P((GENERIC_LIST *, sh_glist_func_t *)); -extern void wlist_walk __P((WORD_LIST *, sh_icpfunc_t *)); -extern GENERIC_LIST *list_reverse (); -extern int list_length (); -extern GENERIC_LIST *list_append (); -extern GENERIC_LIST *list_remove (); - -/* Declarations for functions defined in stringlib.c */ -extern int find_string_in_alist __P((char *, STRING_INT_ALIST *, int)); -extern char *find_token_in_alist __P((int, STRING_INT_ALIST *, int)); -extern int find_index_in_alist __P((char *, STRING_INT_ALIST *, int)); - -extern char *substring __P((char *, int, int)); -extern char *strsub __P((char *, char *, char *, int)); -extern char *strcreplace __P((char *, int, char *, int)); -extern void strip_leading __P((char *)); -extern void strip_trailing __P((char *, int, int)); -extern void xbcopy __P((char *, char *, int)); - -/* Functions from version.c. */ -extern char *shell_version_string __P((void)); -extern void show_shell_version __P((int)); - -/* Functions from the bash library, lib/sh/libsh.a. These should really - go into a separate include file. */ - -/* declarations for functions defined in lib/sh/clktck.c */ -extern long get_clk_tck __P((void)); - -/* declarations for functions defined in lib/sh/clock.c */ -extern void clock_t_to_secs (); -extern void print_clock_t (); - -/* Declarations for functions defined in lib/sh/fmtulong.c */ -#define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */ -#define FL_ADDBASE 0x02 /* add base# prefix to converted value */ -#define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */ -#define FL_UNSIGNED 0x08 /* don't add any sign */ - -extern char *fmtulong __P((unsigned long int, int, char *, size_t, int)); - -/* Declarations for functions defined in lib/sh/fmtulong.c */ -#if defined (HAVE_LONG_LONG) -extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); -#endif - -/* Declarations for functions defined in lib/sh/fmtumax.c */ -extern char *fmtumax __P((uintmax_t, int, char *, size_t, int)); - -/* Declarations for functions defined in lib/sh/getcwd.c */ -#if !defined (HAVE_GETCWD) -extern char *getcwd __P((char *, size_t)); -#endif - -/* Declarations for functions defined in lib/sh/itos.c */ -extern char *inttostr __P((intmax_t, char *, size_t)); -extern char *itos __P((intmax_t)); -extern char *uinttostr __P((uintmax_t, char *, size_t)); -extern char *uitos __P((uintmax_t)); - -/* declarations for functions defined in lib/sh/makepath.c */ -#define MP_DOTILDE 0x01 -#define MP_DOCWD 0x02 -#define MP_RMDOT 0x04 - -extern char *sh_makepath __P((const char *, const char *, int)); - -/* declarations for functions defined in lib/sh/netconn.c */ -extern int isnetconn __P((int)); - -/* declarations for functions defined in lib/sh/netopen.c */ -extern int netopen __P((char *)); - -/* Declarations for functions defined in lib/sh/oslib.c */ - -#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) -extern int dup2 __P((int, int)); -#endif - -#if !defined (HAVE_GETDTABLESIZE) -extern int getdtablesize __P((void)); -#endif /* !HAVE_GETDTABLESIZE */ - -#if !defined (HAVE_GETHOSTNAME) -extern int gethostname __P((char *, int)); -#endif /* !HAVE_GETHOSTNAME */ - -extern int getmaxgroups __P((void)); -extern long getmaxchild __P((void)); - -/* declarations for functions defined in lib/sh/pathcanon.c */ -#define PATH_CHECKDOTDOT 0x0001 -#define PATH_CHECKEXISTS 0x0002 -#define PATH_HARDPATH 0x0004 -#define PATH_NOALLOC 0x0008 - -extern char *sh_canonpath __P((char *, int)); - -/* declarations for functions defined in lib/sh/pathphys.c */ -extern char *sh_physpath __P((char *, int)); -extern char *sh_realpath __P((const char *, char *)); - -/* declarations for functions defined in lib/sh/setlinebuf.c */ -#ifdef NEED_SH_SETLINEBUF_DECL -extern int sh_setlinebuf __P((FILE *)); -#endif - -/* declarations for functions defined in lib/sh/shmatch.c */ -extern int sh_regmatch __P((const char *, const char *, int)); - -/* defines for flags argument to sh_regmatch. */ -#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */ -#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */ - -/* declarations for functions defined in lib/sh/shquote.c */ -extern char *sh_single_quote __P((char *)); -extern char *sh_double_quote __P((char *)); -extern char *sh_un_double_quote __P((char *)); -extern char *sh_backslash_quote __P((char *)); -extern char *sh_backslash_quote_for_double_quotes __P((char *)); -extern int sh_contains_shell_metas __P((char *)); - -/* declarations for functions defined in lib/sh/spell.c */ -extern int spname __P((char *, char *)); - -/* declarations for functions defined in lib/sh/strcasecmp.c */ -#if !defined (HAVE_STRCASECMP) -extern int strncasecmp __P((const char *, const char *, int)); -extern int strcasecmp __P((const char *, const char *)); -#endif /* HAVE_STRCASECMP */ - -/* declarations for functions defined in lib/sh/strerror.c */ -#if !defined (strerror) -extern char *strerror __P((int)); -#endif - -/* declarations for functions defined in lib/sh/strftime.c */ -#if !defined (HAVE_STRFTIME) && defined (NEED_STRFTIME_DECL) -extern size_t strftime __P((char *, size_t, const char *, const struct tm *)); -#endif - -/* declarations for functions defined in lib/sh/strindex.c */ -extern char *strindex __P((const char *, const char *)); - -/* declarations for functions and structures defined in lib/sh/stringlist.c */ - -/* This is a general-purpose argv-style array struct. */ -typedef struct _list_of_strings { - char **list; - int list_size; - int list_len; -} STRINGLIST; - -typedef int sh_strlist_map_func_t __P((char *)); - -extern STRINGLIST *strlist_create __P((int)); -extern STRINGLIST *strlist_resize __P((STRINGLIST *, int)); -extern void strlist_flush __P((STRINGLIST *)); -extern void strlist_dispose __P((STRINGLIST *)); -extern int strlist_remove __P((STRINGLIST *, char *)); -extern STRINGLIST *strlist_copy __P((STRINGLIST *)); -extern STRINGLIST *strlist_merge __P((STRINGLIST *, STRINGLIST *)); -extern STRINGLIST *strlist_append __P((STRINGLIST *, STRINGLIST *)); -extern STRINGLIST *strlist_prefix_suffix __P((STRINGLIST *, char *, char *)); -extern void strlist_print __P((STRINGLIST *, char *)); -extern void strlist_walk __P((STRINGLIST *, sh_strlist_map_func_t *)); -extern void strlist_sort __P((STRINGLIST *)); - -/* declarations for functions defined in lib/sh/stringvec.c */ - -extern char **strvec_create __P((int)); -extern char **strvec_resize __P((char **, int)); -extern void strvec_flush __P((char **)); -extern void strvec_dispose __P((char **)); -extern int strvec_remove __P((char **, char *)); -extern int strvec_len __P((char **)); -extern int strvec_search __P((char **, char *)); -extern char **strvec_copy __P((char **)); -extern int strvec_strcmp __P((char **, char **)); -extern void strvec_sort __P((char **)); - -extern char **strvec_from_word_list __P((WORD_LIST *, int, int, int *)); -extern WORD_LIST *strvec_to_word_list __P((char **, int, int)); - -/* declarations for functions defined in lib/sh/strtod.c */ -#if !defined (HAVE_STRTOD) -extern double strtod __P((const char *, char **)); -#endif - -/* declarations for functions defined in lib/sh/strtol.c */ -#if !HAVE_DECL_STRTOL -extern long strtol __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoll.c */ -#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOLL -extern long long strtoll __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoul.c */ -#if !HAVE_DECL_STRTOUL -extern unsigned long strtoul __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoull.c */ -#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOULL -extern unsigned long long strtoull __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strimax.c */ -#if !HAVE_DECL_STRTOIMAX -extern intmax_t strtoimax __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strumax.c */ -#if !HAVE_DECL_STRTOUMAX -extern uintmax_t strtoumax __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtrans.c */ -extern char *ansicstr __P((char *, int, int, int *, int *)); -extern char *ansic_quote __P((char *, int, int *)); -extern int ansic_shouldquote __P((const char *)); -extern char *ansiexpand __P((char *, int, int, int *)); - -/* declarations for functions defined in lib/sh/timeval.c. No prototypes - so we don't have to count on having a definition of struct timeval in - scope when this file is included. */ -extern void timeval_to_secs (); -extern void print_timeval (); - -/* declarations for functions defined in lib/sh/tmpfile.c */ -#define MT_USETMPDIR 0x0001 -#define MT_READWRITE 0x0002 -#define MT_USERANDOM 0x0004 - -extern char *sh_mktmpname __P((char *, int)); -extern int sh_mktmpfd __P((char *, int, char **)); -/* extern FILE *sh_mktmpfp __P((char *, int, char **)); */ - -/* declarations for functions defined in lib/sh/xstrchr.c */ -#undef xstrchr -extern char *xstrchr __P((const char *, int)); - -/* declarations for functions defined in lib/sh/zread.c */ -extern ssize_t zread __P((int, char *, size_t)); -extern ssize_t zreadintr __P((int, char *, size_t)); -extern ssize_t zreadc __P((int, char *)); -extern void zreset __P((void)); -extern void zsyncfd __P((int)); - -/* declarations for functions defined in lib/sh/zwrite.c */ -extern int zwrite __P((int, char *, size_t)); - -#endif /* _EXTERNS_H_ */ diff --git a/flags.c~ b/flags.c~ deleted file mode 100644 index 77d991926..000000000 --- a/flags.c~ +++ /dev/null @@ -1,355 +0,0 @@ -/* 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 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* Flags hacking. */ -#include "config.h" -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "shell.h" -#include "flags.h" - -#if defined (BANG_HISTORY) -# include "bashhist.h" -#endif - -#if defined (JOB_CONTROL) -extern int set_job_control __P((int)); -#endif - -#if defined (RESTRICTED_SHELL) -extern char *shell_name; -#endif - -extern int shell_intialized; - -/* -c, -s invocation options -- not really flags, but they show up in $- */ -extern int want_pending_command, read_from_stdin; - -/* **************************************************************** */ -/* */ -/* 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 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 them. This is useful - for debugging shell scripts that should do something hairy and possibly - destructive. */ -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. */ -/* */ -/* **************************************************************** */ - -#if 0 -/* Non-zero means do lexical scoping in the body of a FOR command. */ -int lexical_scoping = 0; -#endif - -/* Non-zero means no such thing as invisible variables. */ -int no_invisible_vars = 0; - -/* Non-zero means look up and remember command names in a hash table, */ -int hashing_enabled = 1; - -#if defined (BANG_HISTORY) -/* Non-zero means that we are doing history expansion. The default. - 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. */ -int interactive_comments = 1; - -#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; /* currently restricted */ -int restricted_shell = 0; /* shell was started in restricted mode. */ -#endif /* RESTRICTED_SHELL */ - -/* Non-zero means that this shell is running in `privileged' mode. This - is required if the shell is to run setuid. If the `-p' option is - not supplied at startup, and the real and effective uids or gids - differ, disable_priv_mode is called to relinquish setuid status. */ -int privileged_mode = 0; - -#if defined (BRACE_EXPANSION) -/* Zero means to disable brace expansion: foo{a,b} -> fooa foob */ -int brace_expansion = 1; -#endif - -/* Non-zero means that shell functions inherit the DEBUG trap. */ -int function_trace_mode = 0; - -/* Non-zero means that shell functions inherit the ERR trap. */ -int error_trace_mode = 0; - -/* Non-zero means that the rightmost non-zero exit status in a pipeline - is the exit status of the entire pipeline. If each processes exits - with a 0 status, the status of the pipeline is 0. */ -int pipefail_opt = 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', &hashing_enabled }, - { '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 }, - - /* New flags that control non-standard things. */ -#if 0 - { 'l', &lexical_scoping }, -#endif -#if defined (BRACE_EXPANSION) - { 'B', &brace_expansion }, -#endif - { 'C', &noclobber }, - { 'E', &error_trace_mode }, -#if defined (BANG_HISTORY) - { 'H', &history_expansion }, -#endif /* BANG_HISTORY */ - { 'I', &no_invisible_vars }, - { 'P', &no_symbolic_links }, - { 'T', &function_trace_mode }, - {0, (int *)NULL} -}; - -#define NUM_SHELL_FLAGS (sizeof (shell_flags) / sizeof (struct flags_alist)) - -char optflags[NUM_SHELL_FLAGS+4] = { '+' }; - -int * -find_flag (name) - int name; -{ - int i; - for (i = 0; shell_flags[i].name; i++) - { - if (shell_flags[i].name == name) - return (shell_flags[i].value); - } - return (FLAG_UNKNOWN); -} - -/* Change the state of a flag, and return it's original value, or return - FLAG_ERROR if there is no flag FLAG. ON_OR_OFF must be either - FLAG_ON or FLAG_OFF. */ -int -change_flag (flag, on_or_off) - int flag; - int on_or_off; -{ - int *value, 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 */ - - value = find_flag (flag); - - if ((value == (int *)FLAG_UNKNOWN) || (on_or_off != FLAG_ON && on_or_off != FLAG_OFF)) - return (FLAG_ERROR); - - old_value = *value; - - *value = (on_or_off == FLAG_ON) ? 1 : 0; - - /* Special cases for a few flags. */ - switch (flag) - { -#if defined (BANG_HISTORY) - case 'H': - if (on_or_off == FLAG_ON) - bash_initialize_history (); - break; -#endif - -#if defined (JOB_CONTROL) - case 'm': - set_job_control (on_or_off == FLAG_ON); - break; -#endif /* JOB_CONTROL */ - - case 'n': - if (interactive_shell) - read_but_dont_execute = 0; - break; - - case 'p': - if (on_or_off == FLAG_OFF) - disable_priv_mode (); - break; - -#if defined (RESTRICTED_SHELL) - case 'r': - if (on_or_off == FLAG_ON && shell_initialized) - maybe_make_restricted (shell_name); - break; -#endif - - } - - return (old_value); -} - -/* Return a string which is the names of all the currently - set shell flags. */ -char * -which_set_flags () -{ - char *temp; - int i, string_index; - - temp = (char *)xmalloc (1 + NUM_SHELL_FLAGS + read_from_stdin + want_pending_command); - for (i = string_index = 0; shell_flags[i].name; i++) - if (*(shell_flags[i].value)) - temp[string_index++] = shell_flags[i].name; - - if (want_pending_command) - temp[string_index++] = 'c'; - if (read_from_stdin) - temp[string_index++] = 's'; - - temp[string_index] = '\0'; - return (temp); -} - -void -reset_shell_flags () -{ - mark_modified_vars = exit_immediately_on_error = disallow_filename_globbing = 0; - place_keywords_in_env = read_but_dont_execute = just_one_command = 0; - noclobber = unbound_vars_is_error = echo_input_at_read = 0; - echo_command_at_execute = jobs_m_flag = forced_interactive = 0; - no_symbolic_links = no_invisible_vars = privileged_mode = pipefail_opt = 0; - - hashing_enabled = interactive_comments = 1; - -#if defined (JOB_CONTROL) - asynchronous_notification = 0; -#endif - -#if defined (BANG_HISTORY) - history_expansion = 1; -#endif - -#if defined (BRACE_EXPANSION) - brace_expansion = 1; -#endif - -#if defined (RESTRICTED_SHELL) - restricted = 0; -#endif -} - -void -initialize_flags () -{ - register int i; - - for (i = 0; shell_flags[i].name; i++) - optflags[i+1] = shell_flags[i].name; - optflags[++i] = 'o'; - optflags[++i] = ';'; - optflags[i+1] = '\0'; -} diff --git a/general.c~ b/general.c~ deleted file mode 100644 index 74c00f74d..000000000 --- a/general.c~ +++ /dev/null @@ -1,958 +0,0 @@ -/* general.c -- Stuff that is used by all files. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#ifndef _MINIX -# include -#endif -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "filecntl.h" -#include "bashansi.h" -#include -#include "chartypes.h" -#include - -#include "bashintl.h" - -#include "shell.h" -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int expand_aliases; -extern int interrupt_immediately; -extern int interactive_comments; -extern int check_hashed_filenames; -extern int source_uses_path; -extern int source_searches_cwd; - -static char *bash_special_tilde_expansions __P((char *)); -static int unquoted_tilde_word __P((const char *)); -static void initialize_group_array __P((void)); - -/* A standard error message to use when getcwd() returns NULL. */ -char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories"); - -/* Do whatever is necessary to initialize `Posix mode'. */ -void -posix_initialize (on) - int on; -{ - /* Things that should be turned on when posix mode is enabled. */ - if (on != 0) - { - interactive_comments = source_uses_path = expand_aliases = 1; - } - - /* Things that should be turned on when posix mode is disabled. */ - if (on == 0) - { - source_searches_cwd = 1; - expand_aliases = interactive_shell; - } -} - -/* **************************************************************** */ -/* */ -/* Functions to convert to and from and display non-standard types */ -/* */ -/* **************************************************************** */ - -#if defined (RLIMTYPE) -RLIMTYPE -string_to_rlimtype (s) - char *s; -{ - RLIMTYPE ret; - int neg; - - ret = 0; - neg = 0; - while (s && *s && whitespace (*s)) - s++; - if (*s == '-' || *s == '+') - { - neg = *s == '-'; - s++; - } - for ( ; s && *s && DIGIT (*s); s++) - ret = (ret * 10) + TODIGIT (*s); - return (neg ? -ret : ret); -} - -void -print_rlimtype (n, addnl) - RLIMTYPE n; - int addnl; -{ - char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p; - - p = s + sizeof(s); - *--p = '\0'; - - if (n < 0) - { - do - *--p = '0' - n % 10; - while ((n /= 10) != 0); - - *--p = '-'; - } - else - { - do - *--p = '0' + n % 10; - while ((n /= 10) != 0); - } - - printf ("%s%s", p, addnl ? "\n" : ""); -} -#endif /* RLIMTYPE */ - -/* **************************************************************** */ -/* */ -/* Input Validation Functions */ -/* */ -/* **************************************************************** */ - -/* Return non-zero if all of the characters in STRING are digits. */ -int -all_digits (string) - char *string; -{ - register char *s; - - for (s = string; *s; s++) - if (DIGIT (*s) == 0) - return (0); - - return (1); -} - -/* Return non-zero if the characters pointed to by STRING constitute a - valid number. Stuff the converted number into RESULT if RESULT is - not null. */ -int -legal_number (string, result) - char *string; - intmax_t *result; -{ - intmax_t value; - char *ep; - - if (result) - *result = 0; - - errno = 0; - value = strtoimax (string, &ep, 10); - if (errno) - return 0; /* errno is set on overflow or underflow */ - - /* Skip any trailing whitespace, since strtoimax does not. */ - while (whitespace (*ep)) - ep++; - - /* If *string is not '\0' but *ep is '\0' on return, the entire string - is valid. */ - if (string && *string && *ep == '\0') - { - if (result) - *result = value; - /* The SunOS4 implementation of strtol() will happily ignore - overflow conditions, so this cannot do overflow correctly - on those systems. */ - return 1; - } - - return (0); -} - -/* 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; - unsigned char c; - - if (!name || !(c = *name) || (legal_variable_starter (c) == 0)) - return (0); - - for (s = name + 1; (c = *s) != 0; s++) - { - if (legal_variable_char (c) == 0) - 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. */ -int -check_identifier (word, check_word) - WORD_DESC *word; - int check_word; -{ - if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word)) - { - internal_error (_("`%s': not a valid identifier"), word->word); - return (0); - } - else if (check_word && legal_identifier (word->word) == 0) - { - internal_error (_("`%s': not a valid identifier"), word->word); - return (0); - } - else - return (1); -} - -/* Return 1 if STRING comprises a valid alias name. The shell accepts - essentially all characters except those which must be quoted to the - parser (which disqualifies them from alias expansion anyway) and `/'. */ -int -legal_alias_name (string, flags) - char *string; - int flags; -{ - register char *s; - - for (s = string; *s; s++) - if (shellbreak (*s) || shellquote (*s) || shellexp (*s) || (*s == '/')) - return 0; - return 1; -} - -/* Returns non-zero if STRING is an assignment statement. The returned value - is the index of the `=' sign. */ -int -assignment (string, flags) - const char *string; - int flags; -{ - register unsigned char c; - register int newi, indx; - - c = string[indx = 0]; - -#if defined (ARRAY_VARS) - if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */ -#else - if (legal_variable_starter (c) == 0) -#endif - 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 defined (ARRAY_VARS) - if (c == '[') - { - newi = skipsubscript (string, indx); - if (string[newi++] != ']') - return (0); - return ((string[newi] == '=') ? newi : 0); - } -#endif /* ARRAY_VARS */ - - /* Variable names in assignment statements may contain only letters, - digits, and `_'. */ - if (legal_variable_char (c) == 0) - return (0); - - indx++; - } - return (0); -} - -/* **************************************************************** */ -/* */ -/* Functions to manage files and file descriptors */ -/* */ -/* **************************************************************** */ - -/* A function to unset no-delay mode on a file descriptor. Used in shell.c - to unset it on the fd passed as stdin. Should be called on stdin if - readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */ - -#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. */ -int -sh_unset_nodelay_mode (fd) - int fd; -{ - int flags, bflags; - - if ((flags = fcntl (fd, F_GETFL, 0)) < 0) - return -1; - - bflags = 0; - - /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present - and O_NDELAY is defined. */ -#ifdef O_NONBLOCK - bflags |= O_NONBLOCK; -#endif - -#ifdef O_NDELAY - bflags |= O_NDELAY; -#endif - - if (flags & bflags) - { - flags &= ~bflags; - return (fcntl (fd, F_SETFL, flags)); - } - - return 0; -} - -/* Return 1 if file descriptor FD is valid; 0 otherwise. */ -int -sh_validfd (fd) - int fd; -{ - return (fcntl (fd, F_GETFD, 0) >= 0); -} - -/* There is a bug in the NeXT 2.1 rlogind that causes opens - of /dev/tty to fail. */ - -#if defined (__BEOS__) -/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it - into a no-op. This should probably go away in the future. */ -# undef O_NONBLOCK -# define O_NONBLOCK 0 -#endif /* __BEOS__ */ - -void -check_dev_tty () -{ - int tty_fd; - char *tty; - - tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK); - - if (tty_fd < 0) - { - tty = (char *)ttyname (fileno (stdin)); - if (tty == 0) - return; - tty_fd = open (tty, O_RDWR|O_NONBLOCK); - } - close (tty_fd); -} - -/* 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)); -} - -/* Move FD to a number close to the maximum number of file descriptors - allowed in the shell process, to avoid the user stepping on it with - redirection and causing us extra work. If CHECK_NEW is non-zero, - we check whether or not the file descriptors are in use before - duplicating FD onto them. MAXFD says where to start checking the - file descriptors. If it's less than 20, we get the maximum value - available from getdtablesize(2). */ -int -move_to_high_fd (fd, check_new, maxfd) - int fd, check_new, maxfd; -{ - int script_fd, nfds, ignore; - - if (maxfd < 20) - { - nfds = getdtablesize (); - if (nfds <= 0) - nfds = 20; - if (nfds > HIGH_FD_MAX) - nfds = HIGH_FD_MAX; /* reasonable maximum */ - } - else - nfds = maxfd; - - for (nfds--; check_new && nfds > 3; nfds--) - if (fcntl (nfds, F_GETFD, &ignore) == -1) - break; - - if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1) - { - if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */ - close (fd); - return (script_fd); - } - - /* OK, we didn't find one less than our artificial maximum; return the - original file descriptor. */ - return (fd); -} - -/* Return non-zero if the characters from SAMPLE are not all valid - characters to be found in the first line of a shell script. We - check up to the first newline, or SAMPLE_LEN, whichever comes first. - All of the characters must be printable or whitespace. */ - -int -check_binary_file (sample, sample_len) - char *sample; - int sample_len; -{ - register int i; - unsigned char c; - - for (i = 0; i < sample_len; i++) - { - c = sample[i]; - if (c == '\n') - return (0); - - if (ISSPACE (c) == 0 && ISPRINT (c) == 0) - return (1); - } - - return (0); -} - -/* **************************************************************** */ -/* */ -/* Functions to inspect pathnames */ -/* */ -/* **************************************************************** */ - -int -file_isdir (fn) - char *fn; -{ - struct stat sb; - - return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode)); -} - -int -file_iswdir (fn) - char *fn; -{ - return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0); -} - - -/* **************************************************************** */ -/* */ -/* Functions to manipulate pathnames */ -/* */ -/* **************************************************************** */ - -/* 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; - - if (dot_path == 0 || ABSPATH(string)) -#ifdef __CYGWIN__ - { - char pathbuf[PATH_MAX + 1]; - - cygwin_conv_to_full_posix_path (string, pathbuf); - result = savestring (pathbuf); - } -#else - result = savestring (string); -#endif - else - result = sh_makepath (dot_path, string, 0); - - return (result); -} - -/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd' - to decide whether or not to look up a directory name in $CDPATH. */ -int -absolute_pathname (string) - const char *string; -{ - if (string == 0 || *string == '\0') - return (0); - - if (ABSPATH(string)) - return (1); - - if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */ - return (1); - - if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */ - 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) - const char *string; -{ - return ((char *)xstrchr (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) == 0) - return (string); - - p = (char *)strrchr (string, '/'); - return (p ? ++p : 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 *ret; - - file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file); - - if (ABSPATH(file)) - return (file); - - ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT)); - free (file); - - return (ret); -} - -/* A slightly related function. Get the prettiest name of this - directory possible. */ -static char tdir[PATH_MAX]; - -/* Return a pretty pathname. If the first part of the pathname is - the same as $HOME, then replace that with `~'. */ -char * -polite_directory_format (name) - char *name; -{ - char *home; - int l; - - home = get_string_value ("HOME"); - l = home ? strlen (home) : 0; - if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) - { - strncpy (tdir + 1, name + l, sizeof(tdir) - 2); - tdir[0] = '~'; - tdir[sizeof(tdir) - 1] = '\0'; - return (tdir); - } - else - return (name); -} - -/* 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, len; - char *value; - - if (string == 0) - return (string); - - len = strlen (string); - if (*p_index >= len) - return ((char *)NULL); - - i = *p_index; - - /* Each call to this routine leaves the index pointing at a colon if - there is more to the path. If I is > 0, then increment past the - `:'. If I is 0, then the path has a leading colon. Trailing colons - are handled OK by the `else' part of the if statement; an empty - string is returned in that case. */ - if (i && string[i] == ':') - i++; - - for (start = i; string[i] && string[i] != ':'; i++) - ; - - *p_index = i; - - if (i == start) - { - if (string[i]) - (*p_index)++; - /* Return "" in the case of a trailing `:'. */ - value = (char *)xmalloc (1); - value[0] = '\0'; - } - else - value = substring (string, start, i); - - return (value); -} - -/* **************************************************************** */ -/* */ -/* Tilde Initialization and Expansion */ -/* */ -/* **************************************************************** */ - -#if defined (PUSHD_AND_POPD) -extern char *get_dirstack_from_string __P((char *)); -#endif - -static char **bash_tilde_prefixes; -static char **bash_tilde_suffixes; - -/* 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_preexpansion_hook. It knows how to expand ~- and ~+. - If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the - directory stack. */ -static char * -bash_special_tilde_expansions (text) - char *text; -{ - char *result; - - result = (char *)NULL; - - if (text[0] == '+' && text[1] == '\0') - result = get_string_value ("PWD"); - else if (text[0] == '-' && text[1] == '\0') - result = get_string_value ("OLDPWD"); -#if defined (PUSHD_AND_POPD) - else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1]))) - result = get_dirstack_from_string (text); -#endif - - return (result ? savestring (result) : (char *)NULL); -} - -/* 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 first. */ - tilde_expansion_preexpansion_hook = bash_special_tilde_expansions; - - /* 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) - { - bash_tilde_prefixes = strvec_create (3); - bash_tilde_prefixes[0] = "=~"; - bash_tilde_prefixes[1] = ":~"; - bash_tilde_prefixes[2] = (char *)NULL; - - tilde_additional_prefixes = bash_tilde_prefixes; - - bash_tilde_suffixes = strvec_create (3); - bash_tilde_suffixes[0] = ":"; - bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */ - bash_tilde_suffixes[2] = (char *)NULL; - - tilde_additional_suffixes = bash_tilde_suffixes; - } -} - -/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character - at the beginning of the word, followed by all of the characters preceding - the first unquoted slash in the word, or all the characters in the word - if there is no slash...If none of the characters in the tilde-prefix are - quoted, the characters in the tilde-prefix following the tilde shell be - treated as a possible login name. */ - -#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':') - -static int -unquoted_tilde_word (s) - const char *s; -{ - const char *r; - - for (r = s; TILDE_END(*r) == 0; r++) - { - switch (*r) - { - case '\\': - case '\'': - case '"': - return 0; - } - } - return 1; -} - -/* Tilde-expand S by running it through the tilde expansion library. - ASSIGN_P is 1 if this is a variable assignment, so the alternate - tilde prefixes should be enabled (`=~' and `:~', see above). */ -char * -bash_tilde_expand (s, assign_p) - const char *s; - int assign_p; -{ - int old_immed, r; - char *ret; - - old_immed = interrupt_immediately; - interrupt_immediately = 1; - tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0; - r = (*s == '~') ? unquoted_tilde_word (s) : 1; - ret = r ? tilde_expand (s) : savestring (s); - interrupt_immediately = old_immed; - return (ret); -} - -/* **************************************************************** */ -/* */ -/* Functions to manipulate and search the group list */ -/* */ -/* **************************************************************** */ - -static int ngroups, maxgroups; - -/* The set of groups that this user is a member of. */ -static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; - -#if !defined (NOGROUP) -# define NOGROUP (gid_t) -1 -#endif - -static void -initialize_group_array () -{ - register int i; - - if (maxgroups == 0) - maxgroups = getmaxgroups (); - - ngroups = 0; - group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); - -#if defined (HAVE_GETGROUPS) - ngroups = getgroups (maxgroups, group_array); -#endif - - /* If getgroups returns nothing, or the OS does not support getgroups(), - make sure the groups array includes at least the current gid. */ - if (ngroups == 0) - { - group_array[0] = current_user.gid; - ngroups = 1; - } - - /* If the primary group is not in the groups array, add it as group_array[0] - and shuffle everything else up 1, if there's room. */ - for (i = 0; i < ngroups; i++) - if (current_user.gid == (gid_t)group_array[i]) - break; - if (i == ngroups && ngroups < maxgroups) - { - for (i = ngroups; i > 0; i--) - group_array[i] = group_array[i - 1]; - group_array[0] = current_user.gid; - ngroups++; - } - - /* If the primary group is not group_array[0], swap group_array[0] and - whatever the current group is. The vast majority of systems should - not need this; a notable exception is Linux. */ - if (group_array[0] != current_user.gid) - { - for (i = 0; i < ngroups; i++) - if (group_array[i] == current_user.gid) - break; - if (i < ngroups) - { - group_array[i] = group_array[0]; - group_array[0] = current_user.gid; - } - } -} - -/* Return non-zero if GID is one that we have in our groups list. */ -int -#if defined (__STDC__) || defined ( _MINIX) -group_member (gid_t gid) -#else -group_member (gid) - gid_t gid; -#endif /* !__STDC__ && !_MINIX */ -{ -#if defined (HAVE_GETGROUPS) - register int i; -#endif - - /* Short-circuit if possible, maybe saving a call to getgroups(). */ - if (gid == current_user.gid || gid == current_user.egid) - return (1); - -#if defined (HAVE_GETGROUPS) - if (ngroups == 0) - initialize_group_array (); - - /* In case of error, the user loses. */ - if (ngroups <= 0) - return (0); - - /* Search through the list looking for GID. */ - for (i = 0; i < ngroups; i++) - if (gid == (gid_t)group_array[i]) - return (1); -#endif - - return (0); -} - -char ** -get_group_list (ngp) - int *ngp; -{ - static char **group_vector = (char **)NULL; - register int i; - - if (group_vector) - { - if (ngp) - *ngp = ngroups; - return group_vector; - } - - if (ngroups == 0) - initialize_group_array (); - - if (ngroups <= 0) - { - if (ngp) - *ngp = 0; - return (char **)NULL; - } - - group_vector = strvec_create (ngroups); - for (i = 0; i < ngroups; i++) - group_vector[i] = itos (group_array[i]); - - if (ngp) - *ngp = ngroups; - return group_vector; -} - -int * -get_group_array (ngp) - int *ngp; -{ - int i; - static int *group_iarray = (int *)NULL; - - if (group_iarray) - { - if (ngp) - *ngp = ngroups; - return (group_iarray); - } - - if (ngroups == 0) - initialize_group_array (); - - if (ngroups <= 0) - { - if (ngp) - *ngp = 0; - return (int *)NULL; - } - - group_iarray = (int *)xmalloc (ngroups * sizeof (int)); - for (i = 0; i < ngroups; i++) - group_iarray[i] = (int)group_array[i]; - - if (ngp) - *ngp = ngroups; - return group_iarray; -} diff --git a/general.h~ b/general.h~ deleted file mode 100644 index 9f39a481c..000000000 --- a/general.h~ +++ /dev/null @@ -1,311 +0,0 @@ -/* general.h -- defines that everybody likes to use. */ - -/* Copyright (C) 1993-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_GENERAL_H_) -#define _GENERAL_H_ - -#include "stdc.h" - -#include "bashtypes.h" - -#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE) -# if defined (HAVE_SYS_TIME_H) -# include -# endif -# include -#endif - -#if defined (HAVE_STRING_H) -# include -#else -# include -#endif /* !HAVE_STRING_H */ - -#if defined (HAVE_LIMITS_H) -# include -#endif - -#include "xmalloc.h" - -/* NULL pointer type. */ -#if !defined (NULL) -# if defined (__STDC__) -# define NULL ((void *) 0) -# else -# define NULL 0x0 -# endif /* !__STDC__ */ -#endif /* !NULL */ - -/* Hardly used anymore */ -#define pointer_to_int(x) (int)((char *)x - (char *)0) - -#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif - -#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY) -extern char *strcpy __P((char *, const char *)); -#endif - -#if !defined (savestring) -# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) -#endif - -#ifndef member -# define member(c, s) ((c) ? ((char *)xstrchr ((s), (c)) != (char *)NULL) : 0) -#endif - -#ifndef whitespace -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif - -#ifndef CHAR_MAX -# ifdef __CHAR_UNSIGNED__ -# define CHAR_MAX 0xff -# else -# define CHAR_MAX 0x7f -# endif -#endif - -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -/* Nonzero if the integer type T is signed. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) - -/* Bound on length of the string representing an integer value of type T. - Subtract one for the sign bit if T is signed; - 302 / 1000 is log10 (2) rounded up; - add one for integer division truncation; - add one more for a minus sign if t is signed. */ -#define INT_STRLEN_BOUND(t) \ - ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ - + 1 + TYPE_SIGNED (t)) - - -/* Define exactly what a legal shell identifier consists of. */ -#define legal_variable_starter(c) (ISALPHA(c) || (c == '_')) -#define legal_variable_char(c) (ISALNUM(c) || c == '_') - -/* Definitions used in subst.c and by the `read' builtin for field - splitting. */ -#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') - -/* 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)list_reverse ((GENERIC_LIST *)list) \ - : (type)(list)) - -#if __GNUC__ > 1 -# define FASTCOPY(s, d, n) __builtin_memcpy (d, s, n) -#else /* !__GNUC__ */ -# if !defined (HAVE_BCOPY) -# if !defined (HAVE_MEMMOVE) -# define FASTCOPY(s, d, n) memcpy (d, s, n) -# else -# define FASTCOPY(s, d, n) memmove (d, s, n) -# endif /* !HAVE_MEMMOVE */ -# else /* HAVE_BCOPY */ -# define FASTCOPY(s, d, n) bcopy (s, d, n) -# endif /* 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) ((n == 0) ? (1) \ - : ((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) && c == (s)[0] && !(s)[1]) || (member(c, s))) - -/* A fairly hairy macro to check whether an allocated string has more room, - and to resize it using xrealloc if it does not. - STR is the string (char *) - CIND is the current index into the string (int) - ROOM is the amount of additional room we need in the string (int) - CSIZE is the currently-allocated size of STR (int) - SINCR is how much to increment CSIZE before calling xrealloc (int) */ - -#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \ - do { \ - if ((cind) + (room) >= csize) \ - { \ - while ((cind) + (room) >= csize) \ - csize += (sincr); \ - str = xrealloc (str, csize); \ - } \ - } while (0) - -/* Function pointers can be declared as (Function *)foo. */ -#if !defined (_FUNCTION_DEF) -# define _FUNCTION_DEF -typedef int Function (); -typedef void VFunction (); -typedef char *CPFunction (); /* no longer used */ -typedef char **CPPFunction (); /* no longer used */ -#endif /* _FUNCTION_DEF */ - -#ifndef SH_FUNCTION_TYPEDEF -# define SH_FUNCTION_TYPEDEF - -/* Shell function typedefs with prototypes */ -/* `Generic' function pointer typedefs */ - -typedef int sh_intfunc_t __P((int)); -typedef int sh_ivoidfunc_t __P((void)); -typedef int sh_icpfunc_t __P((char *)); -typedef int sh_icppfunc_t __P((char **)); -typedef int sh_iptrfunc_t __P((PTR_T)); - -typedef void sh_voidfunc_t __P((void)); -typedef void sh_vintfunc_t __P((int)); -typedef void sh_vcpfunc_t __P((char *)); -typedef void sh_vcppfunc_t __P((char **)); -typedef void sh_vptrfunc_t __P((PTR_T)); - -typedef int sh_wdesc_func_t __P((WORD_DESC *)); -typedef int sh_wlist_func_t __P((WORD_LIST *)); - -typedef int sh_glist_func_t __P((GENERIC_LIST *)); - -typedef char *sh_string_func_t __P((char *)); /* like savestring, et al. */ - -typedef int sh_msg_func_t __P((const char *, ...)); /* printf(3)-like */ -typedef void sh_vmsg_func_t __P((const char *, ...)); /* printf(3)-like */ - -/* Specific function pointer typedefs. Most of these could be done - with #defines. */ -typedef void sh_sv_func_t __P((char *)); /* sh_vcpfunc_t */ -typedef void sh_free_func_t __P((PTR_T)); /* sh_vptrfunc_t */ -typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */ - -typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */ - -typedef int sh_assign_func_t __P((const char *)); /* sh_icpfunc_t */ - -typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */ - -#endif /* SH_FUNCTION_TYPEDEF */ - -#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 -#define FS_DIRECTORY 0x10 -#define FS_NODIRS 0x20 - -/* Default maximum for move_to_high_fd */ -#define HIGH_FD_MAX 256 - -/* The type of function passed as the fourth argument to qsort(3). */ -#ifdef __STDC__ -typedef int QSFUNC (const void *, const void *); -#else -typedef int QSFUNC (); -#endif - -/* Some useful definitions for Unix pathnames. Argument convention: - x == string, c == character */ - -#if !defined (__CYGWIN__) -# define ABSPATH(x) ((x)[0] == '/') -# define RELPATH(x) ((x)[0] != '/') -#else /* __CYGWIN__ */ -# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':' && (x)[2] == '/') || (x)[0] == '/') -# define RELPATH(x) (!(x)[0] || ((x)[1] != ':' && (x)[0] != '/')) -#endif /* __CYGWIN__ */ - -#define ROOTEDPATH(x) (ABSPATH(x)) - -#define DIRSEP '/' -#define ISDIRSEP(c) ((c) == '/') -#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0) - -#if 0 -/* Declarations for functions defined in xmalloc.c */ -extern PTR_T xmalloc __P((size_t)); -extern PTR_T xrealloc __P((void *, size_t)); -extern void xfree __P((void *)); -#endif - -/* Declarations for functions defined in general.c */ -extern void posix_initialize __P((int)); - -#if defined (RLIMTYPE) -extern RLIMTYPE string_to_rlimtype __P((char *)); -extern void print_rlimtype __P((RLIMTYPE, int)); -#endif - -extern int all_digits __P((char *)); -extern int legal_number __P((char *, intmax_t *)); -extern int legal_identifier __P((char *)); -extern int check_identifier __P((WORD_DESC *, int)); -extern int assignment __P((const char *, int)); - -extern int sh_unset_nodelay_mode __P((int)); -extern int sh_validfd __P((int)); -extern void check_dev_tty __P((void)); -extern int move_to_high_fd __P((int, int, int)); -extern int check_binary_file __P((char *, int)); - -#ifdef _POSIXSTAT_H_ -extern int same_file __P((char *, char *, struct stat *, struct stat *)); -#endif - -extern int file_isdir __P((char *)); -extern int file_iswdir __P((char *)); - -extern char *make_absolute __P((char *, char *)); -extern int absolute_pathname __P((const char *)); -extern int absolute_program __P((const char *)); -extern char *base_pathname __P((char *)); -extern char *full_pathname __P((char *)); -extern char *polite_directory_format __P((char *)); - -extern char *extract_colon_unit __P((char *, int *)); - -extern void tilde_initialize __P((void)); -extern char *bash_tilde_expand __P((const char *, int)); - -extern int group_member __P((gid_t)); -extern char **get_group_list __P((int *)); -extern int *get_group_array __P((int *)); - -#endif /* _GENERAL_H_ */ diff --git a/include/memalloc.h.save b/include/memalloc.h.save deleted file mode 100644 index a1a270699..000000000 --- a/include/memalloc.h.save +++ /dev/null @@ -1,58 +0,0 @@ -/* memalloc.h -- consolidate code for including alloca.h or malloc.h and - defining alloca. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 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 (__GNUC__) && !defined (C_ALLOCA) -# undef alloca -# define alloca __builtin_alloca -#else /* !__GNUC__ || C_ALLOCA */ -# if defined (HAVE_ALLOCA_H) && !defined (C_ALLOCA) -# if defined (IBMESA) -# include -# else /* !IBMESA */ -# include -# endif /* !IBMESA */ -# else /* !HAVE_ALLOCA_H || C_ALLOCA */ -# if defined (__hpux) && defined (__STDC__) && !defined (alloca) -extern void *alloca (); -# else -# if !defined (alloca) -extern char *alloca (); -# endif /* !alloca */ -# endif /* !__hpux || !__STDC__ && !alloca */ -# endif /* !HAVE_ALLOCA_H || C_ALLOCA */ -#endif /* !__GNUC__ || C_ALLOCA */ - -#endif /* _MEMALLOC_H_ */ diff --git a/include/shmbutil.h.save1 b/include/shmbutil.h.save1 deleted file mode 100644 index 492f6afce..000000000 --- a/include/shmbutil.h.save1 +++ /dev/null @@ -1,470 +0,0 @@ -/* shmbutil.h -- utility functions for multibyte characters. */ - -/* Copyright (C) 2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_SH_MBUTIL_H_) -#define _SH_MBUTIL_H_ - -#include "stdc.h" - -/************************************************/ -/* check multibyte capability for I18N code */ -/************************************************/ - -/* For platforms which support the ISO C amendement 1 functionality we - support user defined character classes. */ - /* Solaris 2.5 has a bug: must be included before . */ -#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) -# include -# include -# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */ -# define HANDLE_MULTIBYTE 1 -# endif -#endif /* HAVE_WCTYPE_H && HAVE_WCHAR_H */ - -/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) -# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) -# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) -# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) -# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) -# define mbstate_t int -#endif /* HANDLE_MULTIBYTE && !HAVE_MBSTATE_T */ - -/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to - handle multibyte chars (some systems define MB_LEN_MAX as 1) */ -#ifdef HANDLE_MULTIBYTE -# include -# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) -# undef MB_LEN_MAX -# endif -# if !defined (MB_LEN_MAX) -# define MB_LEN_MAX 16 -# endif -#endif /* HANDLE_MULTIBYTE */ - -/************************************************/ -/* end of multibyte capability checks for I18N */ -/************************************************/ - -#if defined (HANDLE_MULTIBYTE) - -extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *)); -extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *)); - -extern char *xstrchr __P((const char *, int)); - -#ifndef MB_INVALIDCH -#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2) -#define MB_NULLWCH(x) ((x) == 0) -#endif - -#else /* !HANDLE_MULTIBYTE */ - -#undef MB_LEN_MAX -#undef MB_CUR_MAX - -#define MB_LEN_MAX 1 -#define MB_CUR_MAX 1 - -#undef xstrchr -#define xstrchr(s, c) strchr(s, c) - -#ifndef MB_INVALIDCH -#define MB_INVALIDCH(x) (0) -#define MB_NULLWCH(x) (0) -#endif - -#endif /* !HANDLE_MULTIBYTE */ - -/* Declare and initialize a multibyte state. Call must be terminated - with `;'. */ -#if defined (HANDLE_MULTIBYTE) -# define DECLARE_MBSTATE \ - mbstate_t state; \ - memset (&state, '\0', sizeof (mbstate_t)) -#else -# define DECLARE_MBSTATE -#endif /* !HANDLE_MULTIBYTE */ - -/* Initialize or reinitialize a multibyte state named `state'. Call must be - terminated with `;'. */ -#if defined (HANDLE_MULTIBYTE) -# define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t)) -#else -# define INITIALIZE_MBSTATE -#endif /* !HANDLE_MULTIBYTE */ - -/* Advance one (possibly multi-byte) character in string _STR of length - _STRSIZE, starting at index _I. STATE must have already been declared. */ -#if defined (HANDLE_MULTIBYTE) -# define ADVANCE_CHAR(_str, _strsize, _i) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - (_i)++; \ - } \ - else if (mblength == 0) \ - (_i)++; \ - else \ - (_i) += mblength; \ - } \ - else \ - (_i)++; \ - } \ - while (0) -#else -# define ADVANCE_CHAR(_str, _strsize, _i) (_i)++ -#endif /* !HANDLE_MULTIBYTE */ - -/* Advance one (possibly multibyte) character in the string _STR of length - _STRSIZE. - SPECIAL: assume that _STR will be incremented by 1 after this call. */ -#if defined (HANDLE_MULTIBYTE) -# define ADVANCE_CHAR_P(_str, _strsize) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_str), (_strsize), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - (_str) += (mblength < 1) ? 0 : (mblength - 1); \ - } \ - } \ - while (0) -#else -# define ADVANCE_CHAR_P(_str, _strsize) -#endif /* !HANDLE_MULTIBYTE */ - -/* Back up one (possibly multi-byte) character in string _STR of length - _STRSIZE, starting at index _I. STATE must have already been declared. */ -#if defined (HANDLE_MULTIBYTE) -# define BACKUP_CHAR(_str, _strsize, _i) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _x, _p; /* _x == temp index into string, _p == prev index */ \ -\ - _x = _p = 0; \ - while (_x < (_i)) \ - { \ - state_bak = state; \ - mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - _x++; \ - } \ - else if (mblength == 0) \ - _x++; \ - else \ - { \ - _p = _x; /* _p == start of prev mbchar */ \ - _x += mblength; \ - } \ - } \ - (_i) = _p; \ - } \ - else \ - (_i)--; \ - } \ - while (0) -#else -# define BACKUP_CHAR(_str, _strsize, _i) (_i)-- -#endif /* !HANDLE_MULTIBYTE */ - -/* Back up one (possibly multibyte) character in the string _BASE of length - _STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ). - SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */ -#if defined (HANDLE_MULTIBYTE) -# define BACKUP_CHAR_P(_base, _strsize, _str) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \ -\ - _x = _p = _base; \ - while (_x < (_str)) \ - { \ - state_bak = state; \ - mblength = mbrlen (_x, (_strsize) - _x, &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - _x++; \ - } \ - else if (mblength == 0) \ - _x++; \ - else \ - { \ - _p = _x; /* _p == start of prev mbchar */ \ - _x += mblength; \ - } \ - } \ - (_str) = _p; \ - } \ - else \ - (_str)--; \ - } \ - while (0) -#else -# define BACKUP_CHAR_P(_base, _strsize, _str) (_str)-- -#endif /* !HANDLE_MULTIBYTE */ - -/* Copy a single character from the string _SRC to the string _DST. - _SRCEND is a pointer to the end of _SRC. */ -#if defined (HANDLE_MULTIBYTE) -# define COPY_CHAR_P(_dst, _src, _srcend) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _k; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src), (_srcend) - (_src), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - for (_k = 0; _k < mblength; _k++) \ - *(_dst)++ = *(_src)++; \ - } \ - else \ - *(_dst)++ = *(_src)++; \ - } \ - while (0) -#else -# define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++ -#endif /* !HANDLE_MULTIBYTE */ - -/* Copy a single character from the string _SRC at index _SI to the string - _DST at index _DI. _SRCEND is a pointer to the end of _SRC. */ -#if defined (HANDLE_MULTIBYTE) -# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _k; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - for (_k = 0; _k < mblength; _k++) \ - _dst[_di++] = _src[_si++]; \ - } \ - else \ - _dst[_di++] = _src[_si++]; \ - } \ - while (0) -#else -# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++] -#endif /* !HANDLE_MULTIBYTE */ - -/**************************************************************** - * * - * The following are only guaranteed to work in subst.c * - * * - ****************************************************************/ - -#if defined (HANDLE_MULTIBYTE) -# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _i; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - temp = xmalloc (mblength + 2); \ - temp[0] = _escchar; \ - for (_i = 0; _i < mblength; _i++) \ - temp[_i + 1] = _src[_si++]; \ - temp[mblength + 1] = '\0'; \ -\ - goto add_string; \ - } \ - else \ - { \ - _dst[0] = _escchar; \ - _dst[1] = _sc; \ - } \ - } \ - while (0) -#else -# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \ - _dst[0] = _escchar; \ - _dst[1] = _sc -#endif /* !HANDLE_MULTIBYTE */ - -#if defined (HANDLE_MULTIBYTE) -# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - FASTCOPY(((_src) + (_si)), (_dst), mblength); \ -\ - (_dst) += mblength; \ - (_si) += mblength; \ - } \ - else \ - { \ - *(_dst)++ = _src[(_si)]; \ - (_si)++; \ - } \ - } \ - while (0) -#else -# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \ - *(_dst)++ = _src[(_si)]; \ - (_si)++ -#endif /* !HANDLE_MULTIBYTE */ - -#if HANDLE_MULTIBYTE -# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - int i; \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \ - if (mblength == (size_t)-1 || mblength == (size_t)-2) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - if (mblength < 1) \ - mblength = 1; \ -\ - _dst = (char *)xmalloc (mblength + 1); \ - for (i = 0; i < mblength; i++) \ - (_dst)[i] = (_src)[(_si)++]; \ - (_dst)[mblength] = '\0'; \ -\ - goto add_string; \ - } \ - } \ - while (0) - -#else -# define SADD_MBCHAR(_dst, _src, _si, _srcsize) -#endif - -/* Watch out when using this -- it's just straight textual subsitution */ -#if defined (HANDLE_MULTIBYTE) -# define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \ -\ - int i; \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \ - if (mblength == (size_t)-1 || mblength == (size_t)-2) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - if (mblength < 1) \ - mblength = 1; \ -\ - (_dst) = (char *)xmalloc (mblength + 2); \ - (_dst)[0] = CTLESC; \ - for (i = 0; i < mblength; i++) \ - (_dst)[i+1] = (_src)[(_si)++]; \ - (_dst)[mblength+1] = '\0'; \ -\ - goto add_string - -#endif /* HANDLE_MULTIBYTE */ -#endif /* _SH_MBUTIL_H_ */ diff --git a/include/shmbutil.h~ b/include/shmbutil.h~ deleted file mode 100644 index 492f6afce..000000000 --- a/include/shmbutil.h~ +++ /dev/null @@ -1,470 +0,0 @@ -/* shmbutil.h -- utility functions for multibyte characters. */ - -/* Copyright (C) 2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_SH_MBUTIL_H_) -#define _SH_MBUTIL_H_ - -#include "stdc.h" - -/************************************************/ -/* check multibyte capability for I18N code */ -/************************************************/ - -/* For platforms which support the ISO C amendement 1 functionality we - support user defined character classes. */ - /* Solaris 2.5 has a bug: must be included before . */ -#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) -# include -# include -# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */ -# define HANDLE_MULTIBYTE 1 -# endif -#endif /* HAVE_WCTYPE_H && HAVE_WCHAR_H */ - -/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) -# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) -# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) -# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) -# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) -# define mbstate_t int -#endif /* HANDLE_MULTIBYTE && !HAVE_MBSTATE_T */ - -/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to - handle multibyte chars (some systems define MB_LEN_MAX as 1) */ -#ifdef HANDLE_MULTIBYTE -# include -# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) -# undef MB_LEN_MAX -# endif -# if !defined (MB_LEN_MAX) -# define MB_LEN_MAX 16 -# endif -#endif /* HANDLE_MULTIBYTE */ - -/************************************************/ -/* end of multibyte capability checks for I18N */ -/************************************************/ - -#if defined (HANDLE_MULTIBYTE) - -extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *)); -extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *)); - -extern char *xstrchr __P((const char *, int)); - -#ifndef MB_INVALIDCH -#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2) -#define MB_NULLWCH(x) ((x) == 0) -#endif - -#else /* !HANDLE_MULTIBYTE */ - -#undef MB_LEN_MAX -#undef MB_CUR_MAX - -#define MB_LEN_MAX 1 -#define MB_CUR_MAX 1 - -#undef xstrchr -#define xstrchr(s, c) strchr(s, c) - -#ifndef MB_INVALIDCH -#define MB_INVALIDCH(x) (0) -#define MB_NULLWCH(x) (0) -#endif - -#endif /* !HANDLE_MULTIBYTE */ - -/* Declare and initialize a multibyte state. Call must be terminated - with `;'. */ -#if defined (HANDLE_MULTIBYTE) -# define DECLARE_MBSTATE \ - mbstate_t state; \ - memset (&state, '\0', sizeof (mbstate_t)) -#else -# define DECLARE_MBSTATE -#endif /* !HANDLE_MULTIBYTE */ - -/* Initialize or reinitialize a multibyte state named `state'. Call must be - terminated with `;'. */ -#if defined (HANDLE_MULTIBYTE) -# define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t)) -#else -# define INITIALIZE_MBSTATE -#endif /* !HANDLE_MULTIBYTE */ - -/* Advance one (possibly multi-byte) character in string _STR of length - _STRSIZE, starting at index _I. STATE must have already been declared. */ -#if defined (HANDLE_MULTIBYTE) -# define ADVANCE_CHAR(_str, _strsize, _i) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - (_i)++; \ - } \ - else if (mblength == 0) \ - (_i)++; \ - else \ - (_i) += mblength; \ - } \ - else \ - (_i)++; \ - } \ - while (0) -#else -# define ADVANCE_CHAR(_str, _strsize, _i) (_i)++ -#endif /* !HANDLE_MULTIBYTE */ - -/* Advance one (possibly multibyte) character in the string _STR of length - _STRSIZE. - SPECIAL: assume that _STR will be incremented by 1 after this call. */ -#if defined (HANDLE_MULTIBYTE) -# define ADVANCE_CHAR_P(_str, _strsize) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_str), (_strsize), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - (_str) += (mblength < 1) ? 0 : (mblength - 1); \ - } \ - } \ - while (0) -#else -# define ADVANCE_CHAR_P(_str, _strsize) -#endif /* !HANDLE_MULTIBYTE */ - -/* Back up one (possibly multi-byte) character in string _STR of length - _STRSIZE, starting at index _I. STATE must have already been declared. */ -#if defined (HANDLE_MULTIBYTE) -# define BACKUP_CHAR(_str, _strsize, _i) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _x, _p; /* _x == temp index into string, _p == prev index */ \ -\ - _x = _p = 0; \ - while (_x < (_i)) \ - { \ - state_bak = state; \ - mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - _x++; \ - } \ - else if (mblength == 0) \ - _x++; \ - else \ - { \ - _p = _x; /* _p == start of prev mbchar */ \ - _x += mblength; \ - } \ - } \ - (_i) = _p; \ - } \ - else \ - (_i)--; \ - } \ - while (0) -#else -# define BACKUP_CHAR(_str, _strsize, _i) (_i)-- -#endif /* !HANDLE_MULTIBYTE */ - -/* Back up one (possibly multibyte) character in the string _BASE of length - _STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ). - SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */ -#if defined (HANDLE_MULTIBYTE) -# define BACKUP_CHAR_P(_base, _strsize, _str) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \ -\ - _x = _p = _base; \ - while (_x < (_str)) \ - { \ - state_bak = state; \ - mblength = mbrlen (_x, (_strsize) - _x, &state); \ -\ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - _x++; \ - } \ - else if (mblength == 0) \ - _x++; \ - else \ - { \ - _p = _x; /* _p == start of prev mbchar */ \ - _x += mblength; \ - } \ - } \ - (_str) = _p; \ - } \ - else \ - (_str)--; \ - } \ - while (0) -#else -# define BACKUP_CHAR_P(_base, _strsize, _str) (_str)-- -#endif /* !HANDLE_MULTIBYTE */ - -/* Copy a single character from the string _SRC to the string _DST. - _SRCEND is a pointer to the end of _SRC. */ -#if defined (HANDLE_MULTIBYTE) -# define COPY_CHAR_P(_dst, _src, _srcend) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _k; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src), (_srcend) - (_src), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - for (_k = 0; _k < mblength; _k++) \ - *(_dst)++ = *(_src)++; \ - } \ - else \ - *(_dst)++ = *(_src)++; \ - } \ - while (0) -#else -# define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++ -#endif /* !HANDLE_MULTIBYTE */ - -/* Copy a single character from the string _SRC at index _SI to the string - _DST at index _DI. _SRCEND is a pointer to the end of _SRC. */ -#if defined (HANDLE_MULTIBYTE) -# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _k; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - for (_k = 0; _k < mblength; _k++) \ - _dst[_di++] = _src[_si++]; \ - } \ - else \ - _dst[_di++] = _src[_si++]; \ - } \ - while (0) -#else -# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++] -#endif /* !HANDLE_MULTIBYTE */ - -/**************************************************************** - * * - * The following are only guaranteed to work in subst.c * - * * - ****************************************************************/ - -#if defined (HANDLE_MULTIBYTE) -# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ - int _i; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - temp = xmalloc (mblength + 2); \ - temp[0] = _escchar; \ - for (_i = 0; _i < mblength; _i++) \ - temp[_i + 1] = _src[_si++]; \ - temp[mblength + 1] = '\0'; \ -\ - goto add_string; \ - } \ - else \ - { \ - _dst[0] = _escchar; \ - _dst[1] = _sc; \ - } \ - } \ - while (0) -#else -# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \ - _dst[0] = _escchar; \ - _dst[1] = _sc -#endif /* !HANDLE_MULTIBYTE */ - -#if defined (HANDLE_MULTIBYTE) -# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \ - if (mblength == (size_t)-2 || mblength == (size_t)-1) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - else \ - mblength = (mblength < 1) ? 1 : mblength; \ -\ - FASTCOPY(((_src) + (_si)), (_dst), mblength); \ -\ - (_dst) += mblength; \ - (_si) += mblength; \ - } \ - else \ - { \ - *(_dst)++ = _src[(_si)]; \ - (_si)++; \ - } \ - } \ - while (0) -#else -# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \ - *(_dst)++ = _src[(_si)]; \ - (_si)++ -#endif /* !HANDLE_MULTIBYTE */ - -#if HANDLE_MULTIBYTE -# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \ - do \ - { \ - if (MB_CUR_MAX > 1) \ - { \ - int i; \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \ - if (mblength == (size_t)-1 || mblength == (size_t)-2) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - if (mblength < 1) \ - mblength = 1; \ -\ - _dst = (char *)xmalloc (mblength + 1); \ - for (i = 0; i < mblength; i++) \ - (_dst)[i] = (_src)[(_si)++]; \ - (_dst)[mblength] = '\0'; \ -\ - goto add_string; \ - } \ - } \ - while (0) - -#else -# define SADD_MBCHAR(_dst, _src, _si, _srcsize) -#endif - -/* Watch out when using this -- it's just straight textual subsitution */ -#if defined (HANDLE_MULTIBYTE) -# define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \ -\ - int i; \ - mbstate_t state_bak; \ - size_t mblength; \ -\ - state_bak = state; \ - mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \ - if (mblength == (size_t)-1 || mblength == (size_t)-2) \ - { \ - state = state_bak; \ - mblength = 1; \ - } \ - if (mblength < 1) \ - mblength = 1; \ -\ - (_dst) = (char *)xmalloc (mblength + 2); \ - (_dst)[0] = CTLESC; \ - for (i = 0; i < mblength; i++) \ - (_dst)[i+1] = (_src)[(_si)++]; \ - (_dst)[mblength+1] = '\0'; \ -\ - goto add_string - -#endif /* HANDLE_MULTIBYTE */ -#endif /* _SH_MBUTIL_H_ */ diff --git a/jobs.c~ b/jobs.c~ deleted file mode 100644 index 4fcd07c98..000000000 --- a/jobs.c~ +++ /dev/null @@ -1,3537 +0,0 @@ -/* The thing that makes children, remembers them, and contains wait loops. */ - -/* This file works with both POSIX and BSD systems. It implements job - control. */ - -/* Copyright (C) 1989-2003 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include "trap.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixtime.h" - -#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) -# include -#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ - -#if defined (HAVE_SYS_FILE_H) -# include -#endif - -#include "filecntl.h" -#include -#include - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -/* Need to include this up here for *_TTY_DRIVER definitions. */ -#include "shtty.h" - -/* Define this if your output is getting swallowed. It's a no-op on - machines with the termio or termios tty drivers. */ -/* #define DRAIN_OUTPUT */ - -/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ -#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) -# include -#endif /* hpux && !TERMIOS_TTY_DRIVER */ - -#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) -/* For struct winsize on SCO */ -/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ -# if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) -# if defined (HAVE_SYS_STREAM_H) -# include -# endif -# include -# endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */ -#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */ - -#include "bashansi.h" -#include "bashintl.h" -#include "shell.h" -#include "jobs.h" -#include "flags.h" - -#include "builtins/builtext.h" -#include "builtins/common.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#define DEFAULT_CHILD_MAX 32 -#define MAX_JOBS_IN_ARRAY 4096 /* testing */ - -/* Take care of system dependencies that must be handled when waiting for - children. The arguments to the WAITPID macro match those to the Posix.1 - waitpid() function. */ - -#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION) -# define WAITPID(pid, statusp, options) \ - wait3 ((union wait *)statusp, options, (struct rusage *)0) -#else -# if defined (_POSIX_VERSION) || defined (HAVE_WAITPID) -# define WAITPID(pid, statusp, options) \ - waitpid ((pid_t)pid, statusp, options) -# else -# if defined (HAVE_WAIT3) -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (struct rusage *)0) -# else -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (int *)0) -# endif /* HAVE_WAIT3 */ -# endif /* !_POSIX_VERSION && !HAVE_WAITPID*/ -#endif /* !(Ultrix && mips && _POSIX_VERSION) */ - -/* getpgrp () varies between systems. Even systems that claim to be - Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ -#if defined (GETPGRP_VOID) -# define getpgid(p) getpgrp () -#else -# define getpgid(p) getpgrp (p) -#endif /* !GETPGRP_VOID */ - -/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the - handler for SIGCHLD. */ -#if defined (MUST_REINSTALL_SIGHANDLERS) -# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler) -#else -# define REINSTALL_SIGCHLD_HANDLER -#endif /* !MUST_REINSTALL_SIGHANDLERS */ - -/* Some systems let waitpid(2) tell callers about stopped children. */ -#if !defined (WCONTINUED) -# define WCONTINUED 0 -#endif -#if !defined (WIFCONTINUED) -# define WIFCONTINUED(s) (0) -#endif - -/* The number of additional slots to allocate when we run out. */ -#define JOB_SLOTS 8 - -typedef int sh_job_map_func_t __P((JOB *, int, int, int)); - -#if defined (READLINE) -extern void rl_set_screen_size __P((int, int)); -#endif - -/* Variables used here but defined in other files. */ -extern int subshell_environment, line_number; -extern int posixly_correct, shell_level; -extern int interrupt_immediately; -extern int last_command_exit_value, last_command_exit_signal; -extern int loop_level, breaking; -extern int sourcelevel; -extern sh_builtin_func_t *this_shell_builtin; -extern char *shell_name, *this_command_name; -extern sigset_t top_level_mask; -extern procenv_t wait_intr_buf; -extern int wait_signal_received; -extern WORD_LIST *subst_assign_varlist; - -/* The array of known jobs. */ -JOB **jobs = (JOB **)NULL; - -/* The number of slots currently allocated to JOBS. */ -int job_slots = 0; - -/* 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; - -/* If this is non-zero, $LINES and $COLUMNS are reset after every process - exits from get_tty_state(). */ -int check_window_size; - -/* Functions local to this file. */ - -static void get_new_window_size __P((int)); - -static void run_sigchld_trap __P((int)); - -static sighandler wait_sigint_handler __P((int)); -static sighandler sigchld_handler __P((int)); -static sighandler sigwinch_sighandler __P((int)); -static sighandler sigcont_sighandler __P((int)); -static sighandler sigstop_sighandler __P((int)); - -static int waitchld __P((pid_t, int)); - -static PROCESS *find_pipeline __P((pid_t, int, int *)); - -static char *current_working_directory __P((void)); -static char *job_working_directory __P((void)); -static char *j_strsignal __P((int)); -static char *printable_job_status __P((int, PROCESS *, int)); - -static pid_t find_last_pid __P((int, int)); - -static int set_new_line_discipline __P((int)); -static int map_over_jobs __P((sh_job_map_func_t *, int, int)); -static int job_last_stopped __P((int)); -static int job_last_running __P((int)); -static int most_recent_job_in_state __P((int, JOB_STATE)); -static int find_job __P((pid_t, int)); -static int print_job __P((JOB *, int, int, int)); -static int process_exit_status __P((WAIT)); -static int process_exit_signal __P((WAIT)); -static int job_exit_status __P((int)); -static int job_exit_signal __P((int)); -static int set_job_status_and_cleanup __P((int)); - -static WAIT raw_job_exit_status __P((int)); - -static void notify_of_job_status __P((void)); -static void cleanup_dead_jobs __P((void)); -static int compact_jobs_list __P((int)); -static void discard_pipeline __P((PROCESS *)); -static void add_process __P((char *, pid_t)); -static void print_pipeline __P((PROCESS *, int, int, FILE *)); -static void pretty_print_job __P((int, int, FILE *)); -static void set_current_job __P((int)); -static void reset_current __P((void)); -static void set_job_running __P((int)); -static void setjstatus __P((int)); -static void mark_all_jobs_as_dead __P((void)); -static void mark_dead_jobs_as_notified __P((int)); -static void restore_sigint_handler __P((void)); -#if defined (PGRP_PIPE) -static void pipe_read __P((int *)); -static void pipe_close __P((int *)); -#endif - -#if defined (ARRAY_VARS) -static int *pstatuses; /* list of pipeline statuses */ -static int statsize; -#endif - -/* Used to synchronize between wait_for and other functions and the SIGCHLD - signal handler. */ -static int sigchld; -static int queue_sigchld; - -#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++ - -#define UNQUEUE_SIGCHLD(os) \ - do { \ - queue_sigchld--; \ - if (queue_sigchld == 0 && os != sigchld) \ - waitchld (-1, 0); \ - } while (0) - -static SigHandler *old_tstp, *old_ttou, *old_ttin; -static SigHandler *old_cont = (SigHandler *)SIG_DFL; - -#if defined (TIOCGWINSZ) && defined (SIGWINCH) -static SigHandler *old_winch = (SigHandler *)SIG_DFL; -#endif - -/* A place to temporarily save the current pipeline. */ -static PROCESS *saved_pipeline; -static int saved_already_making_children; - -/* Set this to non-zero whenever you don't want the jobs list to change at - all: no jobs deleted and no status change notifications. This is used, - for example, when executing SIGCHLD traps, which may run arbitrary - commands. */ -static int jobs_list_frozen; - -static char retcode_name_buffer[64]; - -static long child_max = -1L; - -#if !defined (_POSIX_VERSION) - -/* These are definitions to map POSIX 1003.1 functions onto existing BSD - library functions and system calls. */ -#define setpgid(pid, pgrp) setpgrp (pid, pgrp) -#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) - -pid_t -tcgetpgrp (fd) - int fd; -{ - pid_t pgrp; - - /* ioctl will handle setting errno correctly. */ - if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) - return (-1); - return (pgrp); -} - -#endif /* !_POSIX_VERSION */ - -/* Return the working directory for the current process. Unlike - job_working_directory, this does not call malloc (), nor do any - of the functions it calls. This is so that it can safely be called - from a signal handler. */ -static char * -current_working_directory () -{ - char *dir; - static char d[PATH_MAX]; - - dir = get_string_value ("PWD"); - - if (dir == 0 && the_current_working_directory && no_symbolic_links) - dir = the_current_working_directory; - - if (dir == 0) - { - dir = getcwd (d, sizeof(d)); - if (dir) - dir = d; - } - - return (dir == 0) ? "" : 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; - } -} - -void -save_pipeline (clear) - int clear; -{ - saved_pipeline = the_pipeline; - saved_already_making_children = already_making_children; - if (clear) - the_pipeline = (PROCESS *)NULL; -} - -void -restore_pipeline (discard) - int discard; -{ - PROCESS *old_pipeline; - - old_pipeline = the_pipeline; - the_pipeline = saved_pipeline; - already_making_children = saved_already_making_children; - if (discard) - discard_pipeline (old_pipeline); -} - -/* Start building a pipeline. */ -void -start_pipeline () -{ - if (the_pipeline) - { - cleanup_the_pipeline (); - pipeline_pgrp = 0; -#if defined (PGRP_PIPE) - pipe_close (pgrp_pipe); -#endif - } - -#if defined (PGRP_PIPE) - if (job_control) - { - if (pipe (pgrp_pipe) == -1) - sys_error ("start_pipeline: pgrp pipe"); - } -#endif -} - -/* Stop building a pipeline. Install the process list in the job array. - This returns the index of the newly installed job. - DEFERRED is a command structure to be executed upon satisfactory - execution exit of this pipeline. */ -int -stop_pipeline (async, deferred) - int async; - COMMAND *deferred; -{ - register int i, j; - JOB *newjob; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - -#if defined (PGRP_PIPE) - /* The parent closes the process group synchronization pipe. */ - pipe_close (pgrp_pipe); -#endif - - cleanup_dead_jobs (); - - if (job_slots == 0) - { - job_slots = JOB_SLOTS; - jobs = (JOB **)xmalloc (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. */ - /* XXX - revisit this interactive assumption */ - 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] == 0) - break; - } - - /* Do we need more room? */ - - /* First try compaction */ - if (subshell_environment && interactive_shell && i == job_slots && job_slots >= MAX_JOBS_IN_ARRAY) - i = compact_jobs_list (0); - - /* If we can't compact, reallocate */ - 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; - int any_alive, any_stopped; - - 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. */ - p = newjob->pipe; - any_alive = any_stopped = 0; - do - { - any_alive |= p->running; - any_stopped |= WIFSTOPPED (p->status); - p = p->next; - } - while (p != newjob->pipe); - - newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); - newjob->wd = job_working_directory (); - newjob->deferred = deferred; - - newjob->j_cleanup = (sh_vptrfunc_t *)NULL; - newjob->cleanarg = (PTR_T) NULL; - -itrace("stop_pipeline: adding new job %d", i + 1); - jobs[i] = newjob; - if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) - setjstatus (i); - } - else - newjob = (JOB *)NULL; - - 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, 0); - } - } - - 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; - int os; - - if (job_slots == 0 || jobs_list_frozen) - return; - - QUEUE_SIGCHLD(os); - - for (i = 0; i < job_slots; i++) - if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) - delete_job (i, 0); - - UNQUEUE_SIGCHLD(os); -} - -/* Compact the jobs list by removing dead jobs. Assumed that we have filled - the jobs array to some predefined maximum. Called when the shell is not - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is job_slots, then - the list needs to be reallocated. The jobs array is in new memory if - this returns > 0 and < job_slots. FLAGS is reserved for future use. */ -static int -compact_jobs_list (flags) - int flags; -{ - sigset_t set, oset; - register int i, j; - int nremove, ndel; - JOB **newlist; - - if (job_slots == 0 || jobs_list_frozen) - return job_slots; - - if (child_max < 0) - child_max = getmaxchild (); - - /* Take out at most a quarter of the jobs in the jobs array, but leave at - least child_max */ - nremove = job_slots >> 2; - if ((job_slots - nremove) < child_max) - nremove = job_slots - child_max; - - /* need to increase jobs list to at least CHILD_MAX entries */ - if (nremove < 0) - return job_slots; - - BLOCK_CHILD (set, oset); - - for (ndel = i = 0; i < job_slots; i++) - if (jobs[i]) - { - if (DEADJOB (i) && (find_last_pid (i, 0) != last_asynchronous_pid)) - { - delete_job (i, 0); - ndel++; - if (ndel == nremove) - break; - } - } - - if (ndel == 0) - { - UNBLOCK_CHILD (oset); - return job_slots; - } - - newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *)); - for (i = j = 0; i < job_slots; i++) - if (jobs[i]) - newlist[j++] = jobs[i]; - - ndel = j; - for ( ; j < job_slots; j++) - newlist[j] = (JOB *)NULL; - - free (jobs); - jobs = newlist; - - UNBLOCK_CHILD (oset); - - return ndel; -} - -/* Delete the job at INDEX from the job list. Must be called - with SIGCHLD blocked. */ -void -delete_job (job_index, warn_stopped) - int job_index, warn_stopped; -{ - register JOB *temp; - - if (job_slots == 0 || jobs_list_frozen) - return; - - if (warn_stopped && subshell_environment == 0 && STOPPED (job_index)) - internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); - - temp = jobs[job_index]; - if (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); - -itrace("delete_job: deleting job %d", job_index + 1); - free (temp); -} - -/* Must be called with SIGCHLD blocked. */ -void -nohup_job (job_index) - int job_index; -{ - register JOB *temp; - - if (job_slots == 0) - return; - - if (temp = jobs[job_index]) - temp->flags |= J_NOHUP; -} - -/* 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; - 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, *p; - - t = (PROCESS *)xmalloc (sizeof (PROCESS)); - t->next = the_pipeline; - t->pid = pid; - WSTATUS (t->status) = 0; - t->running = PS_RUNNING; - t->command = name; - the_pipeline = t; - - if (t->next == 0) - t->next = t; - else - { - p = t->next; - while (p->next != t->next) - p = p->next; - p->next = t; - } -} - -#if 0 -/* Take the last job and make it the first job. Must be called with - SIGCHLD blocked. */ -int -rotate_the_pipeline () -{ - PROCESS *p; - - if (the_pipeline->next == the_pipeline) - return; - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - the_pipeline = p; -} - -/* Reverse the order of the processes in the_pipeline. Must be called with - SIGCHLD blocked. */ -int -reverse_the_pipeline () -{ - PROCESS *p, *n; - - if (the_pipeline->next == the_pipeline) - return; - - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - p->next = (PROCESS *)NULL; - - n = REVERSE_LIST (the_pipeline, PROCESS *); - - the_pipeline = n; - for (p = the_pipeline; p->next; p = p->next) - ; - p->next = the_pipeline; -} -#endif - -/* Map FUNC over the list of jobs. If FUNC returns non-zero, - then it is time to stop mapping, and that is the return value - for map_over_jobs. FUNC is called with a JOB, arg1, arg2, - and INDEX. */ -static int -map_over_jobs (func, arg1, arg2) - sh_job_map_func_t *func; - int arg1, arg2; -{ - register int i; - int result; - sigset_t set, oset; - - if (job_slots == 0) - return 0; - - BLOCK_CHILD (set, oset); - - for (i = result = 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] && STOPPED (i)) - { - killpg (jobs[i]->pgrp, SIGTERM); - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -/* Cause all jobs, running or stopped, to receive a hangup signal. If - a job is marked J_NOHUP, don't send the SIGHUP. */ -void -hangup_all_jobs () -{ - register int i; - - for (i = 0; i < job_slots; i++) - { - if (jobs[i]) - { - if ((jobs[i]->flags & J_NOHUP) == 0) - killpg (jobs[i]->pgrp, SIGHUP); - if (STOPPED (i)) - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -void -kill_current_pipeline () -{ - stop_making_children (); - start_pipeline (); -} - -/* Return the pipeline that PID belongs to. Note that the pipeline - doesn't have to belong to a job. Must be called with SIGCHLD blocked. */ -static PROCESS * -find_pipeline (pid, running_only, jobp) - pid_t pid; - int running_only; - int *jobp; /* index into jobs list or NO_JOB */ -{ - int job; - register PROCESS *p; - - /* See if this process is in the pipeline that we are building. */ - if (jobp) - *jobp = NO_JOB; - if (the_pipeline) - { - p = the_pipeline; - do - { - /* Return it if we found it. */ - if (p->pid == pid) - { - if ((running_only && PRUNNING(p)) || (running_only == 0)) - return (p); - } - - p = p->next; - } - while (p != the_pipeline); - } - - job = find_job (pid, running_only); - if (jobp) - *jobp = job; - return (job == NO_JOB) ? (PROCESS *)NULL : 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, running_only) - pid_t pid; - int running_only; -{ - 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) - { - if ((running_only && PRUNNING(p)) || (running_only == 0)) - return (i); - } - - p = p->next; - } - while (p != jobs[i]->pipe); - } - } - - return (NO_JOB); -} - -/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as - required by find_job. */ -int -get_job_by_pid (pid, block) - pid_t pid; - int block; -{ - int job; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0); - - if (block) - UNBLOCK_CHILD (oset); - - return job; -} - -/* Print descriptive information about the job with leader pid PID. */ -void -describe_pid (pid) - pid_t pid; -{ - int job; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0); - - if (job != NO_JOB) - printf ("[%d] %ld\n", job + 1, (long)pid); - else - programming_error (_("describe_pid: %ld: no such pid"), (long)pid); - - UNBLOCK_CHILD (oset); -} - -static char * -j_strsignal (s) - int s; -{ - char *x; - - x = strsignal (s); - if (x == 0) - { - x = retcode_name_buffer; - sprintf (x, "Signal %d", s); - } - return x; -} - -static char * -printable_job_status (j, p, format) - int j; - PROCESS *p; - int format; -{ - static char *temp; - int es; - - temp = "Done"; - - if (STOPPED (j) && format == 0) - { - if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) - temp = "Stopped"; - else - { - temp = retcode_name_buffer; - sprintf (temp, "Stopped(%s)", signal_name (WSTOPSIG (p->status))); - } - } - else if (RUNNING (j)) - temp = "Running"; - else - { - if (WIFSTOPPED (p->status)) - temp = j_strsignal (WSTOPSIG (p->status)); - else if (WIFSIGNALED (p->status)) - temp = j_strsignal (WTERMSIG (p->status)); - else if (WIFEXITED (p->status)) - { - temp = retcode_name_buffer; - es = WEXITSTATUS (p->status); - if (es == 0) - strcpy (temp, "Done"); - else if (posixly_correct) - sprintf (temp, "Done(%d)", es); - else - sprintf (temp, "Exit %d", es); - } - else - temp = "Unknown status"; - } - - return temp; -} - -/* This is the way to print out information on a job if you - know the index. FORMAT is: - - JLIST_NORMAL) [1]+ Running emacs - JLIST_LONG ) [1]+ 2378 Running emacs - -1 ) [1]+ 2378 emacs - - JLIST_NORMAL) [1]+ Stopped ls | more - JLIST_LONG ) [1]+ 2369 Stopped ls - 2367 | more - JLIST_PID_ONLY) - Just list the pid of the process group leader (really - the process group). - JLIST_CHANGED_ONLY) - Use format JLIST_NORMAL, but list only jobs about which - the user has not been notified. */ - -/* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into - the JOBS array corresponding to this pipeline. FORMAT is as described - above. Must be called with SIGCHLD blocked. - - If you're printing a pipeline that's not in the jobs array, like the - current pipeline as it's being created, pass -1 for JOB_INDEX */ -static void -print_pipeline (p, job_index, format, stream) - PROCESS *p; - int job_index, format; - FILE *stream; -{ - PROCESS *first, *last, *show; - int es, name_padding; - char *temp; - - if (p == 0) - return; - - first = last = p; - while (last->next != first) - last = last->next; - - for (;;) - { - if (p != first) - fprintf (stream, format ? " " : " |"); - - if (format != JLIST_STANDARD) - fprintf (stream, "%5ld", (long)p->pid); - - fprintf (stream, " "); - - if (format > -1 && job_index >= 0) - { - show = format ? p : last; - temp = printable_job_status (job_index, show, format); - - if (p != first) - { - if (format) - { - if (show->running == first->running && - WSTATUS (show->status) == WSTATUS (first->status)) - temp = ""; - } - else - temp = (char *)NULL; - } - - if (temp) - { - fprintf (stream, "%s", temp); - - es = STRLEN (temp); - if (es == 0) - es = 2; /* strlen ("| ") */ - name_padding = LONGEST_SIGNAL_DESC - es; - - fprintf (stream, "%*s", name_padding, ""); - - if ((WIFSTOPPED (show->status) == 0) && - (WIFCONTINUED (show->status) == 0) && - WIFCORED (show->status)) - fprintf (stream, "(core dumped) "); - } - } - - if (p != first && format) - fprintf (stream, "| "); - - if (p->command) - fprintf (stream, "%s", p->command); - - if (p == last && job_index >= 0) - { - temp = current_working_directory (); - - if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) - fprintf (stream, " &"); - - if (strcmp (temp, jobs[job_index]->wd) != 0) - fprintf (stream, - " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); - } - - if (format || (p == last)) - { - /* We need to add a CR only if this is an interactive shell, and - we're reporting the status of a completed job asynchronously. - We can't really check whether this particular job is being - reported asynchronously, so just add the CR if the shell is - currently interactive and asynchronous notification is enabled. */ - if (asynchronous_notification && interactive) - fprintf (stream, "\r\n"); - else - fprintf (stream, "\n"); - } - - if (p == last) - break; - p = p->next; - } - fflush (stream); -} - -/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT. - Must be called with SIGCHLD blocked or queued with queue_sigchld */ -static void -pretty_print_job (job_index, format, stream) - int job_index, format; - FILE *stream; -{ - register PROCESS *p; - - /* Format only pid information about the process group leader? */ - if (format == JLIST_PID_ONLY) - { - fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); - return; - } - - if (format == JLIST_CHANGED_ONLY) - { - if (IS_NOTIFIED (job_index)) - return; - format = JLIST_STANDARD; - } - - if (format != JLIST_NONINTERACTIVE) - fprintf (stream, "[%d]%c ", job_index + 1, - (job_index == current_job) ? '+': - (job_index == previous_job) ? '-' : ' '); - - if (format == JLIST_NONINTERACTIVE) - format = JLIST_LONG; - - p = jobs[job_index]->pipe; - - print_pipeline (p, job_index, format, stream); - - /* We have printed information about this job. When the job's - status changes, waitchld () sets the notification flag to 0. */ - jobs[job_index]->flags |= J_NOTIFIED; -} - -static int -print_job (job, format, state, job_index) - JOB *job; - int format, state, job_index; -{ - if (state == -1 || (JOB_STATE)state == job->state) - pretty_print_job (job_index, format, stdout); - return (0); -} - -void -list_one_job (job, format, ignore, job_index) - JOB *job; - int format, ignore, job_index; -{ - pretty_print_job (job_index, format, stdout); -} - -void -list_stopped_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JSTOPPED); -} - -void -list_running_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JRUNNING); -} - -/* List jobs. If FORMAT is non-zero, then the long form of the information - is printed, else just a short version. */ -void -list_all_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, -1); -} - -/* Fork, handling errors. Returns the pid of the newly made child, or 0. - COMMAND is just for remembering the name of the command; we don't do - anything else with it. ASYNC_P says what to do with the tty. If - non-zero, then don't give it away. */ -pid_t -make_child (command, async_p) - char *command; - int async_p; -{ - sigset_t set, oset; - pid_t pid; - - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGINT); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - - making_children (); - -#if defined (BUFFERED_INPUT) - /* If default_buffered_input is active, we are reading a script. If - the command is asynchronous, we have already duplicated /dev/null - as fd 0, but have not changed the buffered stream corresponding to - the old fd 0. We don't want to sync the stream in this case. */ - if (default_buffered_input != -1 && - (!async_p || default_buffered_input > 0)) - sync_buffered_stream (default_buffered_input); -#endif /* BUFFERED_INPUT */ - - /* Create the child, handle severe errors. */ - if ((pid = fork ()) < 0) - { - sys_error ("fork"); - - /* Kill all of the processes in the current pipeline. */ - terminate_current_pipeline (); - - /* Discard the current pipeline, if any. */ - if (the_pipeline) - kill_current_pipeline (); - - throw_to_top_level (); /* Reset signals, etc. */ - } - - if (pid == 0) - { - /* In the child. Give this child the right process group, set the - signals to the default state for a new process. */ - pid_t mypid; - - mypid = getpid (); -#if defined (BUFFERED_INPUT) - /* Close default_buffered_input if it's > 0. We don't close it if it's - 0 because that's the file descriptor used when redirecting input, - and it's wrong to close the file in that case. */ - unset_bash_input (0); -#endif /* BUFFERED_INPUT */ - - /* Restore top-level signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); - - if (job_control) - { - /* All processes in this pipeline belong in the same - process group. */ - - if (pipeline_pgrp == 0) /* This is the first child. */ - pipeline_pgrp = mypid; - - /* Check for running command in backquotes. */ - if (pipeline_pgrp == shell_pgrp) - ignore_tty_job_signals (); - else - default_tty_job_signals (); - - /* Set the process group before trying to mess with the terminal's - process group. This is mandated by POSIX. */ - /* This is in accordance with the Posix 1003.1 standard, - section B.7.2.4, which says that trying to set the terminal - process group with tcsetpgrp() to an unused pgrp value (like - this would have for the first child) is an error. Section - B.4.3.3, p. 237 also covers this, in the context of job control - shells. */ - if (setpgid (mypid, pipeline_pgrp) < 0) - sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp); - - /* By convention (and assumption above), if - pipeline_pgrp == shell_pgrp, we are making a child for - command substitution. - In this case, we don't want to give the terminal to the - shell's process group (we could be in the middle of a - pipeline, for example). */ - if (async_p == 0 && pipeline_pgrp != shell_pgrp) - give_terminal_to (pipeline_pgrp, 0); - -#if defined (PGRP_PIPE) - if (pipeline_pgrp == mypid) - pipe_read (pgrp_pipe); -#endif - } - else /* Without job control... */ - { - if (pipeline_pgrp == 0) - pipeline_pgrp = shell_pgrp; - - /* If these signals are set to SIG_DFL, we encounter the curious - situation of an interactive ^Z to a running process *working* - and stopping the process, but being unable to do anything with - that process to change its state. On the other hand, if they - are set to SIG_IGN, jobs started from scripts do not stop when - the shell running the script gets a SIGTSTP and stops. */ - - default_tty_job_signals (); - } - -#if defined (PGRP_PIPE) - /* Release the process group pipe, since our call to setpgid () - is done. The last call to pipe_close is done in stop_pipeline. */ - pipe_close (pgrp_pipe); -#endif /* PGRP_PIPE */ - - if (async_p) - last_asynchronous_pid = 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 == 0) - { - pipeline_pgrp = pid; - /* Don't twiddle terminal pgrps in the parent! This is the bug, - not the good thing of twiddling them in the child! */ - /* give_terminal_to (pipeline_pgrp, 0); */ - } - /* This is done on the recommendation of the Rationale section of - the POSIX 1003.1 standard, where it discusses job control and - shells. It is done to avoid possible race conditions. (Ref. - 1003.1 Rationale, section B.4.3.3, page 236). */ - setpgid (pid, pipeline_pgrp); - } - else - { - if (pipeline_pgrp == 0) - pipeline_pgrp = shell_pgrp; - } - - /* Place all processes into the jobs array regardless of the - state of job_control. */ - add_process (command, pid); - - if (async_p) - last_asynchronous_pid = pid; - - last_made_pid = pid; - - /* Unblock SIGINT and SIGCHLD. */ - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - return (pid); -} - -/* These two functions are called only in child processes. */ -void -ignore_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); -} - -void -default_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); -} - -/* When we end a job abnormally, or if we stop a job, we set the tty to the - state kept in here. When a job ends normally, we set the state in here - to the state of the tty. */ - -static TTYSTRUCT shell_tty_info; - -#if defined (NEW_TTY_DRIVER) -static struct tchars shell_tchars; -static struct ltchars shell_ltchars; -#endif /* NEW_TTY_DRIVER */ - -#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) -/* Since the BSD tty driver does not allow us to change the tty modes - while simultaneously waiting for output to drain and preserving - typeahead, we have to drain the output ourselves before calling - ioctl. We cheat by finding the length of the output queue, and - using select to wait for an appropriate length of time. This is - a hack, and should be labeled as such (it's a hastily-adapted - mutation of a `usleep' implementation). It's only reason for - existing is the flaw in the BSD tty driver. */ - -static int ttspeeds[] = -{ - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400 -}; - -static void -draino (fd, ospeed) - int fd, ospeed; -{ - register int delay = ttspeeds[ospeed]; - int n; - - if (!delay) - return; - - while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) - { - if (n > (delay / 100)) - { - struct timeval tv; - - n *= 10; /* 2 bits more for conservativeness. */ - tv.tv_sec = n / delay; - tv.tv_usec = ((n % delay) * 1000000) / delay; - select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); - } - else - break; - } -} -#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ - -/* Return the fd from which we are actually getting input. */ -#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) - -/* Fill the contents of shell_tty_info with the current tty info. */ -int -get_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) - ioctl (tty, TIOCGETP, &shell_tty_info); - ioctl (tty, TIOCGETC, &shell_tchars); - ioctl (tty, TIOCGLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCGETA, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcgetattr (tty, &shell_tty_info) < 0) - { -#if 0 - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d] tcgetattr", (long)getpid (), shell_level); -#endif - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - if (check_window_size) - get_new_window_size (0); - } - return 0; -} - -/* Make the current tty use the state in shell_tty_info. */ -int -set_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) -# if defined (DRAIN_OUTPUT) - draino (tty, shell_tty_info.sg_ospeed); -# endif /* DRAIN_OUTPUT */ - ioctl (tty, TIOCSETN, &shell_tty_info); - ioctl (tty, TIOCSETC, &shell_tchars); - ioctl (tty, TIOCSLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCSETAW, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - { - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d] tcsetattr", (long)getpid (), shell_level); - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - } - return 0; -} - -/* Given an index into the jobs array JOB, return the pid of the last - process in that job's pipeline. This is the one whose exit status - counts. Must be called with SIGCHLD blocked or queued. */ -static pid_t -find_last_pid (job, block) - int job; - int block; -{ - register PROCESS *p; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - p = jobs[job]->pipe; - while (p->next != jobs[job]->pipe) - p = p->next; - - if (block) - 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 whatever - wait_for returns otherwise. If the child is not found in the - jobs table, it returns 127. */ -int -wait_for_single_pid (pid) - pid_t pid; -{ - register PROCESS *child; - sigset_t set, oset; - int r, job; - - BLOCK_CHILD (set, oset); - child = find_pipeline (pid, 0, (int *)NULL); - UNBLOCK_CHILD (oset); - - if (child == 0) - { - internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); - return (127); - } - - r = wait_for (pid); - - /* POSIX.2: if we just waited for a job, we can remove it from the jobs - table. */ - BLOCK_CHILD (set, oset); - job = find_job (pid, 0); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - return r; -} - -/* Wait for all of the backgrounds of this shell to finish. */ -void -wait_for_background_pids () -{ - register int i, r, waited_for; - sigset_t set, oset; - pid_t pid; - - for (waited_for = 0;;) - { - BLOCK_CHILD (set, oset); - - /* find first running job; if none running in foreground, break */ - for (i = 0; i < job_slots; i++) - if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) - break; - - if (i == job_slots) - { - UNBLOCK_CHILD (oset); - break; - } - - /* now wait for the last pid in that job. */ - pid = find_last_pid (i, 0); - UNBLOCK_CHILD (oset); - QUIT; - errno = 0; /* XXX */ - r = wait_for_single_pid (pid); - if (r == -1) - { - /* If we're mistaken about job state, compensate. */ - if (errno == ECHILD) - mark_all_jobs_as_dead (); - } - else - waited_for++; - } - - /* POSIX.2 says the shell can discard the statuses of all completed jobs if - `wait' is called with no arguments. */ - mark_dead_jobs_as_notified (1); - cleanup_dead_jobs (); -} - -/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ -#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids -static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; - -static void -restore_sigint_handler () -{ - if (old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - set_signal_handler (SIGINT, old_sigint_handler); - old_sigint_handler = INVALID_SIGNAL_HANDLER; - } -} - -static int wait_sigint_received; - -/* Handle SIGINT while we are waiting for children in a script to exit. - The `wait' builtin should be interruptible, but all others should be - effectively ignored (i.e. not cause the shell to exit). */ -static sighandler -wait_sigint_handler (sig) - int sig; -{ - SigHandler *sigint_handler; - - if (interrupt_immediately || - (this_shell_builtin && this_shell_builtin == wait_builtin)) - { - last_command_exit_value = EXECUTION_FAILURE; - restore_sigint_handler (); - /* If we got a SIGINT while in `wait', and SIGINT is trapped, do - what POSIX.2 says (see builtins/wait.def for more info). */ - if (this_shell_builtin && this_shell_builtin == wait_builtin && - signal_is_trapped (SIGINT) && - ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler)) - { - interrupt_immediately = 0; - trap_handler (SIGINT); /* set pending_traps[SIGINT] */ - wait_signal_received = SIGINT; - longjmp (wait_intr_buf, 1); - } - - ADDINTERRUPT; - QUIT; - } - - /* XXX - should this be interrupt_state? If it is, the shell will act - as if it got the SIGINT interrupt. */ - wait_sigint_received = 1; - - /* Otherwise effectively ignore the SIGINT and allow the running job to - be killed. */ - SIGRETURN (0); -} - -static int -process_exit_signal (status) - WAIT status; -{ - return (WIFSIGNALED (status) ? WTERMSIG (status) : 0); -} - -static int -process_exit_status (status) - WAIT status; -{ - if (WIFSIGNALED (status)) - return (128 + WTERMSIG (status)); - else if (WIFSTOPPED (status) == 0) - return (WEXITSTATUS (status)); - else - return (EXECUTION_SUCCESS); -} - -/* Return the exit status of the last process in the pipeline for job JOB. - This is the exit status of the entire job. */ -static WAIT -raw_job_exit_status (job) - int job; -{ - register PROCESS *p; - int fail; - - if (pipefail_opt) - { - fail = 0; - for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) - if (p->status != EXECUTION_SUCCESS) fail = p->status; - return fail; - } - - for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) - ; - return (p->status); -} - -/* Return the exit status of job JOB. This is the exit status of the last - (rightmost) process in the job's pipeline, modified if the job was killed - by a signal or stopped. */ -static int -job_exit_status (job) - int job; -{ - return (process_exit_status (raw_job_exit_status (job))); -} - -static int -job_exit_signal (job) - int job; -{ - return (process_exit_signal (raw_job_exit_status (job))); -} - -#define FIND_CHILD(pid, child) \ - do \ - { \ - child = find_pipeline (pid, 0, (int *)NULL); \ - if (child == 0) \ - { \ - give_terminal_to (shell_pgrp, 0); \ - UNBLOCK_CHILD (oset); \ - internal_error (_("wait_for: No record of process %ld"), (long)pid); \ - restore_sigint_handler (); \ - return (termination_state = 127); \ - } \ - } \ - while (0) - -/* Wait for pid (one of our children) to terminate, then - return the termination state. Returns 127 if PID is not found in - the jobs table. Returns -1 if waitchld() returns -1, indicating - that there are no unwaited-for child processes. */ -int -wait_for (pid) - pid_t pid; -{ - int job, termination_state, r; - WAIT s; - register PROCESS *child; - sigset_t set, oset; - register PROCESS *p; - - /* In the case that this code is interrupted, and we longjmp () out of it, - we are relying on the code in throw_to_top_level () to restore the - top-level signal mask. */ - BLOCK_CHILD (set, oset); - - /* Ignore interrupts while waiting for a job run without job control - to finish. We don't want the shell to exit if an interrupt is - received, only if one of the jobs run is killed via SIGINT. If - job control is not set, the job will be run in the same pgrp as - the shell, and the shell will see any signals the job gets. */ - - /* This is possibly a race condition -- should it go in stop_pipeline? */ - wait_sigint_received = 0; - if (job_control == 0) - old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - - termination_state = last_command_exit_value; - - if (interactive && job_control == 0) - QUIT; - - /* If we say wait_for (), then we have a record of this child somewhere. - If it and none of its peers are running, don't call waitchld(). */ - - job = NO_JOB; - do - { - FIND_CHILD (pid, child); - - /* If this child is part of a job, then we are really waiting for the - job to finish. Otherwise, we are waiting for the child to finish. - We check for JDEAD in case the job state has been set by waitchld - after receipt of a SIGCHLD. */ - if (job == NO_JOB) - job = find_job (pid, 0); - - /* waitchld() takes care of setting the state of the job. If the job - has already exited before this is called, sigchld_handler will have - called waitchld and the state will be set to JDEAD. */ - - if (child->running || (job != NO_JOB && RUNNING (job))) - { -#if defined (WAITPID_BROKEN) /* SCOv4 */ - sigset_t suspend_set; - sigemptyset (&suspend_set); - sigsuspend (&suspend_set); -#else /* !WAITPID_BROKEN */ -# if defined (MUST_UNBLOCK_CHLD) - struct sigaction act, oact; - sigset_t nullset, chldset; - - sigemptyset (&nullset); - sigemptyset (&chldset); - sigprocmask (SIG_SETMASK, &nullset, &chldset); - act.sa_handler = SIG_DFL; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - act.sa_flags = 0; - sigaction (SIGCHLD, &act, &oact); -# endif - queue_sigchld = 1; - r = waitchld (pid, 1); -# if defined (MUST_UNBLOCK_CHLD) - sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); - sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); -# endif - queue_sigchld = 0; - if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin) - { - termination_state = -1; - goto wait_for_return; - } - - /* If child is marked as running, but waitpid() returns -1/ECHILD, - there is something wrong. Somewhere, wait should have returned - that child's pid. Mark the child as not running and the job, - if it exists, as JDEAD. */ - if (r == -1 && errno == ECHILD) - { - child->running = PS_DONE; - child->status = 0; /* XXX -- can't find true status */ - if (job != NO_JOB) - jobs[job]->state = JDEAD; - } -#endif /* WAITPID_BROKEN */ - } - - /* If the shell is interactive, and job control is disabled, see - if the foreground process has died due to SIGINT and jump out - of the wait loop if it has. waitchld has already restored the - old SIGINT signal handler. */ - if (interactive && job_control == 0) - QUIT; - } - while (child->running || (job != NO_JOB && RUNNING (job))); - - /* The exit state of the command is either the termination state of the - child, or the termination state of the job. If a job, the status - of the last child in the pipeline is the significant one. If the command - or job was terminated by a signal, note that value also. */ - termination_state = (job != NO_JOB) ? job_exit_status (job) - : process_exit_status (child->status); - last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job) - : process_exit_signal (child->status); - - if (job == NO_JOB || IS_JOBCONTROL (job)) - { - /* XXX - under what circumstances is a job not present in the jobs - table (job == NO_JOB)? - 1. command substitution - - In the case of command substitution, at least, it's probably not - the right thing to give the terminal to the shell's process group, - even though there is code in subst.c:command_substitute to work - around it. - - Things that don't: - $PROMPT_COMMAND execution - process substitution - */ -#if 0 -if (job == NO_JOB) - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); -#endif - - give_terminal_to (shell_pgrp, 0); - } - - /* If the command did not exit cleanly, or the job is just - being stopped, then reset the tty state back to what it - was before this command. Reset the tty state and notify - the user of the job termination only if the shell is - interactive. Clean up any dead jobs in either case. */ - if (job != NO_JOB) - { - if (interactive_shell && subshell_environment == 0) - { - /* This used to use `child->status'. That's wrong, however, for - pipelines. `child' is the first process in the pipeline. It's - likely that the process we want to check for abnormal termination - or stopping is the last process in the pipeline, especially if - it's long-lived and the first process is short-lived. Since we - know we have a job here, we can check all the processes in this - job's pipeline and see if one of them stopped or terminated due - to a signal. We might want to change this later to just check - the last process in the pipeline. If no process exits due to a - signal, S is left as the status of the last job in the pipeline. */ - p = jobs[job]->pipe; - do - { - s = p->status; - if (WIFSIGNALED(s) || WIFSTOPPED(s)) - break; - p = p->next; - } - while (p != jobs[job]->pipe); - - if (WIFSIGNALED (s) || WIFSTOPPED (s)) - { - set_tty_state (); - - /* If the current job was stopped or killed by a signal, and - the user has requested it, get a possibly new window size */ - if (check_window_size && (job == current_job || IS_FOREGROUND (job))) - get_new_window_size (0); - } - else - get_tty_state (); - - /* If job control is enabled, the job was started with job - control, the job was the foreground job, and it was killed - by SIGINT, then print a newline to compensate for the kernel - printing the ^C without a trailing newline. */ - if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && - WIFSIGNALED (s) && WTERMSIG (s) == SIGINT) - { - /* If SIGINT is not trapped and the shell is in a for, while, - or until loop, act as if the shell received SIGINT as - well, so the loop can be broken. This doesn't call the - SIGINT signal handler; maybe it should. */ - if (signal_is_trapped (SIGINT) == 0 && loop_level) - ADDINTERRUPT; - else - { - putchar ('\n'); - fflush (stdout); - } - } - } - - /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD - signal handler path */ - if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/) - setjstatus (job); - - /* If this job is dead, notify the user of the status. If the shell - is interactive, this will display a message on the terminal. If - the shell is not interactive, make sure we turn on the notify bit - so we don't get an unwanted message about the job's termination, - and so delete_job really clears the slot in the jobs table. */ - notify_and_cleanup (); - } - -wait_for_return: - - UNBLOCK_CHILD (oset); - - /* Restore the original SIGINT signal handler before we return. */ - restore_sigint_handler (); - - return (termination_state); -} - -/* Wait for the last process in the pipeline for JOB. Returns whatever - wait_for returns: the last process's termination state or -1 if there - are no unwaited-for child processes or an error occurs. */ -int -wait_for_job (job) - int job; -{ - pid_t pid; - int r; - sigset_t set, oset; - - BLOCK_CHILD(set, oset); - if (JOBSTATE (job) == JSTOPPED) - internal_warning (_("wait_for_job: job %d is stopped"), job+1); - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD(oset); - r = wait_for (pid); - - /* POSIX.2: we can remove the job from the jobs table if we just waited - for it. */ - BLOCK_CHILD (set, oset); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - return r; -} - -/* Print info about dead jobs, and then delete them from the list - of known jobs. This does not actually delete jobs when the - shell is not interactive, because the dead jobs are not marked - as notified. */ -void -notify_and_cleanup () -{ - if (jobs_list_frozen) - return; - - if (interactive || interactive_shell == 0 || sourcelevel) - notify_of_job_status (); - - cleanup_dead_jobs (); -} - -/* Make dead jobs disappear from the jobs array without notification. - This is used when the shell is not interactive. */ -void -reap_dead_jobs () -{ - mark_dead_jobs_as_notified (0); - cleanup_dead_jobs (); -} - -/* Return the next closest (chronologically) job to JOB which is in - STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if - there is no next recent job. */ -static int -most_recent_job_in_state (job, state) - int job; - JOB_STATE state; -{ - register int i, result; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - for (result = NO_JOB, i = job - 1; i >= 0; i--) - { - if (jobs[i] && (JOBSTATE (i) == state)) - { - result = i; - break; - } - } - - UNBLOCK_CHILD (oset); - - return (result); -} - -/* Return the newest *stopped* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_stopped (job) - int job; -{ - return (most_recent_job_in_state (job, JSTOPPED)); -} - -/* Return the newest *running* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_running (job) - int job; -{ - return (most_recent_job_in_state (job, JRUNNING)); -} - -/* Make JOB be the current job, and make previous be useful. Must be - called with SIGCHLD blocked. */ -static void -set_current_job (job) - int job; -{ - int candidate; - - if (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] && - STOPPED (previous_job)) - return; - - /* Second choice: Newest stopped job that is older than - the current job. */ - candidate = NO_JOB; - if (STOPPED (current_job)) - { - candidate = job_last_stopped (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. */ - - candidate = RUNNING (current_job) ? job_last_running (current_job) - : job_last_running (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; - - if (job_slots && current_job != NO_JOB && jobs[current_job] && STOPPED (current_job)) - candidate = current_job; - else - { - candidate = NO_JOB; - - /* First choice: the previous job. */ - if (previous_job != NO_JOB && jobs[previous_job] && STOPPED (previous_job)) - candidate = previous_job; - - /* Second choice: the most recently stopped job. */ - if (candidate == NO_JOB) - candidate = job_last_stopped (job_slots); - - /* Third choice: the newest running job. */ - if (candidate == NO_JOB) - candidate = job_last_running (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; -} - -/* Set up the job structures so we know the job and its processes are - all running. */ -static void -set_job_running (job) - int job; -{ - register PROCESS *p; - - /* Each member of the pipeline is now running. */ - p = jobs[job]->pipe; - - do - { - if (WIFSTOPPED (p->status)) - p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */ - p = p->next; - } - while (p != jobs[job]->pipe); - - /* This means that the job is running. */ - JOBSTATE (job) = JRUNNING; -} - -/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, - start the job in the background. JOB is a zero-based index into - JOBS. Returns -1 if it is unable to start a job, and the return - status of the job otherwise. */ -int -start_job (job, foreground) - int job, foreground; -{ - register PROCESS *p; - int already_running; - sigset_t set, oset; - char *wd; - static TTYSTRUCT save_stty; - - BLOCK_CHILD (set, oset); - - if (DEADJOB (job)) - { - internal_error (_("%s: job has terminated"), this_command_name); - UNBLOCK_CHILD (oset); - return (-1); - } - - already_running = RUNNING (job); - - if (foreground == 0 && already_running) - { - internal_error (_("%s: job %d already in background"), this_command_name, job + 1); - UNBLOCK_CHILD (oset); - return (-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 == 0) - 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 == 0) - 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 == 0) - set_job_running (job); - - /* Save the tty settings before we start the job in the foreground. */ - if (foreground) - { - get_tty_state (); - save_stty = shell_tty_info; - /* Give the terminal to this job. */ - if (IS_JOBCONTROL (job)) - give_terminal_to (jobs[job]->pgrp, 0); - } - else - jobs[job]->flags &= ~J_FOREGROUND; - - /* If the job is already running, then don't bother jump-starting it. */ - if (already_running == 0) - { - jobs[job]->flags |= J_NOTIFIED; - killpg (jobs[job]->pgrp, SIGCONT); - } - - if (foreground) - { - pid_t pid; - int s; - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD (oset); - s = wait_for (pid); - shell_tty_info = save_stty; - set_tty_state (); - return (s); - } - else - { - reset_current (); - UNBLOCK_CHILD (oset); - return (0); - } -} - -/* Give PID SIGNAL. This determines what job the pid belongs to (if any). - If PID does belong to a job, and the job is stopped, then CONTinue the - job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, - then kill the process group associated with PID. */ -int -kill_pid (pid, sig, group) - pid_t pid; - int sig, group; -{ - register PROCESS *p; - int job, result; - sigset_t set, oset; - - result = EXECUTION_SUCCESS; - if (group) - { - BLOCK_CHILD (set, oset); - p = find_pipeline (pid, 0, &job); - - if (job != NO_JOB) - { - jobs[job]->flags &= ~J_NOTIFIED; - - /* Kill process in backquotes or one started without job control? */ - if (jobs[job]->pgrp == shell_pgrp) - { - p = jobs[job]->pipe; - - do - { - kill (p->pid, sig); - if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP)) - kill (p->pid, SIGCONT); - p = p->next; - } - while (p != jobs[job]->pipe); - } - else - { - result = killpg (jobs[job]->pgrp, sig); - if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) - killpg (jobs[job]->pgrp, SIGCONT); - /* If we're continuing a stopped job via kill rather than bg or - fg, emulate the `bg' behavior. */ - if (p && STOPPED (job) && (sig == SIGCONT)) - { - set_job_running (job); - jobs[job]->flags &= ~J_FOREGROUND; - jobs[job]->flags |= J_NOTIFIED; - } - } - } - else - result = killpg (pid, sig); - - UNBLOCK_CHILD (oset); - } - else - result = kill (pid, sig); - - return (result); -} - -/* sigchld_handler () flushes at least one of the children that we are - waiting for. It gets run when we have gotten a SIGCHLD signal. */ -static sighandler -sigchld_handler (sig) - int sig; -{ - int n, oerrno; - - oerrno = errno; - REINSTALL_SIGCHLD_HANDLER; - sigchld++; - n = 0; - if (queue_sigchld == 0) - n = waitchld (-1, 0); - errno = oerrno; - SIGRETURN (n); -} - -/* waitchld() reaps dead or stopped children. It's called by wait_for and - sigchld_handler, and runs until there aren't any children terminating any - more. - If BLOCK is 1, this is to be a blocking wait for a single child, although - an arriving SIGCHLD could cause the wait to be non-blocking. It returns - the number of children reaped, or -1 if there are no unwaited-for child - processes. */ -static int -waitchld (wpid, block) - pid_t wpid; - int block; -{ - WAIT status; - PROCESS *child; - pid_t pid; - int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; - - call_set_current = children_exited = 0; - last_stopped_job = NO_JOB; - - do - { - /* We don't want to be notified about jobs stopping if job control - is not active. XXX - was interactive_shell instead of job_control */ - waitpid_flags = (job_control && subshell_environment == 0) - ? (WUNTRACED|WCONTINUED) - : 0; - if (sigchld || block == 0) - waitpid_flags |= WNOHANG; - pid = WAITPID (-1, &status, waitpid_flags); - - /* The check for WNOHANG is to make sure we decrement sigchld only - if it was non-zero before we called waitpid. */ - if (sigchld > 0 && (waitpid_flags & WNOHANG)) - sigchld--; - - /* If waitpid returns -1 with errno == ECHILD, there are no more - unwaited-for child processes of this shell. */ - if (pid < 0 && errno == ECHILD) - { - if (children_exited == 0) - return -1; - else - break; - } - - /* If waitpid returns 0, there are running children. If it returns -1, - the only other error POSIX says it can return is EINTR. */ - if (pid <= 0) - continue; /* jumps right to the test */ - - /* children_exited is used to run traps on SIGCHLD. We don't want to - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) - children_exited++; - - /* Locate our PROCESS for this pid. */ - child = find_pipeline (pid, 1, &job); /* want running procs only */ - - /* It is not an error to have a child terminate that we did - not have a record of. This child could have been part of - a pipeline in backquote substitution. Even so, I'm not - sure child is ever non-zero. */ - if (child == 0) - continue; - - while (child->pid != pid) - child = child->next; - - /* Remember status, and whether or not the process is running. */ - child->status = status; - child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE; - - if (job == NO_JOB) - continue; - - call_set_current += set_job_status_and_cleanup (job); - - if (STOPPED (job)) - last_stopped_job = job; - else if (DEADJOB (job) && last_stopped_job == job) - last_stopped_job = NO_JOB; - } - while ((sigchld || block == 0) && pid > (pid_t)0); - - /* If a job was running and became stopped, then set the current - job. Otherwise, don't change a thing. */ - if (call_set_current) - { - if (last_stopped_job != NO_JOB) - set_current_job (last_stopped_job); - else - reset_current (); - } - - /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ - if (job_control && signal_is_trapped (SIGCHLD) && children_exited && - trap_list[SIGCHLD] != (char *)IGNORE_SIG) - run_sigchld_trap (children_exited); - - /* We have successfully recorded the useful information about this process - that has just changed state. If we notify asynchronously, and the job - that this process belongs to is no longer running, then notify the user - of that fact now. */ - if (asynchronous_notification && interactive) - notify_of_job_status (); - - return (children_exited); -} - -/* Set the status of JOB and perform any necessary cleanup if the job is - marked as JDEAD. - - Currently, the cleanup activity is restricted to handling any SIGINT - received while waiting for a foreground job to finish. */ -static int -set_job_status_and_cleanup (job) - int job; -{ - PROCESS *child; - int tstatus, job_state, any_stopped, any_tstped, call_set_current; - SigHandler *temp_handler; - - child = jobs[job]->pipe; - jobs[job]->flags &= ~J_NOTIFIED; - - call_set_current = 0; - - /* - * COMPUTE JOB STATUS - */ - - /* If all children are not running, but any of them is stopped, then - the job is stopped, not dead. */ - job_state = any_stopped = any_tstped = 0; - do - { - job_state |= child->running; - if (child->running == PS_DONE && (WIFSTOPPED (child->status))) - { - any_stopped = 1; - any_tstped |= interactive && job_control && - (WSTOPSIG (child->status) == SIGTSTP); - } - child = child->next; - } - while (child != jobs[job]->pipe); - - /* If job_state != 0, the job is still running, so don't bother with - setting the process exit status and job state unless we're - transitioning from stopped to running. */ - if (job_state != 0 && JOBSTATE(job) != JSTOPPED) - return 0; - - /* - * SET JOB STATUS - */ - - /* The job is either stopped or dead. Set the state of the job accordingly. */ - if (any_stopped) - { - jobs[job]->state = JSTOPPED; - jobs[job]->flags &= ~J_FOREGROUND; - call_set_current++; - /* Suspending a job with SIGTSTP breaks all active loops. */ - if (any_tstped && loop_level) - breaking = loop_level; - } - else if (job_state != 0) /* was stopped, now running */ - { - jobs[job]->state = JRUNNING; - call_set_current++; - } - else - { - jobs[job]->state = JDEAD; - -#if 0 - if (IS_FOREGROUND (job)) - setjstatus (job); -#endif - - /* If this job has a cleanup function associated with it, call it - with `cleanarg' as the single argument, then set the function - pointer to NULL so it is not inadvertently called twice. The - cleanup function is responsible for deallocating cleanarg. */ - if (jobs[job]->j_cleanup) - { - (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); - jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; - } - } - - /* - * CLEANUP - * - * Currently, we just do special things if we got a SIGINT while waiting - * for a foreground job to complete - */ - - if (jobs[job]->state == JDEAD) - { - /* If we're running a shell script and we get a SIGINT with a - SIGINT trap handler, but the foreground job handles it and - does not exit due to SIGINT, run the trap handler but do not - otherwise act as if we got the interrupt. */ - if (wait_sigint_received && interactive_shell == 0 && - WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) && - signal_is_trapped (SIGINT)) - { - int old_frozen; - wait_sigint_received = 0; - last_command_exit_value = process_exit_status (child->status); - - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - } - - /* If the foreground job is killed by SIGINT when job control is not - active, we need to perform some special handling. - - The check of wait_sigint_received is a way to determine if the - SIGINT came from the keyboard (in which case the shell has already - seen it, and wait_sigint_received is non-zero, because keyboard - signals are sent to process groups) or via kill(2) to the foreground - process by another process (or itself). If the shell did receive the - SIGINT, it needs to perform normal SIGINT processing. */ - else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) && - IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0) - { - int old_frozen; - - wait_sigint_received = 0; - - /* If SIGINT is trapped, set the exit status so that the trap - handler can see it. */ - if (signal_is_trapped (SIGINT)) - last_command_exit_value = process_exit_status (child->status); - - /* If the signal is trapped, let the trap handler get it no matter - what and simply return if the trap handler returns. - maybe_call_trap_handler() may cause dead jobs to be removed from - the job table because of a call to execute_command. We work - around this by setting JOBS_LIST_FROZEN. */ - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - /* wait_sigint_handler () has already seen SIGINT and - allowed the wait builtin to jump out. We need to - call the original SIGINT handler, if necessary. If - the original handler is SIG_DFL, we need to resend - the signal to ourselves. */ - - temp_handler = old_sigint_handler; - - /* Bogus. If we've reset the signal handler as the result - of a trap caught on SIGINT, then old_sigint_handler - will point to trap_handler, which now knows nothing about - SIGINT (if we reset the sighandler to the default). - In this case, we have to fix things up. What a crock. */ - if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0) - temp_handler = trap_to_sighandler (SIGINT); - restore_sigint_handler (); - if (temp_handler == SIG_DFL) - termination_unwind_protect (SIGINT); - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); - } - } - } - - return call_set_current; -} - -/* Build the array of values for the $PIPESTATUS variable from the set of - exit statuses of all processes in the job J. */ -static void -setjstatus (j) - int j; -{ -#if defined (ARRAY_VARS) - register int i; - register PROCESS *p; - - for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++) - ; - i++; - if (statsize < i) - { - pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int)); - statsize = i; - } - i = 0; - p = jobs[j]->pipe; - do - { - pstatuses[i++] = process_exit_status (p->status); - p = p->next; - } - while (p != jobs[j]->pipe); - - pstatuses[i] = -1; /* sentinel */ - set_pipestatus_array (pstatuses, i); -#endif -} - -static void -run_sigchld_trap (nchild) - int nchild; -{ - char *trap_command; - int i; - - /* Turn off the trap list during the call to parse_and_execute () - to avoid potentially infinite recursive calls. Preserve the - values of last_command_exit_value, last_made_pid, and the_pipeline - around the execution of the trap commands. */ - trap_command = savestring (trap_list[SIGCHLD]); - - begin_unwind_frame ("SIGCHLD trap"); - unwind_protect_int (last_command_exit_value); - unwind_protect_int (last_command_exit_signal); - unwind_protect_var (last_made_pid); - unwind_protect_int (interrupt_immediately); - unwind_protect_int (jobs_list_frozen); - unwind_protect_pointer (the_pipeline); - unwind_protect_pointer (subst_assign_varlist); - - /* We have to add the commands this way because they will be run - in reverse order of adding. We don't want maybe_set_sigchld_trap () - to reference freed memory. */ - add_unwind_protect (xfree, trap_command); - add_unwind_protect (maybe_set_sigchld_trap, trap_command); - - subst_assign_varlist = (WORD_LIST *)NULL; - the_pipeline = (PROCESS *)NULL; - - restore_default_signal (SIGCHLD); - jobs_list_frozen = 1; - for (i = 0; i < nchild; i++) - { - interrupt_immediately = 1; - parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); - } - - run_unwind_frame ("SIGCHLD trap"); -} - -/* Function to call when you want to notify people of changes - in job status. This prints out all jobs which are pending - notification to stderr, and marks those printed as already - notified, thus making them candidates for cleanup. */ -static void -notify_of_job_status () -{ - register int job, termsig; - char *dir; - sigset_t set, oset; - WAIT s; - - if (jobs == 0 || job_slots == 0) - return; - - if (old_ttou != 0) - { - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGTTOU); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - } - else - queue_sigchld++; - - for (job = 0, dir = (char *)NULL; job < job_slots; job++) - { - if (jobs[job] && IS_NOTIFIED (job) == 0) - { - s = raw_job_exit_status (job); - termsig = WTERMSIG (s); - - /* POSIX.2 says we have to hang onto the statuses of at most the - last CHILD_MAX background processes if the shell is running a - script. If the shell is not interactive, don't print anything - unless the job was killed by a signal. */ - if (startup_state == 0 && WIFSIGNALED (s) == 0 && - ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) - continue; - -#if 0 - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2, we were started to run `-c command', so - don't print anything. */ - if ((job_control == 0 && interactive_shell) || startup_state == 2) -#else - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2 and subshell_environment has the - SUBSHELL_COMSUB bit turned on, we were started to run a command - substitution, so don't print anything. */ - if ((job_control == 0 && interactive_shell) || - (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB))) -#endif - { - /* POSIX.2 compatibility: if the shell is not interactive, - hang onto the job corresponding to the last asynchronous - pid until the user has been notified of its status or does - a `wait'. */ - if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid))) - jobs[job]->flags |= J_NOTIFIED; - continue; - } - - /* Print info on jobs that are running in the background, - and on foreground jobs that were killed by anything - except SIGINT (and possibly SIGPIPE). */ - switch (JOBSTATE (job)) - { - case JDEAD: - if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && - termsig != SIGINT && -#if defined (DONT_REPORT_SIGPIPE) - termsig != SIGPIPE && -#endif - signal_is_trapped (termsig) == 0) - { - /* Don't print `0' for a line number. */ - fprintf (stderr, "%s: line %d: ", get_name_for_error (), (line_number == 0) ? 1 : line_number); - pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); - } - else if (IS_FOREGROUND (job)) - { -#if !defined (DONT_REPORT_SIGPIPE) - if (termsig && WIFSIGNALED (s) && termsig != SIGINT) -#else - if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE) -#endif - { - fprintf (stderr, "%s", j_strsignal (termsig)); - - if (WIFCORED (s)) - fprintf (stderr, " (core dumped)"); - - fprintf (stderr, "\n"); - } - } - else - { - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && strcmp (dir, jobs[job]->wd) != 0) - fprintf (stderr, - "(wd now: %s)\n", polite_directory_format (dir)); - } - - jobs[job]->flags |= J_NOTIFIED; - break; - - case JSTOPPED: - fprintf (stderr, "\n"); - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && (strcmp (dir, jobs[job]->wd) != 0)) - fprintf (stderr, - "(wd now: %s)\n", polite_directory_format (dir)); - jobs[job]->flags |= J_NOTIFIED; - break; - - case JRUNNING: - case JMIXED: - break; - - default: - programming_error ("notify_of_job_status"); - } - } - } - if (old_ttou != 0) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - else - queue_sigchld--; -} - -/* Initialize the job control mechanism, and set up the tty stuff. */ -int -initialize_job_control (force) - int force; -{ - shell_pgrp = getpgid (0); - - if (shell_pgrp == -1) - { - sys_error ("initialize_job_control: getpgrp failed"); - exit (1); - } - - /* We can only have job control if we are interactive. */ - if (interactive == 0) - { - job_control = 0; - original_pgrp = NO_PID; - shell_tty = fileno (stderr); - } - else - { - /* Get our controlling terminal. If job_control is set, or - interactive is set, then this is an interactive shell no - matter where fd 2 is directed. */ - shell_tty = dup (fileno (stderr)); /* fd 2 */ - - shell_tty = move_to_high_fd (shell_tty, 1, -1); - - /* Compensate for a bug in systems that compiled the BSD - rlogind with DEBUG defined, like NeXT and Alliant. */ - if (shell_pgrp == 0) - { - shell_pgrp = getpid (); - setpgid (0, shell_pgrp); - tcsetpgrp (shell_tty, shell_pgrp); - } - - while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1) - { - if (shell_pgrp != terminal_pgrp) - { - SigHandler *ottin; - - ottin = set_signal_handler(SIGTTIN, SIG_DFL); - kill (0, SIGTTIN); - set_signal_handler (SIGTTIN, ottin); - continue; - } - break; - } - - /* Make sure that we are using the new line discipline. */ - if (set_new_line_discipline (shell_tty) < 0) - { - sys_error ("initialize_job_control: line discipline"); - job_control = 0; - } - else - { - original_pgrp = shell_pgrp; - shell_pgrp = getpid (); - - if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) - { - sys_error ("initialize_job_control: setpgid"); - shell_pgrp = original_pgrp; - } - - job_control = 1; - - /* If (and only if) we just set our process group to our pid, - thereby becoming a process group leader, and the terminal - is not in the same process group as our (new) process group, - then set the terminal's process group to our (new) process - group. If that fails, set our process group back to what it - was originally (so we can still read from the terminal) and - turn off job control. */ - if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp) - { - if (give_terminal_to (shell_pgrp, 0) < 0) - { - setpgid (0, original_pgrp); - shell_pgrp = original_pgrp; - job_control = 0; - } - } - } - if (job_control == 0) - internal_error (_("no job control in this shell")); - } - - if (shell_tty != fileno (stderr)) - SET_CLOSE_ON_EXEC (shell_tty); - - set_signal_handler (SIGCHLD, sigchld_handler); - - change_flag ('m', job_control ? '-' : '+'); - - if (interactive) - get_tty_state (); - - return job_control; -} - -#ifdef DEBUG -void -debug_print_pgrps () -{ - itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", - (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); - itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", - shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); -} -#endif - -/* Set the line discipline to the best this system has to offer. - Return -1 if this is not possible. */ -static int -set_new_line_discipline (tty) - int tty; -{ -#if defined (NEW_TTY_DRIVER) - int ldisc; - - if (ioctl (tty, TIOCGETD, &ldisc) < 0) - return (-1); - - if (ldisc != NTTYDISC) - { - ldisc = NTTYDISC; - - if (ioctl (tty, TIOCSETD, &ldisc) < 0) - return (-1); - } - return (0); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) -# if defined (TERMIO_LDISC) && (NTTYDISC) - if (ioctl (tty, TCGETA, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIO_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (TERMIOS_LDISC) && defined (NTTYDISC) - if (tcgetattr (tty, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIOS_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIOS_TTY_DRIVER */ - -#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) - return (-1); -#endif -} - -#if defined (TIOCGWINSZ) && defined (SIGWINCH) -static void -get_new_window_size (from_sig) - int from_sig; -{ - struct winsize win; - - 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 - sh_set_lines_and_columns (win.ws_row, win.ws_col); -#if defined (READLINE) - rl_set_screen_size (win.ws_row, win.ws_col); -#endif - } -} - -static sighandler -sigwinch_sighandler (sig) - int sig; -{ -#if defined (MUST_REINSTALL_SIGHANDLERS) - set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* MUST_REINSTALL_SIGHANDLERS */ - get_new_window_size (1); - SIGRETURN (0); -} -#else -static void -get_new_window_size (from_sig) - int from_sig; -{ -} -#endif /* TIOCGWINSZ && SIGWINCH */ - -void -set_sigwinch_handler () -{ -#if defined (TIOCGWINSZ) && defined (SIGWINCH) - old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif -} - -void -unset_sigwinch_handler () -{ -#if defined (TIOCGWINSZ) && defined (SIGWINCH) - set_signal_handler (SIGWINCH, old_winch); -#endif -} - -/* Setup this shell to handle C-C, etc. */ -void -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); - set_sigwinch_handler (); - } - else if (job_control) - { - old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler); - old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler); - old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler); - } - /* Leave these things alone for non-interactive shells without job - control. */ -} - -/* Here we handle CONT signals. */ -static sighandler -sigcont_sighandler (sig) - int sig; -{ - initialize_job_signals (); - set_signal_handler (SIGCONT, old_cont); - kill (getpid (), SIGCONT); - - SIGRETURN (0); -} - -/* Here we handle stop signals while we are running not as a login shell. */ -static sighandler -sigstop_sighandler (sig) - int sig; -{ - set_signal_handler (SIGTSTP, old_tstp); - set_signal_handler (SIGTTOU, old_ttou); - set_signal_handler (SIGTTIN, old_ttin); - - old_cont = set_signal_handler (SIGCONT, sigcont_sighandler); - - give_terminal_to (shell_pgrp, 0); - - kill (getpid (), sig); - - SIGRETURN (0); -} - -/* Give the terminal to PGRP. */ -int -give_terminal_to (pgrp, force) - pid_t pgrp; - int force; -{ - sigset_t set, oset; - int r; - - r = 0; - if (job_control || force) - { - sigemptyset (&set); - sigaddset (&set, SIGTTOU); - sigaddset (&set, SIGTTIN); - sigaddset (&set, SIGTSTP); - sigaddset (&set, SIGCHLD); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - - if (tcsetpgrp (shell_tty, pgrp) < 0) - { - /* Maybe we should print an error message? */ -#if 0 - sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", - shell_tty, (long)getpid(), (long)pgrp); -#endif - r = -1; - } - else - terminal_pgrp = pgrp; - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - return r; -} - -/* Clear out any jobs in the job array. This is intended to be used by - children of the shell, who should not have any job structures as baggage - when they start executing (forking subshells for parenthesized execution - and functions with pipes are the two that spring to mind). If RUNNING_ONLY - is nonzero, only running jobs are removed from the table. */ -void -delete_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - if (job_slots) - { - current_job = previous_job = NO_JOB; - - for (i = 0; i < job_slots; i++) - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - delete_job (i, 1); - - if (running_only == 0) - { - free ((char *)jobs); - job_slots = 0; - } - } - - UNBLOCK_CHILD (oset); -} - -/* Mark all jobs in the job array so that they don't get a SIGHUP when the - shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ -void -nohup_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - if (job_slots) - { - for (i = 0; i < job_slots; i++) - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - nohup_job (i); - } - - UNBLOCK_CHILD (oset); -} - -int -count_all_jobs () -{ - int i, n; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - for (i = n = 0; i < job_slots; i++) - if (jobs[i] && DEADJOB(i) == 0) - n++; - UNBLOCK_CHILD (oset); - return n; -} - -static void -mark_all_jobs_as_dead () -{ - register int i; - sigset_t set, oset; - - if (job_slots == 0) - return; - - BLOCK_CHILD (set, oset); - - for (i = 0; i < job_slots; i++) - if (jobs[i]) - jobs[i]->state = JDEAD; - - UNBLOCK_CHILD (oset); -} - -/* Mark all dead jobs as notified, so delete_job () cleans them out - of the job table properly. POSIX.2 says we need to save the - status of the last CHILD_MAX jobs, so we count the number of dead - jobs and mark only enough as notified to save CHILD_MAX statuses. */ -static void -mark_dead_jobs_as_notified (force) - int force; -{ - register int i, ndead; - sigset_t set, oset; - - if (job_slots == 0) - return; - - BLOCK_CHILD (set, oset); - - /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses - around; just run through the array. */ - if (force) - { - for (i = 0; i < job_slots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - jobs[i]->flags |= J_NOTIFIED; - } - UNBLOCK_CHILD (oset); - return; - } - - /* Mark enough dead jobs as notified to keep CHILD_MAX jobs left in the - array not marked as notified. */ - - /* Count the number of dead jobs */ - for (i = ndead = 0; i < job_slots; i++) - { - if (jobs[i] && DEADJOB (i)) - ndead++; - } - - if (child_max < 0) - child_max = getmaxchild (); - if (child_max < 0) - child_max = DEFAULT_CHILD_MAX; - - /* Don't do anything if the number of dead jobs is less than CHILD_MAX and - we're not forcing a cleanup. */ - if (ndead <= child_max) - { - UNBLOCK_CHILD (oset); - return; - } - - /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in - the list. This isn't exactly right yet; changes need to be made - to stop_pipeline so we don't mark the newer jobs after we've - created CHILD_MAX slots in the jobs array. */ - for (i = 0; i < job_slots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - { - jobs[i]->flags |= J_NOTIFIED; - if (--ndead <= child_max) - break; - } - } - - UNBLOCK_CHILD (oset); -} - -/* Here to allow other parts of the shell (like the trap stuff) to - unfreeze the jobs list. */ -void -unfreeze_jobs_list () -{ - jobs_list_frozen = 0; -} - -/* Allow or disallow job control to take place. Returns the old value - of job_control. */ -int -set_job_control (arg) - int arg; -{ - int old; - - old = job_control; - job_control = arg; - - /* If we're turning on job control, reset pipeline_pgrp so make_child will - put new child processes into the right pgrp */ - if (job_control != old && job_control) - pipeline_pgrp = 0; - - return (old); -} - -/* Turn off all traces of job control. This is run by children of the shell - which are going to do shellsy things, like wait (), etc. */ -void -without_job_control () -{ - stop_making_children (); - start_pipeline (); - delete_all_jobs (0); - set_job_control (0); -} - -/* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. This is done - before the `exec' builtin calls shell_execve. */ -void -end_job_control () -{ - if (interactive_shell) /* XXX - should it be interactive? */ - { - terminate_stopped_jobs (); - - if (original_pgrp >= 0) - give_terminal_to (original_pgrp, 1); - } - - if (original_pgrp >= 0) - setpgid (0, original_pgrp); -} - -/* Restart job control by closing shell tty and reinitializing. This is - called after an exec fails in an interactive shell and we do not exit. */ -void -restart_job_control () -{ - if (shell_tty != -1) - close (shell_tty); - initialize_job_control (0); -} - -/* Set the handler to run when the shell receives a SIGCHLD signal. */ -void -set_sigchld_handler () -{ - set_signal_handler (SIGCHLD, sigchld_handler); -} - -#if defined (PGRP_PIPE) -/* Read from the read end of a pipe. This is how the process group leader - blocks until all of the processes in a pipeline have been made. */ -static void -pipe_read (pp) - int *pp; -{ - char ch; - - if (pp[1] >= 0) - { - close (pp[1]); - pp[1] = -1; - } - - if (pp[0] >= 0) - { - while (read (pp[0], &ch, 1) == -1 && errno == EINTR) - ; - } -} - -/* Close the read and write ends of PP, an array of file descriptors. */ -static void -pipe_close (pp) - int *pp; -{ - if (pp[0] >= 0) - close (pp[0]); - - if (pp[1] >= 0) - close (pp[1]); - - pp[0] = pp[1] = -1; -} - -/* Functional interface closes our local-to-job-control pipes. */ -void -close_pgrp_pipe () -{ - pipe_close (pgrp_pipe); -} - -#endif /* PGRP_PIPE */ diff --git a/jobs.h~ b/jobs.h~ deleted file mode 100644 index 1e21f8cb7..000000000 --- a/jobs.h~ +++ /dev/null @@ -1,182 +0,0 @@ -/* 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_JOBS_H_) -# define _JOBS_H_ - -#include "quit.h" -#include "siglist.h" - -#include "stdc.h" - -#include "posixwait.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 -#define JLIST_NONINTERACTIVE 4 - -/* 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. */ - -/* Values for the `running' field of a struct process. */ -#define PS_DONE 0 -#define PS_RUNNING 1 -#define PS_STOPPED 2 - -/* 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; - -/* PRUNNING really means `not exited' */ -#define PRUNNING(p) ((p)->running || WIFSTOPPED((p)->status)) -#define PSTOPPED(p) (WIFSTOPPED((p)->status)) -#define PDEADPROC(p) ((p)->running == PS_DONE) - -/* A description of a pipeline's state. */ -typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE; -#define JOBSTATE(job) (jobs[(job)]->state) - -#define STOPPED(j) (jobs[(j)]->state == JSTOPPED) -#define RUNNING(j) (jobs[(j)]->state == JRUNNING) -#define DEADJOB(j) (jobs[(j)]->state == JDEAD) - -/* Values for the FLAGS field in the JOB struct below. */ -#define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */ -#define J_NOTIFIED 0x02 /* Non-zero if already notified about job state. */ -#define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */ -#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */ - -#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0) -#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0) -#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0) - -typedef struct job { - char *wd; /* The working directory at time of invocation. */ - 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. */ - sh_vptrfunc_t *j_cleanup; /* Cleanup function to call when job marked JDEAD */ - PTR_T cleanarg; /* Argument passed to (*j_cleanup)() */ -#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 - -/* System calls. */ -#if !defined (HAVE_UNISTD_H) -extern pid_t fork (), getpid (), getpgrp (); -#endif /* !HAVE_UNISTD_H */ - -/* 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 save_pipeline __P((int)); -extern void restore_pipeline __P((int)); -extern void start_pipeline __P((void)); -extern int stop_pipeline __P((int, COMMAND *)); - -extern void delete_job __P((int, int)); -extern void nohup_job __P((int)); -extern void delete_all_jobs __P((int)); -extern void nohup_all_jobs __P((int)); - -extern int count_all_jobs __P((void)); - -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 int get_job_by_pid __P((int, int)); -extern void describe_pid __P((int)); -#else -extern int get_job_by_pid __P((pid_t, int)); -extern void describe_pid __P((pid_t)); -#endif - -extern void list_one_job __P((JOB *, int, int, int)); -extern void list_all_jobs __P((int)); -extern void list_stopped_jobs __P((int)); -extern void list_running_jobs __P((int)); - -extern pid_t make_child __P((char *, int)); - -extern int get_tty_state __P((void)); -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_job_control __P((int)); -extern void initialize_job_signals __P((void)); -extern int give_terminal_to __P((pid_t, int)); - -extern void set_sigwinch_handler __P((void)); -extern void unset_sigwinch_handler __P((void)); - -extern void unfreeze_jobs_list __P((void)); -extern int set_job_control __P((int)); -extern void without_job_control __P((void)); -extern void end_job_control __P((void)); -extern void restart_job_control __P((void)); -extern void set_sigchld_handler __P((void)); -extern void ignore_tty_job_signals __P((void)); -extern void default_tty_job_signals __P((void)); - -#if defined (JOB_CONTROL) -extern int job_control; -#endif - -#endif /* _JOBS_H_ */ diff --git a/lib/glob/glob.c~ b/lib/glob/glob.c~ deleted file mode 100644 index b1abc660d..000000000 --- a/lib/glob/glob.c~ +++ /dev/null @@ -1,839 +0,0 @@ -/* glob.c -- file-name wildcard pattern matching for Bash. - - Copyright (C) 1985-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111 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. */ - -#include - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixdir.h" -#include "posixstat.h" -#include "shmbutil.h" -#include "xmalloc.h" - -#include "filecntl.h" -#if !defined (F_OK) -# define F_OK 0 -#endif - -#include "stdc.h" -#include "memalloc.h" -#include "quit.h" - -#include "glob.h" -#include "strmatch.h" - -#if !defined (HAVE_BCOPY) && !defined (bcopy) -# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) -#endif /* !HAVE_BCOPY && !bcopy */ - -#if !defined (NULL) -# if defined (__STDC__) -# define NULL ((void *) 0) -# else -# define NULL 0x0 -# endif /* __STDC__ */ -#endif /* !NULL */ - -#if !defined (FREE) -# define FREE(x) if (x) free (x) -#endif - -extern void throw_to_top_level __P((void)); -extern int test_eaccess __P((char *, int)); - -extern int extended_glob; - -/* Global variable which controls whether or not * matches .*. - Non-zero means don't match .*. */ -int noglob_dot_filenames = 1; - -/* Global variable which controls whether or not filename globbing - is done without regard to case. */ -int glob_ignore_case = 0; - -/* Global variable to return to signify an error in globbing. */ -char *glob_error_return; - -/* Some forward declarations. */ -static int skipname __P((char *, char *)); -#if HANDLE_MULTIBYTE -static int mbskipname __P((char *, char *)); -#endif -#if HANDLE_MULTIBYTE -static void udequote_pathname __P((char *)); -static void wdequote_pathname __P((char *)); -#else -# define dequote_pathname udequote_pathname -#endif -static void dequote_pathname __P((char *)); -static int glob_testdir __P((char *)); -static char **glob_dir_to_array __P((char *, char **, int)); - -/* Compile `glob_loop.c' for single-byte characters. */ -#define CHAR unsigned char -#define INT int -#define L(CS) CS -#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p -#include "glob_loop.c" - -/* Compile `glob_loop.c' again for multibyte characters. */ -#if HANDLE_MULTIBYTE - -#define CHAR wchar_t -#define INT wint_t -#define L(CS) L##CS -#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p -#include "glob_loop.c" - -#endif /* HANDLE_MULTIBYTE */ - -/* And now a function that calls either the single-byte or multibyte version - of internal_glob_pattern_p. */ -int -glob_pattern_p (pattern) - const char *pattern; -{ -#if HANDLE_MULTIBYTE - size_t n; - wchar_t *wpattern; - int r; - - if (MB_CUR_MAX == 1) - return (internal_glob_pattern_p (pattern)); - - /* Convert strings to wide chars, and call the multibyte version. */ - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - /* Oops. Invalid multibyte sequence. Try it as single-byte sequence. */ - return (internal_glob_pattern_p (pattern)); - - r = internal_glob_wpattern_p (wpattern); - free (wpattern); - - return r; -#else - return (internal_glob_pattern_p (pattern)); -#endif -} - -/* Return 1 if DNAME should be skipped according to PAT. Mostly concerned - with matching leading `.'. */ - -static int -skipname (pat, dname) - char *pat; - char *dname; -{ - /* If a leading dot need not be explicitly matched, and the pattern - doesn't start with a `.', don't match `.' or `..' */ - if (noglob_dot_filenames == 0 && pat[0] != '.' && - (pat[0] != '\\' || pat[1] != '.') && - (dname[0] == '.' && - (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))) - return 1; - - /* If a dot must be explicity matched, check to see if they do. */ - else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' && - (pat[0] != '\\' || pat[1] != '.')) - return 1; - - return 0; -} - -#if HANDLE_MULTIBYTE -/* Return 1 if DNAME should be skipped according to PAT. Handles multibyte - characters in PAT and DNAME. Mostly concerned with matching leading `.'. */ - -static int -mbskipname (pat, dname) - char *pat, *dname; -{ - int ret; - wchar_t *pat_wc, *dn_wc; - size_t pat_n, dn_n, n; - - pat_n = xdupmbstowcs (&pat_wc, NULL, pat); - dn_n = xdupmbstowcs (&dn_wc, NULL, dname); - - ret = 0; - if (pat_n != (size_t)-1 && dn_n !=(size_t)-1) - { - /* If a leading dot need not be explicitly matched, and the - pattern doesn't start with a `.', don't match `.' or `..' */ - if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.') && - (dn_wc[0] == L'.' && - (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0')))) - ret = 1; - - /* If a leading dot must be explicity matched, check to see if the - pattern and dirname both have one. */ - else if (noglob_dot_filenames && dn_wc[0] == L'.' && - pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.')) - ret = 1; - } - - FREE (pat_wc); - FREE (dn_wc); - - return ret; -} -#endif /* HANDLE_MULTIBYTE */ - -/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ -static void -udequote_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] == 0) - break; - } - pathname[j] = '\0'; -} - -#if HANDLE_MULTIBYTE -/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ -static void -wdequote_pathname (pathname) - char *pathname; -{ - mbstate_t ps; - size_t len, n; - wchar_t *wpathname; - int i, j; -wchar_t *orig_wpathname; - - len = strlen (pathname); - /* Convert the strings into wide characters. */ - n = xdupmbstowcs (&wpathname, NULL, pathname); - if (n == (size_t) -1) - /* Something wrong. */ - return; - -orig_wpathname = wpathname; - - for (i = j = 0; wpathname && wpathname[i]; ) - { - if (wpathname[i] == L'\\') - i++; - - wpathname[j++] = wpathname[i++]; - - if (wpathname[i - 1] == L'\0') - break; - } - wpathname[j] = L'\0'; - -if (wpathname != orig_wpathname) - itrace("wdequote_pathname: 1: wpathname (%p) != orig_wpathname (%p)", wpathname, orig_wpathname); - /* Convert the wide character string into unibyte character set. */ - memset (&ps, '\0', sizeof(mbstate_t)); - n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps); - pathname[len] = '\0'; - -if (wpathname != orig_wpathname) - itrace("wdequote_pathname: 2: wpathname (%p) != orig_wpathname (%p)", wpathname, orig_wpathname); - free (orig_wpathname); -} - -static void -dequote_pathname (pathname) - char *pathname; -{ - if (MB_CUR_MAX > 1) - wdequote_pathname (pathname); - else - udequote_pathname (pathname); -} -#endif /* HANDLE_MULTIBYTE */ - -/* Test whether NAME exists. */ - -#if defined (HAVE_LSTAT) -# define GLOB_TESTNAME(name) (lstat (name, &finfo)) -#else /* !HAVE_LSTAT */ -# if !defined (AFS) -# define GLOB_TESTNAME(name) (test_eaccess (nextname, F_OK)) -# else /* AFS */ -# define GLOB_TESTNAME(name) (access (nextname, F_OK)) -# endif /* AFS */ -#endif /* !HAVE_LSTAT */ - -/* Return 0 if DIR is a directory, -1 otherwise. */ -static int -glob_testdir (dir) - char *dir; -{ - struct stat finfo; - - if (stat (dir, &finfo) < 0) - return (-1); - - if (S_ISDIR (finfo.st_mode) == 0) - return (-1); - - return (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, flags) - char *pat; - char *dir; - int flags; -{ - struct globval - { - struct globval *next; - char *name; - }; - - DIR *d; - register struct dirent *dp; - struct globval *lastlink; - register struct globval *nextlink; - register char *nextname, *npat; - unsigned int count; - int lose, skip; - register char **name_vector; - register unsigned int i; - int mflags; /* Flags passed to strmatch (). */ - - lastlink = 0; - count = lose = skip = 0; - - /* If PAT is empty, skip the loop, but return one (empty) filename. */ - if (pat == 0 || *pat == '\0') - { - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); - - nextlink = (struct globval *)alloca (sizeof (struct globval)); - if (nextlink == NULL) - return ((char **) NULL); - - nextlink->next = (struct globval *)0; - nextname = (char *) malloc (1); - if (nextname == 0) - lose = 1; - else - { - lastlink = nextlink; - nextlink->name = nextname; - nextname[0] = '\0'; - count = 1; - } - - skip = 1; - } - - /* If the filename pattern (PAT) does not contain any globbing characters, - we can dispense with reading the directory, and just see if there is - a filename `DIR/PAT'. If there is, and we can access it, just make the - vector to return and bail immediately. */ - if (skip == 0 && glob_pattern_p (pat) == 0) - { - int dirlen; - struct stat finfo; - - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); - - dirlen = strlen (dir); - nextname = (char *)malloc (dirlen + strlen (pat) + 2); - npat = (char *)malloc (strlen (pat) + 1); - if (nextname == 0 || npat == 0) - lose = 1; - else - { - strcpy (npat, pat); - dequote_pathname (npat); - - strcpy (nextname, dir); - nextname[dirlen++] = '/'; - strcpy (nextname + dirlen, npat); - - if (GLOB_TESTNAME (nextname) >= 0) - { - free (nextname); - nextlink = (struct globval *)alloca (sizeof (struct globval)); - if (nextlink) - { - nextlink->next = (struct globval *)0; - lastlink = nextlink; - nextlink->name = npat; - count = 1; - } - else - lose = 1; - } - else - { - free (nextname); - free (npat); - } - } - - skip = 1; - } - - if (skip == 0) - { - /* Open the directory, punting immediately if we cannot. If opendir - is not robust (i.e., it opens non-directories successfully), test - that DIR is a directory and punt if it's not. */ -#if defined (OPENDIR_NOT_ROBUST) - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); -#endif - - d = opendir (dir); - if (d == NULL) - return ((char **) &glob_error_return); - - /* Compute the flags that will be passed to strmatch(). We don't - need to do this every time through the loop. */ - mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; - -#ifdef FNM_CASEFOLD - if (glob_ignore_case) - mflags |= FNM_CASEFOLD; -#endif - - if (extended_glob) - mflags |= FNM_EXTMATCH; - - /* 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 (1) - { - /* Make globbing interruptible in the shell. */ - if (interrupt_state) - { - lose = 1; - break; - } - - dp = readdir (d); - if (dp == NULL) - break; - - /* If this directory entry is not to be used, try again. */ - if (REAL_DIR_ENTRY (dp) == 0) - continue; - -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name)) - continue; - else -#endif - if (skipname (pat, dp->d_name)) - continue; - - if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH) - { - nextname = (char *) malloc (D_NAMLEN (dp) + 1); - nextlink = (struct globval *) alloca (sizeof (struct globval)); - if (nextlink == 0 || nextname == 0) - { - lose = 1; - break; - } - nextlink->next = lastlink; - lastlink = nextlink; - nextlink->name = nextname; - bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); - ++count; - } - } - - (void) closedir (d); - } - - if (lose == 0) - { - name_vector = (char **) malloc ((count + 1) * sizeof (char *)); - lose |= name_vector == NULL; - } - - /* Have we run out of memory? */ - if (lose) - { - /* Here free the strings we have got. */ - while (lastlink) - { - free (lastlink->name); - lastlink = lastlink->next; - } - - QUIT; - - return ((char **)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. This should handle GX_MARKDIRS. */ -static char ** -glob_dir_to_array (dir, array, flags) - char *dir, **array; - int flags; -{ - register unsigned int i, l; - int add_slash; - char **result, *new; - struct stat sb; - - l = strlen (dir); - if (l == 0) - { - if (flags & GX_MARKDIRS) - for (i = 0; array[i]; i++) - { - if ((stat (array[i], &sb) == 0) && S_ISDIR (sb.st_mode)) - { - l = strlen (array[i]); - new = (char *)realloc (array[i], l + 2); - if (new == 0) - return NULL; - new[l] = '/'; - new[l+1] = '\0'; - array[i] = new; - } - } - 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++) - { - /* 3 == 1 for NUL, 1 for slash at end of DIR, 1 for GX_MARKDIRS */ - result[i] = (char *) malloc (l + strlen (array[i]) + 3); - - if (result[i] == NULL) - return (NULL); - - strcpy (result[i], dir); - if (add_slash) - result[i][l] = '/'; - strcpy (result[i] + l + add_slash, array[i]); - if (flags & GX_MARKDIRS) - { - if ((stat (result[i], &sb) == 0) && S_ISDIR (sb.st_mode)) - { - size_t rlen; - rlen = strlen (result[i]); - result[i][rlen] = '/'; - result[i][rlen+1] = '\0'; - } - } - } - 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, flags) - char *pathname; - int flags; -{ - char **result; - unsigned int result_size; - char *directory_name, *filename; - unsigned int directory_len; - int free_dirname; /* flag */ - - result = (char **) malloc (sizeof (char *)); - result_size = 1; - if (result == NULL) - return (NULL); - - result[0] = NULL; - - directory_name = NULL; - - /* Find the filename. */ - filename = strrchr (pathname, '/'); - if (filename == NULL) - { - filename = pathname; - directory_name = ""; - directory_len = 0; - free_dirname = 0; - } - else - { - directory_len = (filename - pathname) + 1; - directory_name = (char *) malloc (directory_len + 1); - - if (directory_name == 0) /* allocation failed? */ - return (NULL); - - bcopy (pathname, directory_name, directory_len); - directory_name[directory_len] = '\0'; - ++filename; - free_dirname = 1; - } - - /* 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, flags & ~GX_MARKDIRS); - - if (free_dirname) - { - free (directory_name); - directory_name = NULL; - } - - 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], flags & ~GX_MARKDIRS); - - /* 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, flags); - 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); - /* Handle GX_MARKDIRS here. */ - result[0] = (char *) malloc (directory_len + 1); - if (result[0] == NULL) - goto memory_error; - bcopy (directory_name, result[0], directory_len + 1); - if (free_dirname) - free (directory_name); - 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), - flags & ~GX_MARKDIRS); - - if (temp_results == NULL || temp_results == (char **)&glob_error_return) - { - if (free_dirname) - free (directory_name); - return (temp_results); - } - - result = glob_dir_to_array (directory_name, temp_results, flags); - if (free_dirname) - free (directory_name); - return (result); - } - - /* 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 (free_dirname && directory_name) - free (directory_name); - - QUIT; - - 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], 0); - 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/sm_loop.c~ b/lib/glob/sm_loop.c~ deleted file mode 100644 index 0926b01b0..000000000 --- a/lib/glob/sm_loop.c~ +++ /dev/null @@ -1,750 +0,0 @@ -/* Copyright (C) 1991-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -static int FCT __P((CHAR *, CHAR *, int)); -static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int)); -static CHAR *PARSE_COLLSYM __P((CHAR *, INT *)); -static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int)); -static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int)); -static CHAR *PATSCAN __P((CHAR *, CHAR *, INT)); - -static int -FCT (pattern, string, flags) - CHAR *pattern; - CHAR *string; - int flags; -{ - CHAR *se, *pe; - - if (string == 0 || pattern == 0) - return FNM_NOMATCH; - - se = string + STRLEN ((XCHAR *)string); - pe = pattern + STRLEN ((XCHAR *)pattern); - - return (GMATCH (string, se, pattern, pe, flags)); -} - -/* Match STRING against the filename pattern PATTERN, returning zero if - it matches, FNM_NOMATCH if not. */ -static int -GMATCH (string, se, pattern, pe, flags) - CHAR *string, *se; - CHAR *pattern, *pe; - int flags; -{ - CHAR *p, *n; /* pattern, string */ - INT c; /* current pattern character - XXX U_CHAR? */ - INT sc; /* current string character - XXX U_CHAR? */ - - p = pattern; - n = string; - - if (string == 0 || pattern == 0) - return FNM_NOMATCH; - -#if DEBUG_MATCHING -fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se); -fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe); -#endif - - while (p < pe) - { - c = *p++; - c = FOLD (c); - - sc = n < se ? *n : '\0'; - -#ifdef EXTENDED_GLOB - /* EXTMATCH () will handle recursively calling GMATCH, so we can - just return what EXTMATCH() returns. */ - if ((flags & FNM_EXTMATCH) && *p == L('(') && - (c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */ - { - int lflags; - /* If we're not matching the start of the string, we're not - concerned about the special cases for matching `.' */ - lflags = (n == string) ? flags : (flags & ~FNM_PERIOD); - return (EXTMATCH (c, n, se, p, pe, lflags)); - } -#endif /* EXTENDED_GLOB */ - - switch (c) - { - case L('?'): /* Match single character */ - if (sc == '\0') - return FNM_NOMATCH; - else if ((flags & FNM_PATHNAME) && sc == L('/')) - /* If we are matching a pathname, `?' can never match a `/'. */ - return FNM_NOMATCH; - else if ((flags & FNM_PERIOD) && sc == L('.') && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) - /* `?' cannot match a `.' if it is the first character of the - string or if it is the first character following a slash and - we are matching a pathname. */ - return FNM_NOMATCH; - break; - - case L('\\'): /* backslash escape removes special meaning */ - if (p == pe) - return FNM_NOMATCH; - - if ((flags & FNM_NOESCAPE) == 0) - { - c = *p++; - /* A trailing `\' cannot match. */ - if (p > pe) - return FNM_NOMATCH; - c = FOLD (c); - } - if (FOLD (sc) != (U_CHAR)c) - return FNM_NOMATCH; - break; - - case '*': /* Match zero or more characters */ - if (p == pe) - return 0; - - if ((flags & FNM_PERIOD) && sc == L('.') && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) - /* `*' cannot match a `.' if it is the first character of the - string or if it is the first character following a slash and - we are matching a pathname. */ - return FNM_NOMATCH; - - /* Collapse multiple consecutive `*' and `?', but make sure that - one character of the string is consumed for each `?'. */ - for (c = *p++; (c == L('?') || c == L('*')); c = *p++) - { - if ((flags & FNM_PATHNAME) && sc == L('/')) - /* A slash does not match a wildcard under FNM_PATHNAME. */ - return FNM_NOMATCH; -#ifdef EXTENDED_GLOB - else if ((flags & FNM_EXTMATCH) && c == L('?') && *p == L('(')) /* ) */ - { - CHAR *newn; - for (newn = n; newn < se; ++newn) - { - if (EXTMATCH (c, newn, se, p, pe, flags) == 0) - return (0); - } - /* We didn't match. If we have a `?(...)', that's failure. */ - return FNM_NOMATCH; - } -#endif - else if (c == L('?')) - { - if (sc == L('\0')) - return FNM_NOMATCH; - /* One character of the string is consumed in matching - this ? wildcard, so *??? won't match if there are - fewer than three characters. */ - n++; - sc = n < se ? *n : '\0'; - } - -#ifdef EXTENDED_GLOB - /* Handle ******(patlist) */ - if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/ - { - CHAR *newn; - /* We need to check whether or not the extended glob - pattern matches the remainder of the string. - If it does, we match the entire pattern. */ - for (newn = n; newn < se; ++newn) - { - if (EXTMATCH (c, newn, se, p, pe, flags) == 0) - return (0); - } - /* We didn't match the extended glob pattern, but - that's OK, since we can match 0 or more occurrences. - We need to skip the glob pattern and see if we - match the rest of the string. */ - newn = PATSCAN (p + 1, pe, 0); - /* If NEWN is 0, we have an ill-formed pattern. */ - p = newn ? newn : pe; - } -#endif - if (p == pe) - break; - } - - /* If we've hit the end of the pattern and the last character of - the pattern was handled by the loop above, we've succeeded. - Otherwise, we need to match that last character. */ - if (p == pe && (c == L('?') || c == L('*'))) - return (0); - - /* General case, use recursion. */ - { - U_CHAR c1; - - c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c; - c1 = FOLD (c1); - for (--p; n < se; ++n) - { - /* Only call strmatch if the first character indicates a - possible match. We can check the first character if - we're not doing an extended glob match. */ - if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/ - continue; - - /* If we're doing an extended glob match and the pattern is not - one of the extended glob patterns, we can check the first - character. */ - if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/ - STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/ - continue; - - /* Otherwise, we just recurse. */ - if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0) - return (0); - } - return FNM_NOMATCH; - } - - case L('['): - { - if (sc == L('\0') || n == se) - return FNM_NOMATCH; - - /* A character class cannot match a `.' if it is the first - character of the string or if it is the first character - following a slash and we are matching a pathname. */ - if ((flags & FNM_PERIOD) && sc == L('.') && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) - return (FNM_NOMATCH); - - p = BRACKMATCH (p, sc, flags); - if (p == 0) - return FNM_NOMATCH; - } - break; - - default: - if ((U_CHAR)c != FOLD (sc)) - return (FNM_NOMATCH); - } - - ++n; - } - - if (n == se) - return (0); - - if ((flags & FNM_LEADING_DIR) && *n == L('/')) - /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ - return 0; - - return (FNM_NOMATCH); -} - -/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find - the value of the symbol, and move P past the collating symbol expression. - The value is returned in *VP, if VP is not null. */ -static CHAR * -PARSE_COLLSYM (p, vp) - CHAR *p; - INT *vp; -{ - register int pc; - INT val; - - p++; /* move past the `.' */ - - for (pc = 0; p[pc]; pc++) - if (p[pc] == L('.') && p[pc+1] == L(']')) - break; - val = COLLSYM (p, pc); - if (vp) - *vp = val; - return (p + pc + 2); -} - -/* Use prototype definition here because of type promotion. */ -static CHAR * -#if defined (PROTOTYPES) -BRACKMATCH (CHAR *p, U_CHAR test, int flags) -#else -BRACKMATCH (p, test, flags) - CHAR *p; - U_CHAR test; - int flags; -#endif -{ - register CHAR cstart, cend, c; - register int not; /* Nonzero if the sense of the character class is inverted. */ - int brcnt; - INT pc; - CHAR *savep; - - test = FOLD (test); - - savep = p; - - /* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the - circumflex (`^') in its role in a `nonmatching list'. A bracket - expression starting with an unquoted circumflex character produces - unspecified results. This implementation treats the two identically. */ - if (not = (*p == L('!') || *p == L('^'))) - ++p; - - c = *p++; - for (;;) - { - /* Initialize cstart and cend in case `-' is the last - character of the pattern. */ - cstart = cend = c; - - /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find - the end of the equivalence class, move the pattern pointer past - it, and check for equivalence. XXX - this handles only - single-character equivalence classes, which is wrong, or at - least incomplete. */ - if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']')) - { - pc = FOLD (p[1]); - p += 4; - if (COLLEQUIV (test, pc)) - { -/*[*/ /* Move past the closing `]', since the first thing we do at - the `matched:' label is back p up one. */ - p++; - goto matched; - } - else - { - c = *p++; - if (c == L('\0')) - return ((test == L('[')) ? savep : (CHAR *)0); /*]*/ - c = FOLD (c); - continue; - } - } - - /* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */ - if (c == L('[') && *p == L(':')) - { - CHAR *close, *ccname; - - pc = 0; /* make sure invalid char classes don't match. */ - /* Find end of character class name */ - for (close = p + 1; *close != '\0'; close++) - if (*close == L(':') && *(close+1) == L(']')) - break; - - if (*close != L('\0')) - { - ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR)); - if (ccname == 0) - pc = 0; - else - { - bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR)); - *(ccname + (close - p - 1)) = L('\0'); - pc = IS_CCLASS (test, ccname); - } - if (pc == -1) - pc = 0; - else - p = close + 2; - - free (ccname); - } - - if (pc) - { -/*[*/ /* Move past the closing `]', since the first thing we do at - the `matched:' label is back p up one. */ - p++; - goto matched; - } - else - { - /* continue the loop here, since this expression can't be - the first part of a range expression. */ - c = *p++; - if (c == L('\0')) - return ((test == L('[')) ? savep : (CHAR *)0); - else if (c == L(']')) - break; - c = FOLD (c); - continue; - } - } - - /* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of - the symbol name, make sure it is terminated by `.]', translate - the name to a character using the external table, and do the - comparison. */ - if (c == L('[') && *p == L('.')) - { - p = PARSE_COLLSYM (p, &pc); - /* An invalid collating symbol cannot be the first point of a - range. If it is, we set cstart to one greater than `test', - so any comparisons later will fail. */ - cstart = (pc == INVALID) ? test + 1 : pc; - } - - if (!(flags & FNM_NOESCAPE) && c == L('\\')) - { - if (*p == '\0') - return (CHAR *)0; - cstart = cend = *p++; - } - - cstart = cend = FOLD (cstart); - - /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that - is not preceded by a backslash and is not part of a bracket - expression produces undefined results.' This implementation - treats the `[' as just a character to be matched if there is - not a closing `]'. */ - if (c == L('\0')) - return ((test == L('[')) ? savep : (CHAR *)0); - - c = *p++; - c = FOLD (c); - - if ((flags & FNM_PATHNAME) && c == L('/')) - /* [/] can never match when matching a pathname. */ - return (CHAR *)0; - - /* This introduces a range, unless the `-' is the last - character of the class. Find the end of the range - and move past it. */ - if (c == L('-') && *p != L(']')) - { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == L('\\')) - cend = *p++; - if (cend == L('\0')) - return (CHAR *)0; - if (cend == L('[') && *p == L('.')) - { - p = PARSE_COLLSYM (p, &pc); - /* An invalid collating symbol cannot be the second part of a - range expression. If we get one, we set cend to one fewer - than the test character to make sure the range test fails. */ - cend = (pc == INVALID) ? test - 1 : pc; - } - cend = FOLD (cend); - - c = *p++; - - /* POSIX.2 2.8.3.2: ``The ending range point shall collate - equal to or higher than the starting range point; otherwise - the expression shall be treated as invalid.'' Note that this - applies to only the range expression; the rest of the bracket - expression is still checked for matches. */ - if (RANGECMP (cstart, cend) > 0) - { - if (c == L(']')) - break; - c = FOLD (c); - continue; - } - } - - if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0) - goto matched; - - if (c == L(']')) - break; - } - /* No match. */ - return (!not ? (CHAR *)0 : p); - -matched: - /* Skip the rest of the [...] that already matched. */ - c = *--p; - brcnt = 1; - while (brcnt > 0) - { - /* A `[' without a matching `]' is just another character to match. */ - if (c == L('\0')) - return ((test == L('[')) ? savep : (CHAR *)0); - - c = *p++; - if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.'))) - brcnt++; - else if (c == L(']')) - brcnt--; - else if (!(flags & FNM_NOESCAPE) && c == L('\\')) - { - if (*p == '\0') - return (CHAR *)0; - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; - } - } - return (not ? (CHAR *)0 : p); -} - -#if defined (EXTENDED_GLOB) -/* ksh-like extended pattern matching: - - [?*+@!](pat-list) - - where pat-list is a list of one or patterns separated by `|'. Operation - is as follows: - - ?(patlist) match zero or one of the given patterns - *(patlist) match zero or more of the given patterns - +(patlist) match one or more of the given patterns - @(patlist) match exactly one of the given patterns - !(patlist) match anything except one of the given patterns -*/ - -/* Scan a pattern starting at STRING and ending at END, keeping track of - embedded () and []. If DELIM is 0, we scan until a matching `)' - because we're scanning a `patlist'. Otherwise, we scan until we see - DELIM. In all cases, we never scan past END. The return value is the - first character after the matching DELIM. */ -static CHAR * -PATSCAN (string, end, delim) - CHAR *string, *end; - INT delim; -{ - int pnest, bnest; - INT cchar; - CHAR *s, c, *bfirst; - - pnest = bnest = 0; - cchar = 0; - bfirst = NULL; - - for (s = string; c = *s; s++) - { - if (s >= end) - return (s); - switch (c) - { - case L('\0'): - return ((CHAR *)NULL); - - /* `[' is not special inside a bracket expression, but it may - introduce one of the special POSIX bracket expressions - ([.SYM.], [=c=], [: ... :]) that needs special handling. */ - case L('['): - if (bnest == 0) - { - bfirst = s + 1; - if (*bfirst == L('!') || *bfirst == L('^')) - bfirst++; - bnest++; - } - else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('=')) - cchar = s[1]; - break; - - /* `]' is not special if it's the first char (after a leading `!' - or `^') in a bracket expression or if it's part of one of the - special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */ - case L(']'): - if (bnest) - { - if (cchar && s[-1] == cchar) - cchar = 0; - else if (s != bfirst) - { - bnest--; - bfirst = 0; - } - } - break; - - case L('('): - if (bnest == 0) - pnest++; - break; - - case L(')'): - if (bnest == 0 && pnest-- <= 0) - return ++s; - break; - - case L('|'): - if (bnest == 0 && pnest == 0 && delim == L('|')) - return ++s; - break; - } - } - - return (NULL); -} - -/* Return 0 if dequoted pattern matches S in the current locale. */ -static int -STRCOMPARE (p, pe, s, se) - CHAR *p, *pe, *s, *se; -{ - int ret; - CHAR c1, c2; - - c1 = *pe; - c2 = *se; - - *pe = *se = '\0'; -#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL) - ret = STRCOLL ((XCHAR *)p, (XCHAR *)s); -#else - ret = STRCMP ((XCHAR *)p, (XCHAR *)s); -#endif - - *pe = c1; - *se = c2; - - return (ret == 0 ? ret : FNM_NOMATCH); -} - -/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or - 0 on success. This is handed the entire rest of the pattern and string - the first time an extended pattern specifier is encountered, so it calls - gmatch recursively. */ -static int -EXTMATCH (xc, s, se, p, pe, flags) - INT xc; /* select which operation */ - CHAR *s, *se; - CHAR *p, *pe; - int flags; -{ - CHAR *prest; /* pointer to rest of pattern */ - CHAR *psub; /* pointer to sub-pattern */ - CHAR *pnext; /* pointer to next sub-pattern */ - CHAR *srest; /* pointer to rest of string */ - int m1, m2; - -#if DEBUG_MATCHING -fprintf(stderr, "extmatch: xc = %c\n", xc); -fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se); -fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe); -#endif - - prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */ - if (prest == 0) - /* If PREST is 0, we failed to scan a valid pattern. In this - case, we just want to compare the two as strings. */ - return (STRCOMPARE (p - 1, pe, s, se)); - - switch (xc) - { - case L('+'): /* match one or more occurrences */ - case L('*'): /* match zero or more occurrences */ - /* If we can get away with no matches, don't even bother. Just - call GMATCH on the rest of the pattern and return success if - it succeeds. */ - if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0)) - return 0; - - /* OK, we have to do this the hard way. First, we make sure one of - the subpatterns matches, then we try to match the rest of the - string. */ - for (psub = p + 1; ; psub = pnext) - { - pnext = PATSCAN (psub, pe, L('|')); - for (srest = s; srest <= se; srest++) - { - /* Match this substring (S -> SREST) against this - subpattern (psub -> pnext - 1) */ - m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0; - /* OK, we matched a subpattern, so make sure the rest of the - string matches the rest of the pattern. Also handle - multiple matches of the pattern. */ - if (m1) - m2 = (GMATCH (srest, se, prest, pe, flags) == 0) || - (s != srest && GMATCH (srest, se, p - 1, pe, flags) == 0); - if (m1 && m2) - return (0); - } - if (pnext == prest) - break; - } - return (FNM_NOMATCH); - - case L('?'): /* match zero or one of the patterns */ - case L('@'): /* match exactly one of the patterns */ - /* If we can get away with no matches, don't even bother. Just - call gmatch on the rest of the pattern and return success if - it succeeds. */ - if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0)) - return 0; - - /* OK, we have to do this the hard way. First, we see if one of - the subpatterns matches, then, if it does, we try to match the - rest of the string. */ - for (psub = p + 1; ; psub = pnext) - { - pnext = PATSCAN (psub, pe, L('|')); - srest = (prest == pe) ? se : s; - for ( ; srest <= se; srest++) - { - if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 && - GMATCH (srest, se, prest, pe, flags) == 0) - return (0); - } - if (pnext == prest) - break; - } - return (FNM_NOMATCH); - - case '!': /* match anything *except* one of the patterns */ - for (srest = s; srest <= se; srest++) - { - m1 = 0; - for (psub = p + 1; ; psub = pnext) - { - pnext = PATSCAN (psub, pe, L('|')); - /* If one of the patterns matches, just bail immediately. */ - if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0)) - break; - if (pnext == prest) - break; - } - if (m1 == 0 && GMATCH (srest, se, prest, pe, flags) == 0) - return (0); - } - return (FNM_NOMATCH); - } - - return (FNM_NOMATCH); -} -#endif /* EXTENDED_GLOB */ - -#undef IS_CCLASS -#undef FOLD -#undef CHAR -#undef U_CHAR -#undef XCHAR -#undef INT -#undef INVALID -#undef FCT -#undef GMATCH -#undef COLLSYM -#undef PARSE_COLLSYM -#undef PATSCAN -#undef STRCOMPARE -#undef EXTMATCH -#undef BRACKMATCH -#undef STRCHR -#undef STRCOLL -#undef STRLEN -#undef STRCMP -#undef COLLEQUIV -#undef RANGECMP -#undef L diff --git a/lib/glob/smatch.c~ b/lib/glob/smatch.c~ deleted file mode 100644 index 8c54702b0..000000000 --- a/lib/glob/smatch.c~ +++ /dev/null @@ -1,410 +0,0 @@ -/* strmatch.c -- ksh-like extended pattern matching for the shell and filename - globbing. */ - -/* Copyright (C) 1991-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#include /* for debugging */ - -#include "strmatch.h" -#include - -#include "bashansi.h" -#include "shmbutil.h" -#include "xmalloc.h" - -/* First, compile `sm_loop.c' for single-byte characters. */ -#define CHAR unsigned char -#define U_CHAR unsigned char -#define XCHAR char -#define INT int -#define L(CS) CS -#define INVALID -1 - -#undef STREQ -#undef STREQN -#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) - -/* We use strcoll(3) for range comparisons in bracket expressions, - even though it can have unwanted side effects in locales - other than POSIX or US. For instance, in the de locale, [A-Z] matches - all characters. */ - -#if defined (HAVE_STRCOLL) -/* Helper function for collating symbol equivalence. */ -static int rangecmp (c1, c2) - int c1, c2; -{ - static char s1[2] = { ' ', '\0' }; - static char s2[2] = { ' ', '\0' }; - int ret; - - /* Eight bits only. Period. */ - c1 &= 0xFF; - c2 &= 0xFF; - - if (c1 == c2) - return (0); - - s1[0] = c1; - s2[0] = c2; - - if ((ret = strcoll (s1, s2)) != 0) - return ret; - return (c1 - c2); -} -#else /* !HAVE_STRCOLL */ -# define rangecmp(c1, c2) ((int)(c1) - (int)(c2)) -#endif /* !HAVE_STRCOLL */ - -#if defined (HAVE_STRCOLL) -static int -collequiv (c1, c2) - int c1, c2; -{ - return (rangecmp (c1, c2) == 0); -} -#else -# define collequiv(c1, c2) ((c1) == (c2)) -#endif - -#define _COLLSYM _collsym -#define __COLLSYM __collsym -#define POSIXCOLL posix_collsyms -#include "collsyms.h" - -static int -collsym (s, len) - char *s; - int len; -{ - register struct _collsym *csp; - - for (csp = posix_collsyms; csp->name; csp++) - { - if (STREQN(csp->name, s, len) && csp->name[len] == '\0') - return (csp->code); - } - if (len == 1) - return s[0]; - return INVALID; -} - -/* unibyte character classification */ -#if !defined (isascii) && !defined (HAVE_ISASCII) -# define isascii(c) ((unsigned int)(c) <= 0177) -#endif - -enum char_class - { - CC_NO_CLASS = 0, - CC_ASCII, CC_ALNUM, CC_ALPHA, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH, - CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_WORD, CC_XDIGIT - }; - -static char const *const cclass_name[] = - { - "", - "ascii", "alnum", "alpha", "blank", "cntrl", "digit", "graph", - "lower", "print", "punct", "space", "upper", "word", "xdigit" - }; - -#define N_CHAR_CLASS (sizeof(cclass_name) / sizeof (cclass_name[0])) - -static int -is_cclass (c, name) - int c; - const char *name; -{ - enum char_class char_class = CC_NO_CLASS; - int i, result; - - for (i = 1; i < N_CHAR_CLASS; i++) - { - if (STREQ (name, cclass_name[i])) - { - char_class = (enum char_class)i; - break; - } - } - - if (char_class == 0) - return -1; - - switch (char_class) - { - case CC_ASCII: - result = isascii (c); - break; - case CC_ALNUM: - result = ISALNUM (c); - break; - case CC_ALPHA: - result = ISALPHA (c); - break; - case CC_BLANK: - result = ISBLANK (c); - break; - case CC_CNTRL: - result = ISCNTRL (c); - break; - case CC_DIGIT: - result = ISDIGIT (c); - break; - case CC_GRAPH: - result = ISGRAPH (c); - break; - case CC_LOWER: - result = ISLOWER (c); - break; - case CC_PRINT: - result = ISPRINT (c); - break; - case CC_PUNCT: - result = ISPUNCT (c); - break; - case CC_SPACE: - result = ISSPACE (c); - break; - case CC_UPPER: - result = ISUPPER (c); - break; - case CC_WORD: - result = (ISALNUM (c) || c == '_'); - break; - case CC_XDIGIT: - result = ISXDIGIT (c); - break; - default: - result = -1; - break; - } - - return result; -} - -/* Now include `sm_loop.c' for single-byte characters. */ -/* The result of FOLD is an `unsigned char' */ -# define FOLD(c) ((flags & FNM_CASEFOLD) \ - ? TOLOWER ((unsigned char)c) \ - : ((unsigned char)c)) - -#define FCT internal_strmatch -#define GMATCH gmatch -#define COLLSYM collsym -#define PARSE_COLLSYM parse_collsym -#define BRACKMATCH brackmatch -#define PATSCAN patscan -#define STRCOMPARE strcompare -#define EXTMATCH extmatch -#define STRCHR(S, C) strchr((S), (C)) -#define STRCOLL(S1, S2) strcoll((S1), (S2)) -#define STRLEN(S) strlen(S) -#define STRCMP(S1, S2) strcmp((S1), (S2)) -#define RANGECMP(C1, C2) rangecmp((C1), (C2)) -#define COLLEQUIV(C1, C2) collequiv((C1), (C2)) -#define CTYPE_T enum char_class -#define IS_CCLASS(C, S) is_cclass((C), (S)) -#include "sm_loop.c" - -#if HANDLE_MULTIBYTE - -# define CHAR wchar_t -# define U_CHAR wint_t -# define XCHAR wchar_t -# define INT wint_t -# define L(CS) L##CS -# define INVALID WEOF - -# undef STREQ -# undef STREQN -# define STREQ(s1, s2) ((wcscmp (s1, s2) == 0)) -# define STREQN(a, b, n) ((a)[0] == (b)[0] && wcsncmp(a, b, n) == 0) - -static int -rangecmp_wc (c1, c2) - wint_t c1, c2; -{ - static wchar_t s1[2] = { L' ', L'\0' }; - static wchar_t s2[2] = { L' ', L'\0' }; - int ret; - - if (c1 == c2) - return 0; - - s1[0] = c1; - s2[0] = c2; - - return (wcscoll (s1, s2)); -} - -static int -collequiv_wc (c, equiv) - wint_t c, equiv; -{ - return (!(c - equiv)); -} - -/* Helper function for collating symbol. */ -# define _COLLSYM _collwcsym -# define __COLLSYM __collwcsym -# define POSIXCOLL posix_collwcsyms -# include "collsyms.h" - -static wint_t -collwcsym (s, len) - wchar_t *s; - int len; -{ - register struct _collwcsym *csp; - - for (csp = posix_collwcsyms; csp->name; csp++) - { - if (STREQN(csp->name, s, len) && csp->name[len] == L'\0') - return (csp->code); - } - if (len == 1) - return s[0]; - return INVALID; -} - -static int -is_wcclass (wc, name) - wint_t wc; - wchar_t *name; -{ - char *mbs; - mbstate_t state; - size_t mbslength; - wctype_t desc; - int want_word; - - if ((wctype ("ascii") == (wctype_t)0) && (wcscmp (name, L"ascii") == 0)) - { - int c; - - if ((c = wctob (wc)) == EOF) - return 0; - else - return (c <= 0x7F); - } - - want_word = (wcscmp (name, L"word") == 0); - if (want_word) - name = L"alnum"; - - memset (&state, '\0', sizeof (mbstate_t)); - mbs = (char *) malloc (wcslen(name) * MB_CUR_MAX + 1); - mbslength = wcsrtombs(mbs, (const wchar_t **)&name, (wcslen(name) * MB_CUR_MAX + 1), &state); - - if (mbslength == (size_t)-1 || mbslength == (size_t)-2) - { - free (mbs); - return -1; - } - desc = wctype (mbs); - free (mbs); - - if (desc == (wctype_t)0) - return -1; - - if (want_word) - return (iswctype (wc, desc) || wc == L'_'); - else - return (iswctype (wc, desc)); -} - -/* Now include `sm_loop.c' for multibyte characters. */ -#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c)) -#define FCT internal_wstrmatch -#define GMATCH gmatch_wc -#define COLLSYM collwcsym -#define PARSE_COLLSYM parse_collwcsym -#define BRACKMATCH brackmatch_wc -#define PATSCAN patscan_wc -#define STRCOMPARE wscompare -#define EXTMATCH extmatch_wc -#define STRCHR(S, C) wcschr((S), (C)) -#define STRCOLL(S1, S2) wcscoll((S1), (S2)) -#define STRLEN(S) wcslen(S) -#define STRCMP(S1, S2) wcscmp((S1), (S2)) -#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2)) -#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2)) -#define CTYPE_T enum char_class -#define IS_CCLASS(C, S) is_wcclass((C), (S)) -#include "sm_loop.c" - -#endif /* HAVE_MULTIBYTE */ - -int -xstrmatch (pattern, string, flags) - char *pattern; - char *string; - int flags; -{ -#if HANDLE_MULTIBYTE - int ret; - mbstate_t ps; - size_t n; - char *pattern_bak; - wchar_t *wpattern, *wstring; - - if (MB_CUR_MAX == 1) - return (internal_strmatch (pattern, string, flags)); - - pattern_bak = (char *)xmalloc (strlen (pattern) + 1); - strcpy (pattern_bak, pattern); - - memset (&ps, '\0', sizeof (mbstate_t)); - n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps); - if (n == (size_t)-1 || n == (size_t)-2) - { - free (pattern_bak); - return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); - } - - wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t)); - (void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps); - - memset (&ps, '\0', sizeof (mbstate_t)); - n = xmbsrtowcs (NULL, (const char **)&string, 0, &ps); - if (n == (size_t)-1 || n == (size_t)-2) - { - free (wpattern); - ret = internal_strmatch (pattern_bak, string, flags); - free (pattern_bak); - return ret; - } - - wstring = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t)); - (void) xmbsrtowcs (wstring, (const char **)&string, n + 1, &ps); - - ret = internal_wstrmatch (wpattern, wstring, flags); - - free (pattern_bak); - free (wpattern); - free (wstring); - - return ret; -#else - return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); -#endif /* !HANDLE_MULTIBYTE */ -} diff --git a/lib/glob/strmatch.c~ b/lib/glob/strmatch.c~ deleted file mode 100644 index efab8a445..000000000 --- a/lib/glob/strmatch.c~ +++ /dev/null @@ -1,79 +0,0 @@ -/* strmatch.c -- ksh-like extended pattern matching for the shell and filename - globbing. */ - -/* Copyright (C) 1991-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#include "stdc.h" -#include "strmatch.h" - -extern int xstrmatch __P((char *, char *, int)); -#if defined (HAVE_MULTIBYTE) -extern int internal_wstrmatch __P((wchar_t *, wchar_t *, int)); -#endif - -int -strmatch (pattern, string, flags) - char *pattern; - char *string; - int flags; -{ - if (string == 0 || pattern == 0) - return FNM_NOMATCH; - - return (xstrmatch (pattern, string, flags)); -} - -#if defined (HAVE_MULTIBYTE) -int -wcsmatch (wpattern, wstring, flags) - wchar_t *wpattern; - wchar_t *wstring; - int flags; -{ - if (wstring == 0 || wpattern == 0) - return (FNM_NOMATCH); - - return (internal_wstrmatch (wpattern, wstring, flags)); -} -#endif - -#ifdef TEST -main (c, v) - int c; - char **v; -{ - char *string, *pat; - - string = v[1]; - pat = v[2]; - - if (strmatch (pat, string, 0) == 0) - { - printf ("%s matches %s\n", string, pat); - exit (0); - } - else - { - printf ("%s does not match %s\n", string, pat); - exit (1); - } -} -#endif diff --git a/lib/glob/strmatch.h~ b/lib/glob/strmatch.h~ deleted file mode 100644 index d31e5929c..000000000 --- a/lib/glob/strmatch.h~ +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 1991 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#ifndef _STRMATCH_H -#define _STRMATCH_H 1 - -#ifdef HAVE_LIBC_FNM_EXTMATCH - -#include - -#else /* !HAVE_LIBC_FNM_EXTMATCH */ - -#include "stdc.h" - -/* We #undef these before defining them because some losing systems - (HP-UX A.08.07 for example) define these in . */ -#undef FNM_PATHNAME -#undef FNM_NOESCAPE -#undef FNM_PERIOD - -/* Bits set in the FLAGS argument to `strmatch'. */ - -/* standard flags are like fnmatch(3). */ -#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. */ - -/* extended flags not available in most libc fnmatch versions, but we undef - them to avoid any possible warnings. */ -#undef FNM_LEADING_DIR -#undef FNM_CASEFOLD -#undef FNM_EXTMATCH - -#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ -#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ -#define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */ - -/* Value returned by `strmatch' if STRING does not match PATTERN. */ -#undef FNM_NOMATCH - -#define FNM_NOMATCH 1 - -/* Match STRING against the filename pattern PATTERN, - returning zero if it matches, FNM_NOMATCH if not. */ -extern int strmatch __P((char *, char *, int)); - -#endif /* !HAVE_LIBC_FNM_EXTMATCH */ - -#endif /* _STRMATCH_H */ diff --git a/lib/glob/xmbsrtowcs.c~ b/lib/glob/xmbsrtowcs.c~ deleted file mode 100644 index 7ea9e643c..000000000 --- a/lib/glob/xmbsrtowcs.c~ +++ /dev/null @@ -1,247 +0,0 @@ -/* xmbsrtowcs.c -- replacement function for mbsrtowcs */ - -/* Copyright (C) 2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#include - -#include - -/* , and are included in "shmbutil.h". - If , , mbsrtowcs(), exist, HANDLE_MULTIBYTE - is defined as 1. */ -#include - -#if HANDLE_MULTIBYTE -/* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>. - So, this function is made for converting 0x5c to U<0x5c>. */ - -static mbstate_t local_state; -static int local_state_use = 0; - -size_t -xmbsrtowcs (dest, src, len, pstate) - wchar_t *dest; - const char **src; - size_t len; - mbstate_t *pstate; -{ - mbstate_t *ps; - size_t mblength, wclength, n; - - ps = pstate; - if (pstate == NULL) - { - if (!local_state_use) - { - memset (&local_state, '\0', sizeof(mbstate_t)); - local_state_use = 1; - } - ps = &local_state; - } - - n = strlen(*src); - - if (dest == NULL) - { - wchar_t *wsbuf; - char *mbsbuf, *mbsbuf_top; - mbstate_t psbuf; - - wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t)); - mbsbuf_top = mbsbuf = (char *) malloc (n + 1); - memcpy(mbsbuf, *src, n + 1); - psbuf = *ps; - - wclength = mbsrtowcs (wsbuf, (const char **)&mbsbuf, n, &psbuf); - - free (wsbuf); - free (mbsbuf_top); - return wclength; - } - - for (wclength = 0; wclength < len; wclength++, dest++) - { - if(mbsinit(ps)) - { - if (**src == '\0') - { - *dest = L'\0'; - *src = NULL; - return (wclength); - } - else if (**src == '\\') - { - *dest = L'\\'; - mblength = 1; - } - else - mblength = mbrtowc(dest, *src, n, ps); - } - else - mblength = mbrtowc(dest, *src, n, ps); - - /* Cannot convert multibyte character to wide character. */ - if (mblength == (size_t)-1 || mblength == (size_t)-2) - return (size_t)-1; - - *src += mblength; - n -= mblength; - - /* The multibyte string has been completely converted, - including the terminating '\0'. */ - if (*dest == L'\0') - { - *src = NULL; - break; - } - } - - return (wclength); -} - -/* Convert a multibyte string to a wide character string. Memory for the - new wide character string is obtained with malloc. - - The return value is the length of the wide character string. Returns a - pointer to the wide character string in DESTP. If INDICESP is not NULL, - INDICESP stores the pointer to the pointer array. Each pointer is to - the first byte of each multibyte character. Memory for the pointer array - is obtained with malloc, too. - If conversion is failed, the return value is (size_t)-1 and the values - of DESTP and INDICESP are NULL. */ - -#define WSBUF_INC 32 - -size_t -xdupmbstowcs (destp, indicesp, src) - wchar_t **destp; /* Store the pointer to the wide character string */ - char ***indicesp; /* Store the pointer to the pointer array. */ - const char *src; /* Multibyte character string */ -{ - const char *p; /* Conversion start position of src */ - wchar_t wc; /* Created wide character by conversion */ - wchar_t *wsbuf; /* Buffer for wide characters. */ - char **indices; /* Buffer for indices. */ - size_t wsbuf_size; /* Size of WSBUF */ - size_t wcnum; /* Number of wide characters in WSBUF */ - mbstate_t state; /* Conversion State */ - - /* In case SRC or DESP is NULL, conversion doesn't take place. */ - if (src == NULL || destp == NULL) - { - *destp = NULL; - return (size_t)-1; - } - - memset (&state, '\0', sizeof(mbstate_t)); - wsbuf_size = WSBUF_INC; - - wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t)); - if (wsbuf == NULL) - { - *destp = NULL; - return (size_t)-1; - } - - indices = (char **) malloc (wsbuf_size * sizeof(char *)); - if (indices == NULL) - { - free (wsbuf); - *destp = NULL; - return (size_t)-1; - } - - p = src; - wcnum = 0; - do { - size_t mblength; /* Byte length of one multibyte character. */ - - if(mbsinit (&state)) - { - if (*p == '\0') - { - wc = L'\0'; - mblength = 1; - } - else if (*p == '\\') - { - wc = L'\\'; - mblength = 1; - } - else - mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state); - } - else - mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state); - - /* Conversion failed. */ - if (MB_INVALIDCH (mblength)) - { - free (wsbuf); - free (indices); - *destp = NULL; - return (size_t)-1; - } - - ++wcnum; - - /* Resize buffers when they are not large enough. */ - if (wsbuf_size < wcnum) - { - wchar_t *wstmp; - char **idxtmp; - - wsbuf_size += WSBUF_INC; - - wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t)); - if (wstmp == NULL) - { - free (wsbuf); - free (indices); - *destp = NULL; - return (size_t)-1; - } - wsbuf = wstmp; - - idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **)); - if (idxtmp == NULL) - { - free (wsbuf); - free (indices); - *destp = NULL; - return (size_t)-1; - } - indices = idxtmp; - } - - wsbuf[wcnum - 1] = wc; - indices[wcnum - 1] = (char *)p; - p += mblength; - } while (MB_NULLWCH (wc) == 0); - - /* Return the length of the wide character string, not including `\0'. */ - *destp = wsbuf; - if (indicesp != NULL) - *indicesp = indices; - else - free (indices); - - return (wcnum - 1); -} - -#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/malloc/malloc.c.save b/lib/malloc/malloc.c.save deleted file mode 100644 index 39846ec30..000000000 --- a/lib/malloc/malloc.c.save +++ /dev/null @@ -1,1213 +0,0 @@ -/* malloc.c - dynamic memory allocation for bash. */ - -/* Copyright (C) 1985, 1987, 1997 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., 59 Temple Place, Suite 330, Boston, MA 02111 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 MALLOC_STATS 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. - */ - -/* Define MEMSCRAMBLE to have free() write 0xcf into memory as it's freed, to - uncover callers that refer to freed memory, and to have malloc() write 0xdf - into memory as it's allocated to avoid referring to previous contents. */ - -/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE; - handled by configure. */ - -#if defined (HAVE_CONFIG_H) -# include -#endif /* HAVE_CONFIG_H */ - -#if defined (SHELL) -# include "bashtypes.h" -# include "stdc.h" -#else -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -/* Determine which kind of system this is. */ -#include - -#if defined (HAVE_STRING_H) -# include -#else -# include -#endif - -#include - -/* Define getpagesize () if the system does not. */ -#ifndef HAVE_GETPAGESIZE -# include "getpagesize.h" -#endif - -#include "imalloc.h" -#ifdef MALLOC_STATS -# include "mstats.h" -#endif -#ifdef MALLOC_REGISTER -# include "table.h" -#endif -#ifdef MALLOC_WATCH -# include "watch.h" -#endif - -/* System-specific omissions. */ -#ifdef HPUX -# define NO_VALLOC -#endif - -#define NBUCKETS 30 - -#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. */ - - -/* We have a flag indicating whether memory is allocated, an index in - nextf[], a size field, and a sentinel value to determine whether or - not a caller wrote before the start of allocated memory; to realloc() - memory we either copy mh_nbytes or just change mh_nbytes if there is - enough room in the block for the new size. Range checking is always - done. */ -union mhead { - bits64_t mh_align; /* 8 */ - struct { - char mi_alloc; /* ISALLOC or ISFREE */ /* 1 */ - char mi_index; /* index in nextf[] */ /* 1 */ - /* Remainder are valid only when block is allocated */ - u_bits16_t mi_magic2; /* should be == MAGIC2 */ /* 2 */ - u_bits32_t mi_nbytes; /* # of bytes allocated */ /* 4 */ - } minfo; -}; -#define mh_alloc minfo.mi_alloc -#define mh_index minfo.mi_index -#define mh_nbytes minfo.mi_nbytes -#define mh_magic2 minfo.mi_magic2 - -#define MOVERHEAD sizeof(union mhead) -#define MALIGN_MASK 7 /* one less than desired alignment */ - -/* Access free-list pointer of a block. - It is stored at block + sizeof (char *). - This is not a field in the minfo structure member of union mhead - because we want sizeof (union 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) \ - (*(union mhead **) (sizeof (char *) + (char *) (a))) - -/* 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 the 2 bytes before the block's real space (-4 bytes) */ -#define MAGIC2 0x5555 -#define MSLOP 4 /* 4 bytes extra for u_bits32_t size */ - -/* How many bytes are actually allocated for a request of size N -- - rounded up to nearest multiple of 8 after accounting for malloc - overhead. */ -#define ALLOCATED_BYTES(n) \ - (((n) + MOVERHEAD + MSLOP + MALIGN_MASK) & ~MALIGN_MASK) - -#define ASSERT(p) \ - do \ - { \ - if (!(p)) xbotch((PTR_T)0, ERR_ASSERT_FAILED, __STRING(p), file, line); \ - } \ - while (0) - -/* Minimum and maximum bucket indices for block splitting (and to bound - the search for a block to split). */ -#define SPLIT_MIN 2 /* XXX - was 3 */ -#define SPLIT_MID 11 -#define SPLIT_MAX 14 - -/* Minimum and maximum bucket indices for block coalescing. */ -#define COMBINE_MIN 2 -#define COMBINE_MAX (pagebucket - 1) /* XXX */ - -#define LESSCORE_MIN 10 -#define LESSCORE_FRC 13 - -#define STARTBUCK 1 - -/* Flags for the internal functions. */ -#define MALLOC_WRAPPER 0x01 /* wrapper function */ -#define MALLOC_INTERNAL 0x02 /* internal function calling another */ -#define MALLOC_NOTRACE 0x04 /* don't trace this allocation or free */ -#define MALLOC_NOREG 0x08 /* don't register this allocation or free */ - -/* Future use. */ -#define ERR_DUPFREE 0x01 -#define ERR_UNALLOC 0x02 -#define ERR_UNDERFLOW 0x04 -#define ERR_ASSERT_FAILED 0x08 - -/* Evaluates to true if NB is appropriate for bucket NU. NB is adjusted - appropriately by the caller to account for malloc overhead. This only - checks that the recorded size is not too big for the bucket. We - can't check whether or not it's in between NU and NU-1 because we - might have encountered a busy bucket when allocating and moved up to - the next size. */ -#define IN_BUCKET(nb, nu) ((nb) <= binsizes[(nu)]) - -/* Use this when we want to be sure that NB is in bucket NU. */ -#define RIGHT_BUCKET(nb, nu) \ - (((nb) > binsizes[(nu)-1]) && ((nb) <= binsizes[(nu)])) - -/* nextf[i] is free list of blocks of size 2**(i + 3) */ - -static union mhead *nextf[NBUCKETS]; - -/* busy[i] is nonzero while allocation of block size i is in progress. */ - -static char busy[NBUCKETS]; - -static int pagesz; /* system page size. */ -static int pagebucket; /* bucket for requests a page in size */ -static int maxbuck; /* highest bucket receiving allocation request. */ - -static char *memtop; /* top of heap */ - -static unsigned long binsizes[NBUCKETS] = { - 8UL, 16UL, 32UL, 64UL, 128UL, 256UL, 512UL, 1024UL, 2048UL, 4096UL, - 8192UL, 16384UL, 32768UL, 65536UL, 131072UL, 262144UL, 524288UL, - 1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL, - 67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL, - 2147483648UL, 4294967296UL-1 -}; - -/* binsizes[x] == (1 << ((x) + 3)) */ -#define binsize(x) binsizes[(x)] - -/* Declarations for internal functions */ -static PTR_T internal_malloc __P((size_t, const char *, int, int)); -static PTR_T internal_realloc __P((PTR_T, size_t, const char *, int, int)); -static void internal_free __P((PTR_T, const char *, int, int)); -static PTR_T internal_memalign __P((unsigned int, size_t, const char *, int, int)); -#ifndef NO_CALLOC -static PTR_T internal_calloc __P((size_t, size_t, const char *, int, int)); -static void internal_cfree __P((PTR_T, const char *, int, int)); -#endif -#ifndef NO_VALLOC -static PTR_T internal_valloc __P((size_t, const char *, int, int)); -#endif - -#if defined (botch) -extern void botch (); -#else -static void botch __P((const char *, const char *, int)); -#endif -static void xbotch __P((PTR_T, int, const char *, const char *, int)); - -#if !HAVE_DECL_SBRK -extern char *sbrk (); -#endif /* !HAVE_DECL_SBRK */ - -#ifdef SHELL -extern int interrupt_immediately; -extern int signal_is_trapped __P((int)); -#endif - -#ifdef MALLOC_STATS -struct _malstats _mstats; -#endif /* MALLOC_STATS */ - -/* Debugging variables available to applications. */ -int malloc_flags = 0; /* future use */ -int malloc_trace = 0; /* trace allocations and frees to stderr */ -int malloc_register = 0; /* future use */ - -#ifdef MALLOC_TRACE -char _malloc_trace_buckets[NBUCKETS]; - -/* These should really go into a header file. */ -extern void mtrace_alloc __P((const char *, PTR_T, size_t, const char *, int)); -extern void mtrace_free __P((PTR_T, int, const char *, int)); -#endif - -#if !defined (botch) -static void -botch (s, file, line) -{ - fprintf (stderr, "malloc: failed assertion: %s\n", s); - (void)fflush (stderr); - abort (); -} -#endif - -/* print the file and line number that caused the assertion failure and - call botch() to do whatever the application wants with the information */ -static void -xbotch (mem, e, s, file, line) - PTR_T mem; - int e; - const char *s; - const char *file; - int line; -{ - fprintf (stderr, "\r\nmalloc: %s:%d: assertion botched\r\n", - file ? file : "unknown", line); -#ifdef MALLOC_REGISTER - if (mem != NULL && malloc_register) - mregister_describe_mem (mem, stderr); -#endif - (void)fflush (stderr); - botch(s, file, line); -} - -/* Coalesce two adjacent free blocks off the free list for size NU - 1, - as long as we can find two adjacent free blocks. nextf[NU -1] is - assumed to not be busy; the caller (morecore()) checks for this. */ -static void -bcoalesce (nu) - register int nu; -{ - register union mhead *mp, *mp1, *mp2; - register int nbuck; - unsigned long siz; - - nbuck = nu - 1; - if (nextf[nbuck] == 0) - return; - - siz = binsize (nbuck); - - mp2 = mp1 = nextf[nbuck]; - mp = CHAIN (mp1); - while (mp && mp != (union mhead *)((char *)mp1 + siz)) - { - mp2 = mp1; - mp1 = mp; - mp = CHAIN (mp); - } - if (mp == 0) - return; - - /* OK, now we have mp1 pointing to the block we want to add to nextf[NU]. - CHAIN(mp2) must equal mp1. Check that mp1 and mp are adjacent. */ - if (mp2 != mp1 && CHAIN(mp2) != mp1) - xbotch ((PTR_T)0, 0, "bcoalesce: CHAIN(mp2) != mp1", (char *)NULL, 0); - -#ifdef MALLOC_DEBUG - if (CHAIN (mp1) != (union mhead *)((char *)mp1 + siz)) - return; /* not adjacent */ -#endif - -#ifdef MALLOC_STATS - _mstats.tbcoalesce++; - _mstats.ncoalesce[nbuck]++; -#endif - - /* Since they are adjacent, remove them from the free list */ - if (mp1 == nextf[nbuck]) - nextf[nbuck] = CHAIN (mp); - else - CHAIN (mp2) = CHAIN (mp); - - /* And add the combined two blocks to nextf[NU]. */ - mp1->mh_alloc = ISFREE; - mp1->mh_index = nu; - CHAIN (mp1) = nextf[nu]; - nextf[nu] = mp1; -} - -/* Split a block at index > NU (but less than SPLIT_MAX) into a set of - blocks of the correct size, and attach them to nextf[NU]. nextf[NU] - is assumed to be empty. Must be called with signals blocked (e.g., - by morecore()). */ -static void -bsplit (nu) - register int nu; -{ - register union mhead *mp; - int nbuck, nblks, split_max; - unsigned long siz; - - split_max = (maxbuck > SPLIT_MAX) ? maxbuck : SPLIT_MAX; - - if (nu >= SPLIT_MID) - { - for (nbuck = split_max; nbuck > nu; nbuck--) - { - if (busy[nbuck] || nextf[nbuck] == 0) - continue; - break; - } - } - else - { - for (nbuck = nu + 1; nbuck <= split_max; nbuck++) - { - if (busy[nbuck] || nextf[nbuck] == 0) - continue; - break; - } - } - - if (nbuck > split_max || nbuck <= nu) - return; - - /* XXX might want to split only if nextf[nbuck] has >= 2 blocks free - and nbuck is below some threshold. */ - -#ifdef MALLOC_STATS - _mstats.tbsplit++; - _mstats.nsplit[nbuck]++; -#endif - - /* Figure out how many blocks we'll get. */ - siz = binsize (nu); - nblks = binsize (nbuck) / siz; - - /* Remove the block from the chain of larger blocks. */ - mp = nextf[nbuck]; - nextf[nbuck] = CHAIN (mp); - - /* Split the block and put it on the requested chain. */ - nextf[nu] = mp; - while (1) - { - mp->mh_alloc = ISFREE; - mp->mh_index = nu; - if (--nblks <= 0) break; - CHAIN (mp) = (union mhead *)((char *)mp + siz); - mp = (union mhead *)((char *)mp + siz); - } - CHAIN (mp) = 0; -} - -static void -block_signals (setp, osetp) - sigset_t *setp, *osetp; -{ -#ifdef HAVE_POSIX_SIGNALS - sigfillset (setp); - sigemptyset (osetp); - sigprocmask (SIG_BLOCK, setp, osetp); -#else -# if defined (HAVE_BSD_SIGNALS) - *osetp = sigsetmask (-1); -# endif -#endif -} - -static void -unblock_signals (setp, osetp) - sigset_t *setp, *osetp; -{ -#ifdef HAVE_POSIX_SIGNALS - sigprocmask (SIG_SETMASK, osetp, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (*osetp); -# endif -#endif -} - -/* Return some memory to the system by reducing the break. This is only - called with NU > pagebucket, so we're always assured of giving back - more than one page of memory. */ -static void -lesscore (nu) /* give system back some memory */ - register int nu; /* size index we're discarding */ -{ - long siz; - - siz = binsize (nu); - /* Should check for errors here, I guess. */ - sbrk (-siz); - memtop -= siz; - -#ifdef MALLOC_STATS - _mstats.nsbrk++; - _mstats.tsbrk -= siz; - _mstats.nlesscore[nu]++; -#endif -} - -static void -morecore (nu) /* ask system for more memory */ - register int nu; /* size index to get more of */ -{ - register union mhead *mp; - register int nblks; - register long siz; - long sbrk_amt; /* amount to get via sbrk() */ - sigset_t set, oset; - int blocked_sigs; - - /* Block all signals in case we are executed from a signal handler. */ - blocked_sigs = 0; -#ifdef SHELL - if (interrupt_immediately || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD)) -#endif - { - block_signals (&set, &oset); - blocked_sigs = 1; - } - - siz = binsize (nu); /* size of desired block for nextf[nu] */ - - if (siz < 0) - goto morecore_done; /* oops */ - -#ifdef MALLOC_STATS - _mstats.nmorecore[nu]++; -#endif - - /* Try to split a larger block here, if we're within the range of sizes - to split. */ - if (nu >= SPLIT_MIN) - { - bsplit (nu); - if (nextf[nu] != 0) - goto morecore_done; - } - - /* Try to coalesce two adjacent blocks from the free list on nextf[nu - 1], - if we can, and we're withing the range of the block coalescing limits. */ - if (nu >= COMBINE_MIN && nu < COMBINE_MAX && busy[nu - 1] == 0 && nextf[nu - 1]) - { - bcoalesce (nu); - if (nextf[nu] != 0) - goto morecore_done; - } - - /* Take at least a page, and figure out how many blocks of the requested - size we're getting. */ - if (siz <= pagesz) - { - sbrk_amt = pagesz; - nblks = sbrk_amt / siz; - } - else - { - /* We always want to request an integral multiple of the page size - from the kernel, so let's compute whether or not `siz' is such - an amount. If it is, we can just request it. If not, we want - the smallest integral multiple of pagesize that is larger than - `siz' and will satisfy the request. */ - sbrk_amt = siz & (pagesz - 1); - if (sbrk_amt == 0) - sbrk_amt = siz; - else - sbrk_amt = siz + pagesz - sbrk_amt; - nblks = 1; - } - -#ifdef MALLOC_STATS - _mstats.nsbrk++; - _mstats.tsbrk += sbrk_amt; -#endif - - mp = (union mhead *) sbrk (sbrk_amt); - - /* Totally out of memory. */ - if ((long)mp == -1) - goto morecore_done; - - memtop += sbrk_amt; - - /* shouldn't happen, but just in case -- require 8-byte alignment */ - if ((long)mp & MALIGN_MASK) - { - mp = (union mhead *) (((long)mp + MALIGN_MASK) & ~MALIGN_MASK); - nblks--; - } - - /* save new header and link the nblks blocks together */ - nextf[nu] = mp; - while (1) - { - mp->mh_alloc = ISFREE; - mp->mh_index = nu; - if (--nblks <= 0) break; - CHAIN (mp) = (union mhead *)((char *)mp + siz); - mp = (union mhead *)((char *)mp + siz); - } - CHAIN (mp) = 0; - -morecore_done: - if (blocked_sigs) - unblock_signals (&set, &oset); -} - -static void -malloc_debug_dummy () -{ - write (1, "malloc_debug_dummy\n", 19); -} - -#define PREPOP_BIN 2 -#define PREPOP_SIZE 32 - -static int -pagealign () -{ - register long nbytes; - register int nunits; - register union mhead *mp; - long sbrk_needed; - char *curbrk; - - pagesz = getpagesize (); - if (pagesz < 1024) - pagesz = 1024; - - /* OK, how much do we need to allocate to make things page-aligned? - Some of this partial page will be wasted space, but we'll use as - much as we can. Once we figure out how much to advance the break - pointer, go ahead and do it. */ - memtop = curbrk = sbrk (0); - sbrk_needed = pagesz - ((long)curbrk & (pagesz - 1)); /* sbrk(0) % pagesz */ - if (sbrk_needed < 0) - sbrk_needed += pagesz; - - /* Now allocate the wasted space. */ - if (sbrk_needed) - { -#ifdef MALLOC_STATS - _mstats.nsbrk++; - _mstats.tsbrk += sbrk_needed; -#endif - curbrk = sbrk (sbrk_needed); - if ((long)curbrk == -1) - return -1; - memtop += sbrk_needed; - - /* Take the memory which would otherwise be wasted and populate the most - popular bin (2 == 32 bytes) with it. Add whatever we need to curbrk - to make things 32-byte aligned, compute how many 32-byte chunks we're - going to get, and set up the bin. */ - curbrk += sbrk_needed & (PREPOP_SIZE - 1); - sbrk_needed -= sbrk_needed & (PREPOP_SIZE - 1); - nunits = sbrk_needed / PREPOP_SIZE; - - mp = (union mhead *)curbrk; - - nextf[PREPOP_BIN] = mp; - while (1) - { - mp->mh_alloc = ISFREE; - mp->mh_index = PREPOP_BIN; - if (--nunits <= 0) break; - CHAIN(mp) = (union mhead *)((char *)mp + PREPOP_SIZE); - mp = (union mhead *)((char *)mp + PREPOP_SIZE); - } - CHAIN(mp) = 0; - } - - /* compute which bin corresponds to the page size. */ - for (nunits = 7; nunits < NBUCKETS; nunits++) - if (pagesz <= binsize(nunits)) - break; - pagebucket = nunits; - - return 0; -} - -static PTR_T -internal_malloc (n, file, line, flags) /* get a block */ - size_t n; - const char *file; - int line, flags; -{ - register union mhead *p; - register int nunits; - register char *m; - long nbytes; - - /* Get the system page size and align break pointer so future sbrks will - be page-aligned. The page size must be at least 1K -- anything - smaller is increased. */ - if (pagesz == 0) - if (pagealign () < 0) - return ((PTR_T)NULL); - - /* Figure out how many bytes are required, rounding up to the nearest - multiple of 8, then figure out which nextf[] area to use. Try to - be smart about where to start searching -- if the number of bytes - needed is greater than the page size, we can start at pagebucket. */ - nbytes = ALLOCATED_BYTES(n); - nunits = (nbytes <= (pagesz >> 1)) ? STARTBUCK : pagebucket; - for ( ; nunits < NBUCKETS; nunits++) - if (nbytes <= binsize(nunits)) - break; - - /* Silently reject too-large requests. */ - if (nunits >= NBUCKETS) - return ((PTR_T) NULL); - - /* 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. */ -#ifdef MALLOC_STATS - if (busy[nunits]) _mstats.nrecurse++; -#endif - while (busy[nunits]) nunits++; - busy[nunits] = 1; - - if (nunits > maxbuck) - maxbuck = nunits; - - /* If there are no blocks of the appropriate size, go get some */ - if (nextf[nunits] == 0) - morecore (nunits); - - /* Get one block off the list, and set the new list head */ - if ((p = nextf[nunits]) == NULL) - { - busy[nunits] = 0; - return NULL; - } - 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) - xbotch ((PTR_T)(p+1), 0, "malloc: block on free list clobbered", file, line); - - /* Fill in the info, and set up the magic numbers for range checking. */ - p->mh_alloc = ISALLOC; - p->mh_magic2 = MAGIC2; - p->mh_nbytes = n; - - /* End guard */ - m = (char *) (p + 1) + n; - *(u_bits32_t *)m = n; - -#ifdef MEMSCRAMBLE - MALLOC_MEMSET ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ -#endif -#ifdef MALLOC_STATS - _mstats.nmalloc[nunits]++; - _mstats.tmalloc[nunits]++; - _mstats.nmal++; - _mstats.bytesreq += n; -#endif /* MALLOC_STATS */ - -#ifdef MALLOC_TRACE - if (malloc_trace && (flags & MALLOC_NOTRACE) == 0) - mtrace_alloc ("malloc", p + 1, n, file, line); - else if (_malloc_trace_buckets[nunits]) - mtrace_alloc ("malloc", p + 1, n, file, line); -#endif - -#ifdef MALLOC_REGISTER - if (malloc_register && (flags & MALLOC_NOREG) == 0) - mregister_alloc ("malloc", p + 1, n, file, line); -#endif - -#ifdef MALLOC_WATCH - if (_malloc_nwatch > 0) - _malloc_ckwatch (p + 1, file, line, W_ALLOC, n); -#endif - - return (PTR_T) (p + 1); -} - -static void -internal_free (mem, file, line, flags) - PTR_T mem; - const char *file; - int line, flags; -{ - register union mhead *p; - register char *ap; - register int nunits; - register unsigned int nbytes; - int ubytes; /* caller-requested size */ - - if ((ap = (char *)mem) == 0) - return; - - p = (union mhead *) ap - 1; - - if (p->mh_alloc == ISMEMALIGN) - { - ap -= p->mh_nbytes; - p = (union mhead *) ap - 1; - } - -#if defined (MALLOC_TRACE) || defined (MALLOC_REGISTER) - if (malloc_trace || malloc_register) - ubytes = p->mh_nbytes; -#endif - - if (p->mh_alloc != ISALLOC) - { - if (p->mh_alloc == ISFREE) - xbotch (mem, ERR_DUPFREE, - "free: called with already freed block argument", file, line); - else - xbotch (mem, ERR_UNALLOC, - "free: called with unallocated block argument", file, line); - } - - ASSERT (p->mh_magic2 == MAGIC2); - - nunits = p->mh_index; - nbytes = ALLOCATED_BYTES(p->mh_nbytes); - /* Since the sizeof(u_bits32_t) bytes before the memory handed to the user - are now used for the number of bytes allocated, a simple check of - mh_magic2 is no longer sufficient to catch things like p[-1] = 'x'. - We sanity-check the value of mh_nbytes against the size of the blocks - in the appropriate bucket before we use it. This can still cause problems - and obscure errors if mh_nbytes is wrong but still within range; the - checks against the size recorded at the end of the chunk will probably - fail then. Using MALLOC_REGISTER will help here, since it saves the - original number of bytes requested. */ - - if (IN_BUCKET(nbytes, nunits) == 0) - xbotch (mem, ERR_UNDERFLOW, - "free: underflow detected; mh_nbytes out of range", file, line); - - ap += p->mh_nbytes; - if (*(u_bits32_t *)ap != p->mh_nbytes) - xbotch (mem, ERR_ASSERT_FAILED, "free: start and end chunk sizes differ", file, line); - -#if 1 - if (nunits >= LESSCORE_MIN && ((char *)p + binsize(nunits) == memtop)) -#else - if (((char *)p + binsize(nunits) == memtop) && nunits >= LESSCORE_MIN) -#endif - { - /* If above LESSCORE_FRC, give back unconditionally. This should be set - high enough to be infrequently encountered. If between LESSCORE_MIN - and LESSCORE_FRC, call lesscore if the bucket is marked as busy (in - which case we would punt below and leak memory) or if there's already - a block on the free list. */ - if ((nunits >= LESSCORE_FRC) || busy[nunits] || nextf[nunits] != 0) - { - lesscore (nunits); - /* keeps the tracing and registering code in one place */ - goto free_return; - } - } - -#ifdef MEMSCRAMBLE - MALLOC_MEMSET (mem, 0xcf, p->mh_nbytes); -#endif - - ASSERT (nunits < NBUCKETS); - p->mh_alloc = ISFREE; - - if (busy[nunits] == 1) - return; /* this is bogus, but at least it won't corrupt the chains */ - - /* 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; - -free_return: - -#ifdef MALLOC_STATS - _mstats.nmalloc[nunits]--; - _mstats.nfre++; -#endif /* MALLOC_STATS */ - -#ifdef MALLOC_TRACE - if (malloc_trace && (flags & MALLOC_NOTRACE) == 0) - mtrace_free (mem, ubytes, file, line); - else if (_malloc_trace_buckets[nunits]) - mtrace_free (mem, ubytes, file, line); -#endif - -#ifdef MALLOC_REGISTER - if (malloc_register && (flags & MALLOC_NOREG) == 0) - mregister_free (mem, ubytes, file, line); -#endif - -#ifdef MALLOC_WATCH - if (_malloc_nwatch > 0) - _malloc_ckwatch (mem, file, line, W_FREE, ubytes); -#endif - -} - -static PTR_T -internal_realloc (mem, n, file, line, flags) - PTR_T mem; - register size_t n; - const char *file; - int line, flags; -{ - register union mhead *p; - register u_bits32_t tocopy; - register unsigned int nbytes; - register int nunits; - register char *m; - -#ifdef MALLOC_STATS - _mstats.nrealloc++; -#endif - - if (n == 0) - { - internal_free (mem, file, line, MALLOC_INTERNAL); - return (NULL); - } - if ((p = (union mhead *) mem) == 0) - return internal_malloc (n, file, line, MALLOC_INTERNAL); - - p--; - nunits = p->mh_index; - ASSERT (nunits < NBUCKETS); - - if (p->mh_alloc != ISALLOC) - xbotch (mem, ERR_UNALLOC, - "realloc: called with unallocated block argument", file, line); - - ASSERT (p->mh_magic2 == MAGIC2); - nbytes = ALLOCATED_BYTES(p->mh_nbytes); - /* Since the sizeof(u_bits32_t) bytes before the memory handed to the user - are now used for the number of bytes allocated, a simple check of - mh_magic2 is no longer sufficient to catch things like p[-1] = 'x'. - We sanity-check the value of mh_nbytes against the size of the blocks - in the appropriate bucket before we use it. This can still cause problems - and obscure errors if mh_nbytes is wrong but still within range; the - checks against the size recorded at the end of the chunk will probably - fail then. Using MALLOC_REGISTER will help here, since it saves the - original number of bytes requested. */ - if (IN_BUCKET(nbytes, nunits) == 0) - xbotch (mem, ERR_UNDERFLOW, - "realloc: underflow detected; mh_nbytes out of range", file, line); - - m = (char *)mem + (tocopy = p->mh_nbytes); - if (*(u_bits32_t *)m != p->mh_nbytes) - xbotch (mem, ERR_ASSERT_FAILED, "realloc: start and end chunk sizes differ", file, line); - -#ifdef MALLOC_WATCH - if (_malloc_nwatch > 0) - _malloc_ckwatch (p + 1, file, line, W_REALLOC, n); -#endif -#ifdef MALLOC_STATS - _mstats.bytesreq += (n < tocopy) ? 0 : n - tocopy; -#endif - - /* See if desired size rounds to same power of 2 as actual size. */ - nbytes = ALLOCATED_BYTES(n); - - /* If ok, use the same block, just marking its size as changed. */ - if (RIGHT_BUCKET(nbytes, nunits)) - { - *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; - m = (char *)mem + (p->mh_nbytes = n); - *(u_bits32_t *)m = p->mh_nbytes; - return mem; - } - - if (n < tocopy) - tocopy = n; - -#ifdef MALLOC_STATS - _mstats.nrcopy++; -#endif - - if ((m = internal_malloc (n, file, line, MALLOC_INTERNAL|MALLOC_NOTRACE|MALLOC_NOREG)) == 0) - return 0; - FASTCOPY (mem, m, tocopy); - internal_free (mem, file, line, MALLOC_INTERNAL); - -#ifdef MALLOC_TRACE - if (malloc_trace && (flags & MALLOC_NOTRACE) == 0) - mtrace_alloc ("realloc", m, n, file, line); - else if (_malloc_trace_buckets[nunits]) - mtrace_alloc ("realloc", m, n, file, line); -#endif - -#ifdef MALLOC_REGISTER - if (malloc_register && (flags & MALLOC_NOREG) == 0) - mregister_alloc ("realloc", m, n, file, line); -#endif - -#ifdef MALLOC_WATCH - if (_malloc_nwatch > 0) - _malloc_ckwatch (m, file, line, W_RESIZED, n); -#endif - - return m; -} - -static PTR_T -internal_memalign (alignment, size, file, line, flags) - unsigned int alignment; - size_t size; - const char *file; - int line, flags; -{ - register char *ptr; - register char *aligned; - register union mhead *p; - - ptr = internal_malloc (size + alignment, file, line, MALLOC_INTERNAL); - - if (ptr == 0) - return 0; - /* If entire block has the desired alignment, just accept it. */ - if (((long) ptr & (alignment - 1)) == 0) - return ptr; - /* Otherwise, get address of byte in the block that has that alignment. */ -#if 0 - aligned = (char *) (((long) ptr + alignment - 1) & -alignment); -#else - aligned = (char *) (((long) ptr + alignment - 1) & (~alignment + 1)); -#endif - - /* Store a suitable indication of how to free the block, - so that free can find the true beginning of it. */ - p = (union mhead *) aligned - 1; - p->mh_nbytes = aligned - ptr; - p->mh_alloc = ISMEMALIGN; - - return aligned; -} - -#if !defined (NO_VALLOC) -/* This runs into trouble with getpagesize on HPUX, and Multimax machines. - Patching out seems cleaner than the ugly fix needed. */ -static PTR_T -internal_valloc (size, file, line, flags) - size_t size; - const char *file; - int line, flags; -{ - return internal_memalign (getpagesize (), size, file, line, flags|MALLOC_INTERNAL); -} -#endif /* !NO_VALLOC */ - -#ifndef NO_CALLOC -static PTR_T -internal_calloc (n, s, file, line, flags) - size_t n, s; - const char *file; - int line, flags; -{ - size_t total; - PTR_T result; - - total = n * s; - result = internal_malloc (total, file, line, flags|MALLOC_INTERNAL); - if (result) - memset (result, 0, total); - return result; -} - -static void -internal_cfree (p, file, line, flags) - PTR_T p; - const char *file; - int line, flags; -{ - internal_free (p, file, line, flags|MALLOC_INTERNAL); -} -#endif /* !NO_CALLOC */ - -#ifdef MALLOC_STATS -int -malloc_free_blocks (size) - int size; -{ - int nfree; - register union mhead *p; - - nfree = 0; - for (p = nextf[size]; p; p = CHAIN (p)) - nfree++; - - return nfree; -} -#endif - -#if defined (MALLOC_WRAPFUNCS) -PTR_T -sh_malloc (bytes, file, line) - size_t bytes; - const char *file; - int line; -{ - return internal_malloc (bytes, file, line, MALLOC_WRAPPER); -} - -PTR_T -sh_realloc (ptr, size, file, line) - PTR_T ptr; - size_t size; - const char *file; - int line; -{ - return internal_realloc (ptr, size, file, line, MALLOC_WRAPPER); -} - -void -sh_free (mem, file, line) - PTR_T mem; - const char *file; - int line; -{ - internal_free (mem, file, line, MALLOC_WRAPPER); -} - -PTR_T -sh_memalign (alignment, size, file, line) - unsigned int alignment; - size_t size; - const char *file; - int line; -{ - return internal_memalign (alignment, size, file, line, MALLOC_WRAPPER); -} - -#ifndef NO_CALLOC -PTR_T -sh_calloc (n, s, file, line) - size_t n, s; - const char *file; - int line; -{ - return internal_calloc (n, s, file, line, MALLOC_WRAPPER); -} - -void -sh_cfree (mem, file, line) - PTR_T mem; - const char *file; - int line; -{ - internal_cfree (mem, file, line, MALLOC_WRAPPER); -} -#endif - -#ifndef NO_VALLOC -PTR_T -sh_valloc (size, file, line) - size_t size; - const char *file; - int line; -{ - return internal_valloc (size, file, line, MALLOC_WRAPPER); -} -#endif /* !NO_VALLOC */ - -#endif /* MALLOC_WRAPFUNCS */ - -/* Externally-available functions that call their internal counterparts. */ - -PTR_T -malloc (size) - size_t size; -{ - return internal_malloc (size, (char *)NULL, 0, 0); -} - -PTR_T -realloc (mem, nbytes) - PTR_T mem; - size_t nbytes; -{ - return internal_realloc (mem, nbytes, (char *)NULL, 0, 0); -} - -void -free (mem) - PTR_T mem; -{ - internal_free (mem, (char *)NULL, 0, 0); -} - -PTR_T -memalign (alignment, size) - unsigned int alignment; - size_t size; -{ - return internal_memalign (alignment, size, (char *)NULL, 0, 0); -} - -#ifndef NO_VALLOC -PTR_T -valloc (size) - size_t size; -{ - return internal_valloc (size, (char *)NULL, 0, 0); -} -#endif - -#ifndef NO_CALLOC -PTR_T -calloc (n, s) - size_t n, s; -{ - return internal_calloc (n, s, (char *)NULL, 0, 0); -} - -void -cfree (mem) - PTR_T mem; -{ - internal_cfree (mem, (char *)NULL, 0, 0); -} -#endif diff --git a/lib/readline/bind.c~ b/lib/readline/bind.c~ deleted file mode 100644 index 3f243c1ca..000000000 --- a/lib/readline/bind.c~ +++ /dev/null @@ -1,2223 +0,0 @@ -/* 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 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if defined (__TANDEM) -# include -#endif - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include - -#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" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - -/* Variables exported by this file. */ -Keymap rl_binding_keymap; - -static char *_rl_read_file PARAMS((char *, size_t *)); -static void _rl_init_file_error PARAMS((const char *)); -static int _rl_read_init_file PARAMS((const char *, int)); -static int glean_key_from_name PARAMS((char *)); -static int substring_member_of_array PARAMS((char *, const char **)); - -static int currently_reading_init_file; - -/* used only in this file */ -static int _rl_prefer_visible_bell = 1; - -/* **************************************************************** */ -/* */ -/* Binding keys */ -/* */ -/* **************************************************************** */ - -/* rl_add_defun (char *name, rl_command_func_t *function, int key) - Add NAME to the list of named functions. Make FUNCTION be the function - that gets called. If KEY is not -1, then bind it. */ -int -rl_add_defun (name, function, key) - const char *name; - rl_command_func_t *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; - rl_command_func_t *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; - rl_binding_keymap = _rl_keymap; - 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; - rl_command_func_t *function; - Keymap map; -{ - int result; - Keymap oldmap; - - oldmap = _rl_keymap; - _rl_keymap = map; - result = rl_bind_key (key, function); - _rl_keymap = oldmap; - return (result); -} - -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right - now, this is always used to attempt to bind the arrow keys, hence the - check for rl_vi_movement_mode. */ -int -rl_bind_key_if_unbound_in_map (key, default_func, kmap) - int key; - rl_command_func_t *default_func; - Keymap kmap; -{ - char keyseq[2]; - - keyseq[0] = (unsigned char)key; - keyseq[1] = '\0'; - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap)); -} - -int -rl_bind_key_if_unbound (key, default_func) - int key; - rl_command_func_t *default_func; -{ - char keyseq[2]; - - keyseq[0] = (unsigned char)key; - keyseq[1] = '\0'; - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); -} - -/* 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, (rl_command_func_t *)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, (rl_command_func_t *)NULL, map)); -} - -/* Unbind all keys bound to FUNCTION in MAP. */ -int -rl_unbind_function_in_map (func, map) - rl_command_func_t *func; - Keymap map; -{ - register int i, rval; - - for (i = rval = 0; i < KEYMAP_SIZE; i++) - { - if (map[i].type == ISFUNC && map[i].function == func) - { - map[i].function = (rl_command_func_t *)NULL; - rval = 1; - } - } - return rval; -} - -int -rl_unbind_command_in_map (command, map) - const char *command; - Keymap map; -{ - rl_command_func_t *func; - - func = rl_named_function (command); - if (func == 0) - return 0; - return (rl_unbind_function_in_map (func, map)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION, starting in the current keymap. This makes new - keymaps as necessary. */ -int -rl_bind_keyseq (keyseq, function) - const char *keyseq; - rl_command_func_t *function; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION. This makes new keymaps as necessary. The initial - place to do bindings is in MAP. */ -int -rl_bind_keyseq_in_map (keyseq, function, map) - const char *keyseq; - rl_command_func_t *function; - Keymap map; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); -} - -/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */ -int -rl_set_key (keyseq, function, map) - const char *keyseq; - rl_command_func_t *function; - Keymap map; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); -} - -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right - now, this is always used to attempt to bind the arrow keys, hence the - check for rl_vi_movement_mode. */ -int -rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap) - const char *keyseq; - rl_command_func_t *default_func; - Keymap kmap; -{ - rl_command_func_t *func; - - if (keyseq) - { - func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL); -#if defined (VI_MODE) - if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) -#else - if (!func || func == rl_do_lowercase_version) -#endif - return (rl_bind_keyseq_in_map (keyseq, default_func, kmap)); - else - return 1; - } - return 0; -} - -int -rl_bind_keyseq_if_unbound (keyseq, default_func) - const char *keyseq; - rl_command_func_t *default_func; -{ - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the string of characters MACRO. This makes new keymaps as - necessary. The initial place to do bindings is in MAP. */ -int -rl_macro_bind (keyseq, macro, map) - const 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. */ -int -rl_generic_bind (type, keyseq, data, map) - int type; - const char *keyseq; - char *data; - Keymap map; -{ - char *keys; - int keys_len; - register int i; - KEYMAP_ENTRY k; - - k.function = 0; - - /* If no keys to bind to, exit right away. */ - if (!keyseq || !*keyseq) - { - if (type == ISMACR) - free (data); - return -1; - } - - keys = (char *)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++) - { - unsigned char uc = keys[i]; - int ic; - - ic = uc; - if (ic < 0 || ic >= KEYMAP_SIZE) - return -1; - - 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) - { - /* We allow subsequences of keys. If a keymap is being - created that will `shadow' an existing function or macro - key binding, we save that keybinding into the ANYOTHERKEY - index in the new map. The dispatch code will look there - to find the function to execute if the subsequence is not - matched. ANYOTHERKEY was chosen to be greater than - UCHAR_MAX. */ - k = map[ic]; - - map[ic].type = ISKMAP; - map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); - } - map = FUNCTION_TO_KEYMAP (map, ic); - /* The dispatch code will return this function if no matching - key sequence is found in the keymap. This (with a little - help from the dispatch code in readline.c) allows `a' to be - mapped to something, `abc' to be mapped to something else, - and the function bound to `a' to be executed when the user - types `abx', leaving `bx' in the input queue. */ - if (k.function && ((k.type == ISFUNC && k.function != rl_do_lowercase_version) || k.type == ISMACR)) - { - map[ANYOTHERKEY] = k; - k.function = 0; - } - } - else - { - if (map[ic].type == ISMACR) - free ((char *)map[ic].function); - else if (map[ic].type == ISKMAP) - { - map = FUNCTION_TO_KEYMAP (map, ic); - ic = ANYOTHERKEY; - } - - map[ic].function = KEYMAP_TO_FUNCTION (data); - map[ic].type = type; - } - - rl_binding_keymap = map; - } - 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. */ -int -rl_translate_keyseq (seq, array, len) - const char *seq; - char *array; - int *len; -{ - register int i, c, l, temp; - - for (i = l = 0; c = seq[i]; i++) - { - if (c == '\\') - { - c = seq[++i]; - - if (c == 0) - break; - - /* Handle \C- and \M- prefixes. */ - if ((c == 'C' || c == 'M') && seq[i + 1] == '-') - { - /* Handle special case of backwards define. */ - if (strncmp (&seq[i], "C-\\M-", 5) == 0) - { - array[l++] = ESC; /* ESC is meta-prefix */ - i += 5; - array[l++] = CTRL (_rl_to_upper (seq[i])); - if (seq[i] == '\0') - i--; - } - else if (c == 'M') - { - i++; - array[l++] = ESC; /* ESC is meta-prefix */ - } - else if (c == 'C') - { - i += 2; - /* Special hack for C-?... */ - array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - } - continue; - } - - /* Translate other backslash-escaped characters. These are the - same escape sequences that bash's `echo' and `printf' builtins - handle, with the addition of \d -> RUBOUT. A backslash - preceding a character that is not special is stripped. */ - switch (c) - { - case 'a': - array[l++] = '\007'; - break; - case 'b': - array[l++] = '\b'; - break; - case 'd': - array[l++] = RUBOUT; /* readline-specific */ - break; - case 'e': - array[l++] = ESC; - break; - case 'f': - array[l++] = '\f'; - break; - case 'n': - array[l++] = NEWLINE; - break; - case 'r': - array[l++] = RETURN; - break; - case 't': - array[l++] = TAB; - break; - case 'v': - array[l++] = 0x0B; - break; - case '\\': - array[l++] = '\\'; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - i++; - for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++) - c = (c * 8) + OCTVALUE (seq[i]); - i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; - break; - case 'x': - i++; - for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++) - c = (c * 16) + HEXVALUE (seq[i]); - if (temp == 2) - c = 'x'; - i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; - break; - default: /* backslashes before non-special chars just add the char */ - array[l++] = c; - break; /* the backslash is stripped */ - } - continue; - } - - array[l++] = c; - } - - *len = l; - array[l] = '\0'; - return (0); -} - -char * -rl_untranslate_keyseq (seq) - int seq; -{ - static char kseq[16]; - int i, c; - - i = 0; - c = seq; - if (META_CHAR (c)) - { - kseq[i++] = '\\'; - kseq[i++] = 'M'; - kseq[i++] = '-'; - c = UNMETA (c); - } - else if (CTRL_CHAR (c)) - { - kseq[i++] = '\\'; - kseq[i++] = 'C'; - kseq[i++] = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - else if (c == RUBOUT) - { - kseq[i++] = '\\'; - kseq[i++] = 'C'; - kseq[i++] = '-'; - c = '?'; - } - - if (c == ESC) - { - kseq[i++] = '\\'; - c = 'e'; - } - else if (c == '\\' || c == '"') - { - kseq[i++] = '\\'; - } - - kseq[i++] = (unsigned char) c; - kseq[i] = '\0'; - return kseq; -} - -static char * -_rl_untranslate_macro_value (seq) - char *seq; -{ - char *ret, *r, *s; - int c; - - r = ret = (char *)xmalloc (7 * strlen (seq) + 1); - for (s = seq; *s; s++) - { - c = *s; - if (META_CHAR (c)) - { - *r++ = '\\'; - *r++ = 'M'; - *r++ = '-'; - c = UNMETA (c); - } - else if (CTRL_CHAR (c) && c != ESC) - { - *r++ = '\\'; - *r++ = 'C'; - *r++ = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - else if (c == RUBOUT) - { - *r++ = '\\'; - *r++ = 'C'; - *r++ = '-'; - c = '?'; - } - - if (c == ESC) - { - *r++ = '\\'; - c = 'e'; - } - else if (c == '\\' || c == '"') - *r++ = '\\'; - - *r++ = (unsigned char)c; - } - *r = '\0'; - return ret; -} - -/* Return a pointer to the function that STRING represents. - If STRING doesn't have a matching function, then a NULL pointer - is returned. */ -rl_command_func_t * -rl_named_function (string) - const char *string; -{ - register int i; - - rl_initialize_funmap (); - - for (i = 0; funmap[i]; i++) - if (_rl_stricmp (funmap[i]->name, string) == 0) - return (funmap[i]->function); - return ((rl_command_func_t *)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). */ -rl_command_func_t * -rl_function_of_keyseq (keyseq, map, type) - const char *keyseq; - Keymap map; - int *type; -{ - register int i; - - if (!map) - map = _rl_keymap; - - for (i = 0; keyseq && keyseq[i]; i++) - { - unsigned char 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 ((rl_command_func_t *) NULL); -} - -/* The last key bindings file read. */ -static char *last_readline_init_file = (char *)NULL; - -/* The file we're currently reading key bindings from. */ -static const char *current_readline_init_file; -static int current_readline_init_include_level; -static int current_readline_init_lineno; - -/* Read FILENAME into a locally-allocated buffer and return the buffer. - The size of the buffer is returned in *SIZEP. Returns NULL if any - errors were encountered. */ -static char * -_rl_read_file (filename, sizep) - char *filename; - size_t *sizep; -{ - struct stat finfo; - size_t file_size; - char *buffer; - int i, file; - - if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0) - return ((char *)NULL); - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - if (file >= 0) - close (file); -#if defined (EFBIG) - errno = EFBIG; -#endif - return ((char *)NULL); - } - - /* Read the file into BUFFER. */ - buffer = (char *)xmalloc (file_size + 1); - i = read (file, buffer, file_size); - close (file); - - if (i < 0) - { - free (buffer); - return ((char *)NULL); - } - - buffer[i] = '\0'; - if (sizep) - *sizep = i; - - return (buffer); -} - -/* Re-read the current keybindings file. */ -int -rl_re_read_init_file (count, ignore) - int count, ignore; -{ - int r; - r = rl_read_init_file ((const 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) - const char *filename; -{ - /* Default the filename. */ - if (filename == 0) - { - filename = last_readline_init_file; - if (filename == 0) - filename = sh_get_env_value ("INPUTRC"); - if (filename == 0) - filename = DEFAULT_INPUTRC; - } - - if (*filename == 0) - filename = DEFAULT_INPUTRC; - -#if defined (__MSDOS__) - if (_rl_read_init_file (filename, 0) == 0) - return 0; - filename = "~/_inputrc"; -#endif - return (_rl_read_init_file (filename, 0)); -} - -static int -_rl_read_init_file (filename, include_level) - const char *filename; - int include_level; -{ - register int i; - char *buffer, *openname, *line, *end; - size_t file_size; - - current_readline_init_file = filename; - current_readline_init_include_level = include_level; - - openname = tilde_expand (filename); - buffer = _rl_read_file (openname, &file_size); - free (openname); - - if (buffer == 0) - return (errno); - - if (include_level == 0 && filename != last_readline_init_file) - { - FREE (last_readline_init_file); - last_readline_init_file = savestring (filename); - } - - currently_reading_init_file = 1; - - /* Loop over the lines in the file. Lines that start with `#' are - comments; all other lines are commands for readline initialization. */ - current_readline_init_lineno = 1; - line = buffer; - end = buffer + file_size; - while (line < end) - { - /* Find the end of this line. */ - for (i = 0; line + i != end && line[i] != '\n'; i++); - -#if defined (__CYGWIN__) - /* ``Be liberal in what you accept.'' */ - if (line[i] == '\n' && line[i-1] == '\r') - line[i - 1] = '\0'; -#endif - - /* 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; - current_readline_init_lineno++; - } - - free (buffer); - currently_reading_init_file = 0; - return (0); -} - -static void -_rl_init_file_error (msg) - const char *msg; -{ - if (currently_reading_init_file) - fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file, - current_readline_init_lineno, msg); - else - fprintf (stderr, "readline: %s\n", msg); -} - -/* **************************************************************** */ -/* */ -/* Parser Directives */ -/* */ -/* **************************************************************** */ - -typedef int _rl_parser_func_t PARAMS((char *)); - -/* Things that mean `Control'. */ -const char *_rl_possible_control_prefixes[] = { - "Control-", "C-", "CTRL-", (const char *)NULL -}; - -const char *_rl_possible_meta_prefixes[] = { - "Meta", "M-", (const char *)NULL -}; - -/* Conditionals. */ - -/* Calling programs set this to have their argv[0]. */ -const 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; -static int if_stack_size; - -/* 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 && _rl_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. */ - _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && - _rl_stricmp (args + 5, rl_terminal_name); - free (tname); - } -#if defined (VI_MODE) - else if (_rl_strnicmp (args, "mode=", 5) == 0) - { - int mode; - - if (_rl_stricmp (args + 5, "emacs") == 0) - mode = emacs_mode; - else if (_rl_stricmp (args + 5, "vi") == 0) - mode = vi_mode; - else - mode = no_mode; - - _rl_parsing_conditionalized_out = mode != rl_editing_mode; - } -#endif /* VI_MODE */ - /* Check to see if the first word in ARGS is the same as the - value stored in rl_readline_name. */ - else if (_rl_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 == 0) - { - _rl_init_file_error ("$else found without matching $if"); - return 0; - } - -#if 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++) -#else - /* Check the previous (n) levels of the stack to make sure that - we haven't previously turned off parsing. */ - for (i = 0; i < if_stack_depth; i++) -#endif - 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 - _rl_init_file_error ("$endif without matching $if"); - return 0; -} - -static int -parser_include (args) - char *args; -{ - const char *old_init_file; - char *e; - int old_line_number, old_include_level, r; - - if (_rl_parsing_conditionalized_out) - return (0); - - old_init_file = current_readline_init_file; - old_line_number = current_readline_init_lineno; - old_include_level = current_readline_init_include_level; - - e = strchr (args, '\n'); - if (e) - *e = '\0'; - r = _rl_read_init_file ((const char *)args, old_include_level + 1); - - current_readline_init_file = old_init_file; - current_readline_init_lineno = old_line_number; - current_readline_init_include_level = old_include_level; - - return r; -} - -/* Associate textual names with actual functions. */ -static struct { - const char *name; - _rl_parser_func_t *function; -} parser_directives [] = { - { "if", parser_if }, - { "endif", parser_endif }, - { "else", parser_else }, - { "include", parser_include }, - { (char *)0x0, (_rl_parser_func_t *)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 (_rl_stricmp (directive, parser_directives[i].name) == 0) - { - (*parser_directives[i].function) (args); - return (0); - } - - /* display an error message about the unknown parser directive */ - _rl_init_file_error ("unknown parser directive"); - return (1); -} - -/* Read the binding command from STRING and perform it. - A key binding command looks like: Keyname: function-name\0, - a variable binding command looks like: set variable value. - A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ -int -rl_parse_and_bind (string) - char *string; -{ - 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; - } - /* If we didn't find a closing quote, abort the line. */ - if (string[i] == '\0') - { - _rl_init_file_error ("no closing `\"' in key binding"); - return 1; - } - } - - /* Advance to the colon (:) or whitespace which separates the two objects. */ - 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 (_rl_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++], passc; - - for (passc = 0; 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_bind_keyseq (). Otherwise, let the older code deal with it. */ - if (*string == '"') - { - char *seq; - register int j, k, passc; - - seq = (char *)xmalloc (1 + strlen (string)); - for (j = 1, k = passc = 0; 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_bind_keyseq (seq, rl_named_function (funname)); - - 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, _rl_possible_control_prefixes)) - key = CTRL (_rl_to_upper (key)); - - if (substring_member_of_array (string, _rl_possible_meta_prefixes)) - key = META (key); - - /* Temporary. Handle old-style keyname with macro-binding. */ - if (*funname == '\'' || *funname == '"') - { - char useq[2]; - int fl = strlen (funname); - - useq[0] = key; useq[1] = '\0'; - if (fl && funname[fl - 1] == *funname) - funname[fl - 1] = '\0'; - - rl_macro_bind (useq, &funname[1], _rl_keymap); - } -#if defined (PREFIX_META_HACK) - /* Ugly, but working hack to keep prefix-meta around. */ - else if (_rl_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. */ - -#define V_SPECIAL 0x1 - -static struct { - const char *name; - int *value; - int flags; -} boolean_varlist [] = { - { "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL }, - { "byte-oriented", &rl_byte_oriented, 0 }, - { "completion-ignore-case", &_rl_completion_case_fold, 0 }, - { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, - { "disable-completion", &rl_inhibit_completion, 0 }, - { "enable-keypad", &_rl_enable_keypad, 0 }, - { "expand-tilde", &rl_complete_with_tilde_expansion, 0 }, - { "history-preserve-point", &_rl_history_preserve_point, 0 }, - { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode, 0 }, - { "input-meta", &_rl_meta_flag, 0 }, - { "mark-directories", &_rl_complete_mark_directories, 0 }, - { "mark-modified-lines", &_rl_mark_modified_lines, 0 }, - { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 }, - { "match-hidden-files", &_rl_match_hidden_files, 0 }, - { "meta-flag", &_rl_meta_flag, 0 }, - { "output-meta", &_rl_output_meta_chars, 0 }, - { "page-completions", &_rl_page_completions, 0 }, - { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, - { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, - { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, - { "show-all-if-unmodified", &_rl_complete_show_unmodified, 0 }, -#if defined (VISIBLE_STATS) - { "visible-stats", &rl_visible_stats, 0 }, -#endif /* VISIBLE_STATS */ - { (char *)NULL, (int *)NULL } -}; - -static int -find_boolean_var (name) - const char *name; -{ - register int i; - - for (i = 0; boolean_varlist[i].name; i++) - if (_rl_stricmp (name, boolean_varlist[i].name) == 0) - return i; - return -1; -} - -/* Hooks for handling special boolean variables, where a - function needs to be called or another variable needs - to be changed when they're changed. */ -static void -hack_special_boolean_var (i) - int i; -{ - const char *name; - - name = boolean_varlist[i].name; - - if (_rl_stricmp (name, "blink-matching-paren") == 0) - _rl_enable_paren_matching (rl_blink_matching_paren); - else if (_rl_stricmp (name, "prefer-visible-bell") == 0) - { - if (_rl_prefer_visible_bell) - _rl_bell_preference = VISIBLE_BELL; - else - _rl_bell_preference = AUDIBLE_BELL; - } -} - -typedef int _rl_sv_func_t PARAMS((const char *)); - -/* These *must* correspond to the array indices for the appropriate - string variable. (Though they're not used right now.) */ -#define V_BELLSTYLE 0 -#define V_COMBEGIN 1 -#define V_EDITMODE 2 -#define V_ISRCHTERM 3 -#define V_KEYMAP 4 - -#define V_STRING 1 -#define V_INT 2 - -/* Forward declarations */ -static int sv_bell_style PARAMS((const char *)); -static int sv_combegin PARAMS((const char *)); -static int sv_compquery PARAMS((const char *)); -static int sv_editmode PARAMS((const char *)); -static int sv_isrchterm PARAMS((const char *)); -static int sv_keymap PARAMS((const char *)); - -static struct { - const char *name; - int flags; - _rl_sv_func_t *set_func; -} string_varlist[] = { - { "bell-style", V_STRING, sv_bell_style }, - { "comment-begin", V_STRING, sv_combegin }, - { "completion-query-items", V_INT, sv_compquery }, - { "editing-mode", V_STRING, sv_editmode }, - { "isearch-terminators", V_STRING, sv_isrchterm }, - { "keymap", V_STRING, sv_keymap }, - { (char *)NULL, 0 } -}; - -static int -find_string_var (name) - const char *name; -{ - register int i; - - for (i = 0; string_varlist[i].name; i++) - if (_rl_stricmp (name, string_varlist[i].name) == 0) - return i; - return -1; -} - -/* A boolean value that can appear in a `set variable' command is true if - the value is null or empty, `on' (case-insenstive), or "1". Any other - values result in 0 (false). */ -static int -bool_to_int (value) - char *value; -{ - return (value == 0 || *value == '\0' || - (_rl_stricmp (value, "on") == 0) || - (value[0] == '1' && value[1] == '\0')); -} - -int -rl_variable_bind (name, value) - const char *name, *value; -{ - register int i; - int v; - - /* Check for simple variables first. */ - i = find_boolean_var (name); - if (i >= 0) - { - *boolean_varlist[i].value = bool_to_int (value); - if (boolean_varlist[i].flags & V_SPECIAL) - hack_special_boolean_var (i); - return 0; - } - - i = find_string_var (name); - - /* For the time being, unknown variable names or string names without a - handler function are simply ignored. */ - if (i < 0 || string_varlist[i].set_func == 0) - return 0; - - v = (*string_varlist[i].set_func) (value); - return v; -} - -static int -sv_editmode (value) - const char *value; -{ - if (_rl_strnicmp (value, "vi", 2) == 0) - { -#if defined (VI_MODE) - _rl_keymap = vi_insertion_keymap; - rl_editing_mode = vi_mode; -#endif /* VI_MODE */ - return 0; - } - else if (_rl_strnicmp (value, "emacs", 5) == 0) - { - _rl_keymap = emacs_standard_keymap; - rl_editing_mode = emacs_mode; - return 0; - } - return 1; -} - -static int -sv_combegin (value) - const char *value; -{ - if (value && *value) - { - FREE (_rl_comment_begin); - _rl_comment_begin = savestring (value); - return 0; - } - return 1; -} - -static int -sv_compquery (value) - const char *value; -{ - int nval = 100; - - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - rl_completion_query_items = nval; - return 0; -} - -static int -sv_keymap (value) - const char *value; -{ - Keymap kmap; - - kmap = rl_get_keymap_by_name (value); - if (kmap) - { - rl_set_keymap (kmap); - return 0; - } - return 1; -} - -static int -sv_bell_style (value) - const char *value; -{ - if (value == 0 || *value == '\0') - _rl_bell_preference = AUDIBLE_BELL; - else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0) - _rl_bell_preference = NO_BELL; - else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0) - _rl_bell_preference = AUDIBLE_BELL; - else if (_rl_stricmp (value, "visible") == 0) - _rl_bell_preference = VISIBLE_BELL; - else - return 1; - return 0; -} - -static int -sv_isrchterm (value) - const char *value; -{ - int beg, end, delim; - char *v; - - if (value == 0) - return 1; - - /* Isolate the value and translate it into a character string. */ - v = savestring (value); - FREE (_rl_isearch_terminators); - if (v[0] == '"' || v[0] == '\'') - { - delim = v[0]; - for (beg = end = 1; v[end] && v[end] != delim; end++) - ; - } - else - { - for (beg = end = 0; whitespace (v[end]) == 0; end++) - ; - } - - v[end] = '\0'; - - /* The value starts at v + beg. Translate it into a character string. */ - _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1); - rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end); - _rl_isearch_terminators[end] = '\0'; - - free (v); - return 0; -} - -/* Return the character which matches NAME. - For example, `Space' returns ' '. */ - -typedef struct { - const 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 (_rl_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 { - const 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) - const char *name; -{ - register int i; - - for (i = 0; keymap_names[i].name; i++) - if (_rl_stricmp (name, keymap_names[i].name) == 0) - return (keymap_names[i].map); - return ((Keymap) NULL); -} - -char * -rl_get_keymap_name (map) - Keymap map; -{ - register int i; - for (i = 0; keymap_names[i].name; i++) - if (map == keymap_names[i].map) - return ((char *)keymap_names[i].name); - return ((char *)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 */ -} - -char * -rl_get_keymap_name_from_edit_mode () -{ - if (rl_editing_mode == emacs_mode) - return "emacs"; -#if defined (VI_MODE) - else if (rl_editing_mode == vi_mode) - return "vi"; -#endif /* VI_MODE */ - else - return "none"; -} - -/* **************************************************************** */ -/* */ -/* Key Binding and Function Information */ -/* */ -/* **************************************************************** */ - -/* 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 () -{ - register int i; - const 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); -} - -static char * -_rl_get_keyname (key) - int key; -{ - char *keyname; - int i, c; - - keyname = (char *)xmalloc (8); - - c = key; - /* Since this is going to be used to write out keysequence-function - pairs for possible inclusion in an inputrc file, we don't want to - do any special meta processing on KEY. */ - -#if 1 - /* XXX - Experimental */ - /* We might want to do this, but the old version of the code did not. */ - - /* If this is an escape character, we don't want to do any more processing. - Just add the special ESC key sequence and return. */ - if (c == ESC) - { - keyname[0] = '\\'; - keyname[1] = 'e'; - keyname[2] = '\0'; - return keyname; - } -#endif - - /* RUBOUT is translated directly into \C-? */ - if (key == RUBOUT) - { - keyname[0] = '\\'; - keyname[1] = 'C'; - keyname[2] = '-'; - keyname[3] = '?'; - keyname[4] = '\0'; - return keyname; - } - - i = 0; - /* Now add special prefixes needed for control characters. This can - potentially change C. */ - if (CTRL_CHAR (c)) - { - keyname[i++] = '\\'; - keyname[i++] = 'C'; - keyname[i++] = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - - /* XXX experimental code. Turn the characters that are not ASCII or - ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237). - This changes C. */ - if (c >= 128 && c <= 159) - { - keyname[i++] = '\\'; - keyname[i++] = '2'; - c -= 128; - keyname[i++] = (c / 8) + '0'; - c = (c % 8) + '0'; - } - - /* Now, if the character needs to be quoted with a backslash, do that. */ - if (c == '\\' || c == '"') - keyname[i++] = '\\'; - - /* Now add the key, terminate the string, and return it. */ - keyname[i++] = (char) c; - keyname[i] = '\0'; - - return keyname; -} - -/* Return a NULL terminated array of strings which represent the key - sequences that are used to invoke FUNCTION in MAP. */ -char ** -rl_invoking_keyseqs_in_map (function, map) - rl_command_func_t *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 < KEYMAP_SIZE; 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; - - keyname = _rl_get_keyname (key); - - if (result_index + 2 > result_size) - { - result_size += 10; - result = (char **)xrealloc (result, result_size * sizeof (char *)); - } - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; - } - break; - - case ISKMAP: - { - char **seqs; - register int i; - - /* Find the list of keyseqs in this map which have FUNCTION as - their target. Add the key sequences found to RESULT. */ - if (map[key].function) - seqs = - rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); - else - break; - - if (seqs == 0) - break; - - for (i = 0; seqs[i]; i++) - { - char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - - if (key == ESC) -#if 0 - sprintf (keyname, "\\e"); -#else - /* XXX - experimental */ - sprintf (keyname, "\\M-"); -#endif - else if (CTRL_CHAR (key)) - sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } - else - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } - - strcat (keyname, seqs[i]); - free (seqs[i]); - - if (result_index + 2 > result_size) - { - result_size += 10; - result = (char **)xrealloc (result, result_size * 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) - rl_command_func_t *function; -{ - return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); -} - -/* 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; - const char **names; - const char *name; - - names = rl_funmap_names (); - - fprintf (rl_outstream, "\n"); - - for (i = 0; name = names[i]; i++) - { - rl_command_func_t *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); - } - } - } -} - -/* 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; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_function_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -static void -_rl_macro_dumper_internal (print_readably, map, prefix) - int print_readably; - Keymap map; - char *prefix; -{ - register int key; - char *keyname, *out; - int prefix_len; - - for (key = 0; key < KEYMAP_SIZE; key++) - { - switch (map[key].type) - { - case ISMACR: - keyname = _rl_get_keyname (key); - out = _rl_untranslate_macro_value ((char *)map[key].function); - - if (print_readably) - fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", - keyname, - out ? out : ""); - else - fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "", - keyname, - out ? out : ""); - free (keyname); - free (out); - break; - case ISFUNC: - break; - case ISKMAP: - prefix_len = prefix ? strlen (prefix) : 0; - if (key == ESC) - { - keyname = (char *)xmalloc (3 + prefix_len); - if (prefix) - strcpy (keyname, prefix); - keyname[prefix_len] = '\\'; - keyname[prefix_len + 1] = 'e'; - keyname[prefix_len + 2] = '\0'; - } - else - { - keyname = _rl_get_keyname (key); - if (prefix) - { - out = (char *)xmalloc (strlen (keyname) + prefix_len + 1); - strcpy (out, prefix); - strcpy (out + prefix_len, keyname); - free (keyname); - keyname = out; - } - } - - _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); - free (keyname); - break; - } - } -} - -void -rl_macro_dumper (print_readably) - int print_readably; -{ - _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL); -} - -int -rl_dump_macros (count, key) - int count, key; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_macro_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -void -rl_variable_dumper (print_readably) - int print_readably; -{ - int i; - const char *kname; - - for (i = 0; boolean_varlist[i].name; i++) - { - if (print_readably) - fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name, - *boolean_varlist[i].value ? "on" : "off"); - else - fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name, - *boolean_varlist[i].value ? "on" : "off"); - } - - /* bell-style */ - switch (_rl_bell_preference) - { - case NO_BELL: - kname = "none"; break; - case VISIBLE_BELL: - kname = "visible"; break; - case AUDIBLE_BELL: - default: - kname = "audible"; break; - } - if (print_readably) - fprintf (rl_outstream, "set bell-style %s\n", kname); - else - fprintf (rl_outstream, "bell-style is set to `%s'\n", kname); - - /* comment-begin */ - if (print_readably) - fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); - else - fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); - - /* completion-query-items */ - if (print_readably) - fprintf (rl_outstream, "set completion-query-items %d\n", rl_completion_query_items); - else - fprintf (rl_outstream, "completion-query-items is set to `%d'\n", rl_completion_query_items); - - /* editing-mode */ - if (print_readably) - fprintf (rl_outstream, "set editing-mode %s\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); - else - fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); - - /* isearch-terminators */ - if (_rl_isearch_terminators) - { - char *disp; - - disp = _rl_untranslate_macro_value (_rl_isearch_terminators); - - if (print_readably) - fprintf (rl_outstream, "set isearch-terminators \"%s\"\n", disp); - else - fprintf (rl_outstream, "isearch-terminators is set to \"%s\"\n", disp); - - free (disp); - } - - /* keymap */ - kname = rl_get_keymap_name (_rl_keymap); - if (kname == 0) - kname = rl_get_keymap_name_from_edit_mode (); - if (print_readably) - fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none"); - else - fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none"); -} - -/* Print all of the current variables and their values to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_variables (count, key) - int count, key; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_variable_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -/* Return non-zero if any members of ARRAY are a substring in STRING. */ -static int -substring_member_of_array (string, array) - char *string; - const char **array; -{ - while (*array) - { - if (_rl_strindex (string, *array)) - return (1); - array++; - } - return (0); -} diff --git a/lib/readline/complete.c~ b/lib/readline/complete.c~ deleted file mode 100644 index a128d62cf..000000000 --- a/lib/readline/complete.c~ +++ /dev/null @@ -1,2189 +0,0 @@ -/* complete.c -- filename completion for readline. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include - -#include "posixdir.h" -#include "posixstat.h" - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "xmalloc.h" -#include "rlprivate.h" - -#ifdef __STDC__ -typedef int QSFUNC (const void *, const void *); -#else -typedef int QSFUNC (); -#endif - -#ifdef HAVE_LSTAT -# define LSTAT lstat -#else -# define LSTAT stat -#endif - -/* Unix version of a hidden file. Could be different on other systems. */ -#define HIDDEN_FILE(fname) ((fname)[0] == '.') - -/* Most systems don't declare getpwent in if _POSIX_SOURCE is - defined. */ -#if !defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE) -extern struct passwd *getpwent PARAMS((void)); -#endif /* !HAVE_GETPW_DECLS || _POSIX_SOURCE */ - -/* If non-zero, then this is the address of a function to call when - completing a word would normally display the list of possible matches. - This function is called instead of actually doing the display. - It takes three arguments: (char **matches, int num_matches, int max_length) - where MATCHES is the array of strings that matched, NUM_MATCHES is the - number of strings in that array, and MAX_LENGTH is the length of the - longest string in that array. */ -rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)NULL; - -#if defined (VISIBLE_STATS) -# if !defined (X_OK) -# define X_OK 1 -# endif -static int stat_char PARAMS((char *)); -#endif - -static int path_isdir PARAMS((const char *)); - -static char *rl_quote_filename PARAMS((char *, int, char *)); - -static void set_completion_defaults PARAMS((int)); -static int get_y_or_n PARAMS((int)); -static int _rl_internal_pager PARAMS((int)); -static char *printable_part PARAMS((char *)); -static int fnwidth PARAMS((const char *)); -static int fnprint PARAMS((const char *)); -static int print_filename PARAMS((char *, char *)); - -static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int)); - -static char **remove_duplicate_matches PARAMS((char **)); -static void insert_match PARAMS((char *, int, int, char *)); -static int append_to_match PARAMS((char *, int, int, int)); -static void insert_all_matches PARAMS((char **, int, char *)); -static void display_matches PARAMS((char **)); -static int compute_lcd_of_matches PARAMS((char **, int, const char *)); -static int postprocess_matches PARAMS((char ***, int)); - -static char *make_quoted_replacement PARAMS((char *, int, char *)); - -/* **************************************************************** */ -/* */ -/* Completion matching, from readline's point of view. */ -/* */ -/* **************************************************************** */ - -/* Variables known only to the readline library. */ - -/* If non-zero, non-unique completions always show the list of matches. */ -int _rl_complete_show_all = 0; - -/* If non-zero, non-unique completions show the list of matches, unless it - is not possible to do partial completion and modify the line. */ -int _rl_complete_show_unmodified = 0; - -/* If non-zero, completed directory names have a slash appended. */ -int _rl_complete_mark_directories = 1; - -/* If non-zero, the symlinked directory completion behavior introduced in - readline-4.2a is disabled, and symlinks that point to directories have - a slash appended (subject to the value of _rl_complete_mark_directories). - This is user-settable via the mark-symlinked-directories variable. */ -int _rl_complete_mark_symlink_dirs = 0; - -/* If non-zero, completions are printed horizontally in alphabetical order, - like `ls -x'. */ -int _rl_print_completions_horizontally; - -/* Non-zero means that case is not significant in filename completion. */ -#if defined (__MSDOS__) && !defined (__DJGPP__) -int _rl_completion_case_fold = 1; -#else -int _rl_completion_case_fold; -#endif - -/* If non-zero, don't match hidden files (filenames beginning with a `.' on - Unix) when doing filename completion. */ -int _rl_match_hidden_files = 1; - -/* Global variables available to applications using readline. */ - -#if defined (VISIBLE_STATS) -/* 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 */ - -/* 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. */ -rl_icppfunc_t *rl_directory_completion_hook = (rl_icppfunc_t *)NULL; - -rl_icppfunc_t *rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; - -/* Non-zero means readline completion functions perform tilde expansion. */ -int rl_complete_with_tilde_expansion = 0; - -/* Pointer to the generator function for completion_matches (). - NULL means to use rl_filename_completion_function (), the default filename - completer. */ -rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)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. */ -rl_completion_func_t *rl_attempted_completion_function = (rl_completion_func_t *)NULL; - -/* Non-zero means to suppress normal filename completion after the - user-specified completion function has been called. */ -int rl_attempted_completion_over = 0; - -/* Set to a character indicating the type of completion being performed - by rl_complete_internal, available for use by application completion - functions. */ -int rl_completion_type = 0; - -/* Up to this many items will be displayed in response to a - possible-completions call. After that, we ask the user if - she is sure she wants to see them all. */ -int rl_completion_query_items = 100; - -int _rl_page_completions = 1; - -/* 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\"\\'`@$><=" */ -const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; /* }) */ - -/* List of basic quoting characters. */ -const char *rl_basic_quote_characters = "\"'"; - -/* The list of characters that signal a break between words for - rl_complete_internal. The default list is the contents of - rl_basic_word_break_characters. */ -/*const*/ char *rl_completer_word_break_characters = (/*const*/ char *)NULL; - -/* Hook function to allow an application to set the completion word - break characters before readline breaks up the line. Allows - position-dependent word break characters. */ -rl_cpvfunc_t *rl_completion_word_break_hook = (rl_cpvfunc_t *)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. */ -const char *rl_completer_quote_characters = (const char *)NULL; - -/* List of characters that should be quoted in filenames by the completer. */ -const char *rl_filename_quote_characters = (const 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. */ -const char *rl_special_prefixes = (const 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_filename_quote_chars. This is - ALWAYS non-zero on entry, and can only be changed within a completion - entry finder function. */ -int rl_filename_quoting_desired = 1; - -/* 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. */ -rl_compignore_func_t *rl_ignore_some_completions_function = (rl_compignore_func_t *)NULL; - -/* Set to a function to quote a filename in an application-specific fashion. - Called with the text to quote, the type of match found (single or multiple) - and a pointer to the quoting character to be used, which the function can - reset if desired. */ -rl_quote_func_t *rl_filename_quoting_function = rl_quote_filename; - -/* Function to call to remove quoting characters from a filename. Called - before completion is attempted, so the embedded quotes do not interfere - with matching names in the file system. Readline doesn't do anything - with this; it's set only by applications. */ -rl_dequote_func_t *rl_filename_dequoting_function = (rl_dequote_func_t *)NULL; - -/* Function to call to decide whether or not a word break character is - quoted. If a character is quoted, it does not break words for the - completer. */ -rl_linebuf_func_t *rl_char_is_quoted_p = (rl_linebuf_func_t *)NULL; - -/* If non-zero, the completion functions don't append anything except a - possible closing quote. This is set to 0 by rl_complete_internal and - may be changed by an application-specific completion function. */ -int rl_completion_suppress_append = 0; - -/* Character appended to completed words when at the end of the line. The - default is a space. */ -int rl_completion_append_character = ' '; - -/* If non-zero, the completion functions don't append any closing quote. - This is set to 0 by rl_complete_internal and may be changed by an - application-specific completion function. */ -int rl_completion_suppress_quote = 0; - -/* Set to any quote character readline thinks it finds before any application - completion function is called. */ -int rl_completion_quote_character; - -/* Set to a non-zero value if readline found quoting anywhere in the word to - be completed; set before any application completion function is called. */ -int rl_completion_found_quote; - -/* If non-zero, a slash will be appended to completed filenames that are - symbolic links to directory names, subject to the value of the - mark-directories variable (which is user-settable). This exists so - that application completion functions can override the user's preference - (set via the mark-symlinked-directories variable) if appropriate. - It's set to the value of _rl_complete_mark_symlink_dirs in - rl_complete_internal before any application-specific completion - function is called, so without that function doing anything, the user's - preferences are honored. */ -int rl_completion_mark_symlink_dirs; - -/* If non-zero, inhibit completion (temporarily). */ -int rl_inhibit_completion; - -/* Variables local to this file. */ - -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer; - -/*************************************/ -/* */ -/* Bindable completion functions */ -/* */ -/*************************************/ - -/* Complete the word at or before point. You have supplied the function - that does the initial simple matching selection algorithm (see - rl_completion_matches ()). The default is to do filename completion. */ -int -rl_complete (ignore, invoking_key) - int ignore, invoking_key; -{ - if (rl_inhibit_completion) - return (_rl_insert_char (ignore, invoking_key)); - else if (rl_last_func == rl_complete && !completion_changed_buffer) - return (rl_complete_internal ('?')); - else if (_rl_complete_show_all) - return (rl_complete_internal ('!')); - else if (_rl_complete_show_unmodified) - return (rl_complete_internal ('@')); - else - return (rl_complete_internal (TAB)); -} - -/* List the possible completions. See description of rl_complete (). */ -int -rl_possible_completions (ignore, invoking_key) - int ignore, invoking_key; -{ - return (rl_complete_internal ('?')); -} - -int -rl_insert_completions (ignore, invoking_key) - int ignore, invoking_key; -{ - return (rl_complete_internal ('*')); -} - -/* Return the correct value to pass to rl_complete_internal performing - the same tests as rl_complete. This allows consecutive calls to an - application's completion function to list possible completions and for - an application-specific completion function to honor the - show-all-if-ambiguous readline variable. */ -int -rl_completion_mode (cfunc) - rl_command_func_t *cfunc; -{ - if (rl_last_func == cfunc && !completion_changed_buffer) - return '?'; - else if (_rl_complete_show_all) - return '!'; - else if (_rl_complete_show_unmodified) - return '@'; - else - return TAB; -} - -/************************************/ -/* */ -/* Completion utility functions */ -/* */ -/************************************/ - -/* Set default values for readline word completion. These are the variables - that application completion functions can change or inspect. */ -static void -set_completion_defaults (what_to_do) - int what_to_do; -{ - /* Only the completion entry function can change these. */ - rl_filename_completion_desired = 0; - rl_filename_quoting_desired = 1; - rl_completion_type = what_to_do; - rl_completion_suppress_append = rl_completion_suppress_quote = 0; - - /* The completion entry function may optionally change this. */ - rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs; -} - -/* The user must press "y" or "n". Non-zero return means "y" pressed. */ -static int -get_y_or_n (for_pager) - int for_pager; -{ - int c; - - for (;;) - { - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c == 'y' || c == 'Y' || c == ' ') - return (1); - if (c == 'n' || c == 'N' || c == RUBOUT) - return (0); - if (c == ABORT_CHAR) - _rl_abort_internal (); - if (for_pager && (c == NEWLINE || c == RETURN)) - return (2); - if (for_pager && (c == 'q' || c == 'Q')) - return (0); - rl_ding (); - } -} - -static int -_rl_internal_pager (lines) - int lines; -{ - int i; - - fprintf (rl_outstream, "--More--"); - fflush (rl_outstream); - i = get_y_or_n (1); - _rl_erase_entire_line (); - if (i == 0) - return -1; - else if (i == 2) - return (lines - 1); - else - return 0; -} - -static int -path_isdir (filename) - const char *filename; -{ - struct stat finfo; - - return (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)); -} - -#if defined (VISIBLE_STATS) -/* Return the character which best describes FILENAME. - `@' for symbolic links - `/' for directories - `*' for executables - `=' for sockets - `|' for FIFOs - `%' for character special devices - `#' for block special devices */ -static int -stat_char (filename) - char *filename; -{ - struct stat finfo; - int character, r; - -#if defined (HAVE_LSTAT) && 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_ISCHR) - else if (S_ISCHR (finfo.st_mode)) - character = '%'; -#endif /* S_ISCHR */ -#if defined (S_ISBLK) - else if (S_ISBLK (finfo.st_mode)) - character = '#'; -#endif /* S_ISBLK */ -#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 */ -#if defined (S_ISFIFO) - else if (S_ISFIFO (finfo.st_mode)) - character = '|'; -#endif - else if (S_ISREG (finfo.st_mode)) - { - if (access (filename, X_OK) == 0) - character = '*'; - } - return (character); -} -#endif /* VISIBLE_STATS */ - -/* 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. Since - printing empty strings is not very informative, if we're doing - filename completion, and the basename is the empty string, we look - for the previous slash and return the portion following that. If - there's no previous slash, we just return what we were passed. */ -static char * -printable_part (pathname) - char *pathname; -{ - char *temp, *x; - - if (rl_filename_completion_desired == 0) /* don't need to do anything */ - return (pathname); - - temp = strrchr (pathname, '/'); -#if defined (__MSDOS__) - if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':') - temp = pathname + 1; -#endif - - if (temp == 0 || *temp == '\0') - return (pathname); - /* If the basename is NULL, we might have a pathname like '/usr/src/'. - Look for a previous slash and, if one is found, return the portion - following that slash. If there's no previous slash, just return the - pathname we were passed. */ - else if (temp[1] == '\0') - { - for (x = temp - 1; x > pathname; x--) - if (*x == '/') - break; - return ((*x == '/') ? x + 1 : pathname); - } - else - return ++temp; -} - -/* Compute width of STRING when displayed on screen by print_filename */ -static int -fnwidth (string) - const char *string; -{ - int width, pos; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - int left, w; - size_t clen; - wchar_t wc; - - left = strlen (string) + 1; - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - width = pos = 0; - while (string[pos]) - { - if (CTRL_CHAR (*string) || *string == RUBOUT) - { - width += 2; - pos++; - } - else - { -#if defined (HANDLE_MULTIBYTE) - clen = mbrtowc (&wc, string + pos, left - pos, &ps); - if (MB_INVALIDCH (clen)) - { - width++; - pos++; - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (clen)) - break; - else - { - pos += clen; - w = wcwidth (wc); - width += (w >= 0) ? w : 1; - } -#else - width++; - pos++; -#endif - } - } - - return width; -} - -static int -fnprint (to_print) - const char *to_print; -{ - int printed_len; - const char *s; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - const char *end; - size_t tlen; - - end = to_print + strlen (to_print) + 1; - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - printed_len = 0; - s = to_print; - while (*s) - { - if (CTRL_CHAR (*s)) - { - putc ('^', rl_outstream); - putc (UNCTRL (*s), rl_outstream); - printed_len += 2; - s++; -#if defined (HANDLE_MULTIBYTE) - memset (&ps, 0, sizeof (mbstate_t)); -#endif - } - else if (*s == RUBOUT) - { - putc ('^', rl_outstream); - putc ('?', rl_outstream); - printed_len += 2; - s++; -#if defined (HANDLE_MULTIBYTE) - memset (&ps, 0, sizeof (mbstate_t)); -#endif - } - else - { -#if defined (HANDLE_MULTIBYTE) - tlen = mbrlen (s, end - s, &ps); - if (MB_INVALIDCH (tlen)) - { - tlen = 1; - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (tlen)) - break; - fwrite (s, 1, tlen, rl_outstream); - s += tlen; -#else - putc (*s, rl_outstream); - s++; -#endif - printed_len++; - } - } - - return printed_len; -} - -/* 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 the number of characters we output. */ - -static int -print_filename (to_print, full_pathname) - char *to_print, *full_pathname; -{ - int printed_len, extension_char, slen, tlen; - char *s, c, *new_full_pathname; - - printed_len = fnprint (to_print); - -#if defined (VISIBLE_STATS) - if (rl_filename_completion_desired && (rl_visible_stats || _rl_complete_mark_directories)) -#else - if (rl_filename_completion_desired && _rl_complete_mark_directories) -#endif - { - /* 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'; - - /* If setting the last slash in full_pathname to a NUL results in - full_pathname being the empty string, we are trying to complete - files in the root directory. If we pass a null string to the - bash directory completion hook, for example, it will expand it - to the current directory. We just want the `/'. */ - s = tilde_expand (full_pathname && *full_pathname ? full_pathname : "/"); - if (rl_directory_completion_hook) - (*rl_directory_completion_hook) (&s); - - slen = strlen (s); - tlen = strlen (to_print); - new_full_pathname = (char *)xmalloc (slen + tlen + 2); - strcpy (new_full_pathname, s); - new_full_pathname[slen] = '/'; - strcpy (new_full_pathname + slen + 1, to_print); - -#if defined (VISIBLE_STATS) - if (rl_visible_stats) - extension_char = stat_char (new_full_pathname); - else -#endif - if (path_isdir (new_full_pathname)) - extension_char = '/'; - - free (new_full_pathname); - to_print[-1] = c; - } - else - { - s = tilde_expand (full_pathname); -#if defined (VISIBLE_STATS) - if (rl_visible_stats) - extension_char = stat_char (s); - else -#endif - if (path_isdir (new_full_pathname)) - extension_char = '/'; - } - - free (s); - if (extension_char) - { - putc (extension_char, rl_outstream); - printed_len++; - } - } - - return printed_len; -} - -static char * -rl_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - char *r; - - r = (char *)xmalloc (strlen (s) + 2); - *r = *rl_completer_quote_characters; - strcpy (r + 1, s); - if (qcp) - *qcp = *rl_completer_quote_characters; - return r; -} - -/* Find the bounds of the current word for completion purposes, and leave - rl_point set to the end of the word. This function skips quoted - substrings (characters between matched pairs of characters in - rl_completer_quote_characters). First we try to find an unclosed - quoted substring on which to do matching. If one is not found, we use - the word break characters to find the boundaries of the current word. - We call an application-specific function to decide whether or not a - particular word break character is quoted; if that function returns a - non-zero result, the character does not break a word. This function - returns the opening quote character if we found an unclosed quoted - substring, '\0' otherwise. FP, if non-null, is set to a value saying - which (shell-like) quote characters we found (single quote, double - quote, or backslash) anywhere in the string. DP, if non-null, is set to - the value of the delimiter character that caused a word break. */ - -char -_rl_find_completion_word (fp, dp) - int *fp, *dp; -{ - int scan, end, found_quote, delimiter, pass_next, isbrk; - char quote_char, *brkchars; - - end = rl_point; - found_quote = delimiter = 0; - quote_char = '\0'; - - brkchars = 0; - if (rl_completion_word_break_hook) - brkchars = (*rl_completion_word_break_hook) (); - if (brkchars == 0) - brkchars = rl_completer_word_break_characters; - - if (rl_completer_quote_characters) - { - /* We have a list of characters which can be used in pairs to - quote substrings for the completer. Try to find the start - of an unclosed quoted substring. */ - /* FOUND_QUOTE is set so we know what kind of quotes we found. */ -#if defined (HANDLE_MULTIBYTE) - for (scan = pass_next = 0; scan < end; - scan = ((MB_CUR_MAX == 1 || rl_byte_oriented) - ? (scan + 1) - : _rl_find_next_mbchar (rl_line_buffer, scan, 1, MB_FIND_ANY))) -#else - for (scan = pass_next = 0; scan < end; scan++) -#endif - { - if (pass_next) - { - pass_next = 0; - continue; - } - - /* Shell-like semantics for single quotes -- don't allow backslash - to quote anything in single quotes, especially not the closing - quote. If you don't like this, take out the check on the value - of quote_char. */ - if (quote_char != '\'' && rl_line_buffer[scan] == '\\') - { - pass_next = 1; - found_quote |= RL_QF_BACKSLASH; - continue; - } - - if (quote_char != '\0') - { - /* Ignore everything until the matching close quote char. */ - if (rl_line_buffer[scan] == quote_char) - { - /* Found matching close. Abandon this substring. */ - quote_char = '\0'; - rl_point = end; - } - } - else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan])) - { - /* Found start of a quoted substring. */ - quote_char = rl_line_buffer[scan]; - rl_point = scan + 1; - /* Shell-like quoting conventions. */ - if (quote_char == '\'') - found_quote |= RL_QF_SINGLE_QUOTE; - else if (quote_char == '"') - found_quote |= RL_QF_DOUBLE_QUOTE; - else - found_quote |= RL_QF_OTHER_QUOTE; - } - } - } - - if (rl_point == end && quote_char == '\0') - { - /* We didn't find an unclosed quoted substring upon which to do - completion, so use the word break characters to find the - substring on which to complete. */ -#if defined (HANDLE_MULTIBYTE) - while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY)) -#else - while (--rl_point) -#endif - { - scan = rl_line_buffer[rl_point]; - - if (strchr (brkchars, scan) == 0) - continue; - - /* Call the application-specific function to tell us whether - this word break character is quoted and should be skipped. */ - if (rl_char_is_quoted_p && found_quote && - (*rl_char_is_quoted_p) (rl_line_buffer, rl_point)) - continue; - - /* 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 there is an application-specific function to say whether or not - a character is quoted and we found a quote character, let that - function decide whether or not a character is a word break, even - if it is found in rl_completer_word_break_characters. Don't bother - if we're at the end of the line, though. */ - if (scan) - { - if (rl_char_is_quoted_p) - isbrk = (found_quote == 0 || - (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) && - strchr (brkchars, scan) != 0; - else - isbrk = strchr (brkchars, scan) != 0; - - if (isbrk) - { - /* If the character that caused the word break was a quoting - character, then remember it as the delimiter. */ - if (rl_basic_quote_characters && - strchr (rl_basic_quote_characters, scan) && - (end - rl_point) > 1) - delimiter = scan; - - /* If the character isn't needed to determine something special - about what kind of completion to perform, then advance past it. */ - if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0) - rl_point++; - } - } - - if (fp) - *fp = found_quote; - if (dp) - *dp = delimiter; - - return (quote_char); -} - -static char ** -gen_completion_matches (text, start, end, our_func, found_quote, quote_char) - char *text; - int start, end; - rl_compentry_func_t *our_func; - int found_quote, quote_char; -{ - char **matches, *temp; - - rl_completion_found_quote = found_quote; - rl_completion_quote_character = quote_char; - - /* 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; - return (matches); - } - } - - /* Beware -- we're stripping the quotes here. Do this only if we know - we are doing filename completion and the application has defined a - filename dequoting function. */ - temp = (char *)NULL; - - if (found_quote && our_func == rl_filename_completion_function && - rl_filename_dequoting_function) - { - /* delete single and double quotes */ - temp = (*rl_filename_dequoting_function) (text, quote_char); - text = temp; /* not freeing text is not a memory leak */ - } - - matches = rl_completion_matches (text, our_func); - FREE (temp); - return matches; -} - -/* Filter out duplicates in MATCHES. This frees up the strings in - MATCHES. */ -static char ** -remove_duplicate_matches (matches) - char **matches; -{ - char *lowest_common; - int i, j, newlen; - char dead_slot; - char **temp_array; - - /* Sort the items. */ - for (i = 0; matches[i]; i++) - ; - - /* Sort the array without matches[0], since we need it to - stay in place no matter what. */ - if (i) - qsort (matches+1, i-1, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); - - /* Remember the lowest common denominator for it may be unique. */ - lowest_common = savestring (matches[0]); - - for (i = newlen = 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]); - - /* Place the lowest common denominator back in [0]. */ - temp_array[0] = lowest_common; - - /* If there is one string left, and it is identical to the - lowest common denominator, then the LCD is the string to - insert. */ - if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0) - { - free (temp_array[1]); - temp_array[1] = (char *)NULL; - } - return (temp_array); -} - -/* Find the common prefix of the list of matches, and put it into - matches[0]. */ -static int -compute_lcd_of_matches (match_list, matches, text) - char **match_list; - int matches; - const char *text; -{ - register int i, c1, c2, si; - int low; /* Count of max-matched characters. */ - char *dtext; /* dequoted TEXT, if needed */ -#if defined (HANDLE_MULTIBYTE) - int v; - mbstate_t ps1, ps2; - wchar_t wc1, wc2; -#endif - - /* If only one match, just use that. Otherwise, compare each - member of the list with the next, finding out where they - stop matching. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - return 1; - } - - for (i = 1, low = 100000; i < matches; i++) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - memset (&ps1, 0, sizeof (mbstate_t)); - memset (&ps2, 0, sizeof (mbstate_t)); - } -#endif - if (_rl_completion_case_fold) - { - for (si = 0; - (c1 = _rl_to_lower(match_list[i][si])) && - (c2 = _rl_to_lower(match_list[i + 1][si])); - si++) -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); - mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); - wc1 = towlower (wc1); - wc2 = towlower (wc2); - if (wc1 != wc2) - break; - else if (v > 1) - si += v - 1; - } - else -#endif - if (c1 != c2) - break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - mbstate_t ps_back = ps1; - if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2)) - break; - else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1) - si += v - 1; - } - else -#endif - if (c1 != c2) - break; - } - - if (low > si) - low = si; - } - - /* If there were multiple matches, but none matched up to even the - first character, and the user typed something, use that as the - value of matches[0]. */ - if (low == 0 && text && *text) - { - match_list[0] = (char *)xmalloc (strlen (text) + 1); - strcpy (match_list[0], text); - } - else - { - match_list[0] = (char *)xmalloc (low + 1); - - /* XXX - this might need changes in the presence of multibyte chars */ - - /* If we are ignoring case, try to preserve the case of the string - the user typed in the face of multiple matches differing in case. */ - if (_rl_completion_case_fold) - { - /* We're making an assumption here: - IF we're completing filenames AND - the application has defined a filename dequoting function AND - we found a quote character AND - the application has requested filename quoting - THEN - we assume that TEXT was dequoted before checking against - the file system and needs to be dequoted here before we - check against the list of matches - FI */ - dtext = (char *)NULL; - if (rl_filename_completion_desired && - rl_filename_dequoting_function && - rl_completion_found_quote && - rl_filename_quoting_desired) - { - dtext = (*rl_filename_dequoting_function) (text, rl_completion_quote_character); - text = dtext; - } - - /* sort the list to get consistent answers. */ - qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare); - - si = strlen (text); - if (si <= low) - { - for (i = 1; i <= matches; i++) - if (strncmp (match_list[i], text, si) == 0) - { - strncpy (match_list[0], match_list[i], low); - break; - } - /* no casematch, use first entry */ - if (i > matches) - strncpy (match_list[0], match_list[1], low); - } - else - /* otherwise, just use the text the user typed. */ - strncpy (match_list[0], text, low); - - FREE (dtext); - } - else - strncpy (match_list[0], match_list[1], low); - - match_list[0][low] = '\0'; - } - - return matches; -} - -static int -postprocess_matches (matchesp, matching_filenames) - char ***matchesp; - int matching_filenames; -{ - char *t, **matches, **temp_matches; - int nmatch, i; - - matches = *matchesp; - - if (matches == 0) - return 0; - - /* It seems to me that in all the cases we handle we would like - to ignore duplicate possiblilities. Scan for the text to - insert being identical to the other completions. */ - if (rl_ignore_completion_duplicates) - { - temp_matches = remove_duplicate_matches (matches); - free (matches); - matches = temp_matches; - } - - /* 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 && matching_filenames) - { - for (nmatch = 1; matches[nmatch]; nmatch++) - ; - (void)(*rl_ignore_some_completions_function) (matches); - if (matches == 0 || matches[0] == 0) - { - FREE (matches); - *matchesp = (char **)0; - return 0; - } - else - { - /* If we removed some matches, recompute the common prefix. */ - for (i = 1; matches[i]; i++) - ; - if (i > 1 && i < nmatch) - { - t = matches[0]; - compute_lcd_of_matches (matches, i - 1, t); - FREE (t); - } - } - } - - *matchesp = matches; - return (1); -} - -/* A convenience function for displaying a list of strings in - columnar format on readline's output stream. MATCHES is the list - of strings, in argv format, LEN is the number of strings in MATCHES, - and MAX is the length of the longest string in MATCHES. */ -void -rl_display_match_list (matches, len, max) - char **matches; - int len, max; -{ - int count, limit, printed_len, lines; - int i, j, k, l; - char *temp; - - /* How many items of MAX length can we fit in the screen window? */ - max += 2; - limit = _rl_screenwidth / max; - if (limit != 1 && (limit * max == _rl_screenwidth)) - limit--; - - /* Avoid a possible floating exception. If max > _rl_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 == 0) - qsort (matches + 1, len, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); - - rl_crlf (); - - lines = 0; - if (_rl_print_completions_horizontally == 0) - { - /* Print the sorted items, up-and-down alphabetically, like ls. */ - for (i = 1; i <= count; i++) - { - for (j = 0, l = i; j < limit; j++) - { - if (l > len || matches[l] == 0) - break; - else - { - temp = printable_part (matches[l]); - printed_len = print_filename (temp, matches[l]); - - if (j + 1 < limit) - for (k = 0; k < max - printed_len; k++) - putc (' ', rl_outstream); - } - l += count; - } - rl_crlf (); - lines++; - if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count) - { - lines = _rl_internal_pager (lines); - if (lines < 0) - return; - } - } - } - else - { - /* Print the sorted items, across alphabetically, like ls -x. */ - for (i = 1; matches[i]; i++) - { - temp = printable_part (matches[i]); - printed_len = print_filename (temp, matches[i]); - /* Have we reached the end of this line? */ - if (matches[i+1]) - { - if (i && (limit > 1) && (i % limit) == 0) - { - rl_crlf (); - lines++; - if (_rl_page_completions && lines >= _rl_screenheight - 1) - { - lines = _rl_internal_pager (lines); - if (lines < 0) - return; - } - } - else - for (k = 0; k < max - printed_len; k++) - putc (' ', rl_outstream); - } - } - rl_crlf (); - } -} - -/* Display MATCHES, a list of matching filenames in argv format. This - handles the simple case -- a single match -- first. If there is more - than one match, we compute the number of strings in the list and the - length of the longest string, which will be needed by the display - function. If the application wants to handle displaying the list of - matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the - address of a function, and we just call it. If we're handling the - display ourselves, we just call rl_display_match_list. We also check - that the list of matches doesn't exceed the user-settable threshold, - and ask the user if he wants to see the list if there are more matches - than RL_COMPLETION_QUERY_ITEMS. */ -static void -display_matches (matches) - char **matches; -{ - int len, max, i; - char *temp; - - /* Move to the last visible line of a possibly-multiple-line command. */ - _rl_move_vert (_rl_vis_botlin); - - /* Handle simple case first. What if there is only one answer? */ - if (matches[1] == 0) - { - temp = printable_part (matches[0]); - rl_crlf (); - print_filename (temp, matches[0]); - rl_crlf (); - - rl_forced_update_display (); - rl_display_fixed = 1; - - return; - } - - /* There is more than one answer. Find out how many there are, - and find the maximum printed length of a single entry. */ - for (max = 0, i = 1; matches[i]; i++) - { - temp = printable_part (matches[i]); - len = fnwidth (temp); - - if (len > max) - max = len; - } - - len = i - 1; - - /* If the caller has defined a display hook, then call that now. */ - if (rl_completion_display_matches_hook) - { - (*rl_completion_display_matches_hook) (matches, len, max); - return; - } - - /* If there are many items, then ask the user if she really wants to - see them all. */ - if (len >= rl_completion_query_items) - { - rl_crlf (); - fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); - fflush (rl_outstream); - if (get_y_or_n (0) == 0) - { - rl_crlf (); - - rl_forced_update_display (); - rl_display_fixed = 1; - - return; - } - } - - rl_display_match_list (matches, len, max); - - rl_forced_update_display (); - rl_display_fixed = 1; -} - -static char * -make_quoted_replacement (match, mtype, qc) - char *match; - int mtype; - char *qc; /* Pointer to quoting character, if any */ -{ - int should_quote, do_replace; - char *replacement; - - /* If we are doing completion on quoted substrings, and any matches - contain any of the completer_word_break_characters, then auto- - matically prepend the substring with a quote character (just pick - the first one from the list of such) if it does not already begin - with a quote string. FIXME: Need to remove any such automatically - inserted quote character when it no longer is necessary, such as - if we change the string we are completing on and the new set of - matches don't require a quoted substring. */ - replacement = match; - - should_quote = match && rl_completer_quote_characters && - rl_filename_completion_desired && - rl_filename_quoting_desired; - - if (should_quote) - should_quote = should_quote && (!qc || !*qc || - (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc))); - - if (should_quote) - { - /* If there is a single match, see if we need to quote it. - This also checks whether the common prefix of several - matches needs to be quoted. */ - should_quote = rl_filename_quote_characters - ? (_rl_strpbrk (match, rl_filename_quote_characters) != 0) - : 0; - - do_replace = should_quote ? mtype : NO_MATCH; - /* Quote the replacement, since we found an embedded - word break character in a potential match. */ - if (do_replace != NO_MATCH && rl_filename_quoting_function) - replacement = (*rl_filename_quoting_function) (match, do_replace, qc); - } - return (replacement); -} - -static void -insert_match (match, start, mtype, qc) - char *match; - int start, mtype; - char *qc; -{ - char *replacement; - char oqc; - - oqc = qc ? *qc : '\0'; - replacement = make_quoted_replacement (match, mtype, qc); - - /* Now insert the match. */ - if (replacement) - { - /* Don't double an opening quote character. */ - if (qc && *qc && start && rl_line_buffer[start - 1] == *qc && - replacement[0] == *qc) - start--; - /* If make_quoted_replacement changed the quoting character, remove - the opening quote and insert the (fully-quoted) replacement. */ - else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc && - replacement[0] != oqc) - start--; - _rl_replace_text (replacement, start, rl_point - 1); - if (replacement != match) - free (replacement); - } -} - -/* Append any necessary closing quote and a separator character to the - just-inserted match. If the user has specified that directories - should be marked by a trailing `/', append one of those instead. The - default trailing character is a space. Returns the number of characters - appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS - has them) and don't add a suffix for a symlink to a directory. A - nontrivial match is one that actually adds to the word being completed. - The variable rl_completion_mark_symlink_dirs controls this behavior - (it's initially set to the what the user has chosen, indicated by the - value of _rl_complete_mark_symlink_dirs, but may be modified by an - application's completion function). */ -static int -append_to_match (text, delimiter, quote_char, nontrivial_match) - char *text; - int delimiter, quote_char, nontrivial_match; -{ - char temp_string[4], *filename; - int temp_string_index, s; - struct stat finfo; - - temp_string_index = 0; - if (quote_char && rl_point && rl_completion_suppress_quote == 0 && - rl_line_buffer[rl_point - 1] != quote_char) - temp_string[temp_string_index++] = quote_char; - - if (delimiter) - temp_string[temp_string_index++] = delimiter; - else if (rl_completion_suppress_append == 0 && rl_completion_append_character) - temp_string[temp_string_index++] = rl_completion_append_character; - - temp_string[temp_string_index++] = '\0'; - - if (rl_filename_completion_desired) - { - filename = tilde_expand (text); - s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0) - ? LSTAT (filename, &finfo) - : stat (filename, &finfo); - if (s == 0 && S_ISDIR (finfo.st_mode)) - { - if (_rl_complete_mark_directories) - { - /* This is clumsy. Avoid putting in a double slash if point - is at the end of the line and the previous character is a - slash. */ - if (rl_point && rl_line_buffer[rl_point] == '\0' && rl_line_buffer[rl_point - 1] == '/') - ; - else if (rl_line_buffer[rl_point] != '/') - rl_insert_text ("/"); - } - } -#ifdef S_ISLNK - /* Don't add anything if the filename is a symlink and resolves to a - directory. */ - else if (s == 0 && S_ISLNK (finfo.st_mode) && - stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)) - ; -#endif - else - { - if (rl_point == rl_end && temp_string_index) - rl_insert_text (temp_string); - } - free (filename); - } - else - { - if (rl_point == rl_end && temp_string_index) - rl_insert_text (temp_string); - } - - return (temp_string_index); -} - -static void -insert_all_matches (matches, point, qc) - char **matches; - int point; - char *qc; -{ - int i; - char *rp; - - rl_begin_undo_group (); - /* remove any opening quote character; make_quoted_replacement will add - it back. */ - if (qc && *qc && point && rl_line_buffer[point - 1] == *qc) - point--; - rl_delete_text (point, rl_point); - rl_point = point; - - if (matches[1]) - { - for (i = 1; matches[i]; i++) - { - rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc); - rl_insert_text (rp); - rl_insert_text (" "); - if (rp != matches[i]) - free (rp); - } - } - else - { - rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc); - rl_insert_text (rp); - rl_insert_text (" "); - if (rp != matches[0]) - free (rp); - } - rl_end_undo_group (); -} - -void -_rl_free_match_list (matches) - char **matches; -{ - register int i; - - if (matches == 0) - return; - - for (i = 0; matches[i]; i++) - free (matches[i]); - free (matches); -} - -/* 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. - `@' means to do standard completion, and list all possible completions if - there is more than one and partial completion is not possible. */ -int -rl_complete_internal (what_to_do) - int what_to_do; -{ - char **matches; - rl_compentry_func_t *our_func; - int start, end, delimiter, found_quote, i, nontrivial_lcd; - char *text, *saved_line_buffer; - char quote_char; - - RL_SETSTATE(RL_STATE_COMPLETING); - - set_completion_defaults (what_to_do); - - saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; - our_func = rl_completion_entry_function - ? rl_completion_entry_function - : rl_filename_completion_function; - /* We now look backwards for the start of a filename/variable word. */ - end = rl_point; - found_quote = delimiter = 0; - quote_char = '\0'; - - if (rl_point) - /* This (possibly) changes rl_point. If it returns a non-zero char, - we know we have an open quote. */ - quote_char = _rl_find_completion_word (&found_quote, &delimiter); - - start = rl_point; - rl_point = end; - - text = rl_copy_text (start, end); - matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char); - /* nontrivial_lcd is set if the common prefix adds something to the word - being completed. */ - nontrivial_lcd = matches && strcmp (text, matches[0]) != 0; - free (text); - - if (matches == 0) - { - rl_ding (); - FREE (saved_line_buffer); - completion_changed_buffer = 0; - RL_UNSETSTATE(RL_STATE_COMPLETING); - return (0); - } - - /* If we are matching filenames, the attempted completion function will - have set rl_filename_completion_desired to a non-zero value. The basic - rl_filename_completion_function does this. */ - i = rl_filename_completion_desired; - - if (postprocess_matches (&matches, i) == 0) - { - rl_ding (); - FREE (saved_line_buffer); - completion_changed_buffer = 0; - RL_UNSETSTATE(RL_STATE_COMPLETING); - return (0); - } - - switch (what_to_do) - { - case TAB: - case '!': - case '@': - /* Insert the first match with proper quoting. */ - if (*matches[0]) - insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); - - /* If there are more matches, ring the bell to indicate. - If we are in vi mode, Posix.2 says to not ring the bell. - If the `show-all-if-ambiguous' variable is set, display - all the matches immediately. Otherwise, if this was the - only match, and we are hacking files, check the file to - see if it was a directory. If so, and the `mark-directories' - variable is set, add a '/' to the name. If not, and we - are at the end of the line, then add a space. */ - if (matches[1]) - { - if (what_to_do == '!') - { - display_matches (matches); - break; - } - else if (what_to_do == '@') - { - if (nontrivial_lcd == 0) - display_matches (matches); - break; - } - else if (rl_editing_mode != vi_mode) - rl_ding (); /* There are other matches remaining. */ - } - else - append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); - - break; - - case '*': - insert_all_matches (matches, start, "e_char); - break; - - case '?': - display_matches (matches); - break; - - default: - fprintf (stderr, "\r\nreadline: bad value %d for what_to_do in rl_complete\n", what_to_do); - rl_ding (); - FREE (saved_line_buffer); - RL_UNSETSTATE(RL_STATE_COMPLETING); - return 1; - } - - _rl_free_match_list (matches); - - /* Check to see if the line has changed through all of this manipulation. */ - if (saved_line_buffer) - { - completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0; - free (saved_line_buffer); - } - - RL_UNSETSTATE(RL_STATE_COMPLETING); - return 0; -} - -/***************************************************************/ -/* */ -/* Application-callable completion match generator functions */ -/* */ -/***************************************************************/ - -/* 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 ** -rl_completion_matches (text, entry_function) - const char *text; - rl_compentry_func_t *entry_function; -{ - /* Number of slots in match_list. */ - int match_list_size; - - /* The list of matches. */ - char **match_list; - - /* Number of matches actually found. */ - int matches; - - /* Temporary string binder. */ - char *string; - - matches = 0; - match_list_size = 10; - match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); - match_list[1] = (char *)NULL; - - while (string = (*entry_function) (text, matches)) - { - 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) - compute_lcd_of_matches (match_list, matches, text); - else /* There were no matches. */ - { - free (match_list); - match_list = (char **)NULL; - } - return (match_list); -} - -/* A completion function for usernames. - TEXT contains a partial username preceded by a random - character (usually `~'). */ -char * -rl_username_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) - return (char *)NULL; -#else /* !__WIN32__ && !__OPENNT) */ - static char *username = (char *)NULL; - static struct passwd *entry; - static int namelen, first_char, first_char_loc; - char *value; - - if (state == 0) - { - FREE (username); - - first_char = *text; - first_char_loc = first_char == '~'; - - 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 || (STREQN (username, entry->pw_name, namelen))) - break; - } - - if (entry == 0) - { - endpwent (); - return ((char *)NULL); - } - else - { - value = (char *)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 /* !__WIN32__ && !__OPENNT */ -} - -/* 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 * -rl_filename_completion_function (text, state) - const char *text; - int state; -{ - static DIR *directory = (DIR *)NULL; - static char *filename = (char *)NULL; - static char *dirname = (char *)NULL; - static char *users_dirname = (char *)NULL; - static int filename_len; - char *temp; - int dirlen; - struct dirent *entry; - - /* If we don't have any state, then do some initialization. */ - if (state == 0) - { - /* If we were interrupted before closing the directory or reading - all of its contents, close it. */ - if (directory) - { - closedir (directory); - directory = (DIR *)NULL; - } - FREE (dirname); - FREE (filename); - FREE (users_dirname); - - filename = savestring (text); - if (*text == 0) - text = "."; - dirname = savestring (text); - - temp = strrchr (dirname, '/'); - -#if defined (__MSDOS__) - /* special hack for //X/... */ - if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/') - temp = strrchr (dirname + 3, '/'); -#endif - - if (temp) - { - strcpy (filename, ++temp); - *temp = '\0'; - } -#if defined (__MSDOS__) - /* searches from current directory on the drive */ - else if (ISALPHA ((unsigned char)dirname[0]) && dirname[1] == ':') - { - strcpy (filename, dirname + 2); - dirname[2] = '\0'; - } -#endif - else - { - dirname[0] = '.'; - dirname[1] = '\0'; - } - - /* We aren't done yet. We also support the "~user" syntax. */ - - /* Save the version of the directory that the user typed. */ - users_dirname = savestring (dirname); - - if (*dirname == '~') - { - temp = tilde_expand (dirname); - free (dirname); - dirname = temp; - } - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&dirname); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&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. */ - - entry = (struct dirent *)NULL; - while (directory && (entry = readdir (directory))) - { - /* Special case for no filename. If the user has disabled the - `match-hidden-files' variable, skip filenames beginning with `.'. - All other entries except "." and ".." match. */ - if (filename_len == 0) - { - if (_rl_match_hidden_files == 0 && HIDDEN_FILE (entry->d_name)) - continue; - - if (entry->d_name[0] != '.' || - (entry->d_name[1] && - (entry->d_name[1] != '.' || entry->d_name[2]))) - break; - } - else - { - /* Otherwise, if these match up to the length of filename, then - it is a match. */ - if (_rl_completion_case_fold) - { - if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) && - (((int)D_NAMLEN (entry)) >= filename_len) && - (_rl_strnicmp (filename, entry->d_name, filename_len) == 0)) - break; - } - else - { - if ((entry->d_name[0] == filename[0]) && - (((int)D_NAMLEN (entry)) >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) - break; - } - } - } - - if (entry == 0) - { - 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 - { - /* dirname && (strcmp (dirname, ".") != 0) */ - if (dirname && (dirname[0] != '.' || dirname[1])) - { - if (rl_complete_with_tilde_expansion && *users_dirname == '~') - { - dirlen = strlen (dirname); - temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); - strcpy (temp, dirname); - /* Canonicalization cuts off any final slash present. We - may need to add it back. */ - if (dirname[dirlen - 1] != '/') - { - temp[dirlen++] = '/'; - temp[dirlen] = '\0'; - } - } - else - { - dirlen = strlen (users_dirname); - temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); - strcpy (temp, users_dirname); - /* Make sure that temp has a trailing slash here. */ - if (users_dirname[dirlen - 1] != '/') - temp[dirlen++] = '/'; - } - - strcpy (temp + dirlen, entry->d_name); - } - else - temp = savestring (entry->d_name); - - return (temp); - } -} - -/* An initial implementation of a menu completion function a la tcsh. The - first time (if the last readline command was not rl_menu_complete), we - generate the list of matches. This code is very similar to the code in - rl_complete_internal -- there should be a way to combine the two. Then, - for each item in the list of matches, we insert the match in an undoable - fashion, with the appropriate character appended (this happens on the - second and subsequent consecutive calls to rl_menu_complete). When we - hit the end of the match list, we restore the original unmatched text, - ring the bell, and reset the counter to zero. */ -int -rl_menu_complete (count, ignore) - int count, ignore; -{ - rl_compentry_func_t *our_func; - int matching_filenames, found_quote; - - static char *orig_text; - static char **matches = (char **)0; - static int match_list_index = 0; - static int match_list_size = 0; - static int orig_start, orig_end; - static char quote_char; - static int delimiter; - - /* The first time through, we generate the list of matches and set things - up to insert them. */ - if (rl_last_func != rl_menu_complete) - { - /* Clean up from previous call, if any. */ - FREE (orig_text); - if (matches) - _rl_free_match_list (matches); - - match_list_index = match_list_size = 0; - matches = (char **)NULL; - - /* Only the completion entry function can change these. */ - set_completion_defaults ('%'); - - our_func = rl_completion_entry_function - ? rl_completion_entry_function - : rl_filename_completion_function; - - /* We now look backwards for the start of a filename/variable word. */ - orig_end = rl_point; - found_quote = delimiter = 0; - quote_char = '\0'; - - if (rl_point) - /* This (possibly) changes rl_point. If it returns a non-zero char, - we know we have an open quote. */ - quote_char = _rl_find_completion_word (&found_quote, &delimiter); - - orig_start = rl_point; - rl_point = orig_end; - - orig_text = rl_copy_text (orig_start, orig_end); - matches = gen_completion_matches (orig_text, orig_start, orig_end, - our_func, found_quote, quote_char); - - /* If we are matching filenames, the attempted completion function will - have set rl_filename_completion_desired to a non-zero value. The basic - rl_filename_completion_function does this. */ - matching_filenames = rl_filename_completion_desired; - - if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) - { - rl_ding (); - FREE (matches); - matches = (char **)0; - FREE (orig_text); - orig_text = (char *)0; - completion_changed_buffer = 0; - return (0); - } - - for (match_list_size = 0; matches[match_list_size]; match_list_size++) - ; - /* matches[0] is lcd if match_list_size > 1, but the circular buffer - code below should take care of it. */ - } - - /* Now we have the list of matches. Replace the text between - rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with - matches[match_list_index], and add any necessary closing char. */ - - if (matches == 0 || match_list_size == 0) - { - rl_ding (); - FREE (matches); - matches = (char **)0; - completion_changed_buffer = 0; - return (0); - } - - match_list_index = (match_list_index + count) % match_list_size; - if (match_list_index < 0) - match_list_index += match_list_size; - - if (match_list_index == 0 && match_list_size > 1) - { - rl_ding (); - insert_match (orig_text, orig_start, MULT_MATCH, "e_char); - } - else - { - insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char); - append_to_match (matches[match_list_index], delimiter, quote_char, - strcmp (orig_text, matches[match_list_index])); - } - - completion_changed_buffer = 1; - return (0); -} diff --git a/lib/readline/display.c~ b/lib/readline/display.c~ deleted file mode 100644 index a118dd279..000000000 --- a/lib/readline/display.c~ +++ /dev/null @@ -1,2280 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include "posixstat.h" - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -/* Termcap library stuff. */ -#include "tcap.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - -#if defined (HACK_TERMCAP_MOTION) -extern char *_rl_term_forward_char; -#endif - -static void update_line PARAMS((char *, char *, int, int, int, int)); -static void space_to_eol PARAMS((int)); -static void delete_chars PARAMS((int)); -static void insert_some_chars PARAMS((char *, int, int)); -static void cr PARAMS((void)); - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -static int *_rl_wrapped_line; -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -static int *inv_lbreaks, *vis_lbreaks; -static int inv_lbsize, vis_lbsize; - -/* 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. */ - -/* Application-specific redisplay function. */ -rl_voidfunc_t *rl_redisplay_function = rl_redisplay; - -/* Global variables declared here. */ -/* What YOU turn on when you have handled all redisplay yourself. */ -int rl_display_fixed = 0; - -int _rl_suppress_redisplay = 0; - -/* The stuff that gets printed out before the actual text of the line. - This is usually pointing to rl_prompt. */ -char *rl_display_prompt = (char *)NULL; - -/* 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; - -/* 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; - -/* Default and initial buffer size. Can grow. */ -static int line_size = 1024; - -/* Variables to keep track of the expanded prompt string, which may - include invisible characters. */ - -static char *local_prompt, *local_prompt_prefix; -static int prompt_visible_length, prompt_prefix_length; - -/* The number of invisible characters in the line currently being - displayed on the screen. */ -static int visible_wrap_offset; - -/* The number of invisible characters in the prompt string. Static so it - can be shared between rl_redisplay and update_line */ -static int wrap_offset; - -/* The index of the last invisible character in the prompt string. */ -static int prompt_last_invisible; - -/* The length (buffer offset) of the first line of the last (possibly - multi-line) buffer displayed on the screen. */ -static int visible_first_line_len; - -/* Number of invisible characters on the first physical line of the prompt. - Only valid when the number of physical characters in the prompt exceeds - (or is equal to) _rl_screenwidth. */ -static int prompt_invis_chars_first_line; - -static int prompt_last_screen_line; - -static int prompt_physical_chars; - -/* 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. LIP, if non-null is a place to store the - index of the last invisible character in the returned string. NIFLP, - if non-zero, is a place to store the number of invisible characters in - the first prompt line. The previous are used as byte counts -- indexes - into a character buffer. */ - -/* 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, lip, niflp, vlp) - char *pmt; - int *lp, *lip, *niflp, *vlp; -{ - char *r, *ret, *p; - int l, rl, last, ignoring, ninvis, invfl, ind, pind, physchars; - - /* Short-circuit if we can. */ - if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0) - { - r = savestring (pmt); - if (lp) - *lp = strlen (r); - if (lip) - *lip = 0; - if (niflp) - *niflp = 0; - if (vlp) - *vlp = lp ? *lp : strlen (r); - return r; - } - - l = strlen (pmt); - r = ret = (char *)xmalloc (l + 1); - - invfl = 0; /* invisible chars in first line of prompt */ - - for (rl = ignoring = last = ninvis = physchars = 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; - last = r - ret - 1; - continue; - } - else - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - pind = p - pmt; - ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO); - l = ind - pind; - while (l--) - *r++ = *p++; - if (!ignoring) - rl += ind - pind; - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - rl++; /* visible length byte counter */ - else - ninvis++; /* invisible chars byte counter */ - } - - if (rl >= _rl_screenwidth) - invfl = ninvis; - - if (ignoring == 0) - physchars++; - } - } - - if (rl < _rl_screenwidth) - invfl = ninvis; - - *r = '\0'; - if (lp) - *lp = rl; - if (lip) - *lip = last; - if (niflp) - *niflp = invfl; - if (vlp) - *vlp = physchars; - return ret; -} - -/* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from - PMT and return the rest of PMT. */ -char * -_rl_strip_prompt (pmt) - char *pmt; -{ - char *ret; - - ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL); - 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 - * prompt_visible_length = number of visible characters in local_prompt - * 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. */ - FREE (local_prompt); - FREE (local_prompt_prefix); - - local_prompt = local_prompt_prefix = (char *)0; - prompt_last_invisible = prompt_visible_length = 0; - - if (prompt == 0 || *prompt == 0) - return (0); - - p = strrchr (prompt, '\n'); - if (!p) - { - /* The prompt is only one logical line, though it might wrap. */ - local_prompt = expand_prompt (prompt, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - (int *)NULL, - (int *)NULL); - 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, &prompt_prefix_length, - (int *)NULL, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - *t = c; - return (prompt_prefix_length); - } -} - -/* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated - arrays of line break markers. MINSIZE is the minimum size of VISIBLE_LINE - and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is - increased. If the lines have already been allocated, this ensures that - they can hold at least MINSIZE characters. */ -static void -init_line_structures (minsize) - int minsize; -{ - register int n; - - if (invisible_line == 0) /* initialize it */ - { - if (line_size < minsize) - line_size = minsize; - visible_line = (char *)xmalloc (line_size); - invisible_line = (char *)xmalloc (line_size); - } - else if (line_size < minsize) /* ensure it can hold MINSIZE chars */ - { - line_size *= 2; - if (line_size < minsize) - line_size = minsize; - visible_line = (char *)xrealloc (visible_line, line_size); - invisible_line = (char *)xrealloc (invisible_line, line_size); - } - - for (n = minsize; n < line_size; n++) - { - visible_line[n] = 0; - invisible_line[n] = 1; - } - - if (vis_lbreaks == 0) - { - /* should be enough. */ - inv_lbsize = vis_lbsize = 256; - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); -#if defined (HANDLE_MULTIBYTE) - _rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int)); -#endif - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int c_pos, inv_botlin, lb_botlin, lb_linenum; - int newlines, lpos, temp, modmark; - char *prompt_this_line; -#if defined (HANDLE_MULTIBYTE) - wchar_t wc; - size_t wc_bytes; - int wc_width; - mbstate_t ps; - int _rl_wrapped_multicolumn = 0; -#endif - - if (!readline_echoing_p) - return; - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (invisible_line == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - c_pos = -1; - - line = invisible_line; - out = inv_botlin = 0; - - /* Mark the line as modified or not. We only do this for history - lines. */ - modmark = 0; - if (_rl_mark_modified_lines && current_history () && rl_undo_list) - { - line[out++] = '*'; - line[out] = '\0'; - modmark = 1; - } - - /* 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 || local_prompt) - { - int local_len = local_prompt ? strlen (local_prompt) : 0; - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_len > 0) - { - temp = local_len + out + 2; - if (temp >= line_size) - { - line_size = (temp + 1024) - (temp % 1024); - visible_line = (char *)xrealloc (visible_line, line_size); - line = invisible_line = (char *)xrealloc (invisible_line, line_size); - } - strncpy (line + out, local_prompt, local_len); - out += local_len; - } - line[out] = '\0'; - wrap_offset = local_len - prompt_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++; - pmtlen = prompt_this_line - rl_display_prompt; /* temp var */ - if (forced_display) - { - _rl_output_some_chars (rl_display_prompt, pmtlen); - /* Make sure we are at column zero even after a newline, - regardless of the state of terminal output processing. */ - if (pmtlen < 2 || prompt_this_line[-2] != '\r') - cr (); - } - } - - prompt_physical_chars = pmtlen = strlen (prompt_this_line); - temp = pmtlen + out + 2; - if (temp >= line_size) - { - line_size = (temp + 1024) - (temp % 1024); - visible_line = (char *)xrealloc (visible_line, line_size); - line = invisible_line = (char *)xrealloc (invisible_line, line_size); - } - strncpy (line + out, prompt_this_line, pmtlen); - out += pmtlen; - line[out] = '\0'; - wrap_offset = prompt_invis_chars_first_line = 0; - } - -#define CHECK_INV_LBREAKS() \ - do { \ - if (newlines >= (inv_lbsize - 2)) \ - { \ - inv_lbsize *= 2; \ - inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ - } \ - } while (0) - -#if defined (HANDLE_MULTIBYTE) -#define CHECK_LPOS() \ - do { \ - lpos++; \ - if (lpos >= _rl_screenwidth) \ - { \ - if (newlines >= (inv_lbsize - 2)) \ - { \ - inv_lbsize *= 2; \ - inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ - _rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \ - } \ - inv_lbreaks[++newlines] = out; \ - _rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \ - lpos = 0; \ - } \ - } while (0) -#else -#define CHECK_LPOS() \ - do { \ - lpos++; \ - if (lpos >= _rl_screenwidth) \ - { \ - if (newlines >= (inv_lbsize - 2)) \ - { \ - inv_lbsize *= 2; \ - inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ - } \ - inv_lbreaks[++newlines] = out; \ - lpos = 0; \ - } \ - } while (0) -#endif - - /* inv_lbreaks[i] is where line i starts in the buffer. */ - inv_lbreaks[newlines = 0] = 0; -#if 0 - lpos = out - wrap_offset; -#else - lpos = prompt_physical_chars + modmark; -#endif - -#if defined (HANDLE_MULTIBYTE) - memset (_rl_wrapped_line, 0, vis_lbsize); -#endif - - /* prompt_invis_chars_first_line is the number of invisible characters in - the first physical line of the prompt. - wrap_offset - prompt_invis_chars_first_line is the number of invis - chars on the second line. */ - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - /* fix from Darin Johnson for prompt string with - invisible characters that is longer than the screen width. The - prompt_invis_chars_first_line variable could be made into an array - saying how many invisible characters there are per line, but that's - probably too much work for the benefit gained. How many people have - prompts that exceed two physical lines? - Additional logic fix from Edward Catmur */ - temp = ((newlines + 1) * _rl_screenwidth) + - ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == 1) ? wrap_offset : 0)) - : ((newlines == 0) ? wrap_offset :0)); - - inv_lbreaks[++newlines] = temp; - lpos -= _rl_screenwidth; - } - - prompt_last_screen_line = newlines; - - /* Draw the rest of the line (after the prompt) into invisible_line, keeping - track of where the cursor is (c_pos), the number of the line containing - the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin). - It maintains an array of line breaks for display (inv_lbreaks). - This handles expanding tabs for display and displaying meta characters. */ - lb_linenum = 0; -#if defined (HANDLE_MULTIBYTE) - in = 0; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - memset (&ps, 0, sizeof (mbstate_t)); - wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps); - } - else - wc_bytes = 1; - while (in < rl_end) -#else - for (in = 0; in < rl_end; in++) -#endif - { - c = (unsigned char)rl_line_buffer[in]; - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (MB_INVALIDCH (wc_bytes)) - { - /* Byte sequence is invalid or shortened. Assume that the - first byte represents a character. */ - wc_bytes = 1; - /* Assume that a character occupies a single column. */ - wc_width = 1; - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (wc_bytes)) - break; /* Found '\0' */ - else - { - temp = wcwidth (wc); - wc_width = (temp >= 0) ? temp : 1; - } - } -#endif - - if (out + 8 >= line_size) /* XXX - 8 for \t */ - { - line_size *= 2; - visible_line = (char *)xrealloc (visible_line, line_size); - invisible_line = (char *)xrealloc (invisible_line, line_size); - line = invisible_line; - } - - if (in == rl_point) - { - c_pos = out; - lb_linenum = newlines; - } - -#if defined (HANDLE_MULTIBYTE) - if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */ -#else - if (META_CHAR (c)) -#endif - { - if (_rl_output_meta_chars == 0) - { - sprintf (line + out, "\\%o", c); - - if (lpos + 4 >= _rl_screenwidth) - { - temp = _rl_screenwidth - lpos; - CHECK_INV_LBREAKS (); - inv_lbreaks[++newlines] = out + temp; - lpos = 4 - temp; - } - else - lpos += 4; - - out += 4; - } - else - { - line[out++] = c; - CHECK_LPOS(); - } - } -#if defined (DISPLAY_TABS) - else if (c == '\t') - { - register int newout; - -#if 0 - newout = (out | (int)7) + 1; -#else - newout = out + 8 - lpos % 8; -#endif - temp = newout - out; - if (lpos + temp >= _rl_screenwidth) - { - register int temp2; - temp2 = _rl_screenwidth - lpos; - CHECK_INV_LBREAKS (); - inv_lbreaks[++newlines] = out + temp2; - lpos = temp - temp2; - while (out < newout) - line[out++] = ' '; - } - else - { - while (out < newout) - line[out++] = ' '; - lpos += temp; - } - } -#endif - else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up) - { - line[out++] = '\0'; /* XXX - sentinel */ - CHECK_INV_LBREAKS (); - inv_lbreaks[++newlines] = out; - lpos = 0; - } - else if (CTRL_CHAR (c) || c == RUBOUT) - { - line[out++] = '^'; - CHECK_LPOS(); - line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; - CHECK_LPOS(); - } - else - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - register int i; - - _rl_wrapped_multicolumn = 0; - - if (_rl_screenwidth < lpos + wc_width) - for (i = lpos; i < _rl_screenwidth; i++) - { - /* The space will be removed in update_line() */ - line[out++] = ' '; - _rl_wrapped_multicolumn++; - CHECK_LPOS(); - } - if (in == rl_point) - { - c_pos = out; - lb_linenum = newlines; - } - for (i = in; i < in+wc_bytes; i++) - line[out++] = rl_line_buffer[i]; - for (i = 0; i < wc_width; i++) - CHECK_LPOS(); - } - else - { - line[out++] = c; - CHECK_LPOS(); - } -#else - line[out++] = c; - CHECK_LPOS(); -#endif - } - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - in += wc_bytes; - wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps); - } - else - in++; -#endif - - } - line[out] = '\0'; - if (c_pos < 0) - { - c_pos = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* C_POS == position in buffer where cursor should be placed. - CURSOR_LINENUM == line number where the 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 == 0 && _rl_term_up && *_rl_term_up) - { - int nleft, 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. */ - if (out >= _rl_screenchars) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY); - else - out = _rl_screenchars - 1; - } - - /* The first line is at character position 0 in the buffer. The - second and subsequent lines start at inv_lbreaks[N], offset by - OFFSET (which has already been calculated above). */ - -#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) -#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) -#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) -#define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) -#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) -#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) - - /* For each line in the buffer, do the updating display. */ - for (linenum = 0; linenum <= inv_botlin; linenum++) - { - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* If this is the line with the prompt, we might need to - compensate for invisible characters in the new line. Do - this only if there is not more than one new line (which - implies that we completely overwrite the old visible line) - and the new line is shorter than the old. Make sure we are - at the end of the new line before clearing. */ - if (linenum == 0 && - inv_botlin == 0 && _rl_last_c_pos == out && - (wrap_offset > visible_wrap_offset) && - (_rl_last_c_pos < visible_first_line_len)) - { - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_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) ? inv_lbreaks[1] : 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); - _rl_clear_to_eol - ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth); - } - } - _rl_vis_botlin = inv_botlin; - - /* 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 _rl_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. But we - only need to reprint it if the cursor is before the last - invisible character in the prompt string. */ - nleft = prompt_visible_length + wrap_offset; - if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && - _rl_last_c_pos <= prompt_last_invisible && local_prompt) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - _rl_output_some_chars (local_prompt, nleft); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft); - else - _rl_last_c_pos = nleft; - } - - /* Where on that line? And where does that line start - in the buffer? */ - pos = inv_lbreaks[cursor_linenum]; - /* nleft == number of characters in the line buffer between the - start of the line and the cursor position. */ - nleft = c_pos - pos; - - /* Since _rl_backspace() doesn't know about invisible characters in the - prompt, and there's no good way to tell it, we compensate for - those characters here and call _rl_backspace() directly. */ - if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) - { - _rl_backspace (_rl_last_c_pos - nleft); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width (&visible_line[pos], 0, nleft); - else - _rl_last_c_pos = nleft; - } - - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_move_cursor_relative (nleft, &invisible_line[pos]); - else 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 = prompt_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 = _rl_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 > _rl_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 < _rl_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 character 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) + _rl_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, - _rl_screenwidth + visible_wrap_offset, - _rl_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 = _rl_screenwidth - t; - _rl_clear_to_eol (nleft); - } - visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); - if (visible_first_line_len > _rl_screenwidth) - visible_first_line_len = _rl_screenwidth; - - _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - char *vtemp = visible_line; - int *itemp = vis_lbreaks, ntemp = vis_lbsize; - - visible_line = invisible_line; - invisible_line = vtemp; - - vis_lbreaks = inv_lbreaks; - inv_lbreaks = itemp; - - vis_lbsize = inv_lbsize; - inv_lbsize = ntemp; - - 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 handled. - - 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, inv_botlin; -{ - register char *ofd, *ols, *oe, *nfd, *nls, *ne; - int temp, lendiff, wsatend, od, nd; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset, tmp; -#endif - - /* 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 == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode - && _rl_last_v_pos == current_line - 1) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - wchar_t wc; - mbstate_t ps; - int tempwidth, bytes; - size_t ret; - - /* This fixes only double-column characters, but if the wrapped - character comsumes more than three columns, spaces will be - inserted in the string buffer. */ - if (_rl_wrapped_line[current_line] > 0) - _rl_clear_to_eol (_rl_wrapped_line[current_line]); - - memset (&ps, 0, sizeof (mbstate_t)); - ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); - if (MB_INVALIDCH (ret)) - { - tempwidth = 1; - ret = 1; - } - else if (MB_NULLWCH (ret)) - tempwidth = 0; - else - tempwidth = wcwidth (wc); - - if (tempwidth > 0) - { - int count; - bytes = ret; - for (count = 0; count < bytes; count++) - putc (new[count], rl_outstream); - _rl_last_c_pos = tempwidth; - _rl_last_v_pos++; - memset (&ps, 0, sizeof (mbstate_t)); - ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps); - if (ret != 0 && bytes != 0) - { - if (MB_INVALIDCH (ret)) - memmove (old+bytes, old+1, strlen (old+1)); - else - memmove (old+bytes, old+ret, strlen (old+ret)); - memcpy (old, new, bytes); - } - } - else - { - putc (' ', rl_outstream); - _rl_last_c_pos = 1; - _rl_last_v_pos++; - if (old[0] && new[0]) - old[0] = new[0]; - } - } - else -#endif - { - 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. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* See if the old line is a subset of the new line, so that the - only change is adding characters. */ - temp = (omax < nmax) ? omax : nmax; - if (memcmp (old, new, temp) == 0) - { - ofd = old + temp; - nfd = new + temp; - } - else - { - memset (&ps_new, 0, sizeof(mbstate_t)); - memset (&ps_old, 0, sizeof(mbstate_t)); - - if (omax == nmax && STREQN (new, old, omax)) - { - ofd = old + omax; - nfd = new + nmax; - } - else - { - new_offset = old_offset = 0; - for (ofd = old, nfd = new; - (ofd - old < omax) && *ofd && - _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) - { - old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); - new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); - ofd = old + old_offset; - nfd = new + new_offset; - } - } - } - } - else -#endif - 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 */ - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY); - nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY); - while ((ols > ofd) && (nls > nfd)) - { - memset (&ps_old, 0, sizeof (mbstate_t)); - memset (&ps_new, 0, sizeof (mbstate_t)); - -#if 0 - /* On advice from jir@yamato.ibm.com */ - _rl_adjust_point (old, ols - old, &ps_old); - _rl_adjust_point (new, nls - new, &ps_new); -#endif - - if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0) - break; - - if (*ols == ' ') - wsatend = 0; - - ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY); - nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY); - } - } - else - { -#endif /* HANDLE_MULTIBYTE */ - ols = oe - 1; /* find last same */ - nls = ne - 1; - while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) - { - if (*ols != ' ') - wsatend = 0; - ols--; - nls--; - } -#if defined (HANDLE_MULTIBYTE) - } -#endif - - if (wsatend) - { - ols = oe; - nls = ne; - } -#if defined (HANDLE_MULTIBYTE) - /* This may not work for stateful encoding, but who cares? To handle - stateful encoding properly, we have to scan each string from the - beginning and compare. */ - else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0) -#else - else if (*ols != *nls) -#endif - { - if (*ols) /* don't step past the NUL */ - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY); - else - ols++; - } - if (*nls) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY); - else - nls++; - } - } - - /* count of invisible characters in the current invisible line. */ - current_invis_chars = W_OFFSET (current_line, wrap_offset); - if (_rl_last_v_pos != current_line) - { - _rl_move_vert (current_line); - if (current_line == 0 && visible_wrap_offset) - _rl_last_c_pos += visible_wrap_offset; - } - - /* If this is the first line and there are invisible characters in the - prompt string, and the prompt string has not changed, and the current - cursor position is before the last invisible character in the prompt, - and the index of the character to move to is past the end of the prompt - string, then redraw the entire prompt string. We can only do this - reliably if the terminal supports a `cr' capability. - - This is not an efficiency hack -- there is a problem with redrawing - portions of the prompt string if they contain terminal escape - sequences (like drawing the `unbold' sequence without a corresponding - `bold') that manifests itself on certain terminals. */ - - lendiff = local_prompt ? strlen (local_prompt) : 0; - od = ofd - old; /* index of first difference in visible line */ - if (current_line == 0 && !_rl_horizontal_scroll_mode && - _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 && - od >= lendiff && _rl_last_c_pos <= prompt_last_invisible) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff); - else - _rl_last_c_pos = lendiff; - } - - _rl_move_cursor_relative (od, old); - - /* if (len (new) > len (old)) - lendiff == difference in buffer - col_lendiff == difference on screen - When not using multibyte characters, these are equal */ - lendiff = (nls - nfd) - (ols - ofd); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old); - else - col_lendiff = lendiff; - - /* If we are changing the number of invisible characters in a line, and - the spot of first difference is before the end of the invisible chars, - lendiff needs to be adjusted. */ - if (current_line == 0 && !_rl_horizontal_scroll_mode && - current_invis_chars != visible_wrap_offset) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - lendiff += visible_wrap_offset - current_invis_chars; - col_lendiff += visible_wrap_offset - current_invis_chars; - } - else - { - lendiff += visible_wrap_offset - current_invis_chars; - col_lendiff = lendiff; - } - } - - /* Insert (diff (len (old), len (new)) ch. */ - temp = ne - nfd; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - col_temp = _rl_col_width (new, nfd - new, ne - new); - else - col_temp = temp; - - if (col_lendiff > 0) /* XXX - was lendiff */ - { - /* 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 (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) - { - /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and - _rl_horizontal_scroll_mode == 1, inserting the characters with - _rl_term_IC or _rl_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 <= prompt_visible_length || !current_invis_chars)) - { - insert_some_chars (nfd, lendiff, col_lendiff); - _rl_last_c_pos += col_lendiff; - } - else if (*ols == 0 && lendiff > 0) - { - /* At the end of a line the characters do not have to - be "inserted". They can just be placed on the screen. */ - /* However, this screws up the rest of this block, which - assumes you've done the insert because you can. */ - _rl_output_some_chars (nfd, lendiff); - _rl_last_c_pos += col_lendiff; - } - else - { - /* We have horizontal scrolling and we are not inserting at - the end. We have invisible characters in this line. This - is a dumb update. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - return; - } - /* 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); -#if 1 - /* XXX -- this bears closer inspection. Fixes a redisplay bug - reported against bash-3.0-alpha by Andreas Schwab involving - multibyte characters and prompt strings with invisible - characters, but was previously disabled. */ - _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); -#else - _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff); -#endif - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - } - } - else /* Delete characters from line. */ - { - /* If possible and inexpensive to use terminal deletion, then do so. */ - if (_rl_term_dc && (2 * col_temp) >= -col_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) - col_lendiff = 0; - - if (col_lendiff) - delete_chars (-col_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 += _rl_col_width (nfd, 0, temp);; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - } - lendiff = (oe - old) - (ne - new); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new); - else - col_lendiff = lendiff; - - if (col_lendiff) - { - if (_rl_term_autowrap && current_line < inv_botlin) - space_to_eol (col_lendiff); - else - _rl_clear_to_eol (col_lendiff); - } - } - } -} - -/* Tell the update routines that we have moved onto a new (empty) line. */ -int -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; - if (vis_lbreaks) - vis_lbreaks[0] = vis_lbreaks[1] = 0; - visible_wrap_offset = 0; - return 0; -} - -/* Tell the update routines that we have moved onto a new line with the - prompt already displayed. Code originally from the version of readline - distributed with CLISP. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line; - - /* Initialize visible_line and invisible_line to ensure that they can hold - the already-displayed prompt. */ - prompt_size = strlen (rl_prompt) + 1; - init_line_structures (prompt_size); - - /* Make sure the line structures hold the already-displayed prompt for - redisplay. */ - strcpy (visible_line, rl_prompt); - strcpy (invisible_line, rl_prompt); - - /* If the prompt contains newlines, take the last tail. */ - prompt_last_line = strrchr (rl_prompt, '\n'); - if (!prompt_last_line) - prompt_last_line = rl_prompt; - - l = strlen (prompt_last_line); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l); - else - _rl_last_c_pos = l; - - /* Dissect prompt_last_line into screen lines. Note that here we have - to use the real screenwidth. Readline's notion of screenwidth might be - one less, see terminal.c. */ - real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1); - _rl_last_v_pos = l / real_screenwidth; - /* If the prompt length is a multiple of real_screenwidth, we don't know - whether the cursor is at the end of the last line, or already at the - beginning of the next line. Output a newline just to be safe. */ - if (l > 0 && (l % real_screenwidth) == 0) - _rl_output_some_chars ("\n", 1); - last_lmargin = 0; - - newlines = 0; i = 0; - while (i <= l) - { - _rl_vis_botlin = newlines; - vis_lbreaks[newlines++] = i; - i += real_screenwidth; - } - vis_lbreaks[newlines] = l; - visible_wrap_offset = 0; - - rl_display_prompt = rl_prompt; /* XXX - make sure it's set */ - - return 0; -} - -/* Actually update the display, period. */ -int -rl_forced_update_display () -{ - if (visible_line) - { - register char *temp = visible_line; - - while (*temp) - *temp++ = '\0'; - } - rl_on_new_line (); - forced_display++; - (*rl_redisplay_function) (); - 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; - const char *data; -{ - register int i; - - /* If we don't have to do anything, then return. */ -#if defined (HANDLE_MULTIBYTE) - /* If we have multibyte characters, NEW is indexed by the buffer point in - a multibyte string, but _rl_last_c_pos is the display position. In - this case, NEW's display position is not obvious and must be - calculated. */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - if (_rl_last_c_pos == new) - return; - } - else if (_rl_last_c_pos == _rl_col_width (data, 0, new)) - return; -#else - if (_rl_last_c_pos == new) return; -#endif - - /* 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 (new == 0 || CR_FASTER (new, _rl_last_c_pos) || - (_rl_term_autowrap && i == _rl_screenwidth)) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_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) - if (_rl_term_forward_char) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int width; - width = _rl_col_width (data, _rl_last_c_pos, new); - for (i = 0; i < width; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - for (i = _rl_last_c_pos; i < new; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - } - else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - else - for (i = _rl_last_c_pos; i < new; i++) - putc (data[i], rl_outstream); - -#else /* !HACK_TERMCAP_MOTION */ - - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; 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 */ - - } -#if defined (HANDLE_MULTIBYTE) - /* NEW points to the buffer point, but _rl_last_c_pos is the display point. - The byte length of the string is probably bigger than the column width - of the string, which means that if NEW == _rl_last_c_pos, then NEW's - display point is less than _rl_last_c_pos. */ - else if (_rl_last_c_pos >= new) -#else - else if (_rl_last_c_pos > new) -#endif - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_backspace (_rl_last_c_pos - _rl_col_width (data, 0, new)); - else - _rl_backspace (_rl_last_c_pos - new); - } - - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width (data, 0, new); - else - _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 > _rl_screenheight) - return; - - if ((delta = to - _rl_last_v_pos) > 0) - { - for (i = 0; i < delta; i++) - putc ('\n', rl_outstream); -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - _rl_last_c_pos = 0; - } - else - { /* delta < 0 */ - if (_rl_term_up && *_rl_term_up) - for (i = 0; i < -delta; i++) - tputs (_rl_term_up, 1, _rl_output_character_function); - } - - _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. */ -int -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 ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT) -#else - if (CTRL_CHAR (c) || c == RUBOUT) -#endif /* !DISPLAY_TABS */ - { - fprintf (rl_outstream, "C-"); - n += 2; - c = CTRL_CHAR (c) ? UNCTRL (c) : '?'; - } - - 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 */ - } - - if (CTRL_CHAR (c) || c == RUBOUT) - return (2); - - return ((ISPRINT (uc)) ? 1 : 2); -} - -/* How to print things in the "echo-area". The prompt is treated as a - mini-modeline. */ - -#if defined (USE_VARARGS) -int -#if defined (PREFER_STDARG) -rl_message (const char *format, ...) -#else -rl_message (va_alist) - va_dcl -#endif -{ - va_list args; -#if defined (PREFER_VARARGS) - char *format; -#endif - -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); - format = va_arg (args, char *); -#endif - -#if defined (HAVE_VSNPRINTF) - vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args); -#else - vsprintf (msg_buf, format, args); - msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ -#endif - va_end (args); - - rl_display_prompt = msg_buf; - (*rl_redisplay_function) (); - return 0; -} -#else /* !USE_VARARGS */ -int -rl_message (format, arg1, arg2) - char *format; -{ - sprintf (msg_buf, format, arg1, arg2); - msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ - rl_display_prompt = msg_buf; - (*rl_redisplay_function) (); - return 0; -} -#endif /* !USE_VARARGS */ - -/* How to clear things from the "echo-area". */ -int -rl_clear_message () -{ - rl_display_prompt = rl_prompt; - (*rl_redisplay_function) (); - return 0; -} - -int -rl_reset_line_state () -{ - rl_on_new_line (); - - rl_display_prompt = rl_prompt ? rl_prompt : ""; - forced_display = 1; - return 0; -} - -/* These are getting numerous enough that it's time to create a struct. */ - -static char *saved_local_prompt; -static char *saved_local_prefix; -static int saved_last_invisible; -static int saved_visible_length; -static int saved_invis_chars_first_line; -static int saved_physical_chars; - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_last_invisible = prompt_last_invisible; - saved_visible_length = prompt_visible_length; - saved_invis_chars_first_line = prompt_invis_chars_first_line; - saved_physical_chars = prompt_physical_chars; - - local_prompt = local_prompt_prefix = (char *)0; - prompt_last_invisible = prompt_visible_length = 0; - prompt_invis_chars_first_line = prompt_physical_chars = 0; -} - -void -rl_restore_prompt () -{ - FREE (local_prompt); - FREE (local_prompt_prefix); - - local_prompt = saved_local_prompt; - local_prompt_prefix = saved_local_prefix; - prompt_last_invisible = saved_last_invisible; - prompt_visible_length = saved_visible_length; - prompt_invis_chars_first_line = saved_invis_chars_first_line; - prompt_physical_chars = saved_physical_chars; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt; - - rl_save_prompt (); - - if (saved_local_prompt == 0) - { - len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, rl_prompt); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - else - { - len = *saved_local_prompt ? strlen (saved_local_prompt) : 0; - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, saved_local_prompt); - pmt[len] = pchar; - pmt[len+1] = '\0'; - local_prompt = savestring (pmt); - prompt_last_invisible = saved_last_invisible; - prompt_visible_length = saved_visible_length + 1; - } - - return pmt; -} - -/* Quick redisplay hack when erasing characters at the end of the line. */ -void -_rl_erase_at_end_of_line (l) - int l; -{ - register int i; - - _rl_backspace (l); - for (i = 0; i < l; i++) - putc (' ', rl_outstream); - _rl_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, */ -void -_rl_clear_to_eol (count) - int count; -{ - if (_rl_term_clreol) - tputs (_rl_term_clreol, 1, _rl_output_character_function); - else if (count) - 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; -} - -void -_rl_clear_screen () -{ - if (_rl_term_clrpag) - tputs (_rl_term_clrpag, 1, _rl_output_character_function); - else - rl_crlf (); -} - -/* Insert COUNT characters from STRING to the output stream at column COL. */ -static void -insert_some_chars (string, count, col) - char *string; - int count, col; -{ - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - fprintf(stderr, "readline: debug: insert_some_chars: count (%d) != col (%d)\n", count, col); - - /* If IC is defined, then we do not have to "enter" insert mode. */ - if (_rl_term_IC) - { - char *buffer; - - buffer = tgoto (_rl_term_IC, 0, col); - 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 (_rl_term_im && *_rl_term_im) - tputs (_rl_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 (_rl_term_ic && *_rl_term_ic) - { - for (i = col; i--; ) - tputs (_rl_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 (_rl_term_ei && *_rl_term_ei) - tputs (_rl_term_ei, 1, _rl_output_character_function); - } -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - - if (_rl_term_DC && *_rl_term_DC) - { - char *buffer; - buffer = tgoto (_rl_term_DC, count, count); - tputs (buffer, count, _rl_output_character_function); - } - else - { - if (_rl_term_dc && *_rl_term_dc) - while (count--) - tputs (_rl_term_dc, 1, _rl_output_character_function); - } -} - -void -_rl_update_final () -{ - int full_lines; - - full_lines = 0; - /* If the cursor is the only thing on an otherwise-blank last line, - compensate so we don't print an extra CRLF. */ - if (_rl_vis_botlin && _rl_last_c_pos == 0 && - visible_line[vis_lbreaks[_rl_vis_botlin]] == 0) - { - _rl_vis_botlin--; - full_lines = 1; - } - _rl_move_vert (_rl_vis_botlin); - /* If we've wrapped lines, remove the final xterm line-wrap flag. */ - if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth)) - { - char *last_line; - - last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]]; - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); - _rl_clear_to_eol (0); - putc (last_line[_rl_screenwidth - 1], rl_outstream); - } - _rl_vis_botlin = 0; - rl_crlf (); - fflush (rl_outstream); - rl_display_fixed++; -} - -/* Move to the start of the current line. */ -static void -cr () -{ - if (_rl_term_cr) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - _rl_last_c_pos = 0; - } -} - -/* Redraw the last line of a multi-line prompt that may possibly contain - terminal escape sequences. Called with the cursor at column 0 of the - line to draw the prompt on. */ -static void -redraw_prompt (t) - char *t; -{ - char *oldp, *oldl, *oldlprefix; - int oldlen, oldlast, oldplen, oldninvis, oldphyschars; - - /* Geez, I should make this a struct. */ - oldp = rl_display_prompt; - oldl = local_prompt; - oldlprefix = local_prompt_prefix; - oldlen = prompt_visible_length; - oldplen = prompt_prefix_length; - oldlast = prompt_last_invisible; - oldninvis = prompt_invis_chars_first_line; - oldphyschars = prompt_physical_chars; - - rl_display_prompt = t; - local_prompt = expand_prompt (t, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - rl_forced_update_display (); - - rl_display_prompt = oldp; - local_prompt = oldl; - local_prompt_prefix = oldlprefix; - prompt_visible_length = oldlen; - prompt_prefix_length = oldplen; - prompt_last_invisible = oldlast; - prompt_invis_chars_first_line = oldninvis; - prompt_physical_chars = oldphyschars; -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* 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 (_rl_term_cr) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - _rl_last_c_pos = 0; -#if defined (__MSDOS__) - space_to_eol (_rl_screenwidth); - putc ('\r', rl_outstream); -#else - if (_rl_term_clreol) - tputs (_rl_term_clreol, 1, _rl_output_character_function); - else - { - space_to_eol (_rl_screenwidth); - tputs (_rl_term_cr, 1, _rl_output_character_function); - } -#endif - if (_rl_last_v_pos > 0) - _rl_move_vert (0); - } - else - rl_crlf (); - - /* Redraw only the last line of a multi-line prompt. */ - t = strrchr (rl_display_prompt, '\n'); - if (t) - redraw_prompt (++t); - else - rl_forced_update_display (); -} - -void -_rl_clean_up_for_exit () -{ - if (readline_echoing_p) - { - _rl_move_vert (_rl_vis_botlin); - _rl_vis_botlin = 0; - fflush (rl_outstream); - rl_restart_output (1, 0); - } -} - -void -_rl_erase_entire_line () -{ - cr (); - _rl_clear_to_eol (0); - cr (); - fflush (rl_outstream); -} - -/* return the `current display line' of the cursor -- the number of lines to - move up to get to the first screen line of the current readline line. */ -int -_rl_current_display_line () -{ - int ret, 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 - _rl_screenwidth - rl_visible_prompt_length; - else - nleft = _rl_last_c_pos - _rl_screenwidth; - - if (nleft > 0) - ret = 1 + nleft / _rl_screenwidth; - else - ret = 0; - - return ret; -} - -#if defined (HANDLE_MULTIBYTE) -/* Calculate the number of screen columns occupied by STR from START to END. - In the case of multibyte characters with stateful encoding, we have to - scan from the beginning of the string to take the state into account. */ -static int -_rl_col_width (str, start, end) - const char *str; - int start, end; -{ - wchar_t wc; - mbstate_t ps = {0}; - int tmp, point, width, max; - - if (end <= start) - return 0; - - point = 0; - max = end; - - while (point < start) - { - tmp = mbrlen (str + point, max, &ps); - if (MB_INVALIDCH ((size_t)tmp)) - { - /* In this case, the bytes are invalid or too short to compose a - multibyte character, so we assume that the first byte represents - a single character. */ - point++; - max--; - - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (tmp)) - break; /* Found '\0' */ - else - { - point += tmp; - max -= tmp; - } - } - - /* If START is not a byte that starts a character, then POINT will be - greater than START. In this case, assume that (POINT - START) gives - a byte count that is the number of columns of difference. */ - width = point - start; - - while (point < end) - { - tmp = mbrtowc (&wc, str + point, max, &ps); - if (MB_INVALIDCH ((size_t)tmp)) - { - /* In this case, the bytes are invalid or too short to compose a - multibyte character, so we assume that the first byte represents - a single character. */ - point++; - max--; - - /* and assume that the byte occupies a single column. */ - width++; - - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (tmp)) - break; /* Found '\0' */ - else - { - point += tmp; - max -= tmp; - tmp = wcwidth(wc); - width += (tmp >= 0) ? tmp : 1; - } - } - - width += point - end; - - return width; -} -#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/readline/doc/rluser.texi~ b/lib/readline/doc/rluser.texi~ deleted file mode 100644 index ad2866f00..000000000 --- a/lib/readline/doc/rluser.texi~ +++ /dev/null @@ -1,1824 +0,0 @@ -@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-2004 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. - -@ifclear BashFeatures -@defcodeindex bt -@end ifclear - -@node Command Line Editing -@chapter Command Line Editing - -This chapter describes the basic features of the @sc{gnu} -command line editing interface. -@ifset BashFeatures -Command line editing is provided by the Readline library, which is -used by several different programs, including Bash. -@end ifset - -@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. -@ifset BashFeatures -* Programmable Completion:: How to specify the possible completions for - a specific command. -* Programmable Completion Builtins:: Builtin commands to specify how to - complete arguments for a particular command. -@end ifset -@end menu - -@node Introduction and Notation -@section Introduction to Line Editing - -The following paragraphs describe the notation used to represent -keystrokes. - -The text @kbd{C-k} is read as `Control-K' and describes the character -produced when the @key{k} key is pressed while the Control key -is depressed. - -The text @kbd{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 pressed. -The Meta key is labeled @key{ALT} on many keyboards. -On keyboards with two keys labeled @key{ALT} (usually to either side of -the space bar), the @key{ALT} on the left side is generally set to -work as a Meta key. -The @key{ALT} key on the right may also be configured to work as a -Meta key or may be configured as some other modifier, such as a -Compose key for typing accented characters. - -If you do not have a Meta or @key{ALT} key, or another key working as -a Meta key, the identical keystroke can be generated by typing @key{ESC} -@emph{first}, and then typing @key{k}. -Either process is known as @dfn{metafying} the @key{k} key. - -The text @kbd{M-C-k} is read as `Meta-Control-k' and describes the -character produced by @dfn{metafying} @kbd{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}). -If your keyboard lacks a @key{LFD} key, typing @key{C-j} will -produce the desired character. -The @key{RET} key may be labeled @key{Return} or @key{Enter} on -some keyboards. - -@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{RET}. You do not have to be at the -end of the line to press @key{RET}; the entire line is accepted -regardless of the location of the cursor within the line. - -@menu -* Readline Bare Essentials:: The least you need to know about Readline. -* Readline Movement Commands:: Moving about the input line. -* Readline Killing Commands:: How to delete text, and how to get it back! -* Readline Arguments:: Giving numeric arguments to commands. -* Searching:: Searching through previous lines. -@end menu - -@node Readline Bare Essentials -@subsection Readline Bare Essentials -@cindex notation, readline -@cindex command editing -@cindex editing command lines - -In order to enter characters into the line, simply type them. The typed -character appears where the cursor was, and then the cursor moves one -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 mistype a character, and -not notice the error until you have typed several other characters. In -that case, you can type @kbd{C-b} to move the cursor to the left, and then -correct your mistake. Afterwards, you can move the cursor to the right -with @kbd{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 bare -essentials for editing the text of an input line follows. - -@table @asis -@item @kbd{C-b} -Move back one character. -@item @kbd{C-f} -Move forward one character. -@item @key{DEL} or @key{Backspace} -Delete the character to the left of the cursor. -@item @kbd{C-d} -Delete the character underneath the cursor. -@item @w{Printing characters} -Insert the character into the line at the cursor. -@item @kbd{C-_} or @kbd{C-x C-u} -Undo the last editing command. You can undo all the way back to an -empty line. -@end table - -@noindent -(Depending on your configuration, the @key{Backspace} key be set to -delete the character to the left of the cursor and the @key{DEL} key set -to delete the character underneath the cursor, like @kbd{C-d}, rather -than the character to the left of the cursor.) - -@node Readline Movement Commands -@subsection Readline Movement Commands - - -The above table describes the most basic 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 @kbd{C-b}, @kbd{C-f}, -@kbd{C-d}, and @key{DEL}. Here are some commands for moving more rapidly -about the line. - -@table @kbd -@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, where a word is composed of letters and digits. -@item M-b -Move backward a word. -@item C-l -Clear the screen, reprinting the current line at the top. -@end table - -Notice how @kbd{C-f} moves forward a character, while @kbd{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. -(`Cut' and `paste' are more recent jargon for `kill' and `yank'.) - -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 @kbd -@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. -Word boundaries are the same as those used by @kbd{M-f}. - -@item M-@key{DEL} -Kill from the cursor the start of the current word, or, if between -words, to the start of the previous word. -Word boundaries are the same as those used by @kbd{M-b}. - -@item C-w -Kill from the cursor to the previous whitespace. This is different than -@kbd{M-@key{DEL}} because the word boundaries differ. - -@end table - -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 @kbd -@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 @kbd{C-y} or @kbd{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 @samp{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' typed is a minus -sign (@samp{-}), 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 @kbd{C-d} command an argument of 10, you could type @samp{M-1 0 C-d}, -which will delete the next ten characters on the input line. - -@node Searching -@subsection Searching for Commands in the History - -Readline provides commands for searching through the command history -@ifset BashFeatures -(@pxref{Bash History Facilities}) -@end ifset -for lines containing a specified string. -There are two search modes: @dfn{incremental} and @dfn{non-incremental}. - -Incremental searches begin before the user has finished typing the -search string. -As each character of the search string is typed, Readline displays -the next entry from the history matching the string typed so far. -An incremental search requires only as many characters as needed to -find the desired history entry. -To search backward in the history for a particular string, type -@kbd{C-r}. Typing @kbd{C-s} searches forward through the history. -The characters present in the value of the @code{isearch-terminators} variable -are used to terminate an incremental search. -If that variable has not been assigned a value, the @key{ESC} and -@kbd{C-J} characters will terminate an incremental search. -@kbd{C-g} will abort an incremental search and restore the original line. -When the search is terminated, the history entry containing the -search string becomes the current line. - -To find other matching entries in the history list, type @kbd{C-r} or -@kbd{C-s} as appropriate. -This will search backward or forward in the history for the next -entry matching the search string typed so far. -Any other key sequence bound to a Readline command will terminate -the search and execute that command. -For instance, a @key{RET} will terminate the search and accept -the line, thereby executing the command from the history list. -A movement command will terminate the search, make the last line found -the current line, and begin editing. - -Readline remembers the last incremental search string. If two -@kbd{C-r}s are typed without any intervening characters defining a new -search string, any remembered search string is used. - -Non-incremental searches read the entire search string before starting -to search for matching history lines. The search string may be -typed by the user or be part of the contents of the current line. - -@node Readline Init File -@section Readline Init File -@cindex initialization file, readline - -Although the Readline library comes with a set of Emacs-like -keybindings installed by default, it is possible to use a different set -of keybindings. -Any user can customize programs that use Readline by putting -commands in an @dfn{inputrc} file, conventionally in his home directory. -The name of this -@ifset BashFeatures -file is taken from the value of the shell variable @env{INPUTRC}. If -@end ifset -@ifclear BashFeatures -file is taken from the value of the environment variable @env{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 File Syntax:: Syntax for the commands in the inputrc file. - -* Conditional Init Constructs:: Conditional key bindings in the inputrc file. - -* Sample Init File:: An example inputrc file. -@end menu - -@node Readline Init File Syntax -@subsection Readline Init File Syntax - -There are only a few basic constructs allowed in the -Readline init file. Blank lines are ignored. -Lines beginning with a @samp{#} are comments. -Lines beginning with a @samp{$} indicate conditional -constructs (@pxref{Conditional Init Constructs}). Other lines -denote variable settings and key bindings. - -@table @asis -@item Variable Settings -You can modify the run-time behavior of Readline by -altering the values of variables in Readline -using the @code{set} command within the init file. -The syntax is simple: - -@example -set @var{variable} @var{value} -@end example - -@noindent -Here, for example, is how to -change from the default Emacs-like key binding to use -@code{vi} line editing commands: - -@example -set editing-mode vi -@end example - -Variable names and values, where appropriate, are recognized without regard -to case. - -@ifset BashFeatures -The @w{@code{bind -V}} command lists the current Readline variable names -and values. @xref{Bash Builtins}. -@end ifset - -A great deal of run-time behavior is changeable with the following -variables. - -@cindex variables, readline -@table @code - -@item bell-style -@vindex bell-style -Controls what happens when Readline wants to ring the terminal bell. -If set to @samp{none}, Readline never rings the bell. If set to -@samp{visible}, Readline uses a visible bell if one is available. -If set to @samp{audible} (the default), Readline attempts to ring -the terminal's bell. - -@item comment-begin -@vindex comment-begin -The string to insert at the beginning of the line when the -@code{insert-comment} command is executed. The default value -is @code{"#"}. - -@item completion-ignore-case -If set to @samp{on}, Readline performs filename matching and completion -in a case-insensitive fashion. -The default value is @samp{off}. - -@item completion-query-items -@vindex completion-query-items -The number of possible completions that determines when the user is -asked whether the list of possibilities should be displayed. -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. -This variable must be set to an integer value greater than or equal to 0. -The default limit is @code{100}. - -@item convert-meta -@vindex convert-meta -If set to @samp{on}, Readline will convert characters with the -eighth bit set to an @sc{ascii} key sequence by stripping the eighth -bit and prefixing an @key{ESC} character, converting them to a -meta-prefixed key sequence. The default value is @samp{on}. - -@item disable-completion -@vindex disable-completion -If set to @samp{On}, Readline will inhibit word completion. -Completion characters will be inserted into the line as if they had -been mapped to @code{self-insert}. The default is @samp{off}. - -@item editing-mode -@vindex editing-mode -The @code{editing-mode} variable controls which default set of -key bindings is used. By default, Readline starts up in Emacs editing -mode, where the keystrokes are most similar to Emacs. This variable can be -set to either @samp{emacs} or @samp{vi}. - -@item enable-keypad -@vindex enable-keypad -When set to @samp{on}, Readline will try to enable the application -keypad when it is called. Some systems need this to enable the -arrow keys. The default is @samp{off}. - -@item expand-tilde -@vindex expand-tilde -If set to @samp{on}, tilde expansion is performed when Readline -attempts word completion. The default is @samp{off}. - -@vindex history-preserve-point -If set to @samp{on}, the history code attempts to place point at the -same location on each history line retrieved with @code{previous-history} -or @code{next-history}. - -@item horizontal-scroll-mode -@vindex horizontal-scroll-mode -This variable can be set to either @samp{on} or @samp{off}. Setting it -to @samp{on} means that the text of the lines being edited will scroll -horizontally on a single screen line when they are longer than the width -of the screen, instead of wrapping onto a new screen line. By default, -this variable is set to @samp{off}. - -@item input-meta -@vindex input-meta -@vindex meta-flag -If set to @samp{on}, Readline will enable eight-bit input (it -will not clear the eighth bit in the characters it reads), -regardless of what the terminal claims it can support. The -default value is @samp{off}. The name @code{meta-flag} is a -synonym for this variable. - -@item isearch-terminators -@vindex isearch-terminators -The string of characters that should terminate an incremental search without -subsequently executing the character as a command (@pxref{Searching}). -If this variable has not been given a value, the characters @key{ESC} and -@kbd{C-J} will terminate an incremental search. - -@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 mark-directories -If set to @samp{on}, completed directory names have a slash -appended. The default is @samp{on}. - -@item mark-modified-lines -@vindex mark-modified-lines -This variable, when set to @samp{on}, causes Readline to display an -asterisk (@samp{*}) at the start of history lines which have been modified. -This variable is @samp{off} by default. - -@item mark-symlinked-directories -@vindex mark-symlinked-directories -If set to @samp{on}, completed names which are symbolic links -to directories have a slash appended (subject to the value of -@code{mark-directories}). -The default is @samp{off}. - -@item match-hidden-files -@vindex match-hidden-files -This variable, when set to @samp{on}, causes Readline to match files whose -names begin with a @samp{.} (hidden files) when performing filename -completion, unless the leading @samp{.} is -supplied by the user in the filename to be completed. -This variable is @samp{on} by default. - -@item output-meta -@vindex output-meta -If set to @samp{on}, Readline will display characters with the -eighth bit set directly rather than as a meta-prefixed escape -sequence. The default is @samp{off}. - -@item page-completions -@vindex page-completions -If set to @samp{on}, Readline uses an internal @code{more}-like pager -to display a screenful of possible completions at a time. -This variable is @samp{on} by default. - -@item print-completions-horizontally -If set to @samp{on}, Readline will display completions with matches -sorted horizontally in alphabetical order, rather than down the screen. -The default is @samp{off}. - -@item show-all-if-ambiguous -@vindex show-all-if-ambiguous -This alters the default behavior of the completion functions. If -set to @samp{on}, -words which have more than one possible completion cause the -matches to be listed immediately instead of ringing the bell. -The default value is @samp{off}. - -@item show-all-if-unmodified -@vindex show-all-if-unmodified -This alters the default behavior of the completion functions in -a fashion similar to @var{show-all-if-ambiguous}. -If set to @samp{on}, -words which have more than one possible completion without any -possible partial completion (the possible completions don't share -a common prefix) cause the matches to be listed immediately instead -of ringing the bell. -The default value is @samp{off}. - -@item visible-stats -@vindex visible-stats -If set to @samp{on}, a character denoting a file's type -is appended to the filename when listing possible -completions. The default is @samp{off}. - -@end table - -@item Key Bindings -The syntax for controlling key bindings in the init file is -simple. First you need to find the name of the command that you -want to change. The following sections contain tables of the command -name, the default keybinding, if any, and a short description of what -the command does. - -Once you know the name of the command, simply place on a line -in the init file the name of the key -you wish to bind the command to, a colon, and then the name of the -command. The name of the key -can be expressed in different ways, depending on what you find most -comfortable. - -In addition to command names, readline allows keys to be bound -to a string that is inserted when the key is pressed (a @var{macro}). - -@ifset BashFeatures -The @w{@code{bind -p}} command displays Readline function names and -bindings in a format that can put directly into an initialization file. -@xref{Bash Builtins}. -@end ifset - -@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, @kbd{C-u} is bound to the function -@code{universal-argument}, -@kbd{M-DEL} is bound to the function @code{backward-kill-word}, and -@kbd{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). - -A number of symbolic character names are recognized while -processing this key binding syntax: -@var{DEL}, -@var{ESC}, -@var{ESCAPE}, -@var{LFD}, -@var{NEWLINE}, -@var{RET}, -@var{RETURN}, -@var{RUBOUT}, -@var{SPACE}, -@var{SPC}, -and -@var{TAB}. - -@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 @sc{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, @kbd{C-u} is again bound to the function -@code{universal-argument} (just as it was in the first example), -@samp{@kbd{C-x} @kbd{C-r}} is bound to the function @code{re-read-init-file}, -and @samp{@key{ESC} @key{[} @key{1} @key{1} @key{~}} is bound to insert -the text @samp{Function Key 1}. - -@end table - -The following @sc{gnu} Emacs style 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{"}, a double quotation mark -@item @kbd{\'} -@key{'}, a single quote or apostrophe -@end table - -In addition to the @sc{gnu} Emacs style escape sequences, a second -set of backslash escapes is available: - -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \d -delete -@item \f -form feed -@item \n -newline -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@end table - -When entering the text of a macro, single or double quotes must -be used to indicate a macro definition. -Unquoted text is assumed to be a function name. -In the macro body, the backslash escapes described above are expanded. -Backslash will quote any other character in the macro text, -including @samp{"} and @samp{'}. -For example, the following binding will make @samp{@kbd{C-x} \} -insert a single @samp{\} into the line: -@example -"\C-x\\": "\\" -@end example - -@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 four parser directives used. - -@table @code -@item $if -The @code{$if} construct allows bindings to be made based on the -editing mode, the terminal being used, or the application using -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 both the full name of the terminal and -the portion of the terminal name before the first @samp{-}. This -allows @code{sun} to match both @code{sun} and @code{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 -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: -@example -$if Bash -# Quote the current or previous word -"\C-xq": "\eb\"\ef\"" -$endif -@end example -@end table - -@item $endif -This command, as seen 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. - -@item $include -This directive takes a single filename as an argument and reads commands -and bindings from that file. -For example, the following directive reads from @file{/etc/inputrc}: -@example -$include /etc/inputrc -@end example -@end table - -@node Sample Init File -@subsection Sample Init File - -Here is an example of an @var{inputrc} file. This illustrates key -binding, variable assignment, and conditional syntax. - -@example -@page -# This file controls the behaviour of line input editing for -# programs that use the GNU Readline library. Existing -# programs include FTP, Bash, and GDB. -# -# You can re-read the inputrc file with C-x C-r. -# Lines beginning with '#' are comments. -# -# First, include any systemwide bindings and variable -# assignments from /etc/Inputrc -$include /etc/Inputrc - -# -# Set various bindings for emacs mode. - -set editing-mode emacs - -$if mode=emacs - -Meta-Control-h: backward-kill-word Text after the function name is ignored - -# -# Arrow keys in keypad mode -# -#"\M-OD": backward-char -#"\M-OC": forward-char -#"\M-OA": previous-history -#"\M-OB": next-history -# -# Arrow keys in ANSI mode -# -"\M-[D": backward-char -"\M-[C": forward-char -"\M-[A": previous-history -"\M-[B": next-history -# -# Arrow keys in 8 bit keypad mode -# -#"\M-\C-OD": backward-char -#"\M-\C-OC": forward-char -#"\M-\C-OA": previous-history -#"\M-\C-OB": next-history -# -# Arrow keys in 8 bit ANSI mode -# -#"\M-\C-[D": backward-char -#"\M-\C-[C": forward-char -#"\M-\C-[A": previous-history -#"\M-\C-[B": next-history - -C-q: quoted-insert - -$endif - -# An old-style binding. This happens to be the default. -TAB: complete - -# Macros that are convenient for shell interaction -$if Bash -# edit the path -"\C-xp": "PATH=$@{PATH@}\e\C-e\C-a\ef\C-f" -# prepare to type a quoted word -- -# insert open and close double quotes -# and move to just after the open quote -"\C-x\"": "\"\"\C-b" -# insert a backslash (testing backslash escapes -# in sequences and macros) -"\C-x\\": "\\" -# Quote the current or previous word -"\C-xq": "\eb\"\ef\"" -# Add a binding to refresh the line, which is unbound -"\C-xr": redraw-current-line -# Edit variable on current line. -"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y=" -$endif - -# use a visible bell if one is available -set bell-style visible - -# don't strip characters to 7 bits when reading -set input-meta on - -# allow iso-latin1 characters to be inserted rather -# than converted to prefix-meta sequences -set convert-meta off - -# display characters with the eighth bit set directly -# rather than as meta-prefixed characters -set output-meta on - -# if there are more than 150 possible completions for -# a word, ask the user if he wants to see all of them -set completion-query-items 150 - -# For FTP -$if Ftp -"\C-xg": "get \M-?" -"\C-xt": "put \M-?" -"\M-.": yank-last-arg -$endif -@end example - -@node Bindable Readline Commands -@section Bindable Readline Commands - -@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 - -This section describes Readline commands that may be bound to key -sequences. -@ifset BashFeatures -You can list your key bindings by executing -@w{@code{bind -P}} or, for a more terse format, suitable for an -@var{inputrc} file, @w{@code{bind -p}}. (@xref{Bash Builtins}.) -@end ifset -Command names without an accompanying key sequence are unbound by default. - -In the following descriptions, @dfn{point} refers to the current cursor -position, and @dfn{mark} refers to a cursor position saved by the -@code{set-mark} command. -The text between the point and mark is referred to as the @dfn{region}. - -@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 the current or 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 or 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 @env{HISTCONTROL} and @env{HISTIGNORE} variables. -If this line is a modified 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, it may be added to the history list for future recall with -@code{add_history()}. -If this line is a modified history line, the history line is restored -to its original state. -@end ifclear - -@item previous-history (C-p) -Move `back' through the history list, fetching the previous command. - -@item next-history (C-n) -Move `forward' through the history list, fetching the next command. - -@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 currently -being entered. - -@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 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 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) at point. -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-. or M-_) -Insert last argument to the previous command (the last word of the -previous history entry). With an -argument, behave exactly like @code{yank-nth-arg}. -Successive calls to @code{yank-last-arg} move back through the history -list, inserting the last argument of each line in turn. - -@end ftable - -@node Commands For Text -@subsection Commands For Changing Text - -@ftable @code -@item delete-char (C-d) -Delete the character at point. If point is at the -beginning of the line, there are no characters in the line, and -the last character typed was not bound to @code{delete-char}, then -return @sc{eof}. - -@item backward-delete-char (Rubout) -Delete the character behind the cursor. A numeric argument means -to kill the characters instead of deleting them. - -@item forward-backward-delete-char () -Delete the character under the cursor, unless the cursor is at the -end of the line, in which case the character behind the cursor is -deleted. By default, this is not bound to a key. - -@item quoted-insert (C-q or C-v) -Add the next character typed to the line verbatim. This is -how to insert key sequences like @kbd{C-q}, for example. - -@ifclear BashFeatures -@item tab-insert (M-@key{TAB}) -Insert a tab character. -@end ifclear - -@item self-insert (a, b, A, 1, !, @dots{}) -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 arguments have no effect. - -@item transpose-words (M-t) -Drag the word before point past the word after point, -moving point past that word as well. -If the insertion point is at the end of the line, this transposes -the last two words on the line. - -@item upcase-word (M-u) -Uppercase the current (or following) word. With a negative argument, -uppercase the previous word, but do not move the cursor. - -@item downcase-word (M-l) -Lowercase the current (or following) word. With a negative argument, -lowercase the previous word, but do not move the cursor. - -@item capitalize-word (M-c) -Capitalize the current (or following) word. With a negative argument, -capitalize the previous word, but do not move the cursor. - -@item overwrite-mode () -Toggle overwrite mode. With an explicit positive numeric argument, -switches to overwrite mode. With an explicit non-positive numeric -argument, switches to insert mode. This command affects only -@code{emacs} mode; @code{vi} mode does overwrite differently. -Each call to @code{readline()} starts in insert mode. - -In overwrite mode, characters bound to @code{self-insert} replace -the text at point rather than pushing the text to the right. -Characters bound to @code{backward-delete-char} replace the character -before point with a space. - -By default, this command is unbound. - -@end ftable - -@node Commands For Killing -@subsection Killing And Yanking - -@ftable @code - -@item kill-line (C-k) -Kill the text from point 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. - -@item kill-whole-line () -Kill all characters on the current line, no matter where point is. -By default, this is unbound. - -@item kill-word (M-d) -Kill from point 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-@key{DEL}) -Kill the word behind point. -Word boundaries are the same as @code{backward-word}. - -@item unix-word-rubout (C-w) -Kill the word behind point, using white space as a word boundary. -The killed text is saved on the kill-ring. - -@item unix-filename-rubout () -Kill the word behind point, using white space and the slash character -as the word boundaries. -The killed text is saved on the kill-ring. - -@item delete-horizontal-space () -Delete all spaces and tabs around point. By default, this is unbound. - -@item kill-region () -Kill the text in the current region. -By default, this command is unbound. - -@item copy-region-as-kill () -Copy the text in the region to the kill buffer, so it can be yanked -right away. By default, this command is unbound. - -@item copy-backward-word () -Copy the word before point to the kill buffer. -The word boundaries are the same as @code{backward-word}. -By default, this command is unbound. - -@item copy-forward-word () -Copy the word following point to the kill buffer. -The word boundaries are the same as @code{forward-word}. -By default, this command is unbound. - -@item yank (C-y) -Yank the top of the kill ring into the buffer at point. - -@item yank-pop (M-y) -Rotate the kill-ring, and yank the new top. You can only do this if -the prior command is @code{yank} or @code{yank-pop}. -@end ftable - -@node Numeric Arguments -@subsection Specifying Numeric Arguments -@ftable @code - -@item digit-argument (@kbd{M-0}, @kbd{M-1}, @dots{} @kbd{M--}) -Add this digit to the argument already accumulating, or start a new -argument. @kbd{M--} starts a negative argument. - -@item universal-argument () -This is another way to specify an argument. -If this command is followed by one or more digits, optionally with a -leading minus sign, those digits define the argument. -If the command is followed by digits, executing @code{universal-argument} -again ends the numeric argument, but is otherwise ignored. -As a special case, if this command is immediately followed by a -character that is neither a digit or minus sign, the argument count -for the next command is multiplied by four. -The argument count is initially one, so executing this function the -first time makes the argument count four, a second time makes the -argument count sixteen, and so on. -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 (@key{TAB}) -Attempt to perform completion on the text before point. -The actual completion performed is application-specific. -@ifset BashFeatures -Bash attempts completion treating the text as a variable (if the -text begins with @samp{$}), username (if the text begins with -@samp{~}), hostname (if the text begins with @samp{@@}), or -command (including aliases and functions) in turn. If none -of these produces a match, filename completion is attempted. -@end ifset -@ifclear BashFeatures -The default is filename completion. -@end ifclear - -@item possible-completions (M-?) -List the possible completions of the text before point. - -@item insert-completions (M-*) -Insert all completions of the text before point that would have -been generated by @code{possible-completions}. - -@item menu-complete () -Similar to @code{complete}, but replaces the word to be completed -with a single match from the list of possible completions. -Repeated execution of @code{menu-complete} steps through the list -of possible completions, inserting each match in turn. -At the end of the list of completions, the bell is rung -(subject to the setting of @code{bell-style}) -and the original text is restored. -An argument of @var{n} moves @var{n} positions forward in the list -of matches; a negative argument may be used to move backward -through the list. -This command is intended to be bound to @key{TAB}, but is unbound -by default. - -@item delete-char-or-list () -Deletes the character under the cursor if not at the beginning or -end of the line (like @code{delete-char}). -If at the end of the line, behaves identically to -@code{possible-completions}. -This command is unbound by default. - -@ifset BashFeatures -@item complete-filename (M-/) -Attempt filename completion on the text before point. - -@item possible-filename-completions (C-x /) -List the possible completions of the text before point, -treating it as a filename. - -@item complete-username (M-~) -Attempt completion on the text before point, treating -it as a username. - -@item possible-username-completions (C-x ~) -List the possible completions of the text before point, -treating it as a username. - -@item complete-variable (M-$) -Attempt completion on the text before point, treating -it as a shell variable. - -@item possible-variable-completions (C-x $) -List the possible completions of the text before point, -treating it as a shell variable. - -@item complete-hostname (M-@@) -Attempt completion on the text before point, treating -it as a hostname. - -@item possible-hostname-completions (C-x @@) -List the possible completions of the text before point, -treating it as a hostname. - -@item complete-command (M-!) -Attempt completion on the text before point, treating -it as a command name. Command completion attempts to -match the text against aliases, reserved words, shell -functions, shell builtins, and finally executable filenames, -in that order. - -@item possible-command-completions (C-x !) -List the possible completions of the text before point, -treating it as a command name. - -@item dynamic-complete-history (M-@key{TAB}) -Attempt completion on the text before point, comparing -the text against lines from the history list for possible -completion matches. - -@item complete-into-braces (M-@{) -Perform filename completion and insert the list of possible completions -enclosed within braces so the list is available to the shell -(@pxref{Brace Expansion}). - -@end ifset -@end ftable - -@node Keyboard Macros -@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 the @var{inputrc} 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, M-@var{x}, @dots{}) -If the metafied character @var{x} is lowercase, run the command -that is bound to the corresponding uppercase character. - -@item prefix-meta (@key{ESC}) -Metafy the next character typed. This is for keyboards -without a meta key. Typing @samp{@key{ESC} f} is equivalent to typing -@kbd{M-f}. - -@item undo (C-_ or 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 executing the @code{undo} -command enough times to get back to the beginning. - -@ifset BashFeatures -@item tilde-expand (M-&) -@end ifset -@ifclear BashFeatures -@item tilde-expand (M-~) -@end ifclear -Perform tilde expansion on the current word. - -@item set-mark (C-@@) -Set the mark to the point. If a -numeric argument is supplied, the mark is set to that position. - -@item exchange-point-and-mark (C-x C-x) -Swap the point with the mark. The current cursor position is set to -the saved position, and the old cursor position is saved as the mark. - -@item character-search (C-]) -A character is read and point is moved to the next occurrence of that -character. A negative count searches for previous occurrences. - -@item character-search-backward (M-C-]) -A character is read and point is moved to the previous occurrence -of that character. A negative count searches for subsequent -occurrences. - -@item insert-comment (M-#) -Without a numeric argument, the value of the @code{comment-begin} -variable is inserted at the beginning of the current line. -If a numeric argument is supplied, this command acts as a toggle: if -the characters at the beginning of the line do not match the value -of @code{comment-begin}, the value is inserted, otherwise -the characters in @code{comment-begin} are deleted from the beginning of -the line. -In either case, the line is accepted as if a newline had been typed. -@ifset BashFeatures -The default value of @code{comment-begin} causes this command -to make the current line a shell comment. -If a numeric argument causes the comment character to be removed, the line -will be executed by the shell. -@end ifset - -@item dump-functions () -Print all of the functions and their key bindings to the -Readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an @var{inputrc} file. This command is unbound by default. - -@item dump-variables () -Print all of the settable variables and their values to the -Readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an @var{inputrc} file. This command is unbound by default. - -@item dump-macros () -Print all of the Readline key sequences bound to macros and the -strings they output. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an @var{inputrc} file. This command is unbound by default. - -@ifset BashFeatures -@item glob-complete-word (M-g) -The word before point is treated as a pattern for pathname expansion, -with an asterisk implicitly appended. This pattern is used to -generate a list of matching file names for possible completions. - -@item glob-expand-word (C-x *) -The word before point is treated as a pattern for pathname expansion, -and the list of matching file names is inserted, replacing the word. -If a numeric argument is supplied, a @samp{*} is appended before -pathname expansion. - -@item glob-list-expansions (C-x g) -The list of expansions that would have been generated by -@code{glob-expand-word} is displayed, and the line is redrawn. -If a numeric argument is supplied, a @samp{*} is appended before -pathname expansion. - -@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 as the shell does. -This performs alias and history expansion as well as all of the shell -word expansions (@pxref{Shell Expansions}). - -@item history-expand-line (M-^) -Perform history expansion on the current line. - -@item magic-space () -Perform history expansion on the current line and insert a space -(@pxref{History Interaction}). - -@item alias-expand-line () -Perform alias expansion on the current line (@pxref{Aliases}). - -@item history-and-alias-expand-line () -Perform history and alias expansion on the current line. - -@item insert-last-argument (M-. or 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 edit-and-execute-command (C-xC-e) -Invoke an editor on the current command line, and execute the result as shell -commands. -Bash attempts to invoke -@code{$FCEDIT}, @code{$EDITOR}, and @code{emacs} -as the editor, in that order. - -@end ifset - -@ifclear BashFeatures -@item emacs-editing-mode (C-e) -When in @code{vi} command mode, this causes a switch to @code{emacs} -editing mode. - -@item vi-editing-mode (M-C-j) -When in @code{emacs} editing mode, this causes a switch to @code{vi} -editing mode. - -@end ifclear - -@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 @sc{posix} 1003.2 standard. - -@ifset BashFeatures -In order to switch interactively between @code{emacs} and @code{vi} -editing modes, use the @samp{set -o emacs} and @samp{set -o vi} -commands (@pxref{The Set Builtin}). -@end ifset -@ifclear BashFeatures -In order to switch interactively between @code{emacs} and @code{vi} -editing modes, use the command @kbd{M-C-j} (bound to emacs-editing-mode -when in @code{vi} mode and to vi-editing-mode in @code{emacs} 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 subsequent lines with @samp{j}, and -so forth. - -@ifset BashFeatures -@node Programmable Completion -@section Programmable Completion -@cindex programmable completion - -When word completion is attempted for an argument to a command for -which a completion specification (a @var{compspec}) has been defined -using the @code{complete} builtin (@pxref{Programmable Completion Builtins}), -the programmable completion facilities are invoked. - -First, the command name is identified. -If a compspec has been defined for that command, the -compspec is used to generate the list of possible completions for the word. -If the command word is a full pathname, a compspec for the full -pathname is searched for first. -If no compspec is found for the full pathname, an attempt is made to -find a compspec for the portion following the final slash. - -Once a compspec has been found, it is used to generate the list of -matching words. -If a compspec is not found, the default Bash completion -described above (@pxref{Commands For Completion}) is performed. - -First, the actions specified by the compspec are used. -Only matches which are prefixed by the word being completed are -returned. -When the @option{-f} or @option{-d} option is used for filename or -directory name completion, the shell variable @env{FIGNORE} is -used to filter the matches. -@xref{Bash Variables}, for a description of @env{FIGNORE}. - -Any completions specified by a filename expansion pattern to the -@option{-G} option are generated next. -The words generated by the pattern need not match the word being completed. -The @env{GLOBIGNORE} shell variable is not used to filter the matches, -but the @env{FIGNORE} shell variable is used. - -Next, the string specified as the argument to the @option{-W} option -is considered. -The string is first split using the characters in the @env{IFS} -special variable as delimiters. -Shell quoting is honored. -Each word is then expanded using -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and pathname expansion, -as described above (@pxref{Shell Expansions}). -The results are split using the rules described above -(@pxref{Word Splitting}). -The results of the expansion are prefix-matched against the word being -completed, and the matching words become the possible completions. - -After these matches have been generated, any shell function or command -specified with the @option{-F} and @option{-C} options is invoked. -When the command or function is invoked, the @env{COMP_LINE} and -@env{COMP_POINT} variables are assigned values as described above -(@pxref{Bash Variables}). -If a shell function is being invoked, the @env{COMP_WORDS} and -@env{COMP_CWORD} variables are also set. -When the function or command is invoked, the first argument is the -name of the command whose arguments are being completed, the -second argument is the word being completed, and the third argument -is the word preceding the word being completed on the current command line. -No filtering of the generated completions against the word being completed -is performed; the function or command has complete freedom in generating -the matches. - -Any function specified with @option{-F} is invoked first. -The function may use any of the shell facilities, including the -@code{compgen} builtin described below -(@pxref{Programmable Completion Builtins}), to generate the matches. -It must put the possible completions in the @env{COMPREPLY} array -variable. - -Next, any command specified with the @option{-C} option is invoked -in an environment equivalent to command substitution. -It should print a list of completions, one per line, to -the standard output. -Backslash may be used to escape a newline, if necessary. - -After all of the possible completions are generated, any filter -specified with the @option{-X} option is applied to the list. -The filter is a pattern as used for pathname expansion; a @samp{&} -in the pattern is replaced with the text of the word being completed. -A literal @samp{&} may be escaped with a backslash; the backslash -is removed before attempting a match. -Any completion that matches the pattern will be removed from the list. -A leading @samp{!} negates the pattern; in this case any completion -not matching the pattern will be removed. - -Finally, any prefix and suffix specified with the @option{-P} and @option{-S} -options are added to each member of the completion list, and the result is -returned to the Readline completion code as the list of possible -completions. - -If the previously-applied actions do not generate any matches, and the -@option{-o dirnames} option was supplied to @code{complete} when the -compspec was defined, directory name completion is attempted. - -If the @option{-o plusdirs} option was supplied to @code{complete} when -the compspec was defined, directory name completion is attempted and any -matches are added to the results of the other actions. - -By default, if a compspec is found, whatever it generates is returned to -the completion code as the full set of possible completions. -The default Bash completions are not attempted, and the Readline default -of filename completion is disabled. -If the @option{-o bashdefault} option was supplied to @code{complete} when -the compspec was defined, the default Bash completions are attempted -if the compspec generates no matches. -If the @option{-o default} option was supplied to @code{complete} when the -compspec was defined, Readline's default completion will be performed -if the compspec (and, if attempted, the default Bash completions) -generate no matches. - -When a compspec indicates that directory name completion is desired, -the programmable completion functions force Readline to append a slash -to completed names which are symbolic links to directories, subject to -the value of the @var{mark-directories} Readline variable, regardless -of the setting of the @var{mark-symlinked-directories} Readline variable. - -@node Programmable Completion Builtins -@section Programmable Completion Builtins -@cindex completion builtins - -Two builtin commands are available to manipulate the programmable completion -facilities. - -@table @code -@item compgen -@btindex compgen -@example -@code{compgen [@var{option}] [@var{word}]} -@end example - -Generate possible completion matches for @var{word} according to -the @var{option}s, which may be any option accepted by the -@code{complete} -builtin with the exception of @option{-p} and @option{-r}, and write -the matches to the standard output. -When using the @option{-F} or @option{-C} options, the various shell variables -set by the programmable completion facilities, while available, will not -have useful values. - -The matches will be generated in the same way as if the programmable -completion code had generated them directly from a completion specification -with the same flags. -If @var{word} is specified, only those completions matching @var{word} -will be displayed. - -The return value is true unless an invalid option is supplied, or no -matches were generated. - -@item complete -@btindex complete -@example -@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}] -[-P @var{prefix}] [-S @var{suffix}] [-X @var{filterpat}] [-F @var{function}] -[-C @var{command}] @var{name} [@var{name} @dots{}]} -@code{complete -pr [@var{name} @dots{}]} -@end example - -Specify how arguments to each @var{name} should be completed. -If the @option{-p} option is supplied, or if no options are supplied, existing -completion specifications are printed in a way that allows them to be -reused as input. -The @option{-r} option removes a completion specification for -each @var{name}, or, if no @var{name}s are supplied, all -completion specifications. - -The process of applying these completion specifications when word completion -is attempted is described above (@pxref{Programmable Completion}). - -Other options, if specified, have the following meanings. -The arguments to the @option{-G}, @option{-W}, and @option{-X} options -(and, if necessary, the @option{-P} and @option{-S} options) -should be quoted to protect them from expansion before the -@code{complete} builtin is invoked. - - -@table @code -@item -o @var{comp-option} -The @var{comp-option} controls several aspects of the compspec's behavior -beyond the simple generation of completions. -@var{comp-option} may be one of: - -@table @code - -@item bashdefault -Perform the rest of the default Bash completions if the compspec -generates no matches. - -@item default -Use Readline's default filename completion if the compspec generates -no matches. - -@item dirnames -Perform directory name completion if the compspec generates no matches. - -@item filenames -Tell Readline that the compspec generates filenames, so it can perform any -filename-specific processing (like adding a slash to directory names or -suppressing trailing spaces). This option is intended to be used with -shell functions specified with @option{-F}. - -@item nospace -Tell Readline not to append a space (the default) to words completed at -the end of the line. -@end table - -@item -A @var{action} -The @var{action} may be one of the following to generate a list of possible -completions: - -@table @code -@item alias -Alias names. May also be specified as @option{-a}. - -@item arrayvar -Array variable names. - -@item binding -Readline key binding names (@pxref{Bindable Readline Commands}). - -@item builtin -Names of shell builtin commands. May also be specified as @option{-b}. - -@item command -Command names. May also be specified as @option{-c}. - -@item directory -Directory names. May also be specified as @option{-d}. - -@item disabled -Names of disabled shell builtins. - -@item enabled -Names of enabled shell builtins. - -@item export -Names of exported shell variables. May also be specified as @option{-e}. - -@item file -File names. May also be specified as @option{-f}. - -@item function -Names of shell functions. - -@item group -Group names. May also be specified as @option{-g}. - -@item helptopic -Help topics as accepted by the @code{help} builtin (@pxref{Bash Builtins}). - -@item hostname -Hostnames, as taken from the file specified by the -@env{HOSTFILE} shell variable (@pxref{Bash Variables}). - -@item job -Job names, if job control is active. May also be specified as @option{-j}. - -@item keyword -Shell reserved words. May also be specified as @option{-k}. - -@item running -Names of running jobs, if job control is active. - -@item service -Service names. May also be specified as @option{-s}. - -@item setopt -Valid arguments for the @option{-o} option to the @code{set} builtin -(@pxref{The Set Builtin}). - -@item shopt -Shell option names as accepted by the @code{shopt} builtin -(@pxref{Bash Builtins}). - -@item signal -Signal names. - -@item stopped -Names of stopped jobs, if job control is active. - -@item user -User names. May also be specified as @option{-u}. - -@item variable -Names of all shell variables. May also be specified as @option{-v}. -@end table - -@item -G @var{globpat} -The filename expansion pattern @var{globpat} is expanded to generate -the possible completions. - -@item -W @var{wordlist} -The @var{wordlist} is split using the characters in the -@env{IFS} special variable as delimiters, and each resultant word -is expanded. -The possible completions are the members of the resultant list which -match the word being completed. - -@item -C @var{command} -@var{command} is executed in a subshell environment, and its output is -used as the possible completions. - -@item -F @var{function} -The shell function @var{function} is executed in the current shell -environment. -When it finishes, the possible completions are retrieved from the value -of the @env{COMPREPLY} array variable. - -@item -X @var{filterpat} -@var{filterpat} is a pattern as used for filename expansion. -It is applied to the list of possible completions generated by the -preceding options and arguments, and each completion matching -@var{filterpat} is removed from the list. -A leading @samp{!} in @var{filterpat} negates the pattern; in this -case, any completion not matching @var{filterpat} is removed. - -@item -P @var{prefix} -@var{prefix} is added at the beginning of each possible completion -after all other options have been applied. - -@item -S @var{suffix} -@var{suffix} is appended to each possible completion -after all other options have been applied. -@end table - -The return value is true unless an invalid option is supplied, an option -other than @option{-p} or @option{-r} is supplied without a @var{name} -argument, an attempt is made to remove a completion specification for -a @var{name} for which no specification exists, or -an error occurs adding a completion specification. - -@end table -@end ifset diff --git a/lib/readline/histexpand.c~ b/lib/readline/histexpand.c~ deleted file mode 100644 index 9ba35d657..000000000 --- a/lib/readline/histexpand.c~ +++ /dev/null @@ -1,1591 +0,0 @@ -/* histexpand.c -- history expansion. */ - -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. - - This file contains the GNU History Library (the Library), a set of - routines for managing the text of previously typed lines. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, 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, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_UNISTD_H) -# ifndef _MINIX -# include -# endif -# include -#endif - -#include "rlmbutil.h" - -#include "history.h" -#include "histlib.h" - -#include "rlshell.h" -#include "xmalloc.h" - -#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" -#define HISTORY_QUOTE_CHARACTERS "\"'`" - -#define slashify_in_quotes "\\`\"$" - -typedef int _hist_search_func_t PARAMS((const char *, int)); - -extern int rl_byte_oriented; /* declared in mbutil.c */ - -static char error_pointer; - -static char *subst_lhs; -static char *subst_rhs; -static int subst_lhs_len; -static int subst_rhs_len; - -static char *get_history_word_specifier PARAMS((char *, char *, int *)); -static char *history_find_word PARAMS((char *, int)); -static int history_tokenize_word PARAMS((const char *, int)); -static char *history_substring PARAMS((const char *, int, int)); - -static char *quote_breaks PARAMS((char *)); - -/* Variables exported by this file. */ -/* The character that represents the start of a history expansion - request. This is usually `!'. */ -char history_expansion_char = '!'; - -/* The character that invokes word substitution if found at the start of - a line. This is usually `^'. */ -char history_subst_char = '^'; - -/* During tokenization, if this character is seen as the first character - of a word, then it, and all subsequent characters upto a newline are - ignored. For a Bourne shell, this should be '#'. Bash special cases - the interactive comment character to not be a comment delimiter. */ -char history_comment_char = '\0'; - -/* The list of characters which inhibit the expansion of text if found - immediately following history_expansion_char. */ -char *history_no_expand_chars = " \t\n\r="; - -/* If set to a non-zero value, single quotes inhibit history expansion. - The default is 0. */ -int history_quotes_inhibit_expansion = 0; - -/* Used to split words by history_tokenize_internal. */ -char *history_word_delimiters = HISTORY_WORD_DELIMITERS; - -/* If set, this points to a function that is called to verify that a - particular history expansion should be performed. */ -rl_linebuf_func_t *history_inhibit_expansion_function; - -/* **************************************************************** */ -/* */ -/* History Expansion */ -/* */ -/* **************************************************************** */ - -/* Hairy history expansion on text, not tokens. This is of general - use, and thus belongs in this library. */ - -/* The last string searched for by a !?string? search. */ -static char *search_string; - -/* The last string matched by a !?string? search. */ -static char *search_match; - -/* Return the event specified at TEXT + OFFSET modifying OFFSET to - point to after the event specifier. Just a pointer to the history - line is returned; NULL is returned in the event of a bad specifier. - You pass STRING with *INDEX equal to the history_expansion_char that - begins this specification. - DELIMITING_QUOTE is a character that is allowed to end the string - specification for what to search for in addition to the normal - characters `:', ` ', `\t', `\n', and sometimes `?'. - So you might call this function like: - line = get_history_event ("!echo:p", &index, 0); */ -char * -get_history_event (string, caller_index, delimiting_quote) - const char *string; - int *caller_index; - int delimiting_quote; -{ - register int i; - register char c; - HIST_ENTRY *entry; - int which, sign, local_index, substring_okay; - _hist_search_func_t *search_func; - char *temp; - - /* The event can be specified in a number of ways. - - !! the previous command - !n command line N - !-n current command-line minus N - !str the most recent command starting with STR - !?str[?] - the most recent command containing STR - - All values N are determined via HISTORY_BASE. */ - - i = *caller_index; - - if (string[i] != history_expansion_char) - return ((char *)NULL); - - /* Move on to the specification. */ - i++; - - sign = 1; - substring_okay = 0; - -#define RETURN_ENTRY(e, w) \ - return ((e = history_get (w)) ? e->line : (char *)NULL) - - /* Handle !! case. */ - if (string[i] == history_expansion_char) - { - i++; - which = history_base + (history_length - 1); - *caller_index = i; - RETURN_ENTRY (entry, which); - } - - /* Hack case of numeric line specification. */ - if (string[i] == '-') - { - sign = -1; - i++; - } - - if (_rl_digit_p (string[i])) - { - /* Get the extent of the digits and compute the value. */ - for (which = 0; _rl_digit_p (string[i]); i++) - which = (which * 10) + _rl_digit_value (string[i]); - - *caller_index = i; - - if (sign < 0) - which = (history_length + history_base) - which; - - RETURN_ENTRY (entry, which); - } - - /* This must be something to search for. If the spec begins with - a '?', then the string may be anywhere on the line. Otherwise, - the string must be found at the start of a line. */ - if (string[i] == '?') - { - substring_okay++; - i++; - } - - /* Only a closing `?' or a newline delimit a substring search string. */ - for (local_index = i; c = string[i]; i++) -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int v; - mbstate_t ps; - - memset (&ps, 0, sizeof (mbstate_t)); - /* These produce warnings because we're passing a const string to a - function that takes a non-const string. */ - _rl_adjust_point ((char *)string, i, &ps); - if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1) - { - i += v - 1; - continue; - } - } - else -#endif /* HANDLE_MULTIBYTE */ - if ((!substring_okay && (whitespace (c) || c == ':' || - (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || - string[i] == delimiting_quote)) || - string[i] == '\n' || - (substring_okay && string[i] == '?')) - break; - - which = i - local_index; - temp = (char *)xmalloc (1 + which); - if (which) - strncpy (temp, string + local_index, which); - temp[which] = '\0'; - - if (substring_okay && string[i] == '?') - i++; - - *caller_index = i; - -#define FAIL_SEARCH() \ - do { \ - history_offset = history_length; free (temp) ; return (char *)NULL; \ - } while (0) - - /* If there is no search string, try to use the previous search string, - if one exists. If not, fail immediately. */ - if (*temp == '\0' && substring_okay) - { - if (search_string) - { - free (temp); - temp = savestring (search_string); - } - else - FAIL_SEARCH (); - } - - search_func = substring_okay ? history_search : history_search_prefix; - while (1) - { - local_index = (*search_func) (temp, -1); - - if (local_index < 0) - FAIL_SEARCH (); - - if (local_index == 0 || substring_okay) - { - entry = current_history (); - history_offset = history_length; - - /* If this was a substring search, then remember the - string that we matched for word substitution. */ - if (substring_okay) - { - FREE (search_string); - search_string = temp; - - FREE (search_match); - search_match = history_find_word (entry->line, local_index); - } - else - free (temp); - - return (entry->line); - } - - if (history_offset) - history_offset--; - else - FAIL_SEARCH (); - } -#undef FAIL_SEARCH -#undef RETURN_ENTRY -} - -/* Function for extracting single-quoted strings. Used for inhibiting - history expansion within single quotes. */ - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing - to the closing single quote. */ -static void -hist_string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - - for (i = *sindex; string[i] && string[i] != '\''; i++) - ; - - *sindex = i; -} - -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 = (char *)xmalloc (len); - *r++ = '\''; - for (p = s; p && *p; ) - { - if (*p == '\'') - { - *r++ = '\''; - *r++ = '\\'; - *r++ = '\''; - *r++ = '\''; - p++; - } - else if (whitespace (*p) || *p == '\n') - { - *r++ = '\''; - *r++ = *p++; - *r++ = '\''; - } - else - *r++ = *p++; - } - *r++ = '\''; - *r = '\0'; - return ret; -} - -static char * -hist_error(s, start, current, errtype) - char *s; - int start, current, errtype; -{ - char *temp; - const char *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; - case NO_PREV_SUBST: - emsg = "no previous substitution"; - elen = 24; - break; - default: - emsg = "unknown expansion error"; - elen = 23; - break; - } - - temp = (char *)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; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; -#endif - - s = (char *)NULL; - i = *iptr; - -#if defined (HANDLE_MULTIBYTE) - memset (&ps, 0, sizeof (mbstate_t)); - _rl_adjust_point (str, i, &ps); -#endif - - for (si = i; str[si] && str[si] != delimiter; si++) -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int v; - if ((v = _rl_get_char_len (str + si, &ps)) > 1) - si += v - 1; - else if (str[si] == '\\' && str[si + 1] == delimiter) - si++; - } - else -#endif /* HANDLE_MULTIBYTE */ - if (str[si] == '\\' && str[si + 1] == delimiter) - si++; - - if (si > i || is_rhs) - { - s = (char *)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 = (char *)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 = (char *)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 = (char *)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, subst_bywords, want_quotes, print_only; - char *event, *temp, *result, *tstr, *t, c, *word_spec; - int result_len; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - result = (char *)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 defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int c, l; - l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY); - c = string[l]; - /* XXX - original patch had i - 1 ??? If i == 0 it would fail. */ - if (i && (c == '\'' || c == '"')) - quoted_search_delimiter = c; - } - else -#endif /* HANDLE_MULTIBYTE */ - if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) - quoted_search_delimiter = string[i - 1]; - - event = get_history_event (string, &i, quoted_search_delimiter); - } - - if (event == 0) - { - *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); - free (result); - return (-1); - } - - /* If a word specifier is found, then do what that requires. */ - starting_index = i; - word_spec = get_history_word_specifier (string, event, &i); - - /* There is no such thing as a `malformed word specifier'. However, - it is possible for a specifier that has no match. In that case, - we complain. */ - if (word_spec == (char *)&error_pointer) - { - *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); - free (result); - return (-1); - } - - /* If no word specifier, than the thing of interest was the event. */ - temp = word_spec ? savestring (word_spec) : savestring (event); - FREE (word_spec); - - /* Perhaps there are other modifiers involved. Do what they say. */ - want_quotes = substitute_globally = subst_bywords = print_only = 0; - starting_index = i; - - while (string[i] == ':') - { - c = string[i + 1]; - - if (c == 'g' || c == 'a') - { - substitute_globally = 1; - i++; - c = string[i + 1]; - } - else if (c == 'G') - { - subst_bywords = 1; - i++; - c = string[i + 1]; - } - - switch (c) - { - default: - *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); - free (result); - free (temp); - return -1; - - case 'q': - want_quotes = 'q'; - break; - - case 'x': - want_quotes = 'x'; - break; - - /* :p means make this the last executed line. So we - return an error state after adding this line to the - history. */ - case 'p': - print_only++; - break; - - /* :t discards all but the last part of the pathname. */ - case 't': - tstr = strrchr (temp, '/'); - if (tstr) - { - tstr++; - t = savestring (tstr); - free (temp); - temp = t; - } - break; - - /* :h discards the last part of a pathname. */ - case 'h': - tstr = strrchr (temp, '/'); - if (tstr) - *tstr = '\0'; - break; - - /* :r discards the suffix. */ - case 'r': - tstr = strrchr (temp, '.'); - if (tstr) - *tstr = '\0'; - break; - - /* :e discards everything but the suffix. */ - case 'e': - tstr = strrchr (temp, '.'); - if (tstr) - { - t = savestring (tstr); - free (temp); - temp = t; - } - break; - - /* :s/this/that substitutes `that' for the first - occurrence of `this'. :gs/this/that substitutes `that' - for each occurrence of `this'. :& repeats the last - substitution. :g& repeats the last substitution - globally. */ - - case '&': - case 's': - { - char *new_event; - int delimiter, failed, si, l_temp, ws, we; - - if (c == 's') - { - if (i + 2 < (int)strlen (string)) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_adjust_point (string, i + 2, &ps); - if (_rl_get_char_len (string + i + 2, &ps) > 1) - delimiter = 0; - else - delimiter = string[i + 2]; - } - else -#endif /* HANDLE_MULTIBYTE */ - delimiter = string[i + 2]; - } - else - break; /* no search delimiter */ - - i += 3; - - t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len); - /* An empty substitution lhs with no previous substitution - uses the last search string as the lhs. */ - if (t) - { - FREE (subst_lhs); - subst_lhs = t; - } - else if (!subst_lhs) - { - if (search_string && *search_string) - { - subst_lhs = savestring (search_string); - subst_lhs_len = strlen (subst_lhs); - } - else - { - subst_lhs = (char *) NULL; - subst_lhs_len = 0; - } - } - - 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; - - /* If there is no lhs, the substitution can't succeed. */ - if (subst_lhs_len == 0) - { - *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST); - free (result); - free (temp); - return -1; - } - - 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. */ - /* Substitute SUBST_RHS for SUBST_LHS in TEMP. There are three - cases to consider: - - 1. substitute_globally == subst_bywords == 0 - 2. substitute_globally == 1 && subst_bywords == 0 - 3. substitute_globally == 0 && subst_bywords == 1 - - In the first case, we substitute for the first occurrence only. - In the second case, we substitute for every occurrence. - In the third case, we tokenize into words and substitute the - first occurrence of each word. */ - - si = we = 0; - for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) - { - /* First skip whitespace and find word boundaries if - we're past the end of the word boundary we found - the last time. */ - if (subst_bywords && si > we) - { - for (; temp[si] && whitespace (temp[si]); si++) - ; - ws = si; - we = history_tokenize_word (temp, si); - } - - if (STREQN (temp+si, subst_lhs, subst_lhs_len)) - { - int len = subst_rhs_len - subst_lhs_len + l_temp; - new_event = (char *)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) - { - /* Reported to fix a bug that causes it to skip every - other match when matching a single character. Was - si += subst_rhs_len previously. */ - si += subst_rhs_len - 1; - l_temp = strlen (temp); - substitute_globally++; - continue; - } - else if (subst_bywords) - { - si = we; - l_temp = strlen (temp); - continue; - } - else - break; - } - } - - if (substitute_globally > 1) - { - substitute_globally = 0; - continue; /* don't want to increment i */ - } - - if (failed == 0) - continue; /* don't want to increment i */ - - *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); - free (result); - free (temp); - return (-1); - } - } - i += 2; - } - /* Done with modfiers. */ - /* Believe it or not, we have to back the pointer up by one. */ - --i; - - if (want_quotes) - { - char *x; - - if (want_quotes == 'q') - x = sh_single_quote (temp); - else if (want_quotes == 'x') - x = quote_breaks (temp); - else - x = savestring (temp); - - free (temp); - temp = x; - } - - n = strlen (temp); - if (n >= result_len) - result = (char *)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 = (char *)xrealloc (result, result_len); \ - } \ - strcpy (result + j - sl, s); \ - } \ - while (0) - -#define ADD_CHAR(c) \ - do \ - { \ - if (j >= result_len - 1) \ - result = (char *)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, dquote; - char *string; - - /* The output string, and its length. */ - int result_len; - char *result; - -#if defined (HANDLE_MULTIBYTE) - char mb[MB_LEN_MAX]; - mbstate_t ps; -#endif - - /* Used when adding the string. */ - char *temp; - - if (output == 0) - return 0; - - /* 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 = (char *)xmalloc (result_len = 256); - result[0] = '\0'; - - only_printing = modified = 0; - l = strlen (hstring); - - /* Grovel the string. Only backslash and single quotes 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 = (char *)xmalloc (l + 5); - - string[0] = string[1] = history_expansion_char; - string[2] = ':'; - string[3] = 's'; - strcpy (string + 4, hstring); - l += 4; - } - else - { -#if defined (HANDLE_MULTIBYTE) - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - 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 = dquote = 0; string[i]; i++) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int v; - v = _rl_get_char_len (string + i, &ps); - if (v > 1) - { - i += v - 1; - continue; - } - } -#endif /* HANDLE_MULTIBYTE */ - - cc = string[i + 1]; - /* The history_comment_char, if set, appearing at the beginning - of a word signifies that the rest of the line should not have - history expansion performed on it. - Skip the rest of the line and break out of the loop. */ - if (history_comment_char && string[i] == history_comment_char && - (i == 0 || member (string[i - 1], history_word_delimiters))) - { - while (string[i]) - i++; - break; - } - else if (string[i] == history_expansion_char) - { - if (!cc || member (cc, history_no_expand_chars)) - continue; - /* If the calling application has set - history_inhibit_expansion_function to a function that checks - for special cases that should not be history expanded, - call the function and skip the expansion if it returns a - non-zero value. */ - else if (history_inhibit_expansion_function && - (*history_inhibit_expansion_function) (string, i)) - continue; - else - break; - } - /* Shell-like quoting: allow backslashes to quote double quotes - inside a double-quoted string. */ - else if (dquote && string[i] == '\\' && cc == '"') - i++; - /* More shell-like quoting: if we're paying attention to single - quotes and letting them quote the history expansion character, - then we need to pay attention to double quotes, because single - quotes are not special inside double-quoted strings. */ - else if (history_quotes_inhibit_expansion && string[i] == '"') - { - dquote = 1 - dquote; - } - else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'') - { - /* If this is bash, single quotes inhibit history expansion. */ - i++; - hist_string_extract_single_quoted (string, &i); - } - else if (history_quotes_inhibit_expansion && string[i] == '\\') - { - /* If this is bash, allow backslashes to quote single - quotes and the history expansion character. */ - if (cc == '\'' || cc == history_expansion_char) - i++; - } - - } - - if (string[i] != history_expansion_char) - { - free (result); - *output = savestring (string); - return (0); - } - } - - /* Extract and perform the substitution. */ - for (passc = dquote = i = j = 0; i < l; i++) - { - int tchar = string[i]; - - if (passc) - { - passc = 0; - ADD_CHAR (tchar); - continue; - } - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int k, c; - - c = tchar; - memset (mb, 0, sizeof (mb)); - for (k = 0; k < MB_LEN_MAX; k++) - { - mb[k] = (char)c; - memset (&ps, 0, sizeof (mbstate_t)); - if (_rl_get_char_len (mb, &ps) == -2) - c = string[++i]; - else - break; - } - if (strlen (mb) > 1) - { - ADD_STRING (mb); - break; - } - } -#endif /* HANDLE_MULTIBYTE */ - - if (tchar == history_expansion_char) - tchar = -3; - else if (tchar == history_comment_char) - tchar = -2; - - switch (tchar) - { - default: - ADD_CHAR (string[i]); - break; - - case '\\': - passc++; - ADD_CHAR (tchar); - break; - - case '"': - dquote = 1 - dquote; - ADD_CHAR (tchar); - break; - - case '\'': - { - /* If history_quotes_inhibit_expansion is set, single quotes - inhibit history expansion. */ - if (dquote == 0 && history_quotes_inhibit_expansion) - { - int quote, slen; - - quote = i++; - hist_string_extract_single_quoted (string, &i); - - slen = i - quote + 2; - temp = (char *)xmalloc (slen); - strncpy (temp, string + quote, slen); - temp[slen - 1] = '\0'; - ADD_STRING (temp); - free (temp); - } - else - ADD_CHAR (string[i]); - break; - } - - case -2: /* history_comment_char */ - if (i == 0 || member (string[i - 1], history_word_delimiters)) - { - temp = (char *)xmalloc (l - i + 1); - strcpy (temp, string + i); - ADD_STRING (temp); - free (temp); - i = l; - } - else - ADD_CHAR (string[i]); - break; - - case -3: /* history_expansion_char */ - cc = string[i + 1]; - - /* If the history_expansion_char is followed by one of the - characters in history_no_expand_chars, then it is not a - candidate for expansion of any kind. */ - if (member (cc, history_no_expand_chars)) - { - ADD_CHAR (string[i]); - break; - } - -#if defined (NO_BANG_HASH_MODIFIERS) - /* There is something that is listed as a `word specifier' in csh - documentation which means `the expanded text to this point'. - That is not a word specifier, it is an event specifier. If we - don't want to allow modifiers with `!#', just stick the current - output line in again. */ - if (cc == '#') - { - if (result) - { - temp = (char *)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) - { -#if 0 - add_history (result); -#endif - 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; - i++; - } - else if (_rl_digit_p (spec[i]) && expecting_word_spec) - { - for (first = 0; _rl_digit_p (spec[i]); i++) - first = (first * 10) + _rl_digit_value (spec[i]); - } - else - return ((char *)NULL); /* no valid `first' for word specifier */ - - if (spec[i] == '^' || spec[i] == '*') - { - last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ - i++; - } - else if (spec[i] != '-') - last = first; - else - { - i++; - - if (_rl_digit_p (spec[i])) - { - for (last = 0; _rl_digit_p (spec[i]); i++) - last = (last * 10) + _rl_digit_value (spec[i]); - } - else if (spec[i] == '$') - { - i++; - last = '$'; - } -#if 0 - else if (!spec[i] || spec[i] == ':') - /* check against `:' because there could be a modifier separator */ -#else - else - /* csh seems to allow anything to terminate the word spec here, - leaving it as an abbreviation. */ -#endif - 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; - const char *string; -{ - register int i, len; - char *result; - int size, offset; - char **list; - - /* XXX - think about making history_tokenize return a struct array, - each struct in array being a string and a length to avoid the - calls to strlen below. */ - if ((list = history_tokenize (string)) == NULL) - return ((char *)NULL); - - for (len = 0; list[len]; len++) - ; - - if (last < 0) - last = len + last - 1; - - if (first < 0) - first = len + first - 1; - - if (last == '$') - last = len - 1; - - if (first == '$') - first = len - 1; - - last++; - - if (first >= len || last > len || first < 0 || last < 0 || first > last) - result = ((char *)NULL); - else - { - for (size = 0, i = first; i < last; i++) - size += strlen (list[i]) + 1; - result = (char *)xmalloc (size + 1); - result[0] = '\0'; - - for (i = first, offset = 0; i < last; i++) - { - strcpy (result + offset, list[i]); - offset += strlen (list[i]); - if (i + 1 < last) - { - result[offset++] = ' '; - result[offset] = 0; - } - } - } - - for (i = 0; i < len; i++) - free (list[i]); - free (list); - - return (result); -} - -static int -history_tokenize_word (string, ind) - const char *string; - int ind; -{ - register int i; - int delimiter; - - i = ind; - delimiter = 0; - - if (member (string[i], "()\n")) - { - i++; - return i; - } - - if (member (string[i], "<>;&|$")) - { - int peek = string[i + 1]; - - if (peek == string[i] && peek != '$') - { - if (peek == '<' && string[i + 2] == '-') - i++; - i += 2; - return i; - } - else - { - if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || - (peek == '>' && string[i] == '&') || - (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */ - (peek == '(' && string[i] == '$')) /* ) */ - { - i += 2; - return i; - } - } - - if (string[i] != '$') - { - i++; - return i; - } - } - - /* Get word from string + i; */ - - if (member (string[i], HISTORY_QUOTE_CHARACTERS)) - 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], history_word_delimiters))) - break; - - if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) - delimiter = string[i]; - } - - return i; -} - -static char * -history_substring (string, start, end) - const char *string; - int start, end; -{ - register int len; - register char *result; - - len = end - start; - result = (char *)xmalloc (len + 1); - strncpy (result, string + start, len); - result[len] = '\0'; - return result; -} - -/* 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) - const char *string; - int wind, *indp; -{ - char **result; - register int i, start, result_index, size; - - /* If we're searching for a string that's not part of a word (e.g., " "), - make sure we set *INDP to a reasonable value. */ - if (indp && wind != -1) - *indp = -1; - - /* Get a token, and stuff it into RESULT. The tokens are split - exactly where the shell would split them. */ - for (i = result_index = size = 0, result = (char **)NULL; string[i]; ) - { - /* Skip leading whitespace. */ - for (; string[i] && whitespace (string[i]); i++) - ; - if (string[i] == 0 || string[i] == history_comment_char) - return (result); - - start = i; - - i = history_tokenize_word (string, start); - - /* If we have a non-whitespace delimiter character (which would not be - skipped by the loop above), use it and any adjacent delimiters to - make a separate field. Any adjacent white space will be skipped the - next time through the loop. */ - if (i == start && history_word_delimiters) - { - i++; - while (string[i] && member (string[i], history_word_delimiters)) - i++; - } - - /* If we are looking for the word in which the character at a - particular index falls, remember it. */ - if (indp && wind != -1 && wind >= start && wind < i) - *indp = result_index; - - if (result_index + 2 >= size) - result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); - - result[result_index++] = history_substring (string, start, i); - 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) - const 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 || words == 0) - return ((char *)NULL); - s = words[wind]; - for (i = 0; i < wind; i++) - free (words[i]); - for (i = wind + 1; words[i]; i++) - free (words[i]); - free (words); - return s; -} diff --git a/lib/readline/histfile.c~ b/lib/readline/histfile.c~ deleted file mode 100644 index 977a3017b..000000000 --- a/lib/readline/histfile.c~ +++ /dev/null @@ -1,542 +0,0 @@ -/* histfile.c - functions to manipulate the history file. */ - -/* Copyright (C) 1989-2003 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 2, 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, - 59 Temple Place, Suite 330, Boston, MA 02111 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. */ - -#if defined (__TANDEM) -# include -#endif - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#include -#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#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 (__EMX__) || defined (__CYGWIN__) -# undef HAVE_MMAP -#endif - -#ifdef HISTORY_USE_MMAP -# include - -# ifdef MAP_FILE -# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) -# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) -# else -# define MAP_RFLAGS MAP_PRIVATE -# define MAP_WFLAGS MAP_SHARED -# endif - -# ifndef MAP_FAILED -# define MAP_FAILED ((void *)-1) -# endif - -#endif /* HISTORY_USE_MMAP */ - -/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment - on win 95/98/nt), we want to open files with O_BINARY mode so that there - is no \n -> \r\n conversion performed. On other systems, we don't want to - mess around with O_BINARY at all, so we ensure that it's defined to 0. */ -#if defined (__EMX__) || defined (__CYGWIN__) -# ifndef O_BINARY -# define O_BINARY 0 -# endif -#else /* !__EMX__ && !__CYGWIN__ */ -# undef O_BINARY -# define O_BINARY 0 -#endif /* !__EMX__ && !__CYGWIN__ */ - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include "history.h" -#include "histlib.h" - -#include "rlshell.h" -#include "xmalloc.h" - -/* If non-zero, we write timestamps to the history file in history_do_write() */ -int history_write_timestamps = 0; - -/* Does S look like the beginning of a history timestamp entry? Placeholder - for more extensive tests. */ -#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char) - -/* 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) - const char *filename; -{ - char *return_val; - const char *home; - int home_len; - - return_val = filename ? savestring (filename) : (char *)NULL; - - if (return_val) - return (return_val); - - home = sh_get_env_value ("HOME"); - - if (home == 0) - { - home = "."; - home_len = 1; - } - else - home_len = strlen (home); - - return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ - strcpy (return_val, home); - return_val[home_len] = '/'; -#if defined (__MSDOS__) - strcpy (return_val + home_len + 1, "_history"); -#else - strcpy (return_val + home_len + 1, ".history"); -#endif - - 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) - const 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) - const char *filename; - int from, to; -{ - register char *line_start, *line_end, *p; - char *input, *buffer, *bufend, *last_ts; - int file, current_line, chars_read; - struct stat finfo; - size_t file_size; -#if defined (EFBIG) - int overflow_errno = EFBIG; -#elif defined (EOVERFLOW) - int overflow_errno = EOVERFLOW; -#else - int overflow_errno = EIO; -#endif - - buffer = last_ts = (char *)NULL; - input = history_filename (filename); - file = open (input, O_RDONLY|O_BINARY, 0666); - - if ((file < 0) || (fstat (file, &finfo) == -1)) - goto error_and_exit; - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - errno = overflow_errno; - goto error_and_exit; - } - -#ifdef HISTORY_USE_MMAP - /* We map read/write and private so we can change newlines to NULs without - affecting the underlying object. */ - buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); - if ((void *)buffer == MAP_FAILED) - { - errno = overflow_errno; - goto error_and_exit; - } - chars_read = file_size; -#else - buffer = (char *)malloc (file_size + 1); - if (buffer == 0) - { - errno = overflow_errno; - goto error_and_exit; - } - - chars_read = read (file, buffer, file_size); -#endif - if (chars_read < 0) - { - error_and_exit: - if (errno != 0) - chars_read = errno; - else - chars_read = EIO; - if (file >= 0) - close (file); - - FREE (input); -#ifndef HISTORY_USE_MMAP - FREE (buffer); -#endif - - return (chars_read); - } - - close (file); - - /* Set TO to larger than end of file if negative. */ - if (to < 0) - to = chars_read; - - /* Start at beginning of file, work to end. */ - bufend = buffer + chars_read; - current_line = 0; - - /* Skip lines until we are at FROM. */ - for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) - if (*line_end == '\n') - { - p = line_end + 1; - /* If we see something we think is a timestamp, continue with this - line. We should check more extensively here... */ - if (HIST_TIMESTAMP_START(p) == 0) - current_line++; - line_start = p; - } - - /* If there are lines left to gobble, then gobble them now. */ - for (line_end = line_start; line_end < bufend; line_end++) - if (*line_end == '\n') - { - *line_end = '\0'; - - if (*line_start) - { - if (HIST_TIMESTAMP_START(line_start) == 0) - { - add_history (line_start); - if (last_ts) - { - add_history_time (last_ts); - last_ts = NULL; - } - } - else - { - last_ts = line_start; - current_line--; - } - } - - current_line++; - - if (current_line >= to) - break; - - line_start = line_end + 1; - } - - FREE (input); -#ifndef HISTORY_USE_MMAP - FREE (buffer); -#else - munmap (buffer, file_size); -#endif - - return (0); -} - -/* Truncate the history file FNAME, leaving only LINES trailing lines. - If FNAME is NULL, then use ~/.history. Returns 0 on success, errno - on failure. */ -int -history_truncate_file (fname, lines) - const char *fname; - int lines; -{ - char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */ - int file, chars_read, rv; - struct stat finfo; - size_t file_size; - - buffer = (char *)NULL; - filename = history_filename (fname); - file = open (filename, O_RDONLY|O_BINARY, 0666); - rv = 0; - - /* Don't try to truncate non-regular files. */ - if (file == -1 || fstat (file, &finfo) == -1) - { - rv = errno; - if (file != -1) - close (file); - goto truncate_exit; - } - - if (S_ISREG (finfo.st_mode) == 0) - { - close (file); -#ifdef EFTYPE - rv = EFTYPE; -#else - rv = EINVAL; -#endif - goto truncate_exit; - } - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - close (file); -#if defined (EFBIG) - rv = errno = EFBIG; -#elif defined (EOVERFLOW) - rv = errno = EOVERFLOW; -#else - rv = errno = EINVAL; -#endif - goto truncate_exit; - } - - buffer = (char *)malloc (file_size + 1); - if (buffer == 0) - { - close (file); - goto truncate_exit; - } - - chars_read = read (file, buffer, file_size); - close (file); - - if (chars_read <= 0) - { - rv = (chars_read < 0) ? errno : 0; - goto truncate_exit; - } - - /* Count backwards from the end of buffer until we have passed - LINES lines. bp1 is set funny initially. But since bp[1] can't - be a comment character (since it's off the end) and *bp can't be - both a newline and the history comment character, it should be OK. */ - for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) - { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) - lines--; - bp1 = bp; - } - - /* 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 ( ; bp > buffer; bp--) - { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) - { - bp++; - break; - } - bp1 = bp; - } - - /* Write only if there are more lines in the file than we want to - truncate to. */ - if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) - { - write (file, bp, chars_read - (bp - buffer)); - -#if defined (__BEOS__) - /* BeOS ignores O_TRUNC. */ - ftruncate (file, chars_read - (bp - buffer)); -#endif - - close (file); - } - - truncate_exit: - - FREE (buffer); - - free (filename); - return rv; -} - -/* 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) - const char *filename; - int nelements, overwrite; -{ - register int i; - char *output; - int file, mode, rv; -#ifdef HISTORY_USE_MMAP - size_t cursize; - - mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; -#else - mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; -#endif - output = history_filename (filename); - rv = 0; - - if ((file = open (output, mode, 0600)) == -1) - { - FREE (output); - return (errno); - } - -#ifdef HISTORY_USE_MMAP - cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); -#endif - - if (nelements > history_length) - nelements = history_length; - - /* Build a buffer of all the lines to write, and write them in one syscall. - Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ - { - HIST_ENTRY **the_history; /* local */ - register int j; - int buffer_size; - char *buffer; - - the_history = history_list (); - /* Calculate the total number of bytes to write. */ - for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) -#if 0 - buffer_size += 2 + HISTENT_BYTES (the_history[i]); -#else - { - if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) - buffer_size += strlen (the_history[i]->timestamp) + 1; - buffer_size += strlen (the_history[i]->line) + 1; - } -#endif - - /* Allocate the buffer, and fill it. */ -#ifdef HISTORY_USE_MMAP - if (ftruncate (file, buffer_size+cursize) == -1) - goto mmap_error; - buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); - if ((void *)buffer == MAP_FAILED) - { -mmap_error: - rv = errno; - FREE (output); - close (file); - return rv; - } -#else - buffer = (char *)malloc (buffer_size); - if (buffer == 0) - { - rv = errno; - FREE (output); - close (file); - return rv; - } -#endif - - for (j = 0, i = history_length - nelements; i < history_length; i++) - { - if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) - { - strcpy (buffer + j, the_history[i]->timestamp); - j += strlen (the_history[i]->timestamp); - buffer[j++] = '\n'; - } - strcpy (buffer + j, the_history[i]->line); - j += strlen (the_history[i]->line); - buffer[j++] = '\n'; - } - -#ifdef HISTORY_USE_MMAP - if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) - rv = errno; -#else - if (write (file, buffer, buffer_size) < 0) - rv = errno; - free (buffer); -#endif - } - - close (file); - - FREE (output); - - return (rv); -} - -/* 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; - const 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) - const char *filename; -{ - return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); -} diff --git a/lib/readline/input.c~ b/lib/readline/input.c~ deleted file mode 100644 index 6d2bb2f12..000000000 --- a/lib/readline/input.c~ +++ /dev/null @@ -1,551 +0,0 @@ -/* input.c -- character input functions for readline. */ - -/* Copyright (C) 1994 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_SELECT) -# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX) -# include -# endif -#endif /* HAVE_SELECT */ -#if defined (HAVE_SYS_SELECT_H) -# include -#endif - -#if defined (FIONREAD_IN_SYS_IOCTL) -# include -#endif - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -/* Some standard library routines. */ -#include "readline.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -/* What kind of non-blocking I/O do we have? */ -#if !defined (O_NDELAY) && defined (O_NONBLOCK) -# define O_NDELAY O_NONBLOCK /* Posix style */ -#endif - -/* Non-null means it is a pointer to a function to run while waiting for - character input. */ -rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL; - -rl_getc_func_t *rl_getc_function = rl_getc; - -static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */ - -static int ibuffer_space PARAMS((void)); -static int rl_get_char PARAMS((int *)); -static int rl_gather_tyi PARAMS((void)); - -/* **************************************************************** */ -/* */ -/* Character Input Buffering */ -/* */ -/* **************************************************************** */ - -static int pop_index, push_index; -static unsigned char ibuffer[512]; -static int ibuffer_len = sizeof (ibuffer) - 1; - -#define any_typein (push_index != pop_index) - -int -_rl_any_typein () -{ - return any_typein; -} - -/* Return the amount of space available in the buffer for stuffing - characters. */ -static int -ibuffer_space () -{ - if (pop_index > push_index) - return (pop_index - push_index - 1); - else - return (ibuffer_len - (push_index - pop_index)); -} - -/* Get a key from the buffer of characters to be read. - Return the key in KEY. - Result is KEY if there was a key, or 0 if there wasn't. */ -static int -rl_get_char (key) - int *key; -{ - if (push_index == pop_index) - return (0); - - *key = ibuffer[pop_index++]; - - if (pop_index >= ibuffer_len) - pop_index = 0; - - return (1); -} - -/* Stuff KEY into the *front* of the input buffer. - Returns non-zero if successful, zero if there is - no space left in the buffer. */ -int -_rl_unget_char (key) - int key; -{ - if (ibuffer_space ()) - { - pop_index--; - if (pop_index < 0) - pop_index = ibuffer_len - 1; - ibuffer[pop_index] = key; - return (1); - } - return (0); -} - -int -_rl_pushed_input_available () -{ - return (push_index != pop_index); -} - -/* If a character is available to be read, then read it and stuff it into - IBUFFER. Otherwise, just return. Returns number of characters read - (0 if none available) and -1 on error (EIO). */ -static int -rl_gather_tyi () -{ - int tty; - register int tem, result; - int chars_avail, k; - char input; -#if defined(HAVE_SELECT) - fd_set readfds, exceptfds; - struct timeval timeout; -#endif - - tty = fileno (rl_instream); - -#if defined (HAVE_SELECT) - FD_ZERO (&readfds); - FD_ZERO (&exceptfds); - FD_SET (tty, &readfds); - FD_SET (tty, &exceptfds); - timeout.tv_sec = 0; - timeout.tv_usec = _keyboard_input_timeout; - result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout); - if (result <= 0) - return 0; /* Nothing to read. */ -#endif - - result = -1; -#if defined (FIONREAD) - errno = 0; - result = ioctl (tty, FIONREAD, &chars_avail); - if (result == -1 && errno == EIO) - return -1; -#endif - -#if defined (O_NDELAY) - if (result == -1) - { - tem = fcntl (tty, F_GETFL, 0); - - fcntl (tty, F_SETFL, (tem | O_NDELAY)); - chars_avail = read (tty, &input, 1); - - fcntl (tty, F_SETFL, tem); - if (chars_avail == -1 && errno == EAGAIN) - return 0; - } -#endif /* O_NDELAY */ - - /* If there's nothing available, don't waste time trying to read - something. */ - if (chars_avail <= 0) - return 0; - - tem = ibuffer_space (); - - if (chars_avail > tem) - chars_avail = tem; - - /* One cannot read all of the available input. I can only read a single - character at a time, or else programs which require input can be - thwarted. If the buffer is larger than one character, I lose. - Damn! */ - if (tem < ibuffer_len) - chars_avail = 0; - - if (result != -1) - { - while (chars_avail--) - { - k = (*rl_getc_function) (rl_instream); - rl_stuff_char (k); - if (k == NEWLINE || k == RETURN) - break; - } - } - else - { - if (chars_avail) - rl_stuff_char (input); - } - - return 1; -} - -int -rl_set_keyboard_input_timeout (u) - int u; -{ - int o; - - o = _keyboard_input_timeout; - if (u > 0) - _keyboard_input_timeout = u; - return (o); -} - -/* Is there input available to be read on the readline input file - descriptor? Only works if the system has select(2) or FIONREAD. - Uses the value of _keyboard_input_timeout as the timeout; if another - readline function wants to specify a timeout and not leave it up to - the user, it should use _rl_input_queued(timeout_value_in_microseconds) - instead. */ -int -_rl_input_available () -{ -#if defined(HAVE_SELECT) - fd_set readfds, exceptfds; - struct timeval timeout; -#endif -#if !defined (HAVE_SELECT) && defined(FIONREAD) - int chars_avail; -#endif - int tty; - - tty = fileno (rl_instream); - -#if defined (HAVE_SELECT) - FD_ZERO (&readfds); - FD_ZERO (&exceptfds); - FD_SET (tty, &readfds); - FD_SET (tty, &exceptfds); - timeout.tv_sec = 0; - timeout.tv_usec = _keyboard_input_timeout; - return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0); -#else - -#if defined (FIONREAD) - if (ioctl (tty, FIONREAD, &chars_avail) == 0) - return (chars_avail); -#endif - -#endif - - return 0; -} - -int -_rl_input_queued (t) - int t; -{ - int old_timeout, r; - - old_timeout = rl_set_keyboard_input_timeout (t); - r = _rl_input_available (); - rl_set_keyboard_input_timeout (old_timeout); - return r; -} - -void -_rl_insert_typein (c) - int c; -{ - int key, t, i; - char *string; - - i = key = 0; - string = (char *)xmalloc (ibuffer_len + 1); - string[i++] = (char) c; - - while ((t = rl_get_char (&key)) && - _rl_keymap[key].type == ISFUNC && - _rl_keymap[key].function == rl_insert) - string[i++] = key; - - if (t) - _rl_unget_char (key); - - string[i] = '\0'; - rl_insert_text (string); - free (string); -} - -/* Add KEY to the buffer of characters to be read. Returns 1 if the - character was stuffed correctly; 0 otherwise. */ -int -rl_stuff_char (key) - int key; -{ - if (ibuffer_space () == 0) - return 0; - - if (key == EOF) - { - key = NEWLINE; - rl_pending_input = EOF; - RL_SETSTATE (RL_STATE_INPUTPENDING); - } - ibuffer[push_index++] = key; - if (push_index >= ibuffer_len) - push_index = 0; - - return 1; -} - -/* Make C be the next command to be executed. */ -int -rl_execute_next (c) - int c; -{ - rl_pending_input = c; - RL_SETSTATE (RL_STATE_INPUTPENDING); - return 0; -} - -/* Clear any pending input pushed with rl_execute_next() */ -int -rl_clear_pending_input () -{ - rl_pending_input = 0; - RL_UNSETSTATE (RL_STATE_INPUTPENDING); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Character Input */ -/* */ -/* **************************************************************** */ - -/* Read a key, including pending input. */ -int -rl_read_key () -{ - int c; - - rl_key_sequence_length++; - - if (rl_pending_input) - { - c = rl_pending_input; - rl_clear_pending_input (); - } - else - { - /* If input is coming from a macro, then use that. */ - if (c = _rl_next_macro_key ()) - return (c); - - /* If the user has an event function, then call it periodically. */ - if (rl_event_hook) - { - while (rl_event_hook && rl_get_char (&c) == 0) - { - (*rl_event_hook) (); - if (rl_done) /* XXX - experimental */ - return ('\n'); - if (rl_gather_tyi () < 0) /* XXX - EIO */ - { - rl_done = 1; - return ('\n'); - } - } - } - else - { - if (rl_get_char (&c) == 0) - c = (*rl_getc_function) (rl_instream); - } - } - - return (c); -} - -int -rl_getc (stream) - FILE *stream; -{ - int result; - unsigned char c; - - while (1) - { - result = read (fileno (stream), &c, sizeof (unsigned char)); - - if (result == sizeof (unsigned char)) - return (c); - - /* If zero characters are returned, then the file that we are - reading from is empty! Return EOF in that case. */ - if (result == 0) - return (EOF); - -#if defined (__BEOS__) - if (errno == EINTR) - continue; -#endif - -#if defined (EWOULDBLOCK) -# define X_EWOULDBLOCK EWOULDBLOCK -#else -# define X_EWOULDBLOCK -99 -#endif - -#if defined (EAGAIN) -# define X_EAGAIN EAGAIN -#else -# define X_EAGAIN -99 -#endif - - if (errno == X_EWOULDBLOCK || errno == X_EAGAIN) - { - if (sh_unset_nodelay_mode (fileno (stream)) < 0) - return (EOF); - continue; - } - -#undef X_EWOULDBLOCK -#undef X_EAGAIN - - /* If the error that we received was SIGINT, then try again, - this is simply an interrupted system call to read (). - Otherwise, some error ocurred, also signifying EOF. */ - if (errno != EINTR) - return (EOF); - } -} - -#if defined (HANDLE_MULTIBYTE) -/* read multibyte char */ -int -_rl_read_mbchar (mbchar, size) - char *mbchar; - int size; -{ - int mb_len = 0; - size_t mbchar_bytes_length; - wchar_t wc; - mbstate_t ps, ps_back; - - memset(&ps, 0, sizeof (mbstate_t)); - memset(&ps_back, 0, sizeof (mbstate_t)); - - while (mb_len < size) - { - RL_SETSTATE(RL_STATE_MOREINPUT); - mbchar[mb_len++] = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps); - if (mbchar_bytes_length == (size_t)(-1)) - break; /* invalid byte sequence for the current locale */ - else if (mbchar_bytes_length == (size_t)(-2)) - { - /* shorted bytes */ - ps = ps_back; - continue; - } - else if (mbchar_bytes_length > (size_t)(0)) - break; - } - - return mb_len; -} - -/* Read a multibyte-character string whose first character is FIRST into - the buffer MB of length MBLEN. Returns the last character read, which - may be FIRST. Used by the search functions, among others. Very similar - to _rl_read_mbchar. */ -int -_rl_read_mbstring (first, mb, mblen) - int first; - char *mb; - int mblen; -{ - int i, c; - mbstate_t ps; - - c = first; - memset (mb, 0, mblen); - for (i = 0; i < mblen; i++) - { - mb[i] = (char)c; - memset (&ps, 0, sizeof (mbstate_t)); - if (_rl_get_char_len (mb, &ps) == -2) - { - /* Read more for multibyte character */ - RL_SETSTATE (RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE (RL_STATE_MOREINPUT); - } - else - break; - } - return c; -} -#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/readline/misc.c~ b/lib/readline/misc.c~ deleted file mode 100644 index 00e5a61a1..000000000 --- a/lib/readline/misc.c~ +++ /dev/null @@ -1,500 +0,0 @@ -/* misc.c -- miscellaneous bindable readline functions. */ - -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -static int rl_digit_loop PARAMS((void)); -static void _rl_history_set_point PARAMS((void)); - -/* Forward declarations used in this file */ -void _rl_free_history_entry PARAMS((HIST_ENTRY *)); - -/* If non-zero, rl_get_previous_history and rl_get_next_history attempt - to preserve the value of rl_point from line to line. */ -int _rl_history_preserve_point = 0; - -/* Saved target point for when _rl_history_preserve_point is set. Special - value of -1 means that point is at the end of the line. */ -int _rl_history_saved_point = -1; - -/* **************************************************************** */ -/* */ -/* Numeric Arguments */ -/* */ -/* **************************************************************** */ - -/* Handle C-u style numeric args, as well as M--, and M-digits. */ -static int -rl_digit_loop () -{ - int key, c, sawminus, sawdigits; - - rl_save_prompt (); - - RL_SETSTATE(RL_STATE_NUMERICARG); - sawminus = sawdigits = 0; - while (1) - { - if (rl_numeric_arg > 1000000) - { - sawdigits = rl_explicit_arg = rl_numeric_arg = 0; - rl_ding (); - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return 1; - } - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - RL_SETSTATE(RL_STATE_MOREINPUT); - key = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - { - _rl_abort_internal (); - return -1; - } - - /* If we see a key bound to `universal-argument' after seeing digits, - it ends the argument but is otherwise ignored. */ - if (_rl_keymap[c].type == ISFUNC && - _rl_keymap[c].function == rl_universal_argument) - { - if (sawdigits == 0) - { - rl_numeric_arg *= 4; - continue; - } - else - { - RL_SETSTATE(RL_STATE_MOREINPUT); - key = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (_rl_dispatch (key, _rl_keymap)); - } - } - - c = UNMETA (c); - - if (_rl_digit_p (c)) - { - rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; - sawdigits = rl_explicit_arg = 1; - } - else if (c == '-' && rl_explicit_arg == 0) - { - rl_numeric_arg = sawminus = 1; - rl_arg_sign = -1; - } - else - { - /* Make M-- command equivalent to M--1 command. */ - if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) - rl_explicit_arg = 1; - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (_rl_dispatch (key, _rl_keymap)); - } - } - - /*NOTREACHED*/ -} - -/* Add the current digit to the argument in progress. */ -int -rl_digit_argument (ignore, key) - int ignore, key; -{ - rl_execute_next (key); - return (rl_digit_loop ()); -} - -/* What to do when you abort reading an argument. */ -int -rl_discard_argument () -{ - rl_ding (); - rl_clear_message (); - _rl_init_argument (); - return 0; -} - -/* Create a default argument. */ -int -_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. */ -int -rl_universal_argument (count, key) - int count, key; -{ - rl_numeric_arg *= 4; - return (rl_digit_loop ()); -} - -/* **************************************************************** */ -/* */ -/* History Utilities */ -/* */ -/* **************************************************************** */ - -/* We already have a history library, and that is what we use to control - the history features of readline. This is our local interface to - the history mechanism. */ - -/* While we are editing the history, this is the saved - version of the original line. */ -HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL; - -/* Set the history pointer back to the last entry in the history. */ -void -_rl_start_using_history () -{ - using_history (); - if (_rl_saved_line_for_history) - _rl_free_history_entry (_rl_saved_line_for_history); - - _rl_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 == 0) - return; - if (entry->line) - free (entry->line); - free (entry); -} - -/* Perhaps put back the current line if it has changed. */ -int -rl_maybe_replace_line () -{ - HIST_ENTRY *temp; - - temp = current_history (); - /* If the current line has changed, save the changes. */ - if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) - { - temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list); - free (temp->line); - free (temp); - } - return 0; -} - -/* Restore the _rl_saved_line_for_history if there is one. */ -int -rl_maybe_unsave_line () -{ - if (_rl_saved_line_for_history) - { - /* Can't call with `1' because rl_undo_list might point to an undo - list from a history entry, as in rl_replace_from_history() below. */ - rl_replace_line (_rl_saved_line_for_history->line, 0); - rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; - _rl_free_history_entry (_rl_saved_line_for_history); - _rl_saved_line_for_history = (HIST_ENTRY *)NULL; - rl_point = rl_end; /* rl_replace_line sets rl_end */ - } - else - rl_ding (); - return 0; -} - -/* Save the current line in _rl_saved_line_for_history. */ -int -rl_maybe_save_line () -{ - if (_rl_saved_line_for_history == 0) - { - _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - _rl_saved_line_for_history->line = savestring (rl_line_buffer); - _rl_saved_line_for_history->data = (char *)rl_undo_list; - } - return 0; -} - -int -_rl_free_saved_history_line () -{ - if (_rl_saved_line_for_history) - { - _rl_free_history_entry (_rl_saved_line_for_history); - _rl_saved_line_for_history = (HIST_ENTRY *)NULL; - } - return 0; -} - -static void -_rl_history_set_point () -{ - rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) - ? _rl_history_saved_point - : rl_end; - if (rl_point > rl_end) - rl_point = rl_end; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) - rl_point = 0; -#endif /* VI_MODE */ - - if (rl_editing_mode == emacs_mode) - rl_mark = (rl_point == rl_end ? 0 : rl_end); -} - -void -rl_replace_from_history (entry, flags) - HIST_ENTRY *entry; - int flags; /* currently unused */ -{ - /* Can't call with `1' because rl_undo_list might point to an undo list - from a history entry, just like we're setting up here. */ - rl_replace_line (entry->line, 0); - rl_undo_list = (UNDO_LIST *)entry->data; - rl_point = rl_end; - rl_mark = 0; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - { - rl_point = 0; - rl_mark = rl_end; - } -#endif -} - -/* **************************************************************** */ -/* */ -/* History Commands */ -/* */ -/* **************************************************************** */ - -/* Meta-< goes to the start of the history. */ -int -rl_beginning_of_history (count, key) - int count, key; -{ - return (rl_get_previous_history (1 + where_history (), key)); -} - -/* Meta-> goes to the end of the history. (The current line). */ -int -rl_end_of_history (count, key) - int count, key; -{ - rl_maybe_replace_line (); - using_history (); - rl_maybe_unsave_line (); - return 0; -} - -/* Move down to the next history line. */ -int -rl_get_next_history (count, key) - int count, key; -{ - HIST_ENTRY *temp; - - if (count < 0) - return (rl_get_previous_history (-count, key)); - - if (count == 0) - return 0; - - rl_maybe_replace_line (); - - /* either not saved by rl_newline or at end of line, so set appropriately. */ - if (_rl_history_saved_point == -1 && (rl_point || rl_end)) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - temp = (HIST_ENTRY *)NULL; - while (count) - { - temp = next_history (); - if (!temp) - break; - --count; - } - - if (temp == 0) - rl_maybe_unsave_line (); - else - { - rl_replace_from_history (temp, 0); - _rl_history_set_point (); - } - return 0; -} - -/* Get the previous item out of our interactive history, making it the current - line. If there is no previous history, just ding. */ -int -rl_get_previous_history (count, key) - int count, key; -{ - HIST_ENTRY *old_temp, *temp; - - if (count < 0) - return (rl_get_next_history (-count, key)); - - if (count == 0) - return 0; - - /* either not saved by rl_newline or at end of line, so set appropriately. */ - if (_rl_history_saved_point == -1 && (rl_point || rl_end)) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - /* If we don't have a line saved, then save this one. */ - rl_maybe_save_line (); - - /* If the current line has changed, save the changes. */ - rl_maybe_replace_line (); - - temp = old_temp = (HIST_ENTRY *)NULL; - while (count) - { - temp = previous_history (); - if (temp == 0) - break; - - old_temp = temp; - --count; - } - - /* If there was a large argument, and we moved back to the start of the - history, that is not an error. So use the last value found. */ - if (!temp && old_temp) - temp = old_temp; - - if (temp == 0) - rl_ding (); - else - { - rl_replace_from_history (temp, 0); - _rl_history_set_point (); - } - return 0; -} - -/* **************************************************************** */ -/* */ -/* Editing Modes */ -/* */ -/* **************************************************************** */ -/* How to toggle back and forth between editing modes. */ -int -rl_vi_editing_mode (count, key) - int count, key; -{ -#if defined (VI_MODE) - _rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */ - rl_editing_mode = vi_mode; - rl_vi_insertion_mode (1, key); -#endif /* VI_MODE */ - - return 0; -} - -int -rl_emacs_editing_mode (count, key) - int count, key; -{ - rl_editing_mode = emacs_mode; - _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */ - _rl_keymap = emacs_standard_keymap; - return 0; -} - -/* Function for the rest of the library to use to set insert/overwrite mode. */ -void -_rl_set_insert_mode (im, force) - int im, force; -{ -#ifdef CURSOR_MODE - _rl_set_cursor (im, force); -#endif - - rl_insert_mode = im; -} - -/* Toggle overwrite mode. A positive explicit argument selects overwrite - mode. A negative or zero explicit argument selects insert mode. */ -int -rl_overwrite_mode (count, key) - int count, key; -{ - if (rl_explicit_arg == 0) - _rl_set_insert_mode (rl_insert_mode ^ 1, 0); - else if (count > 0) - _rl_set_insert_mode (RL_IM_OVERWRITE, 0); - else - _rl_set_insert_mode (RL_IM_INSERT, 0); - - return 0; -} diff --git a/lib/readline/parens.c~ b/lib/readline/parens.c~ deleted file mode 100644 index 54ef1f369..000000000 --- a/lib/readline/parens.c~ +++ /dev/null @@ -1,179 +0,0 @@ -/* parens.c -- Implementation of matching parentheses 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 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#include "rlconf.h" - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (FD_SET) && !defined (HAVE_SELECT) -# define HAVE_SELECT -#endif - -#if defined (HAVE_SELECT) -# include -#endif /* HAVE_SELECT */ -#if defined (HAVE_SYS_SELECT_H) -# include -#endif - -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - -#include "readline.h" -#include "rlprivate.h" - -static int find_matching_open PARAMS((char *, int, int)); - -/* Non-zero means try to blink the matching open parenthesis when the - close parenthesis is inserted. */ -#if defined (HAVE_SELECT) -int rl_blink_matching_paren = 1; -#else /* !HAVE_SELECT */ -int rl_blink_matching_paren = 0; -#endif /* !HAVE_SELECT */ - -static int _paren_blink_usec = 500000; - -/* Change emacs_standard_keymap to have bindings for paren matching when - ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */ -void -_rl_enable_paren_matching (on_or_off) - int on_or_off; -{ - if (on_or_off) - { /* ([{ */ - rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap); - rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap); - rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap); - } - else - { /* ([{ */ - rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap); - rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap); - rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap); - } -} - -int -rl_set_paren_blink_timeout (u) - int u; -{ - int o; - - o = _paren_blink_usec; - if (u > 0) - _paren_blink_usec = u; - return (o); -} - -int -rl_insert_close (count, invoking_key) - int count, invoking_key; -{ - if (rl_explicit_arg || !rl_blink_matching_paren) - _rl_insert_char (count, invoking_key); - else - { -#if defined (HAVE_SELECT) - int orig_point, match_point, ready; - struct timeval timer; - fd_set readfds; - - _rl_insert_char (1, invoking_key); - (*rl_redisplay_function) (); - 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 = 0; - timer.tv_usec = _paren_blink_usec; - - orig_point = rl_point; - rl_point = match_point; - (*rl_redisplay_function) (); - ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); - rl_point = orig_point; -#else /* !HAVE_SELECT */ - _rl_insert_char (count, invoking_key); -#endif /* !HAVE_SELECT */ - } - 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 (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i])) - delimiter = string[i]; - else if (!delimiter && (string[i] == closer)) - level++; - else if (!delimiter && (string[i] == opener)) - level--; - - if (!level) - break; - } - return (i); -} diff --git a/lib/readline/readline.h~ b/lib/readline/readline.h~ deleted file mode 100644 index 199ff3cb6..000000000 --- a/lib/readline/readline.h~ +++ /dev/null @@ -1,828 +0,0 @@ -/* Readline.h -- the names of functions callable from within readline. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_READLINE_H_) -#define _READLINE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined (READLINE_LIBRARY) -# include "rlstdc.h" -# include "rltypedefs.h" -# include "keymaps.h" -# include "tilde.h" -#else -# include -# include -# include -# include -#endif - -/* Hex-encoded Readline version number. */ -#define RL_READLINE_VERSION 0x0500 /* Readline 5.0 */ -#define RL_VERSION_MAJOR 5 -#define RL_VERSION_MINOR 0 - -/* Readline data structures. */ - -/* Maintaining the state of undo. We remember individual deletes and inserts - on a chain of things to do. */ - -/* The actions that undo knows how to undo. Notice that UNDO_DELETE means - to insert some text, and UNDO_INSERT means to delete some text. I.e., - the code tells undo what to undo, not how to undo it. */ -enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; - -/* What an element of THE_UNDO_LIST looks like. */ -typedef struct undo_list { - struct undo_list *next; - int start, end; /* Where the change took place. */ - char *text; /* The text to insert, if undoing a delete. */ - enum undo_code what; /* Delete, Insert, Begin, End. */ -} UNDO_LIST; - -/* The current undo list for RL_LINE_BUFFER. */ -extern UNDO_LIST *rl_undo_list; - -/* The data structure for mapping textual names to code addresses. */ -typedef struct _funmap { - const char *name; - rl_command_func_t *function; -} FUNMAP; - -extern FUNMAP **funmap; - -/* **************************************************************** */ -/* */ -/* Functions available to bind to key sequences */ -/* */ -/* **************************************************************** */ - -/* Bindable commands for numeric arguments. */ -extern int rl_digit_argument PARAMS((int, int)); -extern int rl_universal_argument PARAMS((int, int)); - -/* Bindable commands for moving the cursor. */ -extern int rl_forward_byte PARAMS((int, int)); -extern int rl_forward_char PARAMS((int, int)); -extern int rl_forward PARAMS((int, int)); -extern int rl_backward_byte PARAMS((int, int)); -extern int rl_backward_char PARAMS((int, int)); -extern int rl_backward PARAMS((int, int)); -extern int rl_beg_of_line PARAMS((int, int)); -extern int rl_end_of_line PARAMS((int, int)); -extern int rl_forward_word PARAMS((int, int)); -extern int rl_backward_word PARAMS((int, int)); -extern int rl_refresh_line PARAMS((int, int)); -extern int rl_clear_screen PARAMS((int, int)); -extern int rl_arrow_keys PARAMS((int, int)); - -/* Bindable commands for inserting and deleting text. */ -extern int rl_insert PARAMS((int, int)); -extern int rl_quoted_insert PARAMS((int, int)); -extern int rl_tab_insert PARAMS((int, int)); -extern int rl_newline PARAMS((int, int)); -extern int rl_do_lowercase_version PARAMS((int, int)); -extern int rl_rubout PARAMS((int, int)); -extern int rl_delete PARAMS((int, int)); -extern int rl_rubout_or_delete PARAMS((int, int)); -extern int rl_delete_horizontal_space PARAMS((int, int)); -extern int rl_delete_or_show_completions PARAMS((int, int)); -extern int rl_insert_comment PARAMS((int, int)); - -/* Bindable commands for changing case. */ -extern int rl_upcase_word PARAMS((int, int)); -extern int rl_downcase_word PARAMS((int, int)); -extern int rl_capitalize_word PARAMS((int, int)); - -/* Bindable commands for transposing characters and words. */ -extern int rl_transpose_words PARAMS((int, int)); -extern int rl_transpose_chars PARAMS((int, int)); - -/* Bindable commands for searching within a line. */ -extern int rl_char_search PARAMS((int, int)); -extern int rl_backward_char_search PARAMS((int, int)); - -/* Bindable commands for readline's interface to the command history. */ -extern int rl_beginning_of_history PARAMS((int, int)); -extern int rl_end_of_history PARAMS((int, int)); -extern int rl_get_next_history PARAMS((int, int)); -extern int rl_get_previous_history PARAMS((int, int)); - -/* Bindable commands for managing the mark and region. */ -extern int rl_set_mark PARAMS((int, int)); -extern int rl_exchange_point_and_mark PARAMS((int, int)); - -/* Bindable commands to set the editing mode (emacs or vi). */ -extern int rl_vi_editing_mode PARAMS((int, int)); -extern int rl_emacs_editing_mode PARAMS((int, int)); - -/* Bindable commands to change the insert mode (insert or overwrite) */ -extern int rl_overwrite_mode PARAMS((int, int)); - -/* Bindable commands for managing key bindings. */ -extern int rl_re_read_init_file PARAMS((int, int)); -extern int rl_dump_functions PARAMS((int, int)); -extern int rl_dump_macros PARAMS((int, int)); -extern int rl_dump_variables PARAMS((int, int)); - -/* Bindable commands for word completion. */ -extern int rl_complete PARAMS((int, int)); -extern int rl_possible_completions PARAMS((int, int)); -extern int rl_insert_completions PARAMS((int, int)); -extern int rl_menu_complete PARAMS((int, int)); - -/* Bindable commands for killing and yanking text, and managing the kill ring. */ -extern int rl_kill_word PARAMS((int, int)); -extern int rl_backward_kill_word PARAMS((int, int)); -extern int rl_kill_line PARAMS((int, int)); -extern int rl_backward_kill_line PARAMS((int, int)); -extern int rl_kill_full_line PARAMS((int, int)); -extern int rl_unix_word_rubout PARAMS((int, int)); -extern int rl_unix_filename_rubout PARAMS((int, int)); -extern int rl_unix_line_discard PARAMS((int, int)); -extern int rl_copy_region_to_kill PARAMS((int, int)); -extern int rl_kill_region PARAMS((int, int)); -extern int rl_copy_forward_word PARAMS((int, int)); -extern int rl_copy_backward_word PARAMS((int, int)); -extern int rl_yank PARAMS((int, int)); -extern int rl_yank_pop PARAMS((int, int)); -extern int rl_yank_nth_arg PARAMS((int, int)); -extern int rl_yank_last_arg PARAMS((int, int)); -/* Not available unless __CYGWIN__ is defined. */ -#ifdef __CYGWIN__ -extern int rl_paste_from_clipboard PARAMS((int, int)); -#endif - -/* Bindable commands for incremental searching. */ -extern int rl_reverse_search_history PARAMS((int, int)); -extern int rl_forward_search_history PARAMS((int, int)); - -/* Bindable keyboard macro commands. */ -extern int rl_start_kbd_macro PARAMS((int, int)); -extern int rl_end_kbd_macro PARAMS((int, int)); -extern int rl_call_last_kbd_macro PARAMS((int, int)); - -/* Bindable undo commands. */ -extern int rl_revert_line PARAMS((int, int)); -extern int rl_undo_command PARAMS((int, int)); - -/* Bindable tilde expansion commands. */ -extern int rl_tilde_expand PARAMS((int, int)); - -/* Bindable terminal control commands. */ -extern int rl_restart_output PARAMS((int, int)); -extern int rl_stop_output PARAMS((int, int)); - -/* Miscellaneous bindable commands. */ -extern int rl_abort PARAMS((int, int)); -extern int rl_tty_status PARAMS((int, int)); - -/* Bindable commands for incremental and non-incremental history searching. */ -extern int rl_history_search_forward PARAMS((int, int)); -extern int rl_history_search_backward PARAMS((int, int)); -extern int rl_noninc_forward_search PARAMS((int, int)); -extern int rl_noninc_reverse_search PARAMS((int, int)); -extern int rl_noninc_forward_search_again PARAMS((int, int)); -extern int rl_noninc_reverse_search_again PARAMS((int, int)); - -/* Bindable command used when inserting a matching close character. */ -extern int rl_insert_close PARAMS((int, int)); - -/* Not available unless READLINE_CALLBACKS is defined. */ -extern void rl_callback_handler_install PARAMS((const char *, rl_vcpfunc_t *)); -extern void rl_callback_read_char PARAMS((void)); -extern void rl_callback_handler_remove PARAMS((void)); - -/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */ -/* VI-mode bindable commands. */ -extern int rl_vi_redo PARAMS((int, int)); -extern int rl_vi_undo PARAMS((int, int)); -extern int rl_vi_yank_arg PARAMS((int, int)); -extern int rl_vi_fetch_history PARAMS((int, int)); -extern int rl_vi_search_again PARAMS((int, int)); -extern int rl_vi_search PARAMS((int, int)); -extern int rl_vi_complete PARAMS((int, int)); -extern int rl_vi_tilde_expand PARAMS((int, int)); -extern int rl_vi_prev_word PARAMS((int, int)); -extern int rl_vi_next_word PARAMS((int, int)); -extern int rl_vi_end_word PARAMS((int, int)); -extern int rl_vi_insert_beg PARAMS((int, int)); -extern int rl_vi_append_mode PARAMS((int, int)); -extern int rl_vi_append_eol PARAMS((int, int)); -extern int rl_vi_eof_maybe PARAMS((int, int)); -extern int rl_vi_insertion_mode PARAMS((int, int)); -extern int rl_vi_movement_mode PARAMS((int, int)); -extern int rl_vi_arg_digit PARAMS((int, int)); -extern int rl_vi_change_case PARAMS((int, int)); -extern int rl_vi_put PARAMS((int, int)); -extern int rl_vi_column PARAMS((int, int)); -extern int rl_vi_delete_to PARAMS((int, int)); -extern int rl_vi_change_to PARAMS((int, int)); -extern int rl_vi_yank_to PARAMS((int, int)); -extern int rl_vi_delete PARAMS((int, int)); -extern int rl_vi_back_to_indent PARAMS((int, int)); -extern int rl_vi_first_print PARAMS((int, int)); -extern int rl_vi_char_search PARAMS((int, int)); -extern int rl_vi_match PARAMS((int, int)); -extern int rl_vi_change_char PARAMS((int, int)); -extern int rl_vi_subst PARAMS((int, int)); -extern int rl_vi_overstrike PARAMS((int, int)); -extern int rl_vi_overstrike_delete PARAMS((int, int)); -extern int rl_vi_replace PARAMS((int, int)); -extern int rl_vi_set_mark PARAMS((int, int)); -extern int rl_vi_goto_mark PARAMS((int, int)); - -/* VI-mode utility functions. */ -extern int rl_vi_check PARAMS((void)); -extern int rl_vi_domove PARAMS((int, int *)); -extern int rl_vi_bracktype PARAMS((int)); - -/* VI-mode pseudo-bindable commands, used as utility functions. */ -extern int rl_vi_fWord PARAMS((int, int)); -extern int rl_vi_bWord PARAMS((int, int)); -extern int rl_vi_eWord PARAMS((int, int)); -extern int rl_vi_fword PARAMS((int, int)); -extern int rl_vi_bword PARAMS((int, int)); -extern int rl_vi_eword PARAMS((int, int)); - -/* **************************************************************** */ -/* */ -/* Well Published Functions */ -/* */ -/* **************************************************************** */ - -/* Readline functions. */ -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ -extern char *readline PARAMS((const char *)); - -extern int rl_set_prompt PARAMS((const char *)); -extern int rl_expand_prompt PARAMS((char *)); - -extern int rl_initialize PARAMS((void)); - -/* Undocumented; unused by readline */ -extern int rl_discard_argument PARAMS((void)); - -/* Utility functions to bind keys to readline commands. */ -extern int rl_add_defun PARAMS((const char *, rl_command_func_t *, int)); -extern int rl_bind_key PARAMS((int, rl_command_func_t *)); -extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap)); -extern int rl_unbind_key PARAMS((int)); -extern int rl_unbind_key_in_map PARAMS((int, Keymap)); -extern int rl_bind_key_if_unbound PARAMS((int, rl_command_func_t *)); -extern int rl_bind_key_if_unbound_in_map PARAMS((int, rl_command_func_t *, Keymap)); -extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap)); -extern int rl_unbind_command_in_map PARAMS((const char *, Keymap)); -extern int rl_bind_keyseq PARAMS((const char *, rl_command_func_t *)); -extern int rl_bind_keyseq_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); -extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *)); -extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); -extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap)); -extern int rl_variable_bind PARAMS((const char *, const char *)); - -/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */ -extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap)); - -/* Backwards compatibility, use rl_generic_bind instead. */ -extern int rl_macro_bind PARAMS((const char *, const char *, Keymap)); - -/* Undocumented in the texinfo manual; not really useful to programs. */ -extern int rl_translate_keyseq PARAMS((const char *, char *, int *)); -extern char *rl_untranslate_keyseq PARAMS((int)); - -extern rl_command_func_t *rl_named_function PARAMS((const char *)); -extern rl_command_func_t *rl_function_of_keyseq PARAMS((const char *, Keymap, int *)); - -extern void rl_list_funmap_names PARAMS((void)); -extern char **rl_invoking_keyseqs_in_map PARAMS((rl_command_func_t *, Keymap)); -extern char **rl_invoking_keyseqs PARAMS((rl_command_func_t *)); - -extern void rl_function_dumper PARAMS((int)); -extern void rl_macro_dumper PARAMS((int)); -extern void rl_variable_dumper PARAMS((int)); - -extern int rl_read_init_file PARAMS((const char *)); -extern int rl_parse_and_bind PARAMS((char *)); - -/* Functions for manipulating keymaps. */ -extern Keymap rl_make_bare_keymap PARAMS((void)); -extern Keymap rl_copy_keymap PARAMS((Keymap)); -extern Keymap rl_make_keymap PARAMS((void)); -extern void rl_discard_keymap PARAMS((Keymap)); - -extern Keymap rl_get_keymap_by_name PARAMS((const char *)); -extern char *rl_get_keymap_name PARAMS((Keymap)); -extern void rl_set_keymap PARAMS((Keymap)); -extern Keymap rl_get_keymap PARAMS((void)); -/* Undocumented; used internally only. */ -extern void rl_set_keymap_from_edit_mode PARAMS((void)); -extern char *rl_get_keymap_name_from_edit_mode PARAMS((void)); - -/* Functions for manipulating the funmap, which maps command names to functions. */ -extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *)); -extern const char **rl_funmap_names PARAMS((void)); -/* Undocumented, only used internally -- there is only one funmap, and this - function may be called only once. */ -extern void rl_initialize_funmap PARAMS((void)); - -/* Utility functions for managing keyboard macros. */ -extern void rl_push_macro_input PARAMS((char *)); - -/* Functions for undoing, from undo.c */ -extern void rl_add_undo PARAMS((enum undo_code, int, int, char *)); -extern void rl_free_undo_list PARAMS((void)); -extern int rl_do_undo PARAMS((void)); -extern int rl_begin_undo_group PARAMS((void)); -extern int rl_end_undo_group PARAMS((void)); -extern int rl_modifying PARAMS((int, int)); - -/* Functions for redisplay. */ -extern void rl_redisplay PARAMS((void)); -extern int rl_on_new_line PARAMS((void)); -extern int rl_on_new_line_with_prompt PARAMS((void)); -extern int rl_forced_update_display PARAMS((void)); -extern int rl_clear_message PARAMS((void)); -extern int rl_reset_line_state PARAMS((void)); -extern int rl_crlf PARAMS((void)); - -#if defined (USE_VARARGS) && defined (PREFER_STDARG) -extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -#else -extern int rl_message (); -#endif - -extern int rl_show_char PARAMS((int)); - -/* Undocumented in texinfo manual. */ -extern int rl_character_len PARAMS((int, int)); - -/* Save and restore internal prompt redisplay information. */ -extern void rl_save_prompt PARAMS((void)); -extern void rl_restore_prompt PARAMS((void)); - -/* Modifying text. */ -extern void rl_replace_line PARAMS((const char *, int)); -extern int rl_insert_text PARAMS((const char *)); -extern int rl_delete_text PARAMS((int, int)); -extern int rl_kill_text PARAMS((int, int)); -extern char *rl_copy_text PARAMS((int, int)); - -/* Terminal and tty mode management. */ -extern void rl_prep_terminal PARAMS((int)); -extern void rl_deprep_terminal PARAMS((void)); -extern void rl_tty_set_default_bindings PARAMS((Keymap)); -extern void rl_tty_unset_default_bindings PARAMS((Keymap)); - -extern int rl_reset_terminal PARAMS((const char *)); -extern void rl_resize_terminal PARAMS((void)); -extern void rl_set_screen_size PARAMS((int, int)); -extern void rl_get_screen_size PARAMS((int *, int *)); - -extern char *rl_get_termcap PARAMS((const char *)); - -/* Functions for character input. */ -extern int rl_stuff_char PARAMS((int)); -extern int rl_execute_next PARAMS((int)); -extern int rl_clear_pending_input PARAMS((void)); -extern int rl_read_key PARAMS((void)); -extern int rl_getc PARAMS((FILE *)); -extern int rl_set_keyboard_input_timeout PARAMS((int)); - -/* `Public' utility functions . */ -extern void rl_extend_line_buffer PARAMS((int)); -extern int rl_ding PARAMS((void)); -extern int rl_alphabetic PARAMS((int)); - -/* Readline signal handling, from signals.c */ -extern int rl_set_signals PARAMS((void)); -extern int rl_clear_signals PARAMS((void)); -extern void rl_cleanup_after_signal PARAMS((void)); -extern void rl_reset_after_signal PARAMS((void)); -extern void rl_free_line_state PARAMS((void)); - -extern int rl_set_paren_blink_timeout PARAMS((int)); - -/* Undocumented. */ -extern int rl_maybe_save_line PARAMS((void)); -extern int rl_maybe_unsave_line PARAMS((void)); -extern int rl_maybe_replace_line PARAMS((void)); - -/* Completion functions. */ -extern int rl_complete_internal PARAMS((int)); -extern void rl_display_match_list PARAMS((char **, int, int)); - -extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *)); -extern char *rl_username_completion_function PARAMS((const char *, int)); -extern char *rl_filename_completion_function PARAMS((const char *, int)); - -extern int rl_completion_mode PARAMS((rl_command_func_t *)); - -#if 0 -/* Backwards compatibility (compat.c). These will go away sometime. */ -extern void free_undo_list PARAMS((void)); -extern int maybe_save_line PARAMS((void)); -extern int maybe_unsave_line PARAMS((void)); -extern int maybe_replace_line PARAMS((void)); - -extern int ding PARAMS((void)); -extern int alphabetic PARAMS((int)); -extern int crlf PARAMS((void)); - -extern char **completion_matches PARAMS((char *, rl_compentry_func_t *)); -extern char *username_completion_function PARAMS((const char *, int)); -extern char *filename_completion_function PARAMS((const char *, int)); -#endif - -/* **************************************************************** */ -/* */ -/* Well Published Variables */ -/* */ -/* **************************************************************** */ - -/* The version of this incarnation of the readline library. */ -extern const char *rl_library_version; /* e.g., "4.2" */ -extern int rl_readline_version; /* e.g., 0x0402 */ - -/* True if this is real GNU readline. */ -extern int rl_gnu_readline_p; - -/* Flags word encapsulating the current readline state. */ -extern int rl_readline_state; - -/* Says which editing mode readline is currently using. 1 means emacs mode; - 0 means vi mode. */ -extern int rl_editing_mode; - -/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means - overwrite mode. Reset to insert mode on each input line. */ -extern int rl_insert_mode; - -/* The name of the calling program. You should initialize this to - whatever was in argv[0]. It is used when parsing conditionals. */ -extern const char *rl_readline_name; - -/* The prompt readline uses. This is set from the argument to - readline (), and should not be assigned to directly. */ -extern char *rl_prompt; - -/* The line buffer that is in use. */ -extern char *rl_line_buffer; - -/* The location of point, and end. */ -extern int rl_point; -extern int rl_end; - -/* The mark, or saved cursor position. */ -extern int rl_mark; - -/* Flag to indicate that readline has finished with the current input - line and should return it. */ -extern int rl_done; - -/* If set to a character value, that will be the next keystroke read. */ -extern int rl_pending_input; - -/* Non-zero if we called this function from _rl_dispatch(). It's present - so functions can find out whether they were called from a key binding - or directly from an application. */ -extern int rl_dispatching; - -/* Non-zero if the user typed a numeric argument before executing the - current function. */ -extern int rl_explicit_arg; - -/* The current value of the numeric argument specified by the user. */ -extern int rl_numeric_arg; - -/* The address of the last command function Readline executed. */ -extern rl_command_func_t *rl_last_func; - -/* The name of the terminal to use. */ -extern const char *rl_terminal_name; - -/* The input and output streams. */ -extern FILE *rl_instream; -extern FILE *rl_outstream; - -/* If non-zero, then this is the address of a function to call just - before readline_internal () prints the first prompt. */ -extern rl_hook_func_t *rl_startup_hook; - -/* If non-zero, this is the address of a function to call just before - readline_internal_setup () returns and readline_internal starts - reading input characters. */ -extern rl_hook_func_t *rl_pre_input_hook; - -/* The address of a function to call periodically while Readline is - awaiting character input, or NULL, for no event handling. */ -extern rl_hook_func_t *rl_event_hook; - -/* The address of the function to call to fetch a character from the current - Readline input stream */ -extern rl_getc_func_t *rl_getc_function; - -extern rl_voidfunc_t *rl_redisplay_function; - -extern rl_vintfunc_t *rl_prep_term_function; -extern rl_voidfunc_t *rl_deprep_term_function; - -/* Dispatch variables. */ -extern Keymap rl_executing_keymap; -extern Keymap rl_binding_keymap; - -/* Display variables. */ -/* If non-zero, readline will erase the entire line, including any prompt, - if the only thing typed on an otherwise-blank line is something bound to - rl_newline. */ -extern int rl_erase_empty_line; - -/* If non-zero, the application has already printed the prompt (rl_prompt) - before calling readline, so readline should not output it the first time - redisplay is done. */ -extern int rl_already_prompted; - -/* A non-zero value means to read only this many characters rather than - up to a character bound to accept-line. */ -extern int rl_num_chars_to_read; - -/* The text of a currently-executing keyboard macro. */ -extern char *rl_executing_macro; - -/* Variables to control readline signal handling. */ -/* If non-zero, readline will install its own signal handlers for - SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ -extern int rl_catch_signals; - -/* If non-zero, readline will install a signal handler for SIGWINCH - that also attempts to call any calling application's SIGWINCH signal - handler. Note that the terminal is not cleaned up before the - application's signal handler is called; use rl_cleanup_after_signal() - to do that. */ -extern int rl_catch_sigwinch; - -/* Completion variables. */ -/* Pointer to the generator function for completion_matches (). - NULL means to use rl_filename_completion_function (), the default - filename completer. */ -extern rl_compentry_func_t *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 rl_compignore_func_t *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 rl_completion_func_t *rl_attempted_completion_function; - -/* 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 const 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 /*const*/ char *rl_completer_word_break_characters; - -/* Hook function to allow an application to set the completion word - break characters before readline breaks up the line. Allows - position-dependent word break characters. */ -extern rl_cpvfunc_t *rl_completion_word_break_hook; - -/* List of characters which can be used to quote a substring of the line. - Completion occurs on the entire substring, and within the substring - rl_completer_word_break_characters are treated as any other character, - unless they also appear within this list. */ -extern const char *rl_completer_quote_characters; - -/* List of quote characters which cause a word break. */ -extern const char *rl_basic_quote_characters; - -/* List of characters that need to be quoted in filenames by the completer. */ -extern const char *rl_filename_quote_characters; - -/* List of characters that are word break characters, but should be left - in TEXT when it is passed to the completion function. The shell uses - this to help determine what kind of completing to do. */ -extern const char *rl_special_prefixes; - -/* If non-zero, then this is the address of a function to call when - completing on a directory name. The function is called with - the address of a string (the current directory name) as an arg. It - changes what is displayed when the possible completions are printed - or inserted. */ -extern rl_icppfunc_t *rl_directory_completion_hook; - -/* If non-zero, this is the address of a function to call when completing - a directory name. This function takes the address of the directory name - to be modified as an argument. Unlike rl_directory_completion_hook, it - only modifies the directory name used in opendir(2), not what is displayed - when the possible completions are printed or inserted. It is called - before rl_directory_completion_hook. I'm not happy with how this works - yet, so it's undocumented. */ -extern rl_icppfunc_t *rl_directory_rewrite_hook; - -/* Backwards compatibility with previous versions of readline. */ -#define rl_symbolic_link_hook rl_directory_completion_hook - -/* If non-zero, then this is the address of a function to call when - completing a word would normally display the list of possible matches. - This function is called instead of actually doing the display. - It takes three arguments: (char **matches, int num_matches, int max_length) - where MATCHES is the array of strings that matched, NUM_MATCHES is the - number of strings in that array, and MAX_LENGTH is the length of the - longest string in that array. */ -extern rl_compdisp_func_t *rl_completion_display_matches_hook; - -/* 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; - -/* Set to a function to quote a filename in an application-specific fashion. - Called with the text to quote, the type of match found (single or multiple) - and a pointer to the quoting character to be used, which the function can - reset if desired. */ -extern rl_quote_func_t *rl_filename_quoting_function; - -/* Function to call to remove quoting characters from a filename. Called - before completion is attempted, so the embedded quotes do not interfere - with matching names in the file system. */ -extern rl_dequote_func_t *rl_filename_dequoting_function; - -/* Function to call to decide whether or not a word break character is - quoted. If a character is quoted, it does not break words for the - completer. */ -extern rl_linebuf_func_t *rl_char_is_quoted_p; - -/* Non-zero means to suppress normal filename completion after the - user-specified completion function has been called. */ -extern int rl_attempted_completion_over; - -/* Set to a character describing the type of completion being attempted by - rl_complete_internal; available for use by application completion - functions. */ -extern int rl_completion_type; - -/* 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. */ -extern int rl_completion_query_items; - -/* Character appended to completed words when at the end of the line. The - default is a space. Nothing is added if this is '\0'. */ -extern int rl_completion_append_character; - -/* If set to non-zero by an application completion function, - rl_completion_append_character will not be appended. */ -extern int rl_completion_suppress_append; - -/* Set to any quote character readline thinks it finds before any application - completion function is called. */ -extern int rl_completion_quote_character; - -/* Set to a non-zero value if readline found quoting anywhere in the word to - be completed; set before any application completion function is called. */ -extern int rl_completion_found_quote; - -/* If non-zero, the completion functions don't append any closing quote. - This is set to 0 by rl_complete_internal and may be changed by an - application-specific completion function. */ -extern int rl_completion_suppress_quote; - -/* If non-zero, a slash will be appended to completed filenames that are - symbolic links to directory names, subject to the value of the - mark-directories variable (which is user-settable). This exists so - that application completion functions can override the user's preference - (set via the mark-symlinked-directories variable) if appropriate. - It's set to the value of _rl_complete_mark_symlink_dirs in - rl_complete_internal before any application-specific completion - function is called, so without that function doing anything, the user's - preferences are honored. */ -extern int rl_completion_mark_symlink_dirs; - -/* If non-zero, then disallow duplicates in the matches. */ -extern int rl_ignore_completion_duplicates; - -/* If this is non-zero, completion is (temporarily) inhibited, and the - completion character will be inserted as any other. */ -extern int rl_inhibit_completion; - -/* Definitions available for use by readline clients. */ -#define RL_PROMPT_START_IGNORE '\001' -#define RL_PROMPT_END_IGNORE '\002' - -/* Possible values for do_replace argument to rl_filename_quoting_function, - called by rl_complete_internal. */ -#define NO_MATCH 0 -#define SINGLE_MATCH 1 -#define MULT_MATCH 2 - -/* Possible state values for rl_readline_state */ -#define RL_STATE_NONE 0x00000 /* no state; before first call */ - -#define RL_STATE_INITIALIZING 0x00001 /* initializing */ -#define RL_STATE_INITIALIZED 0x00002 /* initialization done */ -#define RL_STATE_TERMPREPPED 0x00004 /* terminal is prepped */ -#define RL_STATE_READCMD 0x00008 /* reading a command key */ -#define RL_STATE_METANEXT 0x00010 /* reading input after ESC */ -#define RL_STATE_DISPATCHING 0x00020 /* dispatching to a command */ -#define RL_STATE_MOREINPUT 0x00040 /* reading more input in a command function */ -#define RL_STATE_ISEARCH 0x00080 /* doing incremental search */ -#define RL_STATE_NSEARCH 0x00100 /* doing non-inc search */ -#define RL_STATE_SEARCH 0x00200 /* doing a history search */ -#define RL_STATE_NUMERICARG 0x00400 /* reading numeric argument */ -#define RL_STATE_MACROINPUT 0x00800 /* getting input from a macro */ -#define RL_STATE_MACRODEF 0x01000 /* defining keyboard macro */ -#define RL_STATE_OVERWRITE 0x02000 /* overwrite mode */ -#define RL_STATE_COMPLETING 0x04000 /* doing completion */ -#define RL_STATE_SIGHANDLER 0x08000 /* in readline sighandler */ -#define RL_STATE_UNDOING 0x10000 /* doing an undo */ -#define RL_STATE_INPUTPENDING 0x20000 /* rl_execute_next called */ -#define RL_STATE_TTYCSAVED 0x40000 /* tty special chars saved */ - -#define RL_STATE_DONE 0x80000 /* done; accepted line */ - -#define RL_SETSTATE(x) (rl_readline_state |= (x)) -#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) -#define RL_ISSTATE(x) (rl_readline_state & (x)) - -struct readline_state { - /* line state */ - int point; - int end; - int mark; - char *buffer; - int buflen; - UNDO_LIST *ul; - char *prompt; - - /* global state */ - int rlstate; - int done; - Keymap kmap; - - /* input state */ - rl_command_func_t *lastfunc; - int insmode; - int edmode; - int kseqlen; - FILE *inf; - FILE *outf; - int pendingin; - char *macro; - - /* signal state */ - int catchsigs; - int catchsigwinch; - - /* reserved for future expansion, so the struct size doesn't change */ - char reserved[64]; -}; - -extern int rl_save_state PARAMS((struct readline_state *)); -extern int rl_restore_state PARAMS((struct readline_state *)); - -#ifdef __cplusplus -} -#endif - -#endif /* _READLINE_H_ */ diff --git a/lib/readline/rlprivate.h~ b/lib/readline/rlprivate.h~ deleted file mode 100644 index 8843c0490..000000000 --- a/lib/readline/rlprivate.h~ +++ /dev/null @@ -1,288 +0,0 @@ -/* rlprivate.h -- functions and variables global to the readline library, - but not intended for use by applications. */ - -/* Copyright (C) 1999-2004 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_RL_PRIVATE_H_) -#define _RL_PRIVATE_H_ - -#include "rlconf.h" /* for VISIBLE_STATS */ -#include "rlstdc.h" -#include "posixjmp.h" /* defines procenv_t */ - -/************************************************************************* - * * - * Global functions undocumented in texinfo manual and not in readline.h * - * * - *************************************************************************/ - -/************************************************************************* - * * - * Global variables undocumented in texinfo manual and not in readline.h * - * * - *************************************************************************/ - -/* complete.c */ -extern int rl_complete_with_tilde_expansion; -#if defined (VISIBLE_STATS) -extern int rl_visible_stats; -#endif /* VISIBLE_STATS */ - -/* readline.c */ -extern int rl_line_buffer_len; -extern int rl_arg_sign; -extern int rl_visible_prompt_length; -extern int readline_echoing_p; -extern int rl_key_sequence_length; -extern int rl_byte_oriented; - -/* display.c */ -extern int rl_display_fixed; - -/* parens.c */ -extern int rl_blink_matching_paren; - -/************************************************************************* - * * - * Global functions and variables unsed and undocumented * - * * - *************************************************************************/ - -/* kill.c */ -extern int rl_set_retained_kills PARAMS((int)); - -/* terminal.c */ -extern void _rl_set_screen_size PARAMS((int, int)); - -/* undo.c */ -extern int _rl_fix_last_undo_of_type PARAMS((int, int, int)); - -/* util.c */ -extern char *_rl_savestring PARAMS((const char *)); - -/************************************************************************* - * * - * Functions and variables private to the readline library * - * * - *************************************************************************/ - -/* 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. */ - -/************************************************************************* - * Undocumented private functions * - *************************************************************************/ - -#if defined(READLINE_CALLBACKS) - -/* readline.c */ -extern void readline_internal_setup PARAMS((void)); -extern char *readline_internal_teardown PARAMS((int)); -extern int readline_internal_char PARAMS((void)); - -#endif /* READLINE_CALLBACKS */ - -/* bind.c */ - -/* complete.c */ -extern char _rl_find_completion_word PARAMS((int *, int *)); -extern void _rl_free_match_list PARAMS((char **)); - -/* display.c */ -extern char *_rl_strip_prompt PARAMS((char *)); -extern void _rl_move_cursor_relative PARAMS((int, const char *)); -extern void _rl_move_vert PARAMS((int)); -extern void _rl_save_prompt PARAMS((void)); -extern void _rl_restore_prompt PARAMS((void)); -extern char *_rl_make_prompt_for_search PARAMS((int)); -extern void _rl_erase_at_end_of_line PARAMS((int)); -extern void _rl_clear_to_eol PARAMS((int)); -extern void _rl_clear_screen PARAMS((void)); -extern void _rl_update_final PARAMS((void)); -extern void _rl_redisplay_after_sigwinch PARAMS((void)); -extern void _rl_clean_up_for_exit PARAMS((void)); -extern void _rl_erase_entire_line PARAMS((void)); -extern int _rl_current_display_line PARAMS((void)); - -/* input.c */ -extern int _rl_any_typein PARAMS((void)); -extern int _rl_input_available PARAMS((void)); -extern int _rl_input_queued PARAMS((int)); -extern void _rl_insert_typein PARAMS((int)); -extern int _rl_unget_char PARAMS((int)); -extern int _rl_pushed_input_available PARAMS((void)); - -/* macro.c */ -extern void _rl_with_macro_input PARAMS((char *)); -extern int _rl_next_macro_key PARAMS((void)); -extern void _rl_push_executing_macro PARAMS((void)); -extern void _rl_pop_executing_macro PARAMS((void)); -extern void _rl_add_macro_char PARAMS((int)); -extern void _rl_kill_kbd_macro PARAMS((void)); - -/* misc.c */ -extern int _rl_init_argument PARAMS((void)); -extern void _rl_start_using_history PARAMS((void)); -extern int _rl_free_saved_history_line PARAMS((void)); -extern void _rl_set_insert_mode PARAMS((int, int)); - -/* nls.c */ -extern int _rl_init_eightbit PARAMS((void)); - -/* parens.c */ -extern void _rl_enable_paren_matching PARAMS((int)); - -/* readline.c */ -extern void _rl_init_line_state PARAMS((void)); -extern void _rl_set_the_line PARAMS((void)); -extern int _rl_dispatch PARAMS((int, Keymap)); -extern int _rl_dispatch_subseq PARAMS((int, Keymap, int)); - -/* rltty.c */ -extern int _rl_disable_tty_signals PARAMS((void)); -extern int _rl_restore_tty_signals PARAMS((void)); - -/* terminal.c */ -extern void _rl_get_screen_size PARAMS((int, int)); -extern int _rl_init_terminal_io PARAMS((const char *)); -#ifdef _MINIX -extern void _rl_output_character_function PARAMS((int)); -#else -extern int _rl_output_character_function PARAMS((int)); -#endif -extern void _rl_output_some_chars PARAMS((const char *, int)); -extern int _rl_backspace PARAMS((int)); -extern void _rl_enable_meta_key PARAMS((void)); -extern void _rl_control_keypad PARAMS((int)); -extern void _rl_set_cursor PARAMS((int, int)); - -/* text.c */ -extern void _rl_fix_point PARAMS((int)); -extern int _rl_replace_text PARAMS((const char *, int, int)); -extern int _rl_insert_char PARAMS((int, int)); -extern int _rl_overwrite_char PARAMS((int, int)); -extern int _rl_overwrite_rubout PARAMS((int, int)); -extern int _rl_rubout_char PARAMS((int, int)); -#if defined (HANDLE_MULTIBYTE) -extern int _rl_char_search_internal PARAMS((int, int, char *, int)); -#else -extern int _rl_char_search_internal PARAMS((int, int, int)); -#endif -extern int _rl_set_mark_at_pos PARAMS((int)); - -/* util.c */ -extern int _rl_abort_internal PARAMS((void)); -extern char *_rl_strindex PARAMS((const char *, const char *)); -extern int _rl_qsort_string_compare PARAMS((char **, char **)); -extern int (_rl_uppercase_p) PARAMS((int)); -extern int (_rl_lowercase_p) PARAMS((int)); -extern int (_rl_pure_alphabetic) PARAMS((int)); -extern int (_rl_digit_p) PARAMS((int)); -extern int (_rl_to_lower) PARAMS((int)); -extern int (_rl_to_upper) PARAMS((int)); -extern int (_rl_digit_value) PARAMS((int)); - -/* vi_mode.c */ -extern void _rl_vi_initialize_line PARAMS((void)); -extern void _rl_vi_reset_last PARAMS((int)); -extern void _rl_vi_set_last PARAMS((int, int, int)); -extern int _rl_vi_textmod_command PARAMS((int)); -extern void _rl_vi_done_inserting PARAMS((void)); - -/************************************************************************* - * Undocumented private variables * - *************************************************************************/ - -/* bind.c */ -extern const char *_rl_possible_control_prefixes[]; -extern const char *_rl_possible_meta_prefixes[]; - -/* complete.c */ -extern int _rl_complete_show_all; -extern int _rl_complete_show_unmodified; -extern int _rl_complete_mark_directories; -extern int _rl_complete_mark_symlink_dirs; -extern int _rl_print_completions_horizontally; -extern int _rl_completion_case_fold; -extern int _rl_match_hidden_files; -extern int _rl_page_completions; - -/* display.c */ -extern int _rl_vis_botlin; -extern int _rl_last_c_pos; -extern int _rl_suppress_redisplay; -extern char *rl_display_prompt; - -/* isearch.c */ -extern char *_rl_isearch_terminators; - -/* macro.c */ -extern char *_rl_executing_macro; - -/* misc.c */ -extern int _rl_history_preserve_point; -extern int _rl_history_saved_point; - -/* readline.c */ -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 char *_rl_comment_begin; -extern unsigned char _rl_parsing_conditionalized_out; -extern Keymap _rl_keymap; -extern FILE *_rl_in_stream; -extern FILE *_rl_out_stream; -extern int _rl_last_command_was_kill; -extern int _rl_eof_char; -extern procenv_t readline_top_level; - -/* terminal.c */ -extern int _rl_enable_keypad; -extern int _rl_enable_meta; -extern char *_rl_term_clreol; -extern char *_rl_term_clrpag; -extern char *_rl_term_im; -extern char *_rl_term_ic; -extern char *_rl_term_ei; -extern char *_rl_term_DC; -extern char *_rl_term_up; -extern char *_rl_term_dc; -extern char *_rl_term_cr; -extern char *_rl_term_IC; -extern int _rl_screenheight; -extern int _rl_screenwidth; -extern int _rl_screenchars; -extern int _rl_terminal_can_insert; -extern int _rl_term_autowrap; - -/* undo.c */ -extern int _rl_doing_an_undo; -extern int _rl_undo_group_level; - -/* vi_mode.c */ -extern int _rl_vi_last_command; - -#endif /* _RL_PRIVATE_H_ */ diff --git a/lib/readline/text.c~ b/lib/readline/text.c~ deleted file mode 100644 index ec6f71d42..000000000 --- a/lib/readline/text.c~ +++ /dev/null @@ -1,1547 +0,0 @@ -/* text.c -- text handling commands for readline. */ - -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (__EMX__) -# define INCL_DOSPROCESS -# include -#endif /* __EMX__ */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -/* Forward declarations. */ -static int rl_change_case PARAMS((int, int)); -static int _rl_char_search PARAMS((int, int, int)); - -/* **************************************************************** */ -/* */ -/* 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_char () calls this - function. Returns the number of characters inserted. */ -int -rl_insert_text (string) - const char *string; -{ - register int i, l; - - l = (string && *string) ? strlen (string) : 0; - if (l == 0) - return 0; - - if (rl_end + l >= rl_line_buffer_len) - rl_extend_line_buffer (rl_end + l); - - for (i = rl_end; i >= rl_point; i--) - rl_line_buffer[i + l] = rl_line_buffer[i]; - strncpy (rl_line_buffer + rl_point, string, l); - - /* Remember how to undo this if we aren't undoing something. */ - if (_rl_doing_an_undo == 0) - { - /* 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; - rl_line_buffer[rl_end] = '\0'; - return l; -} - -/* Delete the string between FROM and TO. FROM is inclusive, TO is not. - Returns the number of characters deleted. */ -int -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) - SWAP (from, to); - - /* fix boundaries */ - if (to > rl_end) - { - to = rl_end; - if (from > to) - from = to; - } - if (from < 0) - from = 0; - - 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++) - rl_line_buffer[i] = rl_line_buffer[i + diff]; - - /* Remember how to undo this delete. */ - if (_rl_doing_an_undo == 0) - rl_add_undo (UNDO_DELETE, from, to, text); - else - free (text); - - rl_end -= diff; - rl_line_buffer[rl_end] = '\0'; - return (diff); -} - -/* Fix up point so that it is within the line boundaries after killing - text. If FIX_MARK_TOO is non-zero, the mark is forced within line - boundaries also. */ - -#define _RL_FIX_POINT(x) \ - do { \ - if (x > rl_end) \ - x = rl_end; \ - else if (x < 0) \ - x = 0; \ - } while (0) - -void -_rl_fix_point (fix_mark_too) - int fix_mark_too; -{ - _RL_FIX_POINT (rl_point); - if (fix_mark_too) - _RL_FIX_POINT (rl_mark); -} -#undef _RL_FIX_POINT - -/* Replace the contents of the line buffer between START and END with - TEXT. The operation is undoable. To replace the entire line in an - undoable mode, use _rl_replace_text(text, 0, rl_end); */ -int -_rl_replace_text (text, start, end) - const char *text; - int start, end; -{ - int n; - - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - n = rl_insert_text (text); - rl_end_undo_group (); - - return n; -} - -/* Replace the current line buffer contents with TEXT. If CLEAR_UNDO is - non-zero, we free the current undo list. */ -void -rl_replace_line (text, clear_undo) - const char *text; - int clear_undo; -{ - int len; - - len = strlen (text); - if (len >= rl_line_buffer_len) - rl_extend_line_buffer (len); - strcpy (rl_line_buffer, text); - rl_end = len; - - if (clear_undo) - rl_free_undo_list (); - - _rl_fix_point (1); -} - -/* **************************************************************** */ -/* */ -/* 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 bytes. */ -int -rl_forward_byte (count, key) - int count, key; -{ - if (count < 0) - return (rl_backward_byte (-count, key)); - - if (count > 0) - { - int end = rl_point + count; -#if defined (VI_MODE) - int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end; -#else - int lend = rl_end; -#endif - - if (end > lend) - { - rl_point = lend; - rl_ding (); - } - else - rl_point = end; - } - - if (rl_end < 0) - rl_end = 0; - - return 0; -} - -#if defined (HANDLE_MULTIBYTE) -/* Move forward COUNT characters. */ -int -rl_forward_char (count, key) - int count, key; -{ - int point; - - if (MB_CUR_MAX == 1 || rl_byte_oriented) - return (rl_forward_byte (count, key)); - - if (count < 0) - return (rl_backward_char (-count, key)); - - if (count > 0) - { - point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - -#if defined (VI_MODE) - if (rl_end <= point && rl_editing_mode == vi_mode) - point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO); -#endif - - if (rl_point == point) - rl_ding (); - - rl_point = point; - - if (rl_end < 0) - rl_end = 0; - } - - return 0; -} -#else /* !HANDLE_MULTIBYTE */ -int -rl_forward_char (count, key) - int count, key; -{ - return (rl_forward_byte (count, key)); -} -#endif /* !HANDLE_MULTIBYTE */ - -/* Backwards compatibility. */ -int -rl_forward (count, key) - int count, key; -{ - return (rl_forward_char (count, key)); -} - -/* Move backward COUNT bytes. */ -int -rl_backward_byte (count, key) - int count, key; -{ - if (count < 0) - return (rl_forward_byte (-count, key)); - - if (count > 0) - { - if (rl_point < count) - { - rl_point = 0; - rl_ding (); - } - else - rl_point -= count; - } - - if (rl_point < 0) - rl_point = 0; - - return 0; -} - -#if defined (HANDLE_MULTIBYTE) -/* Move backward COUNT characters. */ -int -rl_backward_char (count, key) - int count, key; -{ - int point; - - if (MB_CUR_MAX == 1 || rl_byte_oriented) - return (rl_backward_byte (count, key)); - - if (count < 0) - return (rl_forward_char (-count, key)); - - if (count > 0) - { - point = rl_point; - - while (count > 0 && point > 0) - { - point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO); - count--; - } - if (count > 0) - { - rl_point = 0; - rl_ding (); - } - else - rl_point = point; - } - - return 0; -} -#else -int -rl_backward_char (count, key) - int count, key; -{ - return (rl_backward_byte (count, key)); -} -#endif - -/* Backwards compatibility. */ -int -rl_backward (count, key) - int count, key; -{ - return (rl_backward_char (count, key)); -} - -/* Move to the beginning of the line. */ -int -rl_beg_of_line (count, key) - int count, key; -{ - rl_point = 0; - return 0; -} - -/* Move to the end of the line. */ -int -rl_end_of_line (count, key) - int count, key; -{ - rl_point = rl_end; - return 0; -} - -/* XXX - these might need changes for multibyte characters */ -/* Move forward a word. We do what Emacs does. */ -int -rl_forward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - return (rl_backward_word (-count, key)); - - 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 = rl_line_buffer[rl_point]; - if (rl_alphabetic (c) == 0) - { - while (++rl_point < rl_end) - { - c = rl_line_buffer[rl_point]; - if (rl_alphabetic (c)) - break; - } - } - - if (rl_point == rl_end) - return 0; - - while (++rl_point < rl_end) - { - c = rl_line_buffer[rl_point]; - if (rl_alphabetic (c) == 0) - break; - } - --count; - } - - return 0; -} - -/* Move backward a word. We do what Emacs does. */ -int -rl_backward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - return (rl_forward_word (-count, key)); - - while (count) - { - if (!rl_point) - return 0; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - c = rl_line_buffer[rl_point - 1]; - if (rl_alphabetic (c) == 0) - { - while (--rl_point) - { - c = rl_line_buffer[rl_point - 1]; - if (rl_alphabetic (c)) - break; - } - } - - while (rl_point) - { - c = rl_line_buffer[rl_point - 1]; - if (rl_alphabetic (c) == 0) - break; - else - --rl_point; - } - - --count; - } - - return 0; -} - -/* Clear the current line. Numeric argument to C-l does this. */ -int -rl_refresh_line (ignore1, ignore2) - int ignore1, ignore2; -{ - int curr_line; - - curr_line = _rl_current_display_line (); - - _rl_move_vert (curr_line); - _rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */ - - _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ - - 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. */ -int -rl_clear_screen (count, key) - int count, key; -{ - if (rl_explicit_arg) - { - rl_refresh_line (count, key); - return 0; - } - - _rl_clear_screen (); /* calls termcap function to clear screen */ - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -int -rl_arrow_keys (count, c) - int count, c; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - switch (_rl_to_upper (ch)) - { - case 'A': - rl_get_previous_history (count, ch); - break; - - case 'B': - rl_get_next_history (count, ch); - break; - - case 'C': - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_forward_char (count, ch); - else - rl_forward_byte (count, ch); - break; - - case 'D': - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_backward_char (count, ch); - else - rl_backward_byte (count, ch); - break; - - default: - rl_ding (); - } - - return 0; -} - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -#ifdef HANDLE_MULTIBYTE -static char pending_bytes[MB_LEN_MAX]; -static int pending_bytes_length = 0; -static mbstate_t ps = {0}; -#endif - -/* Insert the character C at the current location, moving point forward. - If C introduces a multibyte sequence, we read the whole sequence and - then insert the multibyte char into the line buffer. */ -int -_rl_insert_char (count, c) - int count, c; -{ - register int i; - char *string; -#ifdef HANDLE_MULTIBYTE - int string_size; - char incoming[MB_LEN_MAX + 1]; - int incoming_length = 0; - mbstate_t ps_back; - static int stored_count = 0; -#endif - - if (count <= 0) - return 0; - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - incoming[0] = c; - incoming[1] = '\0'; - incoming_length = 1; - } - else - { - wchar_t wc; - size_t ret; - - if (stored_count <= 0) - stored_count = count; - else - count = stored_count; - - ps_back = ps; - pending_bytes[pending_bytes_length++] = c; - ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps); - - if (ret == (size_t)-2) - { - /* Bytes too short to compose character, try to wait for next byte. - Restore the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - ps = ps_back; - return 1; - } - else if (ret == (size_t)-1) - { - /* Invalid byte sequence for the current locale. Treat first byte - as a single character. */ - incoming[0] = pending_bytes[0]; - incoming[1] = '\0'; - incoming_length = 1; - pending_bytes_length--; - memmove (pending_bytes, pending_bytes + 1, pending_bytes_length); - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (ret == (size_t)0) - { - incoming[0] = '\0'; - incoming_length = 0; - pending_bytes_length--; - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else - { - /* We successfully read a single multibyte character. */ - memcpy (incoming, pending_bytes, pending_bytes_length); - incoming[pending_bytes_length] = '\0'; - incoming_length = pending_bytes_length; - pending_bytes_length = 0; - } - } -#endif /* HANDLE_MULTIBYTE */ - - /* If we can optimize, then do it. But don't let people crash - readline because of extra large arguments. */ - if (count > 1 && count <= 1024) - { -#if defined (HANDLE_MULTIBYTE) - string_size = count * incoming_length; - string = (char *)xmalloc (1 + string_size); - - i = 0; - while (i < string_size) - { - strncpy (string + i, incoming, incoming_length); - i += incoming_length; - } - incoming_length = 0; - stored_count = 0; -#else /* !HANDLE_MULTIBYTE */ - string = (char *)xmalloc (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; -#endif /* !HANDLE_MULTIBYTE */ - - string[i] = '\0'; - rl_insert_text (string); - free (string); - - return 0; - } - - if (count > 1024) - { - int decreaser; -#if defined (HANDLE_MULTIBYTE) - string_size = incoming_length * 1024; - string = (char *)xmalloc (1 + string_size); - - i = 0; - while (i < string_size) - { - strncpy (string + i, incoming, incoming_length); - i += incoming_length; - } - - while (count) - { - decreaser = (count > 1024) ? 1024 : count; - string[decreaser*incoming_length] = '\0'; - rl_insert_text (string); - count -= decreaser; - } - - free (string); - incoming_length = 0; - stored_count = 0; -#else /* !HANDLE_MULTIBYTE */ - 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; - } -#endif /* !HANDLE_MULTIBYTE */ - - return 0; - } - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { -#endif - /* We are inserting a single character. - If there is pending input, then make a string of all of the - pending characters that are bound to rl_insert, and insert - them all. */ - if (_rl_any_typein ()) - _rl_insert_typein (c); - else - { - /* Inserting a single character. */ - char str[2]; - - str[1] = '\0'; - str[0] = c; - rl_insert_text (str); - } -#if defined (HANDLE_MULTIBYTE) - } - else - { - rl_insert_text (incoming); - stored_count = 0; - } -#endif - - return 0; -} - -/* Overwrite the character at point (or next COUNT characters) with C. - If C introduces a multibyte character sequence, read the entire sequence - before starting the overwrite loop. */ -int -_rl_overwrite_char (count, c) - int count, c; -{ - int i; -#if defined (HANDLE_MULTIBYTE) - char mbkey[MB_LEN_MAX]; - int k; - - /* Read an entire multibyte character sequence to insert COUNT times. */ - if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) - k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX); -#endif - - rl_begin_undo_group (); - - for (i = 0; i < count; i++) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_insert_text (mbkey); - else -#endif - _rl_insert_char (1, c); - - if (rl_point < rl_end) - rl_delete (1, c); - } - - rl_end_undo_group (); - - return 0; -} - -int -rl_insert (count, c) - int count, c; -{ - return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c) - : _rl_overwrite_char (count, c)); -} - -/* Insert the next typed character verbatim. */ -int -rl_quoted_insert (count, key) - int count, key; -{ - int c; - -#if defined (HANDLE_SIGNALS) - _rl_disable_tty_signals (); -#endif - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - -#if defined (HANDLE_SIGNALS) - _rl_restore_tty_signals (); -#endif - - return (_rl_insert_char (count, c)); -} - -/* Insert a tab character. */ -int -rl_tab_insert (count, key) - int count, key; -{ - return (_rl_insert_char (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. */ -int -rl_newline (count, key) - int count, key; -{ - rl_done = 1; - - if (_rl_history_preserve_point) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - RL_SETSTATE(RL_STATE_DONE); - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - { - _rl_vi_done_inserting (); - if (_rl_vi_textmod_command (_rl_vi_last_command) == 0) /* XXX */ - _rl_vi_reset_last (); - } -#endif /* VI_MODE */ - - /* If we've been asked to erase empty lines, suppress the final update, - since _rl_update_final calls rl_crlf(). */ - if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) - return 0; - - if (readline_echoing_p) - _rl_update_final (); - 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. */ -int -rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; -{ - return 0; -} - -/* This is different from what vi does, so the code's not shared. Emacs - rubout in overwrite mode has one oddity: it replaces a control - character that's displayed as two characters (^X) with two spaces. */ -int -_rl_overwrite_rubout (count, key) - int count, key; -{ - int opoint; - int i, l; - - if (rl_point == 0) - { - rl_ding (); - return 1; - } - - opoint = rl_point; - - /* L == number of spaces to insert */ - for (i = l = 0; i < count; i++) - { - rl_backward_char (1, key); - l += rl_character_len (rl_line_buffer[rl_point], rl_point); /* not exactly right */ - } - - rl_begin_undo_group (); - - if (count > 1 || rl_explicit_arg) - rl_kill_text (opoint, rl_point); - else - rl_delete_text (opoint, rl_point); - - /* Emacs puts point at the beginning of the sequence of spaces. */ - if (rl_point < rl_end) - { - opoint = rl_point; - _rl_insert_char (l, ' '); - rl_point = opoint; - } - - rl_end_undo_group (); - - return 0; -} - -/* Rubout the character behind point. */ -int -rl_rubout (count, key) - int count, key; -{ - if (count < 0) - return (rl_delete (-count, key)); - - if (!rl_point) - { - rl_ding (); - return -1; - } - - if (rl_insert_mode == RL_IM_OVERWRITE) - return (_rl_overwrite_rubout (count, key)); - - return (_rl_rubout_char (count, key)); -} - -int -_rl_rubout_char (count, key) - int count, key; -{ - int orig_point; - unsigned char c; - - /* Duplicated code because this is called from other parts of the library. */ - if (count < 0) - return (rl_delete (-count, key)); - - if (rl_point == 0) - { - rl_ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - orig_point = rl_point; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_backward_char (count, key); - else -#endif - rl_backward_byte (count, key); - rl_kill_text (orig_point, rl_point); - } - else - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { -#endif - c = rl_line_buffer[--rl_point]; - rl_delete_text (rl_point, rl_point + 1); -#if defined (HANDLE_MULTIBYTE) - } - else - { - int orig_point; - - orig_point = rl_point; - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = rl_line_buffer[rl_point]; - rl_delete_text (rl_point, orig_point); - } -#endif /* HANDLE_MULTIBYTE */ - - /* I don't think that the hack for end of line is needed for - multibyte chars. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX == 1 || rl_byte_oriented) -#endif - 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. */ -int -rl_delete (count, key) - int count, key; -{ - int r; - - if (count < 0) - return (_rl_rubout_char (-count, key)); - - if (rl_point == rl_end) - { - rl_ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - int orig_point = rl_point; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_forward_char (count, key); - else -#endif - rl_forward_byte (count, key); - - r = rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - return r; - } - else - { - int new_point; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - else - new_point = rl_point + 1; - - return (rl_delete_text (rl_point, new_point)); - } -} - -/* Delete the character under the cursor, unless the insertion - point is at the end of the line, in which case the character - behind the cursor is deleted. COUNT is obeyed and may be used - to delete forward or backward that many characters. */ -int -rl_rubout_or_delete (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (_rl_rubout_char (count, key)); - else - return (rl_delete (count, key)); -} - -/* Delete all spaces and tabs around point. */ -int -rl_delete_horizontal_space (count, ignore) - int count, ignore; -{ - int start = rl_point; - - while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) - rl_point--; - - start = rl_point; - - while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) - rl_point++; - - if (start != rl_point) - { - rl_delete_text (start, rl_point); - rl_point = start; - } - return 0; -} - -/* Like the tcsh editing function delete-char-or-list. The eof character - is caught before this is invoked, so this really does the same thing as - delete-char-or-list-or-eof, as long as it's bound to the eof character. */ -int -rl_delete_or_show_completions (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_possible_completions (count, key)); - else - return (rl_delete (count, key)); -} - -#ifndef RL_COMMENT_BEGIN_DEFAULT -#define RL_COMMENT_BEGIN_DEFAULT "#" -#endif - -/* Turn the current line into a comment in shell history. - A K*rn shell style function. */ -int -rl_insert_comment (count, key) - int count, key; -{ - char *rl_comment_text; - int rl_comment_len; - - rl_beg_of_line (1, key); - rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT; - - if (rl_explicit_arg == 0) - rl_insert_text (rl_comment_text); - else - { - rl_comment_len = strlen (rl_comment_text); - if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len)) - rl_delete_text (rl_point, rl_point + rl_comment_len); - else - rl_insert_text (rl_comment_text); - } - - (*rl_redisplay_function) (); - rl_newline (1, '\n'); - - return (0); -} - -/* **************************************************************** */ -/* */ -/* Changing Case */ -/* */ -/* **************************************************************** */ - -/* The three kinds of things that we know how to do. */ -#define UpCase 1 -#define DownCase 2 -#define CapCase 3 - -/* Uppercase the word at point. */ -int -rl_upcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, UpCase)); -} - -/* Lowercase the word at point. */ -int -rl_downcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, DownCase)); -} - -/* Upcase the first letter, downcase the rest. */ -int -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, end; - int inword, c; - - start = rl_point; - rl_forward_word (count, 0); - end = rl_point; - - if (count < 0) - SWAP (start, end); - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - for (inword = 0; start < end; start++) - { - c = rl_line_buffer[start]; - switch (op) - { - case UpCase: - rl_line_buffer[start] = _rl_to_upper (c); - break; - - case DownCase: - rl_line_buffer[start] = _rl_to_lower (c); - break; - - case CapCase: - rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c); - inword = rl_alphabetic (rl_line_buffer[start]); - break; - - default: - rl_ding (); - return -1; - } - } - rl_point = end; - return 0; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. If point is at the end of the line, - transpose the two words before point. */ -int -rl_transpose_words (count, key) - int count, key; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) - return 0; - - /* Find the two words. */ - rl_forward_word (count, key); - w2_end = rl_point; - rl_backward_word (1, key); - w2_beg = rl_point; - rl_backward_word (count, key); - w1_beg = rl_point; - rl_forward_word (1, key); - w1_end = rl_point; - - /* Do some check to make sure that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - rl_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. */ -int -rl_transpose_chars (count, key) - int count, key; -{ -#if defined (HANDLE_MULTIBYTE) - char *dummy; - int i, prev_point; -#else - char dummy[2]; -#endif - int char_length; - - if (count == 0) - return 0; - - if (!rl_point || rl_end < 2) - { - rl_ding (); - return -1; - } - - rl_begin_undo_group (); - - if (rl_point == rl_end) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - else - --rl_point; - count = 1; - } - -#if defined (HANDLE_MULTIBYTE) - prev_point = rl_point; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - else -#endif - rl_point--; - -#if defined (HANDLE_MULTIBYTE) - char_length = prev_point - rl_point; - dummy = (char *)xmalloc (char_length + 1); - for (i = 0; i < char_length; i++) - dummy[i] = rl_line_buffer[rl_point + i]; - dummy[i] = '\0'; -#else - dummy[0] = rl_line_buffer[rl_point]; - dummy[char_length = 1] = '\0'; -#endif - - rl_delete_text (rl_point, rl_point + char_length); - - rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - - _rl_fix_point (0); - rl_insert_text (dummy); - rl_end_undo_group (); - -#if defined (HANDLE_MULTIBYTE) - free (dummy); -#endif - - return 0; -} - -/* **************************************************************** */ -/* */ -/* Character Searching */ -/* */ -/* **************************************************************** */ - -int -#if defined (HANDLE_MULTIBYTE) -_rl_char_search_internal (count, dir, smbchar, len) - int count, dir; - char *smbchar; - int len; -#else -_rl_char_search_internal (count, dir, schar) - int count, dir, schar; -#endif -{ - int pos, inc; -#if defined (HANDLE_MULTIBYTE) - int prepos; -#endif - - pos = rl_point; - inc = (dir < 0) ? -1 : 1; - while (count) - { - if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) - { - rl_ding (); - return -1; - } - -#if defined (HANDLE_MULTIBYTE) - pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) - : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); -#else - pos += inc; -#endif - do - { -#if defined (HANDLE_MULTIBYTE) - if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len)) -#else - if (rl_line_buffer[pos] == schar) -#endif - { - count--; - if (dir < 0) - rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) - : pos; - else - rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY) - : pos; - break; - } -#if defined (HANDLE_MULTIBYTE) - prepos = pos; -#endif - } -#if defined (HANDLE_MULTIBYTE) - while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos - : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos); -#else - while ((dir < 0) ? pos-- : ++pos < rl_end); -#endif - } - return (0); -} - -/* Search COUNT times for a character read from the current input stream. - FDIR is the direction to search if COUNT is non-negative; otherwise - the search goes in BDIR. So much is dependent on HANDLE_MULTIBYTE - that there are two separate versions of this function. */ -#if defined (HANDLE_MULTIBYTE) -static int -_rl_char_search (count, fdir, bdir) - int count, fdir, bdir; -{ - char mbchar[MB_LEN_MAX]; - int mb_len; - - mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX); - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, mbchar, mb_len)); - else - return (_rl_char_search_internal (count, fdir, mbchar, mb_len)); -} -#else /* !HANDLE_MULTIBYTE */ -static int -_rl_char_search (count, fdir, bdir) - int count, fdir, bdir; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, c)); - else - return (_rl_char_search_internal (count, fdir, c)); -} -#endif /* !HANDLE_MULTIBYTE */ - -int -rl_char_search (count, key) - int count, key; -{ - return (_rl_char_search (count, FFIND, BFIND)); -} - -int -rl_backward_char_search (count, key) - int count, key; -{ - return (_rl_char_search (count, BFIND, FFIND)); -} - -/* **************************************************************** */ -/* */ -/* The Mark and the Region. */ -/* */ -/* **************************************************************** */ - -/* Set the mark at POSITION. */ -int -_rl_set_mark_at_pos (position) - int position; -{ - if (position > rl_end) - return -1; - - rl_mark = position; - return 0; -} - -/* A bindable command to set the mark. */ -int -rl_set_mark (count, key) - int count, key; -{ - return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); -} - -/* Exchange the position of mark and point. */ -int -rl_exchange_point_and_mark (count, key) - int count, key; -{ - if (rl_mark > rl_end) - rl_mark = -1; - - if (rl_mark == -1) - { - rl_ding (); - return -1; - } - else - SWAP (rl_point, rl_mark); - - return 0; -} diff --git a/lib/readline/vi_mode.c.save b/lib/readline/vi_mode.c.save deleted file mode 100644 index 4b299e165..000000000 --- a/lib/readline/vi_mode.c.save +++ /dev/null @@ -1,1485 +0,0 @@ -/* 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 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -/* **************************************************************** */ -/* */ -/* VI Emulation Mode */ -/* */ -/* **************************************************************** */ -#include "rlconf.h" - -#if defined (VI_MODE) - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -/* Some standard library routines. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -#ifndef member -#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) -#endif - -/* Non-zero means enter insertion mode. */ -static int _rl_vi_doing_insert; - -/* Command keys which do movement for xxx_to commands. */ -static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; - -/* Keymap used for vi replace characters. Created dynamically since - rarely used. */ -static Keymap vi_replace_map; - -/* The number of characters inserted in the last replace operation. */ -static int vi_replace_count; - -/* If non-zero, we have text inserted after a c[motion] command that put - us implicitly into insert mode. Some people want this text to be - attached to the command so that it is `redoable' with `.'. */ -static int vi_continued_command; -static char *vi_insert_buffer; -static int vi_insert_buffer_size; - -static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ -static int _rl_vi_last_repeat = 1; -static int _rl_vi_last_arg_sign = 1; -static int _rl_vi_last_motion; -#if defined (HANDLE_MULTIBYTE) -static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; -#else -static int _rl_vi_last_search_char; -#endif -static int _rl_vi_last_replacement; - -static int _rl_vi_last_key_before_insert; - -static int vi_redoing; - -/* Text modification commands. These are the `redoable' commands. */ -static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; - -/* Arrays for the saved marks. */ -static int vi_mark_chars['z' - 'a' + 1]; - -static void _rl_vi_stuff_insert PARAMS((int)); -static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); -static int rl_digit_loop1 PARAMS((void)); - -void -_rl_vi_initialize_line () -{ - register int i; - - for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) - vi_mark_chars[i] = -1; -} - -void -_rl_vi_reset_last () -{ - _rl_vi_last_command = 'i'; - _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)); -} - -static void -_rl_vi_stuff_insert (count) - int count; -{ - rl_begin_undo_group (); - while (count--) - rl_insert_text (vi_insert_buffer); - rl_end_undo_group (); -} - -/* Bound to `.'. Called from command mode, so we know that we have to - redo a text modification command. The default for _rl_vi_last_command - puts you back into insert mode. */ -int -rl_vi_redo (count, c) - int count, c; -{ - int r; - - if (!rl_explicit_arg) - { - rl_numeric_arg = _rl_vi_last_repeat; - rl_arg_sign = _rl_vi_last_arg_sign; - } - - r = 0; - vi_redoing = 1; - /* If we're redoing an insert with `i', stuff in the inserted text - and do not go into insertion mode. */ - if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) - { - _rl_vi_stuff_insert (count); - /* And back up point over the last character inserted. */ - if (rl_point > 0) - rl_point--; - } - else - r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); - vi_redoing = 0; - - return (r); -} - -/* A placeholder for further expansion. */ -int -rl_vi_undo (count, key) - int count, key; -{ - return (rl_undo_command (count, key)); -} - -/* Yank the nth arg from the previous line into this line at point. */ -int -rl_vi_yank_arg (count, key) - int count, key; -{ - /* 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. */ -int -rl_vi_fetch_history (count, c) - int count, c; -{ - int wanted; - - /* Giving an argument of n means we want the nth command in the history - file. The command number is interpreted the same way that the bash - `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) - { - wanted = history_base + where_history () - count; - if (wanted <= 0) - rl_beginning_of_history (0, 0); - else - rl_get_previous_history (wanted, c); - } - else - rl_beginning_of_history (count, 0); - return (0); -} - -/* Search again for the last thing searched for. */ -int -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. */ -int -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: - rl_ding (); - break; - } - return (0); -} - -/* Completion, from vi's point of view. */ -int -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. */ -int -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. */ -int -rl_vi_prev_word (count, key) - int count, key; -{ - if (count < 0) - return (rl_vi_next_word (-count, key)); - - if (rl_point == 0) - { - rl_ding (); - return (0); - } - - if (_rl_uppercase_p (key)) - rl_vi_bWord (count, key); - else - rl_vi_bword (count, key); - - return (0); -} - -/* Next word in vi mode. */ -int -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)) - { - rl_ding (); - return (0); - } - - if (_rl_uppercase_p (key)) - rl_vi_fWord (count, key); - else - rl_vi_fword (count, key); - return (0); -} - -/* Move to the end of the ?next? word. */ -int -rl_vi_end_word (count, key) - int count, key; -{ - if (count < 0) - { - rl_ding (); - return -1; - } - - if (_rl_uppercase_p (key)) - rl_vi_eWord (count, key); - else - rl_vi_eword (count, key); - return (0); -} - -/* Move forward a word the way that 'W' does. */ -int -rl_vi_fWord (count, ignore) - int count, ignore; -{ - 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); -} - -int -rl_vi_bWord (count, ignore) - int count, ignore; -{ - 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); -} - -int -rl_vi_eWord (count, ignore) - int count, ignore; -{ - 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); -} - -int -rl_vi_fword (count, ignore) - int count, ignore; -{ - while (count-- && rl_point < (rl_end - 1)) - { - /* Move to white space (really non-identifer). */ - if (_rl_isident (rl_line_buffer[rl_point])) - { - while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) - rl_point++; - } - else /* if (!whitespace (rl_line_buffer[rl_point])) */ - { - while (!_rl_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); -} - -int -rl_vi_bword (count, ignore) - int count, ignore; -{ - 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 = _rl_isident (rl_line_buffer[rl_point - 1]); - if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || - (!_rl_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 (_rl_isident (rl_line_buffer[rl_point])) - while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); - else - while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && - !whitespace (rl_line_buffer[rl_point])); - rl_point++; - } - } - return (0); -} - -int -rl_vi_eword (count, ignore) - int count, ignore; -{ - 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 (_rl_isident (rl_line_buffer[rl_point])) - while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); - else - while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) - && !whitespace (rl_line_buffer[rl_point])); - } - rl_point--; - } - return (0); -} - -int -rl_vi_insert_beg (count, key) - int count, key; -{ - rl_beg_of_line (1, key); - rl_vi_insertion_mode (1, key); - return (0); -} - -int -rl_vi_append_mode (count, key) - int count, key; -{ - if (rl_point < rl_end) - { - if (MB_CUR_MAX == 1 || rl_byte_oriented) - rl_point++; - else - { - int point = rl_point; - rl_forward_char (1, key); - if (point == rl_point) - rl_point = rl_end; - } - } - rl_vi_insertion_mode (1, key); - return (0); -} - -int -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. */ -int -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. */ -int -rl_vi_insertion_mode (count, key) - int count, key; -{ - _rl_keymap = vi_insertion_keymap; - _rl_vi_last_key_before_insert = key; - return (0); -} - -static void -_rl_vi_save_insert (up) - UNDO_LIST *up; -{ - int len, start, end; - - if (up == 0) - { - if (vi_insert_buffer_size >= 1) - vi_insert_buffer[0] = '\0'; - return; - } - - start = up->start; - end = up->end; - len = end - start + 1; - if (len >= vi_insert_buffer_size) - { - vi_insert_buffer_size += (len + 32) - (len % 32); - vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); - } - strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); - vi_insert_buffer[len-1] = '\0'; -} - -void -_rl_vi_done_inserting () -{ - if (_rl_vi_doing_insert) - { - /* The `C', `s', and `S' commands set this. */ - 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. It gets copied to VI_INSERT_BUFFER because it depends - on absolute indices into the line which may change (though they - probably will not). */ - _rl_vi_doing_insert = 0; - _rl_vi_save_insert (rl_undo_list->next); - vi_continued_command = 1; - } - else - { - if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) - _rl_vi_save_insert (rl_undo_list); - /* XXX - Other keys probably need to be checked. */ - else if (_rl_vi_last_key_before_insert == 'C') - rl_end_undo_group (); - while (_rl_undo_group_level > 0) - rl_end_undo_group (); - vi_continued_command = 0; - } -} - -int -rl_vi_movement_mode (count, key) - int count, key; -{ - if (rl_point > 0) - rl_backward_char (1, key); - - _rl_keymap = vi_movement_keymap; - _rl_vi_done_inserting (); - return (0); -} - -int -rl_vi_arg_digit (count, c) - int count, c; -{ - if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) - return (rl_beg_of_line (1, c)); - else - return (rl_digit_argument (count, c)); -} - -/* Change the case of the next COUNT characters. */ -#if defined (HANDLE_MULTIBYTE) -static int -_rl_vi_change_mbchar_case (count) - int count; -{ - wchar_t wc; - char mb[MB_LEN_MAX]; - mbstate_t ps; - - memset (&ps, 0, sizeof (mbstate_t)); - if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) - count--; - while (count-- && rl_point < rl_end) - { - mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); - if (iswupper (wc)) - wc = towlower (wc); - else if (iswlower (wc)) - wc = towupper (wc); - else - { - /* Just skip over chars neither upper nor lower case */ - rl_forward_char (1, 0); - continue; - } - - /* Vi is kind of strange here. */ - if (wc) - { - wctomb (mb, wc); - rl_begin_undo_group (); - rl_delete (1, 0); - rl_insert_text (mb); - rl_end_undo_group (); - rl_vi_check (); - } - else - rl_forward_char (1, 0); - } - - return 0; -} -#endif - -int -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); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - return (_rl_vi_change_mbchar_case (count)); -#endif - - while (count-- && rl_point < rl_end) - { - if (_rl_uppercase_p (rl_line_buffer[rl_point])) - c = _rl_to_lower (rl_line_buffer[rl_point]); - else if (_rl_lowercase_p (rl_line_buffer[rl_point])) - c = _rl_to_upper (rl_line_buffer[rl_point]); - else - { - /* Just skip over characters neither upper nor lower case. */ - rl_forward_char (1, c); - continue; - } - - /* Vi is kind of strange here. */ - if (c) - { - rl_begin_undo_group (); - rl_delete (1, c); - _rl_insert_char (1, c); - rl_end_undo_group (); - rl_vi_check (); - } - else - rl_forward_char (1, c); - } - return (0); -} - -int -rl_vi_put (count, key) - int count, key; -{ - if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) - rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - - rl_yank (1, key); - rl_backward_char (1, key); - return (0); -} - -int -rl_vi_check () -{ - if (rl_point && rl_point == rl_end) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - else - rl_point--; - } - return (0); -} - -int -rl_vi_column (count, key) - int count, key; -{ - if (count > rl_end) - rl_end_of_line (1, key); - 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; - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - *nextkey = c; - - if (!member (c, vi_motion)) - { - if (_rl_digit_p (c)) - { - save = rl_numeric_arg; - rl_numeric_arg = _rl_digit_value (c); - rl_digit_loop1 (); - rl_numeric_arg *= save; - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); /* real command */ - RL_UNSETSTATE(RL_STATE_MOREINPUT); - *nextkey = c; - } - else if (key == c && (key == 'd' || key == 'y' || key == 'c')) - { - rl_mark = rl_end; - rl_beg_of_line (1, c); - _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 ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && - !whitespace (rl_line_buffer[rl_point])) - rl_point--; - - /* If cw or cW, back up to the end of a word, so the behaviour of ce - or cE is the actual result. Brute-force, no subtlety. */ - if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) - { - /* Don't move farther back than where we started. */ - while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) - 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) - SWAP (rl_point, rl_mark); - - return (0); -} - -/* A simplified loop for vi. Don't dispatch key at end. - Don't recognize minus sign? - Should this do rl_save_prompt/rl_restore_prompt? */ -static int -rl_digit_loop1 () -{ - int key, c; - - RL_SETSTATE(RL_STATE_NUMERICARG); - while (1) - { - if (rl_numeric_arg > 1000000) - { - rl_explicit_arg = rl_numeric_arg = 0; - rl_ding (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return 1; - } - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - RL_SETSTATE(RL_STATE_MOREINPUT); - key = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c >= 0 && _rl_keymap[c].type == ISFUNC && - _rl_keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } - - c = UNMETA (c); - if (_rl_digit_p (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); - else - rl_numeric_arg = _rl_digit_value (c); - rl_explicit_arg = 1; - } - else - { - rl_clear_message (); - rl_stuff_char (key); - break; - } - } - - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (0); -} - -int -rl_vi_delete_to (count, key) - int count, key; -{ - int c; - - if (_rl_uppercase_p (key)) - rl_stuff_char ('$'); - else if (vi_redoing) - rl_stuff_char (_rl_vi_last_motion); - - if (rl_vi_domove (key, &c)) - { - rl_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); -} - -int -rl_vi_change_to (count, key) - int count, key; -{ - int c, start_pos; - - if (_rl_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)) - { - rl_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 ((_rl_to_upper (c) == 'W') && rl_point < start_pos) - rl_point = start_pos; - - if (vi_redoing) - { - if (vi_insert_buffer && *vi_insert_buffer) - rl_begin_undo_group (); - rl_delete_text (rl_point, rl_mark); - if (vi_insert_buffer && *vi_insert_buffer) - { - rl_insert_text (vi_insert_buffer); - rl_end_undo_group (); - } - } - else - { - rl_begin_undo_group (); /* to make the `u' command work */ - rl_kill_text (rl_point, rl_mark); - /* `C' does not save the text inserted for undoing or redoing. */ - if (_rl_uppercase_p (key) == 0) - _rl_vi_doing_insert = 1; - _rl_vi_set_last (key, count, rl_arg_sign); - rl_vi_insertion_mode (1, key); - } - - return (0); -} - -int -rl_vi_yank_to (count, key) - int count, key; -{ - int c, save = rl_point; - - if (_rl_uppercase_p (key)) - rl_stuff_char ('$'); - - if (rl_vi_domove (key, &c)) - { - rl_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); -} - -int -rl_vi_delete (count, key) - int count, key; -{ - int end; - - if (rl_end == 0) - { - rl_ding (); - return -1; - } - - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - else - 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_char (1, key); - return (0); -} - -int -rl_vi_back_to_indent (count, key) - int count, key; -{ - rl_beg_of_line (1, key); - while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) - rl_point++; - return (0); -} - -int -rl_vi_first_print (count, key) - int count, key; -{ - return (rl_vi_back_to_indent (1, key)); -} - -int -rl_vi_char_search (count, key) - int count, key; -{ -#if defined (HANDLE_MULTIBYTE) - static char *target; - static int mb_len; -#else - static char target; -#endif - static int orig_dir, dir; - - if (key == ';' || key == ',') - dir = key == ';' ? orig_dir : -orig_dir; - else - { - if (vi_redoing) -#if defined (HANDLE_MULTIBYTE) - target = _rl_vi_last_search_mbchar; -#else - target = _rl_vi_last_search_char; -#endif - else - { -#if defined (HANDLE_MULTIBYTE) - mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); - target = _rl_vi_last_search_mbchar; -#else - RL_SETSTATE(RL_STATE_MOREINPUT); - _rl_vi_last_search_char = target = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); -#endif - } - - 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; - } - } - -#if defined (HANDLE_MULTIBYTE) - return (_rl_char_search_internal (count, dir, target, mb_len)); -#else - return (_rl_char_search_internal (count, dir, target)); -#endif -} - -/* Match brackets */ -int -rl_vi_match (ignore, key) - int ignore, key; -{ - int count = 1, brack, pos, tmp, pre; - - pos = rl_point; - if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) - { - pre = rl_point; - rl_forward_char (1, key); - if (pre == rl_point) - break; - } - } - else - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && - rl_point < rl_end - 1) - rl_forward_char (1, key); - - if (brack <= 0) - { - rl_point = pos; - rl_ding (); - return -1; - } - } - - pos = rl_point; - - if (brack < 0) - { - while (count) - { - tmp = pos; - if (MB_CUR_MAX == 1 || rl_byte_oriented) - pos--; - else - { - pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); - if (tmp == pos) - pos--; - } - if (pos >= 0) - { - int b = rl_vi_bracktype (rl_line_buffer[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - rl_ding (); - return -1; - } - } - } - else - { /* brack > 0 */ - while (count) - { - if (MB_CUR_MAX == 1 || rl_byte_oriented) - pos++; - else - pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); - - if (pos < rl_end) - { - int b = rl_vi_bracktype (rl_line_buffer[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - rl_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; - } -} - -/* XXX - think about reading an entire mbchar with _rl_read_mbchar and - inserting it in one bunch instead of the loop below (like in - rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] - for test against 033 or ^C. Make sure that _rl_read_mbchar does - this right. */ -int -rl_vi_change_char (count, key) - int count, key; -{ - int c; - - if (vi_redoing) - c = _rl_vi_last_replacement; - else - { - RL_SETSTATE(RL_STATE_MOREINPUT); - _rl_vi_last_replacement = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - } - - if (c == '\033' || c == CTRL ('C')) - return -1; - - while (count-- && rl_point < rl_end) - { - rl_begin_undo_group (); - - rl_delete (1, c); -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - while (_rl_insert_char (1, c)) - { - RL_SETSTATE (RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE (RL_STATE_MOREINPUT); - } - else -#endif - _rl_insert_char (1, c); - if (count == 0) - rl_backward_char (1, c); - - rl_end_undo_group (); - } - return (0); -} - -int -rl_vi_subst (count, key) - int count, key; -{ - /* If we are redoing, rl_vi_change_to will stuff the last motion char */ - if (vi_redoing == 0) - rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ - - return (rl_vi_change_to (count, 'c')); -} - -int -rl_vi_overstrike (count, key) - int count, key; -{ - if (_rl_vi_doing_insert == 0) - { - _rl_vi_doing_insert = 1; - rl_begin_undo_group (); - } - - if (count > 0) - { - _rl_overwrite_char (count, key); - vi_replace_count += count; - } - - return (0); -} - -int -rl_vi_overstrike_delete (count, key) - int count, key; -{ - int i, s; - - for (i = 0; i < count; i++) - { - if (vi_replace_count == 0) - { - rl_ding (); - break; - } - s = rl_point; - - if (rl_do_undo ()) - vi_replace_count--; - - if (rl_point == s) - rl_backward_char (1, key); - } - - if (vi_replace_count == 0 && _rl_vi_doing_insert) - { - rl_end_undo_group (); - rl_do_undo (); - _rl_vi_doing_insert = 0; - } - return (0); -} - -int -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 ;. */ -int -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] == ';') - { - rl_ding (); - return (0); - } - - rl_possible_completions (); - rl_point = save_pos; - - return (0); -} -#endif - -/* Functions to save and restore marks. */ -int -rl_vi_set_mark (count, key) - int count, key; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (ch < 'a' || ch > 'z') - { - rl_ding (); - return -1; - } - ch -= 'a'; - vi_mark_chars[ch] = rl_point; - return 0; -} - -int -rl_vi_goto_mark (count, key) - int count, key; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (ch == '`') - { - rl_point = rl_mark; - return 0; - } - else if (ch < 'a' || ch > 'z') - { - rl_ding (); - return -1; - } - - ch -= 'a'; - if (vi_mark_chars[ch] == -1) - { - rl_ding (); - return -1; - } - rl_point = vi_mark_chars[ch]; - return 0; -} - -#endif /* VI_MODE */ diff --git a/lib/readline/vi_mode.c~ b/lib/readline/vi_mode.c~ deleted file mode 100644 index 46e9e4b96..000000000 --- a/lib/readline/vi_mode.c~ +++ /dev/null @@ -1,1499 +0,0 @@ -/* vi_mode.c -- A vi emulation mode for Bash. - Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -/* **************************************************************** */ -/* */ -/* VI Emulation Mode */ -/* */ -/* **************************************************************** */ -#include "rlconf.h" - -#if defined (VI_MODE) - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -/* Some standard library routines. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -#ifndef member -#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) -#endif - -int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ - -/* Non-zero means enter insertion mode. */ -static int _rl_vi_doing_insert; - -/* Command keys which do movement for xxx_to commands. */ -static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; - -/* Keymap used for vi replace characters. Created dynamically since - rarely used. */ -static Keymap vi_replace_map; - -/* The number of characters inserted in the last replace operation. */ -static int vi_replace_count; - -/* If non-zero, we have text inserted after a c[motion] command that put - us implicitly into insert mode. Some people want this text to be - attached to the command so that it is `redoable' with `.'. */ -static int vi_continued_command; -static char *vi_insert_buffer; -static int vi_insert_buffer_size; - -static int _rl_vi_last_repeat = 1; -static int _rl_vi_last_arg_sign = 1; -static int _rl_vi_last_motion; -#if defined (HANDLE_MULTIBYTE) -static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; -#else -static int _rl_vi_last_search_char; -#endif -static int _rl_vi_last_replacement; - -static int _rl_vi_last_key_before_insert; - -static int vi_redoing; - -/* Text modification commands. These are the `redoable' commands. */ -static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; - -/* Arrays for the saved marks. */ -static int vi_mark_chars['z' - 'a' + 1]; - -static void _rl_vi_stuff_insert PARAMS((int)); -static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); -static int rl_digit_loop1 PARAMS((void)); - -void -_rl_vi_initialize_line () -{ - register int i; - - for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) - vi_mark_chars[i] = -1; -} - -void -_rl_vi_reset_last () -{ - _rl_vi_last_command = 'i'; - _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; -} - -/* A convenience function that calls _rl_vi_set_last to save the last command - information and enters insertion mode. */ -void -rl_vi_start_inserting (key, repeat, sign) - int key, repeat, sign; -{ - _rl_vi_set_last (key, repeat, sign); - rl_vi_insertion_mode (1, key); -} - -/* Is the command C a VI mode text modification command? */ -int -_rl_vi_textmod_command (c) - int c; -{ - return (member (c, vi_textmod)); -} - -static void -_rl_vi_stuff_insert (count) - int count; -{ - rl_begin_undo_group (); - while (count--) - rl_insert_text (vi_insert_buffer); - rl_end_undo_group (); -} - -/* Bound to `.'. Called from command mode, so we know that we have to - redo a text modification command. The default for _rl_vi_last_command - puts you back into insert mode. */ -int -rl_vi_redo (count, c) - int count, c; -{ - int r; - - if (!rl_explicit_arg) - { - rl_numeric_arg = _rl_vi_last_repeat; - rl_arg_sign = _rl_vi_last_arg_sign; - } - - r = 0; - vi_redoing = 1; - /* If we're redoing an insert with `i', stuff in the inserted text - and do not go into insertion mode. */ - if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) - { - _rl_vi_stuff_insert (count); - /* And back up point over the last character inserted. */ - if (rl_point > 0) - rl_point--; - } - else - r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); - vi_redoing = 0; - - return (r); -} - -/* A placeholder for further expansion. */ -int -rl_vi_undo (count, key) - int count, key; -{ - return (rl_undo_command (count, key)); -} - -/* Yank the nth arg from the previous line into this line at point. */ -int -rl_vi_yank_arg (count, key) - int count, key; -{ - /* 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. */ -int -rl_vi_fetch_history (count, c) - int count, c; -{ - int wanted; - - /* Giving an argument of n means we want the nth command in the history - file. The command number is interpreted the same way that the bash - `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) - { - wanted = history_base + where_history () - count; - if (wanted <= 0) - rl_beginning_of_history (0, 0); - else - rl_get_previous_history (wanted, c); - } - else - rl_beginning_of_history (count, 0); - return (0); -} - -/* Search again for the last thing searched for. */ -int -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. */ -int -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: - rl_ding (); - break; - } - return (0); -} - -/* Completion, from vi's point of view. */ -int -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_start_inserting (key, 1, rl_arg_sign); - - return (0); -} - -/* Tilde expansion for vi mode. */ -int -rl_vi_tilde_expand (ignore, key) - int ignore, key; -{ - rl_tilde_expand (0, key); - rl_vi_start_inserting (key, 1, rl_arg_sign); - return (0); -} - -/* Previous word in vi mode. */ -int -rl_vi_prev_word (count, key) - int count, key; -{ - if (count < 0) - return (rl_vi_next_word (-count, key)); - - if (rl_point == 0) - { - rl_ding (); - return (0); - } - - if (_rl_uppercase_p (key)) - rl_vi_bWord (count, key); - else - rl_vi_bword (count, key); - - return (0); -} - -/* Next word in vi mode. */ -int -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)) - { - rl_ding (); - return (0); - } - - if (_rl_uppercase_p (key)) - rl_vi_fWord (count, key); - else - rl_vi_fword (count, key); - return (0); -} - -/* Move to the end of the ?next? word. */ -int -rl_vi_end_word (count, key) - int count, key; -{ - if (count < 0) - { - rl_ding (); - return -1; - } - - if (_rl_uppercase_p (key)) - rl_vi_eWord (count, key); - else - rl_vi_eword (count, key); - return (0); -} - -/* Move forward a word the way that 'W' does. */ -int -rl_vi_fWord (count, ignore) - int count, ignore; -{ - 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); -} - -int -rl_vi_bWord (count, ignore) - int count, ignore; -{ - 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); -} - -int -rl_vi_eWord (count, ignore) - int count, ignore; -{ - 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])) - 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); -} - -int -rl_vi_fword (count, ignore) - int count, ignore; -{ - while (count-- && rl_point < (rl_end - 1)) - { - /* Move to white space (really non-identifer). */ - if (_rl_isident (rl_line_buffer[rl_point])) - { - while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) - rl_point++; - } - else /* if (!whitespace (rl_line_buffer[rl_point])) */ - { - while (!_rl_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); -} - -int -rl_vi_bword (count, ignore) - int count, ignore; -{ - 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 = _rl_isident (rl_line_buffer[rl_point - 1]); - if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || - (!_rl_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 (_rl_isident (rl_line_buffer[rl_point])) - while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); - else - while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && - !whitespace (rl_line_buffer[rl_point])); - rl_point++; - } - } - return (0); -} - -int -rl_vi_eword (count, ignore) - int count, ignore; -{ - 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 (_rl_isident (rl_line_buffer[rl_point])) - while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); - else - while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) - && !whitespace (rl_line_buffer[rl_point])); - } - rl_point--; - } - return (0); -} - -int -rl_vi_insert_beg (count, key) - int count, key; -{ - rl_beg_of_line (1, key); - rl_vi_insertion_mode (1, key); - return (0); -} - -int -rl_vi_append_mode (count, key) - int count, key; -{ - if (rl_point < rl_end) - { - if (MB_CUR_MAX == 1 || rl_byte_oriented) - rl_point++; - else - { - int point = rl_point; - rl_forward_char (1, key); - if (point == rl_point) - rl_point = rl_end; - } - } - rl_vi_insertion_mode (1, key); - return (0); -} - -int -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. */ -int -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. */ -int -rl_vi_insertion_mode (count, key) - int count, key; -{ - _rl_keymap = vi_insertion_keymap; - _rl_vi_last_key_before_insert = key; - return (0); -} - -static void -_rl_vi_save_insert (up) - UNDO_LIST *up; -{ - int len, start, end; - - if (up == 0) - { - if (vi_insert_buffer_size >= 1) - vi_insert_buffer[0] = '\0'; - return; - } - - start = up->start; - end = up->end; - len = end - start + 1; - if (len >= vi_insert_buffer_size) - { - vi_insert_buffer_size += (len + 32) - (len % 32); - vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); - } - strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); - vi_insert_buffer[len-1] = '\0'; -} - -void -_rl_vi_done_inserting () -{ - if (_rl_vi_doing_insert) - { - /* The `C', `s', and `S' commands set this. */ - 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. It gets copied to VI_INSERT_BUFFER because it depends - on absolute indices into the line which may change (though they - probably will not). */ - _rl_vi_doing_insert = 0; - _rl_vi_save_insert (rl_undo_list->next); - vi_continued_command = 1; - } - else - { - if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list) - _rl_vi_save_insert (rl_undo_list); - /* XXX - Other keys probably need to be checked. */ - else if (_rl_vi_last_key_before_insert == 'C') - rl_end_undo_group (); - while (_rl_undo_group_level > 0) - rl_end_undo_group (); - vi_continued_command = 0; - } -} - -int -rl_vi_movement_mode (count, key) - int count, key; -{ - if (rl_point > 0) - rl_backward_char (1, key); - - _rl_keymap = vi_movement_keymap; - _rl_vi_done_inserting (); - return (0); -} - -int -rl_vi_arg_digit (count, c) - int count, c; -{ - if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) - return (rl_beg_of_line (1, c)); - else - return (rl_digit_argument (count, c)); -} - -/* Change the case of the next COUNT characters. */ -#if defined (HANDLE_MULTIBYTE) -static int -_rl_vi_change_mbchar_case (count) - int count; -{ - wchar_t wc; - char mb[MB_LEN_MAX+1]; - int mblen; - mbstate_t ps; - - memset (&ps, 0, sizeof (mbstate_t)); - if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) - count--; - while (count-- && rl_point < rl_end) - { - mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); - if (iswupper (wc)) - wc = towlower (wc); - else if (iswlower (wc)) - wc = towupper (wc); - else - { - /* Just skip over chars neither upper nor lower case */ - rl_forward_char (1, 0); - continue; - } - - /* Vi is kind of strange here. */ - if (wc) - { - mblen = wcrtomb (mb, wc, &ps); - if (mblen >= 0) - mb[mblen] = '\0'; - rl_begin_undo_group (); - rl_delete (1, 0); - rl_insert_text (mb); - rl_end_undo_group (); - rl_vi_check (); - } - else - rl_forward_char (1, 0); - } - - return 0; -} -#endif - -int -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); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - return (_rl_vi_change_mbchar_case (count)); -#endif - - while (count-- && rl_point < rl_end) - { - if (_rl_uppercase_p (rl_line_buffer[rl_point])) - c = _rl_to_lower (rl_line_buffer[rl_point]); - else if (_rl_lowercase_p (rl_line_buffer[rl_point])) - c = _rl_to_upper (rl_line_buffer[rl_point]); - else - { - /* Just skip over characters neither upper nor lower case. */ - rl_forward_char (1, c); - continue; - } - - /* Vi is kind of strange here. */ - if (c) - { - rl_begin_undo_group (); - rl_delete (1, c); - _rl_insert_char (1, c); - rl_end_undo_group (); - rl_vi_check (); - } - else - rl_forward_char (1, c); - } - return (0); -} - -int -rl_vi_put (count, key) - int count, key; -{ - if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) - rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - - rl_yank (1, key); - rl_backward_char (1, key); - return (0); -} - -int -rl_vi_check () -{ - if (rl_point && rl_point == rl_end) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - else - rl_point--; - } - return (0); -} - -int -rl_vi_column (count, key) - int count, key; -{ - if (count > rl_end) - rl_end_of_line (1, key); - 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; - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - *nextkey = c; - - if (!member (c, vi_motion)) - { - if (_rl_digit_p (c)) - { - save = rl_numeric_arg; - rl_numeric_arg = _rl_digit_value (c); - rl_explicit_arg = 1; - rl_digit_loop1 (); - rl_numeric_arg *= save; - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); /* real command */ - RL_UNSETSTATE(RL_STATE_MOREINPUT); - *nextkey = c; - } - else if (key == c && (key == 'd' || key == 'y' || key == 'c')) - { - rl_mark = rl_end; - rl_beg_of_line (1, c); - _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 ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && - !whitespace (rl_line_buffer[rl_point])) - rl_point--; - - /* If cw or cW, back up to the end of a word, so the behaviour of ce - or cE is the actual result. Brute-force, no subtlety. */ - if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) - { - /* Don't move farther back than where we started. */ - while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) - 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) - SWAP (rl_point, rl_mark); - - return (0); -} - -/* A simplified loop for vi. Don't dispatch key at end. - Don't recognize minus sign? - Should this do rl_save_prompt/rl_restore_prompt? */ -static int -rl_digit_loop1 () -{ - int key, c; - - RL_SETSTATE(RL_STATE_NUMERICARG); - while (1) - { - if (rl_numeric_arg > 1000000) - { - rl_explicit_arg = rl_numeric_arg = 0; - rl_ding (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return 1; - } - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - RL_SETSTATE(RL_STATE_MOREINPUT); - key = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c >= 0 && _rl_keymap[c].type == ISFUNC && - _rl_keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } - - c = UNMETA (c); - if (_rl_digit_p (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); - else - rl_numeric_arg = _rl_digit_value (c); - rl_explicit_arg = 1; - } - else - { - rl_clear_message (); - rl_stuff_char (key); - break; - } - } - - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (0); -} - -int -rl_vi_delete_to (count, key) - int count, key; -{ - int c; - - if (_rl_uppercase_p (key)) - rl_stuff_char ('$'); - else if (vi_redoing) - rl_stuff_char (_rl_vi_last_motion); - - if (rl_vi_domove (key, &c)) - { - rl_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); -} - -int -rl_vi_change_to (count, key) - int count, key; -{ - int c, start_pos; - - if (_rl_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)) - { - rl_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 ((_rl_to_upper (c) == 'W') && rl_point < start_pos) - rl_point = start_pos; - - if (vi_redoing) - { - if (vi_insert_buffer && *vi_insert_buffer) - rl_begin_undo_group (); - rl_delete_text (rl_point, rl_mark); - if (vi_insert_buffer && *vi_insert_buffer) - { - rl_insert_text (vi_insert_buffer); - rl_end_undo_group (); - } - } - else - { - rl_begin_undo_group (); /* to make the `u' command work */ - rl_kill_text (rl_point, rl_mark); - /* `C' does not save the text inserted for undoing or redoing. */ - if (_rl_uppercase_p (key) == 0) - _rl_vi_doing_insert = 1; - rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); - } - - return (0); -} - -int -rl_vi_yank_to (count, key) - int count, key; -{ - int c, save = rl_point; - - if (_rl_uppercase_p (key)) - rl_stuff_char ('$'); - - if (rl_vi_domove (key, &c)) - { - rl_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); -} - -int -rl_vi_delete (count, key) - int count, key; -{ - int end; - - if (rl_end == 0) - { - rl_ding (); - return -1; - } - - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - else - 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_char (1, key); - return (0); -} - -int -rl_vi_back_to_indent (count, key) - int count, key; -{ - rl_beg_of_line (1, key); - while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) - rl_point++; - return (0); -} - -int -rl_vi_first_print (count, key) - int count, key; -{ - return (rl_vi_back_to_indent (1, key)); -} - -int -rl_vi_char_search (count, key) - int count, key; -{ -#if defined (HANDLE_MULTIBYTE) - static char *target; - static int mb_len; -#else - static char target; -#endif - static int orig_dir, dir; - - if (key == ';' || key == ',') - dir = key == ';' ? orig_dir : -orig_dir; - else - { - if (vi_redoing) -#if defined (HANDLE_MULTIBYTE) - target = _rl_vi_last_search_mbchar; -#else - target = _rl_vi_last_search_char; -#endif - else - { -#if defined (HANDLE_MULTIBYTE) - mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); - target = _rl_vi_last_search_mbchar; -#else - RL_SETSTATE(RL_STATE_MOREINPUT); - _rl_vi_last_search_char = target = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); -#endif - } - - 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; - } - } - -#if defined (HANDLE_MULTIBYTE) - return (_rl_char_search_internal (count, dir, target, mb_len)); -#else - return (_rl_char_search_internal (count, dir, target)); -#endif -} - -/* Match brackets */ -int -rl_vi_match (ignore, key) - int ignore, key; -{ - int count = 1, brack, pos, tmp, pre; - - pos = rl_point; - if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) - { - pre = rl_point; - rl_forward_char (1, key); - if (pre == rl_point) - break; - } - } - else - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && - rl_point < rl_end - 1) - rl_forward_char (1, key); - - if (brack <= 0) - { - rl_point = pos; - rl_ding (); - return -1; - } - } - - pos = rl_point; - - if (brack < 0) - { - while (count) - { - tmp = pos; - if (MB_CUR_MAX == 1 || rl_byte_oriented) - pos--; - else - { - pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); - if (tmp == pos) - pos--; - } - if (pos >= 0) - { - int b = rl_vi_bracktype (rl_line_buffer[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - rl_ding (); - return -1; - } - } - } - else - { /* brack > 0 */ - while (count) - { - if (MB_CUR_MAX == 1 || rl_byte_oriented) - pos++; - else - pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); - - if (pos < rl_end) - { - int b = rl_vi_bracktype (rl_line_buffer[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - rl_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; - } -} - -/* XXX - think about reading an entire mbchar with _rl_read_mbchar and - inserting it in one bunch instead of the loop below (like in - rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0] - for test against 033 or ^C. Make sure that _rl_read_mbchar does - this right. */ -int -rl_vi_change_char (count, key) - int count, key; -{ - int c, p; - - if (vi_redoing) - c = _rl_vi_last_replacement; - else - { - RL_SETSTATE(RL_STATE_MOREINPUT); - _rl_vi_last_replacement = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - } - - if (c == '\033' || c == CTRL ('C')) - return -1; - - rl_begin_undo_group (); - while (count-- && rl_point < rl_end) - { - p = rl_point; - rl_vi_delete (1, c); -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - while (_rl_insert_char (1, c)) - { - RL_SETSTATE (RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE (RL_STATE_MOREINPUT); - } - else -#endif - { - if (rl_point < p) /* Did we retreat at EOL? */ - rl_point++; - _rl_insert_char (1, c); - } - } - rl_end_undo_group (); - - return (0); -} - -int -rl_vi_subst (count, key) - int count, key; -{ - /* If we are redoing, rl_vi_change_to will stuff the last motion char */ - if (vi_redoing == 0) - rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ - - return (rl_vi_change_to (count, 'c')); -} - -int -rl_vi_overstrike (count, key) - int count, key; -{ - if (_rl_vi_doing_insert == 0) - { - _rl_vi_doing_insert = 1; - rl_begin_undo_group (); - } - - if (count > 0) - { - _rl_overwrite_char (count, key); - vi_replace_count += count; - } - - return (0); -} - -int -rl_vi_overstrike_delete (count, key) - int count, key; -{ - int i, s; - - for (i = 0; i < count; i++) - { - if (vi_replace_count == 0) - { - rl_ding (); - break; - } - s = rl_point; - - if (rl_do_undo ()) - vi_replace_count--; - - if (rl_point == s) - rl_backward_char (1, key); - } - - if (vi_replace_count == 0 && _rl_vi_doing_insert) - { - rl_end_undo_group (); - rl_do_undo (); - _rl_vi_doing_insert = 0; - } - return (0); -} - -int -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 ;. */ -int -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] == ';') - { - rl_ding (); - return (0); - } - - rl_possible_completions (); - rl_point = save_pos; - - return (0); -} -#endif - -/* Functions to save and restore marks. */ -int -rl_vi_set_mark (count, key) - int count, key; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (ch < 'a' || ch > 'z') - { - rl_ding (); - return -1; - } - ch -= 'a'; - vi_mark_chars[ch] = rl_point; - return 0; -} - -int -rl_vi_goto_mark (count, key) - int count, key; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (ch == '`') - { - rl_point = rl_mark; - return 0; - } - else if (ch < 'a' || ch > 'z') - { - rl_ding (); - return -1; - } - - ch -= 'a'; - if (vi_mark_chars[ch] == -1) - { - rl_ding (); - return -1; - } - rl_point = vi_mark_chars[ch]; - return 0; -} - -#endif /* VI_MODE */ diff --git a/lib/sh/strftime.c~ b/lib/sh/strftime.c~ deleted file mode 100644 index 253d1df4c..000000000 --- a/lib/sh/strftime.c~ +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Modified slightly by Chet Ramey for inclusion in Bash - */ - -/* - * strftime.c - * - * Public-domain implementation of ISO C library routine. - * - * If you can't do prototypes, get GCC. - * - * The C99 standard now specifies just about all of the formats - * that were additional in the earlier versions of this file. - * - * For extensions from SunOS, add SUNOS_EXT. - * For extensions from HP/UX, add HPUX_EXT. - * For VMS dates, add VMS_EXT. - * For complete POSIX semantics, add POSIX_SEMANTICS. - * - * The code for %c, %x, and %X follows the C99 specification for - * the "C" locale. - * - * This version ignores LOCALE information. - * It also doesn't worry about multi-byte characters. - * So there. - * - * This file is also shipped with GAWK (GNU Awk), gawk specific bits of - * code are included if GAWK is defined. - * - * Arnold Robbins - * January, February, March, 1991 - * Updated March, April 1992 - * Updated April, 1993 - * Updated February, 1994 - * Updated May, 1994 - * Updated January, 1995 - * Updated September, 1995 - * Updated January, 1996 - * Updated July, 1997 - * Updated October, 1999 - * Updated September, 2000 - * - * Fixes from ado@elsie.nci.nih.gov, - * February 1991, May 1992 - * Fixes from Tor Lillqvist tml@tik.vtt.fi, - * May 1993 - * Further fixes from ado@elsie.nci.nih.gov, - * February 1994 - * %z code from chip@chinacat.unicom.com, - * Applied September 1995 - * %V code fixed (again) and %G, %g added, - * January 1996 - * %v code fixed, better configuration, - * July 1997 - * Moved to C99 specification. - * September 2000 - */ -#include - -#ifndef GAWK -#include -#include -#include -#endif -#if defined(TM_IN_SYS_TIME) -#include -#include -#endif - -#include -#include - -/* defaults: season to taste */ -#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */ -#define VMS_EXT 1 /* include %v for VMS date format */ -#define HPUX_EXT 1 /* non-conflicting stuff in HP-UX date */ -#ifndef GAWK -#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */ -#endif - -#undef strchr /* avoid AIX weirdness */ - -extern void tzset(void); -static int weeknumber(const struct tm *timeptr, int firstweekday); -static int iso8601wknum(const struct tm *timeptr); - -#ifdef __GNUC__ -#define inline __inline__ -#else -#define inline /**/ -#endif - -#define range(low, item, hi) max(low, min(item, hi)) - -#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) -extern char *tzname[2]; -extern int daylight; -#if defined(SOLARIS) || defined(mips) -extern long int timezone, altzone; -#else -extern int timezone, altzone; -#endif -#endif - -#undef min /* just in case */ - -/* min --- return minimum of two numbers */ - -static inline int -min(int a, int b) -{ - return (a < b ? a : b); -} - -#undef max /* also, just in case */ - -/* max --- return maximum of two numbers */ - -static inline int -max(int a, int b) -{ - return (a > b ? a : b); -} - -/* strftime --- produce formatted time */ - -size_t -strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) -{ - char *endp = s + maxsize; - char *start = s; - auto char tbuf[100]; - long off; - int i, w, y; - static short first = 1; -#ifdef POSIX_SEMANTICS - static char *savetz = NULL; - static int savetzlen = 0; - char *tz; -#endif /* POSIX_SEMANTICS */ -#ifndef HAVE_TM_ZONE -#ifndef HAVE_TM_NAME -#ifndef HAVE_TZNAME - extern char *timezone(); - struct timeval tv; - struct timezone zone; -#endif /* HAVE_TZNAME */ -#endif /* HAVE_TM_NAME */ -#endif /* HAVE_TM_ZONE */ - - /* various tables, useful in North America */ - static const char *days_a[] = { - "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat", - }; - static const char *days_l[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", - }; - static const char *months_a[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - static const char *months_l[] = { - "January", "February", "March", "April", - "May", "June", "July", "August", "September", - "October", "November", "December", - }; - static const char *ampm[] = { "AM", "PM", }; - - if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0) - return 0; - - /* quick check if we even need to bother */ - if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) - return 0; - -#ifndef POSIX_SEMANTICS - if (first) { - tzset(); - first = 0; - } -#else /* POSIX_SEMANTICS */ -#if defined (SHELL) - tz = get_string_value ("TZ"); -#else - tz = getenv("TZ"); -#endif - if (first) { - if (tz != NULL) { - int tzlen = strlen(tz); - - savetz = (char *) malloc(tzlen + 1); - if (savetz != NULL) { - savetzlen = tzlen + 1; - strcpy(savetz, tz); - } - } - tzset(); - first = 0; - } - /* if we have a saved TZ, and it is different, recapture and reset */ - if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) { - i = strlen(tz) + 1; - if (i > savetzlen) { - savetz = (char *) realloc(savetz, i); - if (savetz) { - savetzlen = i; - strcpy(savetz, tz); - } - } else - strcpy(savetz, tz); - tzset(); - } -#endif /* POSIX_SEMANTICS */ - - for (; *format && s < endp - 1; format++) { - tbuf[0] = '\0'; - if (*format != '%') { - *s++ = *format; - continue; - } - again: - switch (*++format) { - case '\0': - *s++ = '%'; - goto out; - - case '%': - *s++ = '%'; - continue; - - case 'a': /* abbreviated weekday name */ - if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) - strcpy(tbuf, "?"); - else - strcpy(tbuf, days_a[timeptr->tm_wday]); - break; - - case 'A': /* full weekday name */ - if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) - strcpy(tbuf, "?"); - else - strcpy(tbuf, days_l[timeptr->tm_wday]); - break; - - case 'b': /* abbreviated month name */ - short_month: - if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) - strcpy(tbuf, "?"); - else - strcpy(tbuf, months_a[timeptr->tm_mon]); - break; - - case 'B': /* full month name */ - if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) - strcpy(tbuf, "?"); - else - strcpy(tbuf, months_l[timeptr->tm_mon]); - break; - - case 'c': /* appropriate date and time representation */ - /* - * This used to be: - * - * strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr); - * - * Now, per the ISO 1999 C standard, it this: - */ - strftime(tbuf, sizeof tbuf, "%A %B %d %T %Y", timeptr); - break; - - case 'C': - century: - sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100); - break; - - case 'd': /* day of the month, 01 - 31 */ - i = range(1, timeptr->tm_mday, 31); - sprintf(tbuf, "%02d", i); - break; - - case 'D': /* date as %m/%d/%y */ - strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); - break; - - case 'e': /* day of month, blank padded */ - sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31)); - break; - - case 'E': - /* POSIX (now C99) locale extensions, ignored for now */ - goto again; - - case 'F': /* ISO 8601 date representation */ - strftime(tbuf, sizeof tbuf, "%Y-%m-%d", timeptr); - break; - - case 'g': - case 'G': - /* - * Year of ISO week. - * - * If it's December but the ISO week number is one, - * that week is in next year. - * If it's January but the ISO week number is 52 or - * 53, that week is in last year. - * Otherwise, it's this year. - */ - w = iso8601wknum(timeptr); - if (timeptr->tm_mon == 11 && w == 1) - y = 1900 + timeptr->tm_year + 1; - else if (timeptr->tm_mon == 0 && w >= 52) - y = 1900 + timeptr->tm_year - 1; - else - y = 1900 + timeptr->tm_year; - - if (*format == 'G') - sprintf(tbuf, "%d", y); - else - sprintf(tbuf, "%02d", y % 100); - break; - - case 'h': /* abbreviated month name */ - goto short_month; - - case 'H': /* hour, 24-hour clock, 00 - 23 */ - i = range(0, timeptr->tm_hour, 23); - sprintf(tbuf, "%02d", i); - break; - - case 'I': /* hour, 12-hour clock, 01 - 12 */ - i = range(0, timeptr->tm_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - sprintf(tbuf, "%02d", i); - break; - - case 'j': /* day of the year, 001 - 366 */ - sprintf(tbuf, "%03d", timeptr->tm_yday + 1); - break; - - case 'm': /* month, 01 - 12 */ - i = range(0, timeptr->tm_mon, 11); - sprintf(tbuf, "%02d", i + 1); - break; - - case 'M': /* minute, 00 - 59 */ - i = range(0, timeptr->tm_min, 59); - sprintf(tbuf, "%02d", i); - break; - - case 'n': /* same as \n */ - tbuf[0] = '\n'; - tbuf[1] = '\0'; - break; - - case 'O': - /* POSIX (now C99) locale extensions, ignored for now */ - goto again; - - case 'p': /* am or pm based on 12-hour clock */ - i = range(0, timeptr->tm_hour, 23); - if (i < 12) - strcpy(tbuf, ampm[0]); - else - strcpy(tbuf, ampm[1]); - break; - - case 'r': /* time as %I:%M:%S %p */ - strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr); - break; - - case 'R': /* time as %H:%M */ - strftime(tbuf, sizeof tbuf, "%H:%M", timeptr); - break; - -#if defined(HAVE_MKTIME) || defined(GAWK) - case 's': /* time as seconds since the Epoch */ - { - struct tm non_const_timeptr; - - non_const_timeptr = *timeptr; - sprintf(tbuf, "%ld", mktime(& non_const_timeptr)); - break; - } -#endif /* defined(HAVE_MKTIME) || defined(GAWK) */ - - case 'S': /* second, 00 - 60 */ - i = range(0, timeptr->tm_sec, 60); - sprintf(tbuf, "%02d", i); - break; - - case 't': /* same as \t */ - tbuf[0] = '\t'; - tbuf[1] = '\0'; - break; - - case 'T': /* time as %H:%M:%S */ - the_time: - strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); - break; - - case 'u': - /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */ - sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 : - timeptr->tm_wday); - break; - - case 'U': /* week of year, Sunday is first day of week */ - sprintf(tbuf, "%02d", weeknumber(timeptr, 0)); - break; - - case 'V': /* week of year according ISO 8601 */ - sprintf(tbuf, "%02d", iso8601wknum(timeptr)); - break; - - case 'w': /* weekday, Sunday == 0, 0 - 6 */ - i = range(0, timeptr->tm_wday, 6); - sprintf(tbuf, "%d", i); - break; - - case 'W': /* week of year, Monday is first day of week */ - sprintf(tbuf, "%02d", weeknumber(timeptr, 1)); - break; - - case 'x': /* appropriate date representation */ - strftime(tbuf, sizeof tbuf, "%A %B %d %Y", timeptr); - break; - - case 'X': /* appropriate time representation */ - goto the_time; - break; - - case 'y': /* year without a century, 00 - 99 */ - year: - i = timeptr->tm_year % 100; - sprintf(tbuf, "%02d", i); - break; - - case 'Y': /* year with century */ - fullyear: - sprintf(tbuf, "%d", 1900 + timeptr->tm_year); - break; - - /* - * From: Chip Rosenthal - * Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST) - * - * Warning: the %z [code] is implemented by inspecting the - * timezone name conditional compile settings, and - * inferring a method to get timezone offsets. I've tried - * this code on a couple of machines, but I don't doubt - * there is some system out there that won't like it. - * Maybe the easiest thing to do would be to bracket this - * with an #ifdef that can turn it off. The %z feature - * would be an admittedly obscure one that most folks can - * live without, but it would be a great help to those of - * us that muck around with various message processors. - */ - case 'z': /* time zone offset east of GMT e.g. -0600 */ -#ifdef HAVE_TM_NAME - /* - * Systems with tm_name probably have tm_tzadj as - * secs west of GMT. Convert to mins east of GMT. - */ - off = -timeptr->tm_tzadj / 60; -#else /* !HAVE_TM_NAME */ -#ifdef HAVE_TM_ZONE - /* - * Systems with tm_zone probably have tm_gmtoff as - * secs east of GMT. Convert to mins east of GMT. - */ - off = timeptr->tm_gmtoff / 60; -#else /* !HAVE_TM_ZONE */ -#if HAVE_TZNAME - /* - * Systems with tzname[] probably have timezone as - * secs west of GMT. Convert to mins east of GMT. - */ - off = -(daylight ? timezone : altzone) / 60; -#else /* !HAVE_TZNAME */ - off = -zone.tz_minuteswest; -#endif /* !HAVE_TZNAME */ -#endif /* !HAVE_TM_ZONE */ -#endif /* !HAVE_TM_NAME */ - if (off < 0) { - tbuf[0] = '-'; - off = -off; - } else { - tbuf[0] = '+'; - } - sprintf(tbuf+1, "%02d%02d", off/60, off%60); - break; - - case 'Z': /* time zone name or abbrevation */ -#ifdef HAVE_TZNAME - i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */ - strcpy(tbuf, tzname[i]); -#else -#ifdef HAVE_TM_ZONE - strcpy(tbuf, timeptr->tm_zone); -#else -#ifdef HAVE_TM_NAME - strcpy(tbuf, timeptr->tm_name); -#else - gettimeofday(& tv, & zone); - strcpy(tbuf, timezone(zone.tz_minuteswest, - timeptr->tm_isdst > 0)); -#endif /* HAVE_TM_NAME */ -#endif /* HAVE_TM_ZONE */ -#endif /* HAVE_TZNAME */ - break; - -#ifdef SUNOS_EXT - case 'k': /* hour, 24-hour clock, blank pad */ - sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23)); - break; - - case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ - i = range(0, timeptr->tm_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - sprintf(tbuf, "%2d", i); - break; -#endif - -#ifdef HPUX_EXT - case 'N': /* Emperor/Era name */ - /* this is essentially the same as the century */ - goto century; /* %C */ - - case 'o': /* Emperor/Era year */ - goto year; /* %y */ -#endif /* HPUX_EXT */ - - -#ifdef VMS_EXT - case 'v': /* date as dd-bbb-YYYY */ - sprintf(tbuf, "%2d-%3.3s-%4d", - range(1, timeptr->tm_mday, 31), - months_a[range(0, timeptr->tm_mon, 11)], - timeptr->tm_year + 1900); - for (i = 3; i < 6; i++) - if (islower(tbuf[i])) - tbuf[i] = toupper(tbuf[i]); - break; -#endif - - default: - tbuf[0] = '%'; - tbuf[1] = *format; - tbuf[2] = '\0'; - break; - } - i = strlen(tbuf); - if (i) { - if (s + i < endp - 1) { - strcpy(s, tbuf); - s += i; - } else - return 0; - } - } -out: - if (s < endp && *format == '\0') { - *s = '\0'; - return (s - start); - } else - return 0; -} - -/* isleap --- is a year a leap year? */ - -static int -isleap(int year) -{ - return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); -} - - -/* iso8601wknum --- compute week number according to ISO 8601 */ - -static int -iso8601wknum(const struct tm *timeptr) -{ - /* - * From 1003.2: - * If the week (Monday to Sunday) containing January 1 - * has four or more days in the new year, then it is week 1; - * otherwise it is the highest numbered week of the previous - * year (52 or 53), and the next week is week 1. - * - * ADR: This means if Jan 1 was Monday through Thursday, - * it was week 1, otherwise week 52 or 53. - * - * XPG4 erroneously included POSIX.2 rationale text in the - * main body of the standard. Thus it requires week 53. - */ - - int weeknum, jan1day, diff; - - /* get week number, Monday as first day of the week */ - weeknum = weeknumber(timeptr, 1); - - /* - * With thanks and tip of the hatlo to tml@tik.vtt.fi - * - * What day of the week does January 1 fall on? - * We know that - * (timeptr->tm_yday - jan1.tm_yday) MOD 7 == - * (timeptr->tm_wday - jan1.tm_wday) MOD 7 - * and that - * jan1.tm_yday == 0 - * and that - * timeptr->tm_wday MOD 7 == timeptr->tm_wday - * from which it follows that. . . - */ - jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7); - if (jan1day < 0) - jan1day += 7; - - /* - * If Jan 1 was a Monday through Thursday, it was in - * week 1. Otherwise it was last year's highest week, which is - * this year's week 0. - * - * What does that mean? - * If Jan 1 was Monday, the week number is exactly right, it can - * never be 0. - * If it was Tuesday through Thursday, the weeknumber is one - * less than it should be, so we add one. - * Otherwise, Friday, Saturday or Sunday, the week number is - * OK, but if it is 0, it needs to be 52 or 53. - */ - switch (jan1day) { - case 1: /* Monday */ - break; - case 2: /* Tuesday */ - case 3: /* Wednesday */ - case 4: /* Thursday */ - weeknum++; - break; - case 5: /* Friday */ - case 6: /* Saturday */ - case 0: /* Sunday */ - if (weeknum == 0) { -#ifdef USE_BROKEN_XPG4 - /* XPG4 (as of March 1994) says 53 unconditionally */ - weeknum = 53; -#else - /* get week number of last week of last year */ - struct tm dec31ly; /* 12/31 last year */ - dec31ly = *timeptr; - dec31ly.tm_year--; - dec31ly.tm_mon = 11; - dec31ly.tm_mday = 31; - dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; - dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900); - weeknum = iso8601wknum(& dec31ly); -#endif - } - break; - } - - if (timeptr->tm_mon == 11) { - /* - * The last week of the year - * can be in week 1 of next year. - * Sigh. - * - * This can only happen if - * M T W - * 29 30 31 - * 30 31 - * 31 - */ - int wday, mday; - - wday = timeptr->tm_wday; - mday = timeptr->tm_mday; - if ( (wday == 1 && (mday >= 29 && mday <= 31)) - || (wday == 2 && (mday == 30 || mday == 31)) - || (wday == 3 && mday == 31)) - weeknum = 1; - } - - return weeknum; -} - -/* weeknumber --- figure how many weeks into the year */ - -/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */ - -static int -weeknumber(const struct tm *timeptr, int firstweekday) -{ - int wday = timeptr->tm_wday; - int ret; - - if (firstweekday == 1) { - if (wday == 0) /* sunday */ - wday = 6; - else - wday--; - } - ret = ((timeptr->tm_yday + 7 - wday) / 7); - if (ret < 0) - ret = 0; - return ret; -} - -#if 0 -/* ADR --- I'm loathe to mess with ado's code ... */ - -Date: Wed, 24 Apr 91 20:54:08 MDT -From: Michal Jaegermann -To: arnold@audiofax.com - -Hi Arnold, -in a process of fixing of strftime() in libraries on Atari ST I grabbed -some pieces of code from your own strftime. When doing that it came -to mind that your weeknumber() function compiles a little bit nicer -in the following form: -/* - * firstweekday is 0 if starting in Sunday, non-zero if in Monday - */ -{ - return (timeptr->tm_yday - timeptr->tm_wday + - (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7; -} -How nicer it depends on a compiler, of course, but always a tiny bit. - - Cheers, - Michal - ntomczak@vm.ucs.ualberta.ca -#endif - -#ifdef TEST_STRFTIME - -/* - * NAME: - * tst - * - * SYNOPSIS: - * tst - * - * DESCRIPTION: - * "tst" is a test driver for the function "strftime". - * - * OPTIONS: - * None. - * - * AUTHOR: - * Karl Vogel - * Control Data Systems, Inc. - * vogelke@c-17igp.wpafb.af.mil - * - * BUGS: - * None noticed yet. - * - * COMPILE: - * cc -o tst -DTEST_STRFTIME strftime.c - */ - -/* ADR: I reformatted this to my liking, and deleted some unneeded code. */ - -#ifndef NULL -#include -#endif -#include -#include - -#define MAXTIME 132 - -/* - * Array of time formats. - */ - -static char *array[] = -{ - "(%%A) full weekday name, var length (Sunday..Saturday) %A", - "(%%B) full month name, var length (January..December) %B", - "(%%C) Century %C", - "(%%D) date (%%m/%%d/%%y) %D", - "(%%E) Locale extensions (ignored) %E", - "(%%F) full month name, var length (January..December) %F", - "(%%H) hour (24-hour clock, 00..23) %H", - "(%%I) hour (12-hour clock, 01..12) %I", - "(%%M) minute (00..59) %M", - "(%%N) Emporer/Era Name %N", - "(%%O) Locale extensions (ignored) %O", - "(%%R) time, 24-hour (%%H:%%M) %R", - "(%%S) second (00..60) %S", - "(%%T) time, 24-hour (%%H:%%M:%%S) %T", - "(%%U) week of year, Sunday as first day of week (00..53) %U", - "(%%V) week of year according to ISO 8601 %V", - "(%%W) week of year, Monday as first day of week (00..53) %W", - "(%%X) appropriate locale time representation (%H:%M:%S) %X", - "(%%Y) year with century (1970...) %Y", - "(%%Z) timezone (EDT), or blank if timezone not determinable %Z", - "(%%a) locale's abbreviated weekday name (Sun..Sat) %a", - "(%%b) locale's abbreviated month name (Jan..Dec) %b", - "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c", - "(%%d) day of the month (01..31) %d", - "(%%e) day of the month, blank-padded ( 1..31) %e", - "(%%h) should be same as (%%b) %h", - "(%%j) day of the year (001..366) %j", - "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k", - "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l", - "(%%m) month (01..12) %m", - "(%%o) Emporer/Era Year %o", - "(%%p) locale's AM or PM based on 12-hour clock %p", - "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r", - "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u", - "(%%v) VMS date (dd-bbb-YYYY) %v", - "(%%w) day of week (0..6, Sunday == 0) %w", - "(%%x) appropriate locale date representation %x", - "(%%y) last two digits of year (00..99) %y", - "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z", - (char *) NULL -}; - -/* main routine. */ - -int -main(argc, argv) -int argc; -char **argv; -{ - long time(); - - char *next; - char string[MAXTIME]; - - int k; - int length; - - struct tm *tm; - - long clock; - - /* Call the function. */ - - clock = time((long *) 0); - tm = localtime(&clock); - - for (k = 0; next = array[k]; k++) { - length = strftime(string, MAXTIME, next, tm); - printf("%s\n", string); - } - - exit(0); -} -#endif /* TEST_STRFTIME */ diff --git a/parse.y~ b/parse.y~ deleted file mode 100644 index 03819993f..000000000 --- a/parse.y~ +++ /dev/null @@ -1,4851 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 LICENSE. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -%{ -#include "config.h" - -#include "bashtypes.h" -#include "bashansi.h" - -#include "filecntl.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include -#include "chartypes.h" -#include - -#include "memalloc.h" - -#include "bashintl.h" - -#define NEED_STRFTIME_DECL /* used in externs.h */ - -#include "shell.h" -#include "trap.h" -#include "flags.h" -#include "parser.h" -#include "mailcheck.h" -#include "test.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#include "shmbutil.h" - -#if defined (READLINE) -# include "bashline.h" -# 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" -#else -typedef void *alias_t; -#endif /* ALIAS */ - -#if defined (PROMPT_STRING_DECODE) -# ifndef _MINIX -# include -# endif -# include -# if defined (TM_IN_SYS_TIME) -# include -# include -# endif /* TM_IN_SYS_TIME */ -# include "maxpath.h" -#endif /* PROMPT_STRING_DECODE */ - -#define RE_READ_TOKEN -99 -#define NO_EXPANSION -100 - -#ifdef DEBUG -# define YYDEBUG 1 -#else -# define YYDEBUG 0 -#endif - -#if defined (HANDLE_MULTIBYTE) -# define last_shell_getc_is_singlebyte \ - ((shell_input_line_index > 1) \ - ? shell_input_line_property[shell_input_line_index - 1] \ - : 1) -# define MBTEST(x) ((x) && last_shell_getc_is_singlebyte) -#else -# define last_shell_getc_is_singlebyte 1 -# define MBTEST(x) ((x)) -#endif - -#if defined (EXTENDED_GLOB) -extern int extended_glob; -#endif - -extern int eof_encountered; -extern int no_line_editing, running_under_emacs; -extern int current_command_number; -extern int sourcelevel; -extern int posixly_correct; -extern int last_command_exit_value; -extern int interrupt_immediately; -extern char *shell_name, *current_host_name; -extern char *dist_version; -extern int patch_level; -extern int dump_translatable_strings, dump_po_strings; -extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; -#if defined (BUFFERED_INPUT) -extern int bash_input_fd_changed; -#endif - -extern int errno; -/* **************************************************************** */ -/* */ -/* "Forward" declarations */ -/* */ -/* **************************************************************** */ - -#ifdef DEBUG -static void debug_parser __P((int)); -#endif - -static int yy_getc __P((void)); -static int yy_ungetc __P((int)); - -#if defined (READLINE) -static int yy_readline_get __P((void)); -static int yy_readline_unget __P((int)); -#endif - -static int yy_string_get __P((void)); -static int yy_string_unget __P((int)); -static int yy_stream_get __P((void)); -static int yy_stream_unget __P((int)); - -static int shell_getc __P((int)); -static void shell_ungetc __P((int)); -static void discard_until __P((int)); - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) -static void push_string __P((char *, int, alias_t *)); -static void pop_string __P((void)); -static void free_string_list __P((void)); -#endif - -static char *read_a_line __P((int)); - -static int reserved_word_acceptable __P((int)); -static int yylex __P((void)); -static int alias_expand_token __P((char *)); -static int time_command_acceptable __P((void)); -static int special_case_tokens __P((char *)); -static int read_token __P((int)); -static char *parse_matched_pair __P((int, int, int, int *, int)); -#if defined (ARRAY_VARS) -static char *parse_compound_assignment __P((int *)); -#endif -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -static int parse_dparen __P((int)); -static int parse_arith_cmd __P((char **, int)); -#endif -#if defined (COND_COMMAND) -static void cond_error __P((void)); -static COND_COM *cond_expr __P((void)); -static COND_COM *cond_or __P((void)); -static COND_COM *cond_and __P((void)); -static COND_COM *cond_term __P((void)); -static int cond_skip_newlines __P((void)); -static COMMAND *parse_cond_command __P((void)); -#endif -#if defined (ARRAY_VARS) -static int token_is_assignment __P((char *, int)); -static int token_is_ident __P((char *, int)); -#endif -static int read_token_word __P((int)); -static void discard_parser_constructs __P((int)); - -static char *error_token_from_token __P((int)); -static char *error_token_from_text __P((void)); -static void print_offending_line __P((void)); -static void report_syntax_error __P((char *)); - -static void handle_eof_input_unit __P((void)); -static void prompt_again __P((void)); -#if 0 -static void reset_readline_prompt __P((void)); -#endif -static void print_prompt __P((void)); - -#if defined (HISTORY) -char *history_delimiting_chars __P((void)); -#endif - -#if defined (HANDLE_MULTIBYTE) -static void set_line_mbstate __P((void)); -static char *shell_input_line_property = NULL; -#else -# define set_line_mbstate() -#endif - -extern int yyerror __P((const char *)); - -#ifdef DEBUG -extern int yydebug; -#endif - -/* Default prompt strings */ -char *primary_prompt = PPROMPT; -char *secondary_prompt = SPROMPT; - -/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ -char *ps1_prompt, *ps2_prompt; - -/* Handle on the current prompt string. Indirectly points through - ps1_ or ps2_prompt. */ -char **prompt_string_pointer = (char **)NULL; -char *current_prompt_string; - -/* Non-zero means we expand aliases in commands. */ -int expand_aliases = 0; - -/* If non-zero, the decoded prompt string undergoes parameter and - variable substitution, command substitution, arithmetic substitution, - string expansion, process substitution, and quote removal in - decode_prompt_string. */ -int promptvars = 1; - -/* If non-zero, $'...' and $"..." are expanded when they appear within - a ${...} expansion, even when the expansion appears within double - quotes. */ -int extended_quote = 1; - -/* The decoded prompt string. Used if READLINE is not defined or if - editing is turned off. Analogous to current_readline_prompt. */ -static char *current_decoded_prompt; - -/* The number of lines read from input while creating the current command. */ -int current_command_line_count; - -/* 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; - -/* 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; -static int shell_input_line_size; /* Amount allocated for shell_input_line. */ -static int shell_input_line_len; /* strlen (shell_input_line) */ - -/* Either zero or EOF. */ -static int shell_input_line_terminator; - -/* The line number in a script on which a function definition starts. */ -static int function_dstart; - -/* The line number in a script on which a function body starts. */ -static int function_bstart; - -/* The line number in a script at which an arithmetic for command starts. */ -static int arith_for_lineno; - -/* The line number in a script where the word in a `case WORD', `select WORD' - or `for WORD' begins. This is a nested command maximum, since the array - index is decremented after a case, select, or for command is parsed. */ -#define MAX_CASE_NEST 128 -static int word_lineno[MAX_CASE_NEST]; -static int word_top = -1; - -/* 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. If token_to_read == WORD or - ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ -static int token_to_read; -static WORD_DESC *word_desc_to_read; - -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 for [[...]] commands. Members of the - third group are recognized only under special circumstances. */ -%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION -%token COND_START COND_END COND_ERROR -%token IN BANG TIME TIMEOPT - -/* More general tokens. yylex () knows how to make these. */ -%token WORD ASSIGNMENT_WORD -%token NUMBER -%token ARITH_CMD ARITH_FOR_EXPRS -%token COND_CMD -%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS -%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 pipeline_command -%type list list0 list1 compound_list simple_list simple_list1 -%type simple_command shell_command -%type for_command select_command case_command group_command -%type arith_command -%type cond_command -%type arith_for_command -%type function_def function_body if_command elif_clause subshell -%type redirection redirection_list -%type simple_command_element -%type word_list pattern -%type pattern_list case_clause_sequence case_clause -%type timespec -%type list_terminator - -%start inputunit - -%left '&' ';' '\n' yacc_EOF -%left AND_AND OR_OR -%right '|' -%% - -inputunit: simple_list simple_list_terminator - { - /* 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; - } - ; - -word_list: WORD - { $$ = make_word_list ($1, (WORD_LIST *)NULL); } - | word_list 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_LESS_LESS WORD - { - redir.filename = $2; - $$ = make_redirection (0, r_reading_string, redir); - } - | NUMBER LESS_LESS_LESS WORD - { - redir.filename = $3; - $$ = make_redirection ($1, r_reading_string, redir); - } - | 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 = 0; - $$ = make_redirection (1, r_close_this, redir); - } - | NUMBER GREATER_AND '-' - { - redir.dest = 0; - $$ = make_redirection ($1, r_close_this, redir); - } - | LESS_AND '-' - { - redir.dest = 0; - $$ = make_redirection (0, r_close_this, redir); - } - | NUMBER LESS_AND '-' - { - redir.dest = 0; - $$ = 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 - { - redir.filename = $2; - $$ = make_redirection (0, r_input_output, redir); - } - | 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; } - ; - -redirection_list: redirection - { - $$ = $1; - } - | redirection_list redirection - { - register REDIRECT *t; - - for (t = $1; 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 redirection_list - { - COMMAND *tc; - - tc = $1; - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $2; - } - else - tc->redirects = $2; - $$ = $1; - } - | function_def - { $$ = $1; } - ; - -shell_command: for_command - { $$ = $1; } - | case_command - { $$ = $1; } - | WHILE compound_list DO compound_list DONE - { $$ = make_while_command ($2, $4); } - | UNTIL compound_list DO compound_list DONE - { $$ = make_until_command ($2, $4); } - | select_command - { $$ = $1; } - | if_command - { $$ = $1; } - | subshell - { $$ = $1; } - | group_command - { $$ = $1; } - | arith_command - { $$ = $1; } - | cond_command - { $$ = $1; } - | arith_for_command - { $$ = $1; } - ; - -for_command: FOR WORD newline_list DO compound_list DONE - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD ';' newline_list DO compound_list DONE - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD ';' newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE - { - $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE - { - $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}' - { - $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE - { - $$ = make_arith_for_command ($2, $6, arith_for_lineno); - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}' - { - $$ = make_arith_for_command ($2, $6, arith_for_lineno); - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS DO compound_list DONE - { - $$ = make_arith_for_command ($2, $4, arith_for_lineno); - if (word_top > 0) word_top--; - } - | FOR ARITH_FOR_EXPRS '{' compound_list '}' - { - $$ = make_arith_for_command ($2, $4, arith_for_lineno); - if (word_top > 0) word_top--; - } - ; - -select_command: SELECT WORD newline_list DO list DONE - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list '{' list '}' - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD ';' newline_list DO list DONE - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD ';' newline_list '{' list '}' - { - $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE - { - $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}' - { - $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -case_command: CASE WORD newline_list IN newline_list ESAC - { - $$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | CASE WORD newline_list IN case_clause_sequence newline_list ESAC - { - $$ = make_case_command ($2, $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - | CASE WORD newline_list IN case_clause ESAC - { - $$ = make_case_command ($2, $5, word_lineno[word_top]); - if (word_top > 0) word_top--; - } - ; - -function_def: WORD '(' ')' newline_list function_body - { $$ = make_function_def ($1, $5, function_dstart, function_bstart); } - - | FUNCTION WORD '(' ')' newline_list function_body - { $$ = make_function_def ($2, $6, function_dstart, function_bstart); } - - | FUNCTION WORD newline_list function_body - { $$ = make_function_def ($2, $4, function_dstart, function_bstart); } - ; - - -function_body: shell_command - { $$ = $1; } - | shell_command redirection_list - { - COMMAND *tc; - - tc = $1; - /* According to Posix.2 3.9.5, redirections - specified after the body of a function should - be attached to the function and performed when - the function is executed, not as part of the - function definition command. */ - /* XXX - I don't think it matters, but we might - want to change this in the future to avoid - problems differentiating between a function - definition with a redirection and a function - definition containing a single command with a - redirection. The two are semantically equivalent, - though -- the only difference is in how the - command printing code displays the redirections. */ - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $2; - } - else - tc->redirects = $2; - $$ = $1; - } - ; - -subshell: '(' compound_list ')' - { - $$ = make_subshell_command ($2); - $$->flags |= CMD_WANT_SUBSHELL; - } - ; - -if_command: IF compound_list THEN compound_list FI - { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | IF compound_list THEN compound_list ELSE compound_list FI - { $$ = make_if_command ($2, $4, $6); } - | IF compound_list THEN compound_list elif_clause FI - { $$ = make_if_command ($2, $4, $5); } - ; - - -group_command: '{' compound_list '}' - { $$ = make_group_command ($2); } - ; - -arith_command: ARITH_CMD - { $$ = make_arith_command ($1); } - ; - -cond_command: COND_START COND_CMD COND_END - { $$ = $2; } - ; - -elif_clause: ELIF compound_list THEN compound_list - { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | ELIF compound_list THEN compound_list ELSE compound_list - { $$ = make_if_command ($2, $4, $6); } - | ELIF compound_list THEN compound_list elif_clause - { $$ = make_if_command ($2, $4, $5); } - ; - -case_clause: pattern_list - | case_clause_sequence pattern_list - { $2->next = $1; $$ = $2; } - ; - -pattern_list: newline_list pattern ')' compound_list - { $$ = make_pattern_list ($2, $4); } - | newline_list pattern ')' newline_list - { $$ = make_pattern_list ($2, (COMMAND *)NULL); } - | newline_list '(' pattern ')' compound_list - { $$ = make_pattern_list ($3, $5); } - | newline_list '(' pattern ')' newline_list - { $$ = make_pattern_list ($3, (COMMAND *)NULL); } - ; - -case_clause_sequence: pattern_list SEMI_SEMI - | case_clause_sequence pattern_list SEMI_SEMI - { $2->next = $1; $$ = $2; } - ; - -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: newline_list list0 - { - $$ = $2; - if (need_here_doc) - gather_here_documents (); - } - ; - -compound_list: list - | newline_list list1 - { - $$ = $2; - } - ; - -list0: list1 '\n' newline_list - | list1 '&' newline_list - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); - else - $$ = command_connect ($1, (COMMAND *)NULL, '&'); - } - | list1 ';' newline_list - - ; - -list1: list1 AND_AND newline_list list1 - { $$ = command_connect ($1, $4, AND_AND); } - | list1 OR_OR newline_list list1 - { $$ = command_connect ($1, $4, OR_OR); } - | list1 '&' newline_list list1 - { - if ($1->type == cm_connection) - $$ = connect_async_list ($1, $4, '&'); - else - $$ = command_connect ($1, $4, '&'); - } - | list1 ';' newline_list list1 - { $$ = command_connect ($1, $4, ';'); } - | list1 '\n' newline_list list1 - { $$ = command_connect ($1, $4, ';'); } - | pipeline_command - { $$ = $1; } - ; - -simple_list_terminator: '\n' - | yacc_EOF - ; - -list_terminator:'\n' - { $$ = '\n'; } - | ';' - { $$ = ';'; } - | yacc_EOF - { $$ = yacc_EOF; } - ; - -newline_list: - | newline_list '\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 newline_list simple_list1 - { $$ = command_connect ($1, $4, AND_AND); } - | simple_list1 OR_OR newline_list 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_command - { $$ = $1; } - ; - -pipeline_command: pipeline - { $$ = $1; } - | BANG pipeline - { - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - $3->flags |= $2|CMD_INVERT_RETURN; - $$ = $3; - } - | timespec list_terminator - { - ELEMENT x; - - /* Boy, this is unclean. `time' by itself can - time a null command. We cheat and push a - newline back if the list_terminator was a newline - to avoid the double-newline problem (one to - terminate this, one to terminate the command) */ - x.word = 0; - x.redirect = 0; - $$ = make_simple_command (x, (COMMAND *)NULL); - $$->flags |= $1; - /* XXX - let's cheat and push a newline back */ - if ($2 == '\n') - token_to_read = '\n'; - } - - ; - -pipeline: - pipeline '|' newline_list pipeline - { $$ = command_connect ($1, $4, '|'); } - | command - { $$ = $1; } - ; - -timespec: TIME - { $$ = CMD_TIME_PIPELINE; } - | TIME TIMEOPT - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - ; -%% - -/* Possible states for the parser that require it to do special things. */ -#define PST_CASEPAT 0x0001 /* in a case pattern list */ -#define PST_ALEXPNEXT 0x0002 /* expand next word for aliases */ -#define PST_ALLOWOPNBRC 0x0004 /* allow open brace for function def */ -#define PST_NEEDCLOSBRC 0x0008 /* need close brace */ -#define PST_DBLPAREN 0x0010 /* double-paren parsing */ -#define PST_SUBSHELL 0x0020 /* ( ... ) subshell */ -#define PST_CMDSUBST 0x0040 /* $( ... ) command substitution */ -#define PST_CASESTMT 0x0080 /* parsing a case statement */ -#define PST_CONDCMD 0x0100 /* parsing a [[...]] command */ -#define PST_CONDEXPR 0x0200 /* parsing the guts of [[...]] */ -#define PST_ARITHFOR 0x0400 /* parsing an arithmetic for command */ -#define PST_ALEXPAND 0x0800 /* OK to expand aliases - unused */ -#define PST_CMDTOKEN 0x1000 /* command token OK - unused */ -#define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */ - -/* Initial size to allocate for tokens, and the - amount to grow them by. */ -#define TOKEN_DEFAULT_INITIAL_SIZE 496 -#define TOKEN_DEFAULT_GROW_SIZE 512 - -/* Should we call prompt_again? */ -#define SHOULD_PROMPT() \ - (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream)) - -#if defined (ALIAS) -# define expanding_alias() (pushed_string_list && pushed_string_list->expander) -#else -# define expanding_alias() 0 -#endif - -/* The token currently being read. */ -static int current_token; - -/* The last read token, or NULL. read_token () uses this for context - checking. */ -static int last_read_token; - -/* The token read prior to last_read_token. */ -static int token_before_that; - -/* The token read prior to token_before_that. */ -static int two_tokens_ago; - -/* The current parser state. */ -static int parser_state; - -/* Global var is non-zero when end of file has been reached. */ -int EOF_Reached = 0; - -#ifdef DEBUG -static void -debug_parser (i) - int i; -{ -#if YYDEBUG != 0 - yydebug = i; -#endif -} -#endif - -/* yy_getc () returns the next available character from input or EOF. - yy_ungetc (c) makes `c' the next character to read. - init_yy_io (get, unget, type, location) makes the function GET the - 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. */ -int -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. Free bash_input.name if it - is non-null, avoiding a memory leak. */ -void -initialize_bash_input () -{ - bash_input.type = st_none; - FREE (bash_input.name); - bash_input.name = (char *)NULL; - bash_input.location.file = (FILE *)NULL; - bash_input.location.string = (char *)NULL; - bash_input.getter = (sh_cget_func_t *)NULL; - bash_input.ungetter = (sh_cunget_func_t *)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) - sh_cget_func_t *get; - sh_cunget_func_t *unget; - enum stream_type type; - const char *name; - INPUT_STREAM location; -{ - bash_input.type = type; - FREE (bash_input.name); - bash_input.name = name ? savestring (name) : (char *)NULL; - - /* XXX */ -#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; -} - -char * -yy_input_name () -{ - return (bash_input.name ? bash_input.name : "stdin"); -} - -/* Call this to get the next character of input. */ -static int -yy_getc () -{ - return (*(bash_input.getter)) (); -} - -/* Call this to unget C. That is, to make C the next character - to be read. */ -static int -yy_ungetc (c) - int c; -{ - return (*(bash_input.ungetter)) (c); -} - -#if defined (BUFFERED_INPUT) -#ifdef INCLUDE_UNUSED -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); - case st_stdin: - default: - return (fileno (stdin)); - } -} -#endif -#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 () -{ - SigHandler *old_sigint; - int line_len; - unsigned char c; - - if (!current_readline_line) - { - if (!bash_readline_initialized) - initialize_readline (); - -#if defined (JOB_CONTROL) - if (job_control) - give_terminal_to (shell_pgrp, 0); -#endif /* JOB_CONTROL */ - - old_sigint = (SigHandler *)NULL; - if (signal_is_ignored (SIGINT) == 0) - { - old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); - interrupt_immediately++; - } - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - if (signal_is_ignored (SIGINT) == 0 && old_sigint) - { - interrupt_immediately--; - set_signal_handler (SIGINT, old_sigint); - } - -#if 0 - /* Reset the prompt to the decoded value of prompt_string_pointer. */ - reset_readline_prompt (); -#endif - - if (current_readline_line == 0) - return (EOF); - - current_readline_line_index = 0; - line_len = strlen (current_readline_line); - - current_readline_line = (char *)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] == 0) - { - free (current_readline_line); - current_readline_line = (char *)NULL; - return (yy_readline_get ()); - } - else - { - c = current_readline_line[current_readline_line_index++]; - return (c); - } -} - -static int -yy_readline_unget (c) - int c; -{ - if (current_readline_line_index && current_readline_line) - current_readline_line[--current_readline_line_index] = c; - return (c); -} - -void -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 char *string; - register unsigned char c; - - string = bash_input.location.string; - - /* If the string doesn't exist, or is empty, EOF found. */ - if (string && *string) - { - c = *string++; - bash_input.location.string = string; - return (c); - } - else - return (EOF); -} - -static int -yy_string_unget (c) - int c; -{ - *(--bash_input.location.string) = c; - return (c); -} - -void -with_input_from_string (string, name) - char *string; - const 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. */ -/* */ -/* **************************************************************** */ - -/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS - define, and just use getc/ungetc if it was defined, but since bash - installs its signal handlers without the SA_RESTART flag, some signals - (like SIGCHLD, SIGWINCH, etc.) received during a read(2) will not cause - the read to be restarted. We need to restart it ourselves. */ - -static int -yy_stream_get () -{ - int result; - - result = EOF; - if (bash_input.location.file) - result = getc_with_restart (bash_input.location.file); - - return (result); -} - -static int -yy_stream_unget (c) - int c; -{ - return (ungetc_with_restart (c, bash_input.location.file)); -} - -void -with_input_from_stream (stream, name) - FILE *stream; - const 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; - -#if defined (COND_COMMAND) -static int cond_lineno; -static int cond_token; -#endif - -STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; - -void -push_stream (reset_lineno) - int reset_lineno; -{ - 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 = set_buffered_stream (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 = 0; - if (reset_lineno) - line_number = 0; -} - -void -pop_stream () -{ - 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; - SET_CLOSE_ON_EXEC (default_buffered_input); - } - } - /* XXX could free buffered stream returned as result here. */ - set_buffered_stream (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) - enum stream_type type; -{ - register STREAM_SAVER *s; - - for (s = stream_list; s; s = s->next) - if (s->bash_input.type == type) - return 1; - return 0; -} - -/* Save the current token state and return it in a malloced array. */ -int * -save_token_state () -{ - int *ret; - - ret = (int *)xmalloc (3 * sizeof (int)); - ret[0] = last_read_token; - ret[1] = token_before_that; - ret[2] = two_tokens_ago; - return ret; -} - -void -restore_token_state (ts) - int *ts; -{ - if (ts == 0) - return; - last_read_token = ts[0]; - token_before_that = ts[1]; - two_tokens_ago = ts[2]; -} - -/* - * 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' - */ - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - -#define END_OF_ALIAS 0 - -/* - * Pseudo-global variables used in implementing token-wise alias expansion. - */ - -/* - * 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; -#if defined (ALIAS) - alias_t *expander; /* alias that caused this line to be pushed. */ -#endif - int saved_line_size, saved_line_index, saved_line_terminator; -} STRING_SAVER; - -STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; - -/* - * 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, ap) - char *s; - int expand; - alias_t *ap; -{ - 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; -#if defined (ALIAS) - temp->expander = ap; -#endif - temp->next = pushed_string_list; - pushed_string_list = temp; - -#if defined (ALIAS) - if (ap) - ap->flags |= AL_BEINGEXPANDED; -#endif - - shell_input_line = s; - shell_input_line_size = strlen (s); - shell_input_line_index = 0; - shell_input_line_terminator = '\0'; -#if 0 - parser_state &= ~PST_ALEXPNEXT; /* XXX */ -#endif - - set_line_mbstate (); -} - -/* - * 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; - - if (pushed_string_list->expand_alias) - parser_state |= PST_ALEXPNEXT; - else - parser_state &= ~PST_ALEXPNEXT; - - t = pushed_string_list; - pushed_string_list = pushed_string_list->next; - -#if defined (ALIAS) - if (t->expander) - t->expander->flags &= ~AL_BEINGEXPANDED; -#endif - - free ((char *)t); - - set_line_mbstate (); -} - -static void -free_string_list () -{ - register STRING_SAVER *t, *t1; - - for (t = pushed_string_list; t; ) - { - t1 = t->next; - FREE (t->saved_line); -#if defined (ALIAS) - if (t->expander) - t->expander->flags &= ~AL_BEINGEXPANDED; -#endif - free ((char *)t); - t = t1; - } - pushed_string_list = (STRING_SAVER *)NULL; -} - -#endif /* ALIAS || DPAREN_ARITHMETIC */ - -void -free_pushed_string_input () -{ -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - free_string_list (); -#endif -} - -/* 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; - -#if defined (READLINE) - if (no_line_editing && SHOULD_PROMPT ()) -#else - if (SHOULD_PROMPT ()) -#endif - print_prompt (); - - pass_next = 0; - while (1) - { - c = yy_getc (); - - /* Allow immediate exit if interrupted during input. */ - QUIT; - - /* Ignore null bytes in input. */ - if (c == 0) - { -#if 0 - internal_warning ("read_a_line: ignored null byte in input"); -#endif - continue; - } - - /* If there is no more input, then we return NULL. */ - if (c == EOF) - { - if (interactive && bash_input.type == st_stream) - clearerr (stdin); - if (indx == 0) - return ((char *)NULL); - c = '\n'; - } - - /* `+2' in case the final character in the buffer is a newline. */ - RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); - - /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a - here document with an unquoted delimiter. In this case, - 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') - { - line_number++; - 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; - if (SHOULD_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 }, -#if defined (COMMAND_TIMING) - { "time", TIME }, -#endif - { "{", '{' }, - { "}", '}' }, - { "!", BANG }, -#if defined (COND_COMMAND) - { "[[", COND_START }, - { "]]", COND_END }, -#endif - { (char *)NULL, 0} -}; - -/* other tokens that can be returned by read_token() */ -STRING_INT_ALIST other_token_alist[] = { - /* Multiple-character tokens with special values */ - { "-p", TIMEOPT }, - { "&&", AND_AND }, - { "||", OR_OR }, - { ">>", GREATER_GREATER }, - { "<<", LESS_LESS }, - { "<&", LESS_AND }, - { ">&", GREATER_AND }, - { ";;", SEMI_SEMI }, - { "<<-", LESS_LESS_MINUS }, - { "<<<", LESS_LESS_LESS }, - { "&>", AND_GREATER }, - { "<>", LESS_GREATER }, - { ">|", GREATER_BAR }, - { "EOF", yacc_EOF }, - /* Tokens whose value is the character itself */ - { ">", '>' }, - { "<", '<' }, - { "-", '-' }, - { "{", '{' }, - { "}", '}' }, - { ";", ';' }, - { "(", '(' }, - { ")", ')' }, - { "|", '|' }, - { "&", '&' }, - { "newline", '\n' }, - { (char *)NULL, 0} -}; - -/* others not listed here: - WORD look at yylval.word - ASSIGNMENT_WORD look at yylval.word - NUMBER look at yylval.number - ARITH_CMD look at yylval.word_list - ARITH_FOR_EXPRS look at yylval.word_list - COND_CMD look at yylval.command -*/ - -/* These are used by read_token_word, but appear up here so that shell_getc - can use them to decide when to add otherwise blank lines to the history. */ - -/* The primary delimiter stack. */ -struct dstack dstack = { (char *)NULL, 0, 0 }; - -/* A temporary delimiter stack to be used when decoding prompt strings. - This is needed because command substitutions in prompt strings (e.g., PS2) - can screw up the parser's quoting state. */ -static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; - -/* Macro for accessing the top delimiter on the stack. Returns the - delimiter or zero if none. */ -#define current_delimiter(ds) \ - (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) - -#define push_delimiter(ds, character) \ - do \ - { \ - if (ds.delimiter_depth + 2 > ds.delimiter_space) \ - ds.delimiters = (char *)xrealloc \ - (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ - ds.delimiters[ds.delimiter_depth] = character; \ - ds.delimiter_depth++; \ - } \ - while (0) - -#define pop_delimiter(ds) ds.delimiter_depth-- - -/* Return the next shell input character. This always reads characters - from shell_input_line; when that line is exhausted, it is time to - read the next line. This is called by read_token when the shell is - processing normal command input. */ - -/* This implements one-character lookahead/lookbehind across physical input - lines, to avoid something being lost because it's pushed back with - shell_ungetc when we're at the start of a line. */ -static int eol_ungetc_lookahead = 0; - -static int -shell_getc (remove_quoted_newline) - int remove_quoted_newline; -{ - register int i; - int c; - unsigned char uc; - static int mustpop = 0; - - QUIT; - - if (eol_ungetc_lookahead) - { - c = eol_ungetc_lookahead; - eol_ungetc_lookahead = 0; - return (c); - } - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - /* 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 && !DPAREN_ARITHMETIC */ - if (!shell_input_line || !shell_input_line[shell_input_line_index]) -#endif /* !ALIAS && !DPAREN_ARITHMETIC */ - { - line_number++; - - restart_read: - - /* Allow immediate exit if interrupted during input. */ - QUIT; - - i = 0; - shell_input_line_terminator = 0; - - /* If the shell is interatctive, but not currently printing a prompt - (interactive_shell && interactive == 0), we don't want to print - notifies or cleanup the jobs -- we want to defer it until we do - print the next prompt. */ - if (interactive_shell == 0 || SHOULD_PROMPT()) - { -#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 (no_line_editing && SHOULD_PROMPT()) -#else - if (SHOULD_PROMPT()) -#endif - print_prompt (); - - if (bash_input.type == st_stream) - clearerr (stdin); - - while (1) - { - c = yy_getc (); - - /* Allow immediate exit if interrupted during input. */ - QUIT; - - if (c == '\0') - { -#if 0 - internal_warning ("shell_getc: ignored null byte in input"); -#endif - continue; - } - - RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); - - if (c == EOF) - { - if (bash_input.type == st_stream) - clearerr (stdin); - - if (i == 0) - 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) */ - - set_line_mbstate (); - -#if defined (HISTORY) - if (remember_on_history && shell_input_line && shell_input_line[0]) - { - char *expansions; -# if defined (BANG_HISTORY) - int old_hist; - - /* If the current delimiter is a single quote, we should not be - performing history expansion, even if we're on a different - line from the original single quote. */ - old_hist = history_expansion_inhibited; - if (current_delimiter (dstack) == '\'') - history_expansion_inhibited = 1; -# endif - expansions = pre_process_line (shell_input_line, 1, 1); -# if defined (BANG_HISTORY) - history_expansion_inhibited = old_hist; -# endif - if (expansions != shell_input_line) - { - 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; - - set_line_mbstate (); - } - } - /* Try to do something intelligent with blank lines encountered while - entering multi-line commands. XXX - this is grotesque */ - else if (remember_on_history && shell_input_line && - shell_input_line[0] == '\0' && - current_command_line_count > 1) - { - if (current_delimiter (dstack)) - /* We know shell_input_line[0] == 0 and we're reading some sort of - quoted string. This means we've got a line consisting of only - a newline in a quoted string. We want to make sure this line - gets added to the history. */ - maybe_add_history (shell_input_line); - else - { - char *hdcs; - hdcs = history_delimiting_chars (); - if (hdcs && hdcs[0] == ';') - maybe_add_history (shell_input_line); - } - } - -#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; - if (SHOULD_PROMPT ()) - 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) - { - if (shell_input_line_len + 3 > shell_input_line_size) - shell_input_line = (char *)xrealloc (shell_input_line, - 1 + (shell_input_line_size += 2)); - - shell_input_line[shell_input_line_len] = '\n'; - shell_input_line[shell_input_line_len + 1] = '\0'; - - set_line_mbstate (); - } - } - - uc = shell_input_line[shell_input_line_index]; - - if (uc) - shell_input_line_index++; - - if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - /* If UC 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 (!uc && (pushed_string_list != (STRING_SAVER *)NULL)) - { - pop_string (); - uc = shell_input_line[shell_input_line_index]; - if (uc) - shell_input_line_index++; - } -#endif /* ALIAS || DPAREN_ARITHMETIC */ - - if (!uc && shell_input_line_terminator == EOF) - return ((shell_input_line_index != 0) ? '\n' : EOF); - - return (uc); -} - -/* Put C back into the input for the shell. This might need changes for - HANDLE_MULTIBYTE around EOLs. Since we (currently) never push back a - character different than we read, shell_input_line_property doesn't need - to change when manipulating shell_input_line. The define for - last_shell_getc_is_singlebyte should take care of it, though. */ -static void -shell_ungetc (c) - int c; -{ - if (shell_input_line && shell_input_line_index) - shell_input_line[--shell_input_line_index] = c; - else - eol_ungetc_lookahead = c; -} - -#ifdef INCLUDE_UNUSED -/* Back the input pointer up by one, effectively `ungetting' a character. */ -static void -shell_ungetchar () -{ - if (shell_input_line && shell_input_line_index) - shell_input_line_index--; -} -#endif - -/* Discard input until CHARACTER is seen, then push that character back - onto the input stream. */ -static void -discard_until (character) - int character; -{ - int c; - - while ((c = shell_getc (0)) != EOF && c != character) - ; - - if (c != EOF) - shell_ungetc (c); -} - -void -execute_prompt_command (command) - char *command; -{ - char *last_lastarg; - sh_parser_state_t ps; - - save_parser_state (&ps); - last_lastarg = get_string_value ("_"); - if (last_lastarg) - last_lastarg = savestring (last_lastarg); - - parse_and_execute (savestring (command), "PROMPT_COMMAND", SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg); - FREE (last_lastarg); - - if (token_to_read == '\n') /* reset_parser was called */ - token_to_read = 0; -} - -/* Place to remember the token. We try to keep the buffer - at a reasonable size, but it can grow. */ -static char *token = (char *)NULL; - -/* Current size of the token buffer. */ -static int token_buffer_size; - -/* Command to read_token () explaining what we want it to do. */ -#define READ 0 -#define RESET 1 -#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. */ -static int -yylex () -{ - if (interactive && (current_token == 0 || current_token == '\n')) - { - /* Before we print a prompt, we might have to check mailboxes. - We do this only if it is time to do so. Notice that only here - 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 && SHOULD_PROMPT ()) - prompt_again (); - } - - two_tokens_ago = token_before_that; - token_before_that = last_read_token; - last_read_token = current_token; - current_token = read_token (READ); - return (current_token); -} - -/* When non-zero, we have read the required tokens - which allow ESAC to be the next one read. */ -static int esacs_needed_count; - -void -gather_here_documents () -{ - int r = 0; - while (need_here_doc) - { - make_here_document (redir_stack[r++]); - need_here_doc--; - } -} - -/* When non-zero, an open-brace used to create a group is awaiting a close - brace partner. */ -static int open_brace_count; - -#define command_token_position(token) \ - (((token) == ASSIGNMENT_WORD) || \ - ((token) != SEMI_SEMI && reserved_word_acceptable(token))) - -#define assignment_acceptable(token) \ - (command_token_position(token) && ((parser_state & PST_CASEPAT) == 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 ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ - break; \ - if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \ - break; \ - if (word_token_alist[i].token == ESAC) \ - parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ - else if (word_token_alist[i].token == CASE) \ - parser_state |= PST_CASESTMT; \ - else if (word_token_alist[i].token == COND_END) \ - parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \ - else if (word_token_alist[i].token == COND_START) \ - parser_state |= PST_CONDCMD; \ - else if (word_token_alist[i].token == '{') \ - open_brace_count++; \ - else if (word_token_alist[i].token == '}' && open_brace_count) \ - open_brace_count--; \ - return (word_token_alist[i].token); \ - } \ - } \ - } while (0) - -#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 EXPAND_ALIASES is set, and - the token is unquoted and the last token read was a command - separator (or expand_next_token is set), and we are currently - processing an alias (pushed_string_list is non-empty) and this - token is not the same as the current or any previously - processed alias. - - Special cases that disqualify: - In a pattern list in a case statement (parser_state & PST_CASEPAT). */ - -static char * -mk_alexpansion (s) - char *s; -{ - int l; - char *r; - - l = strlen (s); - r = xmalloc (l + 2); - strcpy (r, s); - if (r[l -1] != ' ') - r[l++] = ' '; - r[l] = '\0'; - return r; -} - -static int -alias_expand_token (tokstr) - char *tokstr; -{ - char *expanded; - alias_t *ap; - - if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && - (parser_state & PST_CASEPAT) == 0) - { - ap = find_alias (tokstr); - - /* Currently expanding this token. */ - if (ap && (ap->flags & AL_BEINGEXPANDED)) - return (NO_EXPANSION); - - /* mk_alexpansion puts an extra space on the end of the alias expansion, - so the lookahead by the parser works right. If this gets changed, - make sure the code in shell_getc that deals with reaching the end of - an expanded alias is changed with it. */ - expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL; - - if (expanded) - { - push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); - return (RE_READ_TOKEN); - } - else - /* This is an eligible token that does not have an expansion. */ - return (NO_EXPANSION); - } - return (NO_EXPANSION); -} -#endif /* ALIAS */ - -static int -time_command_acceptable () -{ -#if defined (COMMAND_TIMING) - switch (last_read_token) - { - case 0: - case ';': - case '\n': - case AND_AND: - case OR_OR: - case '&': - case DO: - case THEN: - case ELSE: - case '{': /* } */ - case '(': /* ) */ - return 1; - default: - return 0; - } -#else - return 0; -#endif /* COMMAND_TIMING */ -} - -/* Handle special cases of token recognition: - IN is recognized if the last token was WORD and the token - before that was FOR or CASE or SELECT. - - DO is recognized if the last token was WORD and the token - before that was FOR or SELECT. - - ESAC is recognized if the last token caused `esacs_needed_count' - to be set - - `{' is recognized if the last token as WORD and the token - before that was FUNCTION, or if we just parsed an arithmetic - `for' command. - - `}' is recognized if there is an unclosed `{' present. - - `-p' is returned as TIMEOPT if the last read token was TIME. - - ']]' is returned as COND_END if the parser is currently parsing - a conditional expression ((parser_state & PST_CONDEXPR) != 0) - - `time' is returned as TIME if and only if it is immediately - preceded by one of `;', `\n', `||', `&&', or `&'. -*/ - -static int -special_case_tokens (tokstr) - char *tokstr; -{ - 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 - (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0)) - { - if (token_before_that == CASE) - { - parser_state |= PST_CASEPAT; - esacs_needed_count++; - } - return (IN); - } - - if (last_read_token == WORD && -#if defined (SELECT_COMMAND) - (token_before_that == FOR || token_before_that == SELECT) && -#else - (token_before_that == FOR) && -#endif - (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0')) - return (DO); - - /* Ditto for ESAC in the CASE case. - Specifically, this handles "case word in esac", which is a legal - construct, certainly because someone will pass an empty arg to the - case construct, and we don't want it to barf. Of course, we should - insist that the case construct has at least one pattern in it, but - the designers disagree. */ - if (esacs_needed_count) - { - esacs_needed_count--; - if (STREQ (tokstr, "esac")) - { - parser_state &= ~PST_CASEPAT; - return (ESAC); - } - } - - /* The start of a shell function definition. */ - if (parser_state & PST_ALLOWOPNBRC) - { - parser_state &= ~PST_ALLOWOPNBRC; - if (tokstr[0] == '{' && tokstr[1] == '\0') /* } */ - { - open_brace_count++; - function_bstart = line_number; - return ('{'); /* } */ - } - } - - /* We allow a `do' after a for ((...)) without an intervening - list_terminator */ - if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2]) - return (DO); - if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0') /* } */ - { - open_brace_count++; - return ('{'); /* } */ - } - - if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1]) - { - open_brace_count--; /* { */ - return ('}'); - } - -#if defined (COMMAND_TIMING) - /* Handle -p after `time'. */ - if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2]) - return (TIMEOPT); -#endif - -#if 0 -#if defined (COMMAND_TIMING) - if (STREQ (token, "time") && ((parser_state & PST_CASEPAT) == 0) && time_command_acceptable ()) - return (TIME); -#endif /* COMMAND_TIMING */ -#endif - -#if defined (COND_COMMAND) /* [[ */ - if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0') - return (COND_END); -#endif - - return (-1); -} - -/* Called from shell.c when Control-C is typed at top level. Or - by the error rule at top level. */ -void -reset_parser () -{ - dstack.delimiter_depth = 0; /* No delimiters found so far. */ - open_brace_count = 0; - - parser_state = 0; - -#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) - if (pushed_string_list) - free_string_list (); -#endif /* ALIAS || DPAREN_ARITHMETIC */ - - if (shell_input_line) - { - free (shell_input_line); - shell_input_line = (char *)NULL; - shell_input_line_size = shell_input_line_index = 0; - } - - FREE (word_desc_to_read); - word_desc_to_read = (WORD_DESC *)NULL; - - last_read_token = '\n'; - token_to_read = '\n'; -} - -/* Read the next token. Command can be READ (normal operation) or - RESET (to normalize state). */ -static int -read_token (command) - int command; -{ - int character; /* Current character. */ - int peek_char; /* Temporary look-ahead character. */ - int result; /* The thing to return. */ - - if (command == RESET) - { - reset_parser (); - return ('\n'); - } - - if (token_to_read) - { - result = token_to_read; - if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) - { - yylval.word = word_desc_to_read; - word_desc_to_read = (WORD_DESC *)NULL; - } - token_to_read = 0; - return (result); - } - -#if defined (COND_COMMAND) - if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD) - { - cond_lineno = line_number; - parser_state |= PST_CONDEXPR; - yylval.command = parse_cond_command (); - if (cond_token != COND_END) - { - cond_error (); - return (-1); - } - token_to_read = COND_END; - parser_state &= ~(PST_CONDEXPR|PST_CONDCMD); - return (COND_CMD); - } -#endif - -#if defined (ALIAS) - /* 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 MBTEST(character == '#' && (!interactive || interactive_comments)) - { - /* A comment. Discard until EOL or EOF, and then return a newline. */ - discard_until ('\n'); - shell_getc (0); - character = '\n'; /* this will take the next if statement and return. */ - } - - 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) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - - return (character); - } - - /* Shell meta-characters. */ - if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) - { -#if defined (ALIAS) - /* Turn off alias tokenization iff this character sequence would - not leave us ready to read a command. */ - if (character == '<' || character == '>') - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - - peek_char = shell_getc (1); - if (character == peek_char) - { - switch (character) - { - case '<': - /* If '<' then we could be at "<<" or at "<<-". We have to - look ahead one more character. */ - peek_char = shell_getc (1); - if (peek_char == '-') - return (LESS_LESS_MINUS); - else if (peek_char == '<') - return (LESS_LESS_LESS); - else - { - shell_ungetc (peek_char); - return (LESS_LESS); - } - - case '>': - return (GREATER_GREATER); - - case ';': - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - return (SEMI_SEMI); - - case '&': - return (AND_AND); - - case '|': - return (OR_OR); - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) - case '(': /* ) */ - result = parse_dparen (character); - if (result == -2) - break; - else - return result; -#endif - } - } - else if MBTEST(character == '<' && peek_char == '&') - return (LESS_AND); - else if MBTEST(character == '>' && peek_char == '&') - return (GREATER_AND); - else if MBTEST(character == '<' && peek_char == '>') - return (LESS_GREATER); - else if MBTEST(character == '>' && peek_char == '|') - return (GREATER_BAR); - else if MBTEST(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 MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD) - { - parser_state |= PST_ALLOWOPNBRC; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - function_dstart = line_number; - } - - /* case pattern lists may be preceded by an optional left paren. If - we're not trying to parse a case pattern list, the left paren - indicates a subshell. */ - if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ - parser_state |= PST_SUBSHELL; - /*(*/ - else if MBTEST((parser_state & PST_CASEPAT) && character == ')') - parser_state &= ~PST_CASEPAT; - /*(*/ - else if MBTEST((parser_state & PST_SUBSHELL) && character == ')') - parser_state &= ~PST_SUBSHELL; - -#if defined (PROCESS_SUBSTITUTION) - /* Check for the constructs which introduce process substitution. - Shells running in `posix mode' don't do process substitution. */ - if MBTEST(posixly_correct || ((character != '>' && character != '<') || peek_char != '(')) /*)*/ -#endif /* PROCESS_SUBSTITUTION */ - return (character); - } - - /* Hack <&- (close stdin) case. Also <&N- (dup and close). */ - if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) - return (character); - - /* Okay, if we got this far, we have to read a word. Read one, - and then check it against the known ones. */ - result = read_token_word (character); -#if defined (ALIAS) - if (result == RE_READ_TOKEN) - goto re_read_token; -#endif - return result; -} - -/* - * Match a $(...) or other grouping construct. This has to handle embedded - * quoted strings ('', ``, "") and nested constructs. It also must handle - * reprompting the user, if necessary, after reading a newline (unless the - * P_NONL flag is passed), and returning correct error values if it reads - * EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 - -static char matched_pair_error; -static char * -parse_matched_pair (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, was_dollar; - int pass_next_character, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - - count = 1; - pass_next_character = was_dollar = 0; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - while (count) - { - ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0); - if (ch == EOF) - { - free (ret); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - if (pass_next_character) /* last char was backslash */ - { - pass_next_character = 0; - if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ - { - if (retind > 0) retind--; /* swallow previously-added backslash */ - continue; - } - - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - if MBTEST(ch == CTLESC || ch == CTLNUL) - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); - ret[retind++] = CTLESC; - ret[retind++] = ch; - continue; - } - else if MBTEST(ch == close) /* ending delimiter */ - count--; -#if 1 - /* handle nested ${...} specially. */ - else if MBTEST(open != close && was_dollar && open == '{' && ch == open) /* } */ - count++; -#endif - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */ - count++; - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (open == '\'') /* '' inside grouping construct */ - { - if MBTEST((flags & P_ALLOWESC) && ch == '\\') - pass_next_character++; - continue; - } - - if MBTEST(ch == '\\') /* backslashes */ - pass_next_character++; - - if (open != close) /* a grouping construct */ - { - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...) or other grouping construct. */ - push_delimiter (dstack, ch); - if MBTEST(was_dollar && ch == '\'') /* $'...' inside group */ - nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags); - else - nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags); - pop_delimiter (dstack); - if (nestret == &matched_pair_error) - { - free (ret); - return &matched_pair_error; - } - if MBTEST(was_dollar && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - retind -= 2; /* back up before the $' */ - } - else if MBTEST(was_dollar && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - nestret = (char *)xmalloc (ttranslen + 3); - nestret[0] = '"'; - strcpy (nestret + 1, ttrans); - nestret[ttranslen + 1] = '"'; - nestret[ttranslen += 2] = '\0'; - free (ttrans); - nestlen = ttranslen; - retind -= 2; /* back up before the $" */ - } - - if (nestlen) - { - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); - strcpy (ret + retind, nestret); - retind += nestlen; - } - FREE (nestret); - } - } - /* Parse an old-style command substitution within double quotes as a - single word. */ - /* XXX - sh and ksh93 don't do this - XXX */ - else if MBTEST(open == '"' && ch == '`') - { - nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags); - if (nestret == &matched_pair_error) - { - free (ret); - return &matched_pair_error; - } - if (nestlen) - { - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); - strcpy (ret + retind, nestret); - retind += nestlen; - } - FREE (nestret); - } - else if MBTEST(was_dollar && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside quoted string. */ - { - if (open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - if (nestret == &matched_pair_error) - { - free (ret); - return &matched_pair_error; - } - if (nestlen) - { - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); - strcpy (ret + retind, nestret); - retind += nestlen; - } - FREE (nestret); - } - was_dollar = MBTEST(ch == '$'); - } - - ret[retind] = '\0'; - if (lenp) - *lenp = retind; - return ret; -} - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -/* Parse a double-paren construct. It can be either an arithmetic - command, an arithmetic `for' command, or a nested subshell. Returns - the parsed token, -1 on error, or -2 if we didn't do anything and - should just go on. */ -static int -parse_dparen (c) - int c; -{ - int cmdtyp, len, sline; - char *wval, *wv2; - WORD_DESC *wd; - -#if defined (ARITH_FOR_COMMAND) - if (last_read_token == FOR) - { - arith_for_lineno = line_number; - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) - { - wd = make_word (wval); - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - free (wval); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; -#if 0 - cmdtyp = parse_arith_cmd (&wval, 1); -#else - cmdtyp = parse_arith_cmd (&wval, 0); -#endif - if (cmdtyp == 1) /* arithmetic command */ - { - wd = make_word (wval); -#if 0 - wd->flags = W_QUOTED; -#else - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB; -#endif - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - free (wval); /* make_word copies it */ - return (ARITH_CMD); - } - else if (cmdtyp == 0) /* nested subshell */ - { - push_string (wval, 0, (alias_t *)NULL); - if ((parser_state & PST_CASEPAT) == 0) - parser_state |= PST_SUBSHELL; - return (c); - } - else /* ERROR */ - return -1; - } -#endif - - return -2; /* XXX */ -} - -/* We've seen a `(('. Look for the matching `))'. If we get it, return 1. - If not, assume it's a nested subshell for backwards compatibility and - return 0. In any case, put the characters we've consumed into a locally- - allocated buffer and make *ep point to that buffer. Return -1 on an - error, for example EOF. */ -static int -parse_arith_cmd (ep, adddq) - char **ep; - int adddq; -{ - int exp_lineno, rval, c; - char *ttok, *tokstr; - int ttoklen; - - exp_lineno = line_number; - ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); - rval = 1; - if (ttok == &matched_pair_error) - return -1; - /* Check that the next character is the closing right paren. If - not, this is a syntax error. ( */ - c = shell_getc (0); - if MBTEST(c != ')') - rval = 0; - - tokstr = (char *)xmalloc (ttoklen + 4); - - /* if ADDDQ != 0 then (( ... )) -> "..." */ - if (rval == 1 && adddq) /* arith cmd, add double quotes */ - { - tokstr[0] = '"'; - strncpy (tokstr + 1, ttok, ttoklen - 1); - tokstr[ttoklen] = '"'; - tokstr[ttoklen+1] = '\0'; - } - else if (rval == 1) /* arith cmd, don't add double quotes */ - { - strncpy (tokstr, ttok, ttoklen - 1); - tokstr[ttoklen-1] = '\0'; - } - else /* nested subshell */ - { - tokstr[0] = '('; - strncpy (tokstr + 1, ttok, ttoklen - 1); - tokstr[ttoklen] = ')'; - tokstr[ttoklen+1] = c; - tokstr[ttoklen+2] = '\0'; - } - - *ep = tokstr; - FREE (ttok); - return rval; -} -#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */ - -#if defined (COND_COMMAND) -static void -cond_error () -{ - char *etext; - - if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ - parser_error (cond_lineno, _("unexpected EOF while looking for `]]'")); - else if (cond_token != COND_ERROR) - { - if (etext = error_token_from_token (cond_token)) - { - parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext); - free (etext); - } - else - parser_error (cond_lineno, _("syntax error in conditional expression")); - } -} - -static COND_COM * -cond_expr () -{ - return (cond_or ()); -} - -static COND_COM * -cond_or () -{ - COND_COM *l, *r; - - l = cond_and (); - if (cond_token == OR_OR) - { - r = cond_or (); - l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r); - } - return l; -} - -static COND_COM * -cond_and () -{ - COND_COM *l, *r; - - l = cond_term (); - if (cond_token == AND_AND) - { - r = cond_and (); - l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r); - } - return l; -} - -static int -cond_skip_newlines () -{ - while ((cond_token = read_token (READ)) == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - } - return (cond_token); -} - -#define COND_RETURN_ERROR() \ - do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0) - -static COND_COM * -cond_term () -{ - WORD_DESC *op; - COND_COM *term, *tleft, *tright; - int tok, lineno; - char *etext; - - /* Read a token. It can be a left paren, a `!', a unary operator, or a - word that should be the first argument of a binary operator. Start by - skipping newlines, since this is a compound command. */ - tok = cond_skip_newlines (); - lineno = line_number; - if (tok == COND_END) - { - COND_RETURN_ERROR (); - } - else if (tok == '(') - { - term = cond_expr (); - if (cond_token != ')') - { - if (term) - dispose_cond_node (term); /* ( */ - if (etext = error_token_from_token (cond_token)) - { - parser_error (lineno, _("unexpected token `%s', expected `)'"), etext); - free (etext); - } - else - parser_error (lineno, _("expected `)'")); - COND_RETURN_ERROR (); - } - term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL); - (void)cond_skip_newlines (); - } - else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0'))) - { - if (tok == WORD) - dispose_word (yylval.word); /* not needed */ - term = cond_term (); - if (term) - term->flags |= CMD_INVERT_RETURN; - } - else if (tok == WORD && test_unop (yylval.word->word)) - { - op = yylval.word; - tok = read_token (READ); - if (tok == WORD) - { - tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); - } - else - { - dispose_word (op); - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected argument to conditional unary operator")); - COND_RETURN_ERROR (); - } - - (void)cond_skip_newlines (); - } - else if (tok == WORD) /* left argument to binary operator */ - { - /* lhs */ - tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - - /* binop */ - tok = read_token (READ); - if (tok == WORD && test_binop (yylval.word->word)) - op = yylval.word; -#if defined (COND_REGEXP) - else if (tok == WORD && STREQ (yylval.word->word,"=~")) - op = yylval.word; -#endif - else if (tok == '<' || tok == '>') - op = make_word_from_token (tok); /* ( */ - /* There should be a check before blindly accepting the `)' that we have - seen the opening `('. */ - else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')') - { - /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like - the test command. Similarly for [[ x && expr ]] or - [[ x || expr ]] or [[ (x) ]]. */ - op = make_word ("-n"); - term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); - cond_token = tok; - return (term); - } - else - { - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext); - free (etext); - } - else - parser_error (line_number, _("conditional binary operator expected")); - dispose_cond_node (tleft); - COND_RETURN_ERROR (); - } - - /* rhs */ - tok = read_token (READ); - if (tok == WORD) - { - tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); - term = make_cond_node (COND_BINARY, op, tleft, tright); - } - else - { - if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected argument to conditional binary operator")); - dispose_cond_node (tleft); - dispose_word (op); - COND_RETURN_ERROR (); - } - - (void)cond_skip_newlines (); - } - else - { - if (tok < 256) - parser_error (line_number, _("unexpected token `%c' in conditional command"), tok); - else if (etext = error_token_from_token (tok)) - { - parser_error (line_number, _("unexpected token `%s' in conditional command"), etext); - free (etext); - } - else - parser_error (line_number, _("unexpected token %d in conditional command"), tok); - COND_RETURN_ERROR (); - } - return (term); -} - -/* This is kind of bogus -- we slip a mini recursive-descent parser in - here to handle the conditional statement syntax. */ -static COMMAND * -parse_cond_command () -{ - COND_COM *cexp; - - cexp = cond_expr (); - return (make_cond_command (cexp)); -} -#endif - -#if defined (ARRAY_VARS) -/* When this is called, it's guaranteed that we don't care about anything - in t beyond i. We do save and restore the chars, though. */ -static int -token_is_assignment (t, i) - char *t; - int i; -{ - unsigned char c, c1; - int r; - - c = t[i]; c1 = t[i+1]; - t[i] = '='; t[i+1] = '\0'; - r = assignment (t, (parser_state & PST_COMPASSIGN) != 0); - t[i] = c; t[i+1] = c1; - return r; -} - -static int -token_is_ident (t, i) - char *t; - int i; -{ - unsigned char c; - int r; - - c = t[i]; - t[i] = '\0'; - r = legal_identifier (t); - t[i] = c; - return r; -} -#endif - -static int -read_token_word (character) - int character; -{ - /* The value for YYLVAL when a WORD is read. */ - WORD_DESC *the_word; - - /* Index into the token that we are building. */ - int token_index; - - /* ALL_DIGITS becomes zero when we see a non-digit. */ - int all_digit_token; - - /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ - int dollar_present; - - /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ - int quoted; - - /* Non-zero means to ignore the value of the next character, and just - to add it no matter what. */ - int pass_next_character; - - /* The current delimiting character. */ - int cd; - int result, peek_char; - char *ttok, *ttrans; - int ttoklen, ttranslen; - intmax_t lvalue; - - if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE) - token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE); - - token_index = 0; - all_digit_token = DIGIT (character); - dollar_present = quoted = pass_next_character = 0; - - for (;;) - { - if (character == EOF) - goto got_token; - - if (pass_next_character) - { - pass_next_character = 0; - goto got_character; - } - - cd = current_delimiter (dstack); - - /* Handle backslashes. Quote lots of things when not inside of - double-quotes, quote some things inside of double-quotes. */ - if MBTEST(character == '\\') - { - peek_char = shell_getc (0); - - /* Backslash-newline is ignored in all cases except - when quoted with single quotes. */ - if (peek_char == '\n') - { - character = '\n'; - goto next_character; - } - else - { - shell_ungetc (peek_char); - - /* If the next character is to be quoted, note it now. */ - if (cd == 0 || cd == '`' || - (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE))) - pass_next_character++; - - quoted = 1; - goto got_character; - } - } - - /* Parse a matched pair of quote characters. */ - if MBTEST(shellquote (character)) - { - push_delimiter (dstack, character); - ttok = parse_matched_pair (character, character, character, &ttoklen, 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - strcpy (token + token_index, ttok); - token_index += ttoklen; - all_digit_token = 0; - quoted = 1; - dollar_present |= (character == '"' && strchr (ttok, '$') != 0); - FREE (ttok); - goto next_character; - } - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if (extended_glob && PATTERN_CHAR (character)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ - { - push_delimiter (dstack, peek_char); - ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - token[token_index++] = peek_char; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } - else - shell_ungetc (peek_char); - } -#endif /* EXTENDED_GLOB */ - - /* If the delimiter character is not single quote, parse some of - the shell expansions that must be read as a single word. */ - if (shellexp (character)) - { - peek_char = shell_getc (1); - /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ - if MBTEST(peek_char == '(' || \ - ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ - { - if (peek_char == '{') /* } */ - ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE); - else if (peek_char == '(') /* ) */ - { - /* XXX - push and pop the `(' as a delimiter for use by - the command-oriented-history code. This way newlines - appearing in the $(...) string get added to the - history literally rather than causing a possibly- - incorrect `;' to be added. ) */ - push_delimiter (dstack, peek_char); - ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); - pop_delimiter (dstack); - } - else - ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - token[token_index++] = peek_char; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = 1; - all_digit_token = 0; - goto next_character; - } - /* This handles $'...' and $"..." new-style quoted strings. */ - else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"')) - { - int first_line; - - first_line = line_number; - push_delimiter (dstack, peek_char); - ttok = parse_matched_pair (peek_char, peek_char, peek_char, - &ttoklen, - (peek_char == '\'') ? P_ALLOWESC : 0); - pop_delimiter (dstack); - if (ttok == &matched_pair_error) - return -1; - if (peek_char == '\'') - { - ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); - free (ttok); - /* Insert the single quotes and correctly quote any - embedded single quotes (allowed because P_ALLOWESC was - passed to parse_matched_pair). */ - ttok = sh_single_quote (ttrans); - free (ttrans); - ttrans = ttok; - ttranslen = strlen (ttrans); - } - else - { - /* Try to locale-expand the converted string. */ - ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); - free (ttok); - - /* Add the double quotes back */ - ttok = (char *)xmalloc (ttranslen + 3); - ttok[0] = '"'; - strcpy (ttok + 1, ttrans); - ttok[ttranslen + 1] = '"'; - ttok[ttranslen += 2] = '\0'; - free (ttrans); - ttrans = ttok; - } - - RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - strcpy (token + token_index, ttrans); - token_index += ttranslen; - FREE (ttrans); - quoted = 1; - all_digit_token = 0; - goto next_character; - } - /* This could eventually be extended to recognize all of the - shell's single-character parameter expansions, and set flags.*/ - else if MBTEST(character == '$' && peek_char == '$') - { - ttok = (char *)xmalloc (3); - ttok[0] = ttok[1] = '$'; - ttok[2] = '\0'; - RESIZE_MALLOCED_BUFFER (token, token_index, 3, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - strcpy (token + token_index, ttok); - token_index += 2; - dollar_present = 1; - all_digit_token = 0; - FREE (ttok); - goto next_character; - } - else - shell_ungetc (peek_char); - } - -#if defined (ARRAY_VARS) - /* Identify possible array subscript assignment; match [...] */ - else if MBTEST(character == '[' && token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) /* ] */ - { - ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); - if (ttok == &matched_pair_error) - return -1; /* Bail immediately. */ - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - token[token_index++] = character; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - all_digit_token = 0; - goto next_character; - } - /* Identify possible compound array variable assignment. */ - else if MBTEST(character == '=' && token_index > 0 && token_is_assignment (token, token_index)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ - { - ttok = parse_compound_assignment (&ttoklen); - - RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, - token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - - token[token_index++] = '='; - token[token_index++] = '('; - if (ttok) - { - strcpy (token + token_index, ttok); - token_index += ttoklen; - } - token[token_index++] = ')'; - FREE (ttok); - all_digit_token = 0; - goto next_character; - } - else - shell_ungetc (peek_char); - } -#endif - - /* When not parsing a multi-character word construct, shell meta- - characters break words. */ - if MBTEST(shellbreak (character)) - { - shell_ungetc (character); - goto got_token; - } - - got_character: - - all_digit_token &= DIGIT (character); - dollar_present |= character == '$'; - - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; - - token[token_index++] = character; - - RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, - TOKEN_DEFAULT_GROW_SIZE); - - next_character: - if (character == '\n' && SHOULD_PROMPT ()) - 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). */ - cd = current_delimiter (dstack); - character = shell_getc (cd != '\'' && pass_next_character == 0); - } /* end for (;;) */ - -got_token: - - token[token_index] = '\0'; - - /* Check to see what thing we should return. If the last_read_token - is a `<', or a `&', or the character which ended this token is - a '>' or '<', then, and ONLY then, is this input token a NUMBER. - Otherwise, it is just a word, and should be returned as such. */ - if MBTEST(all_digit_token && (character == '<' || character == '>' || \ - last_read_token == LESS_AND || \ - last_read_token == GREATER_AND)) - { - if (legal_number (token, &lvalue) && (int)lvalue == lvalue) - yylval.number = lvalue; - else - yylval.number = -1; - return (NUMBER); - } - - /* Check for special case tokens. */ - result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1; - if (result >= 0) - return result; - -#if defined (ALIAS) - /* Posix.2 does not allow reserved words to be aliased, so check for all - of them, including special cases, before expanding the current token - as an alias. */ - if MBTEST(posixly_correct) - CHECK_FOR_RESERVED_WORD (token); - - /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting - inhibits alias expansion. */ - if (expand_aliases && quoted == 0) - { - result = alias_expand_token (token); - if (result == RE_READ_TOKEN) - return (RE_READ_TOKEN); - else if (result == NO_EXPANSION) - parser_state &= ~PST_ALEXPNEXT; - } - - /* If not in Posix.2 mode, check for reserved words after alias - expansion. */ - if MBTEST(posixly_correct == 0) -#endif - CHECK_FOR_RESERVED_WORD (token); - - the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - the_word->word = (char *)xmalloc (1 + token_index); - the_word->flags = 0; - strcpy (the_word->word, token); - if (dollar_present) - the_word->flags |= W_HASDOLLAR; - if (quoted) - the_word->flags |= W_QUOTED; - /* A word is an assignment if it appears at the beginning of a - simple command, or after another assignment word. This is - context-dependent, so it cannot be handled in the grammar. */ - if (assignment (token, (parser_state & PST_COMPASSIGN) != 0)) - { - the_word->flags |= W_ASSIGNMENT; - /* Don't perform word splitting on assignment statements. */ - if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0) - the_word->flags |= W_NOSPLIT; - } - - yylval.word = the_word; - - result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) - ? ASSIGNMENT_WORD : WORD; - - switch (last_read_token) - { - case FUNCTION: - parser_state |= PST_ALLOWOPNBRC; - function_dstart = line_number; - break; - case CASE: - case SELECT: - case FOR: - if (word_top < MAX_CASE_NEST) - word_top++; - word_lineno[word_top] = line_number; - break; - } - - return (result); -} - -/* Return 1 if TOKSYM is a token that after being read would allow - a reserved word to be seen, else 0. */ -static int -reserved_word_acceptable (toksym) - int toksym; -{ - switch (toksym) - { - case '\n': - case ';': - case '(': - case ')': - case '|': - case '&': - case '{': - case '}': /* XXX */ - case AND_AND: - case BANG: - case DO: - case DONE: - case ELIF: - case ELSE: - case ESAC: - case FI: - case IF: - case OR_OR: - case SEMI_SEMI: - case THEN: - case TIME: - case TIMEOPT: - case UNTIL: - case WHILE: - case 0: - return 1; - default: - 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 (tokstr) - char *tokstr; -{ - int i; - for (i = 0; word_token_alist[i].word; i++) - if (STREQ (tokstr, word_token_alist[i].word)) - return i; - return -1; -} - -#if 0 -#if defined (READLINE) -/* Called after each time readline is called. This insures that whatever - the new prompt string is gets propagated to readline's local prompt - variable. */ -static void -reset_readline_prompt () -{ - char *temp_prompt; - - if (prompt_string_pointer) - { - temp_prompt = (*prompt_string_pointer) - ? decode_prompt_string (*prompt_string_pointer) - : (char *)NULL; - - if (temp_prompt == 0) - { - temp_prompt = (char *)xmalloc (1); - temp_prompt[0] = '\0'; - } - - FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; - } -} -#endif /* READLINE */ -#endif /* 0 */ - -#if defined (HISTORY) -/* A list of tokens which can be followed by newlines, but not by - 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, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN, - 0 -}; - -/* If we are not within a delimited expression, try to be smart - about which separators can be semi-colons and which must be - newlines. Returns the string that should be added into the - history entry. */ -char * -history_delimiting_chars () -{ - register int i; - - if (dstack.delimiter_depth != 0) - return ("\n"); - - /* First, handle some special cases. */ - /*(*/ - /* If we just read `()', assume it's a function definition, and don't - add a semicolon. If the token before the `)' was not `(', and we're - not in the midst of parsing a case statement, assume it's a - parenthesized command and add the semicolon. */ - /*)(*/ - if (token_before_that == ')') - { - if (two_tokens_ago == '(') /*)*/ /* function def */ - return " "; - /* This does not work for subshells inside case statement - command lists. It's a suboptimal solution. */ - else if (parser_state & PST_CASESTMT) /* case statement pattern */ - return " "; - else - return "; "; /* (...) subshell */ - } - else if (token_before_that == WORD && two_tokens_ago == FUNCTION) - return " "; /* function def using `function name' without `()' */ - - else if (token_before_that == WORD && two_tokens_ago == FOR) - { - /* Tricky. `for i\nin ...' should not have a semicolon, but - `for i\ndo ...' should. We do what we can. */ - for (i = shell_input_line_index; whitespace(shell_input_line[i]); i++) - ; - if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n') - return " "; - return ";"; - } - - for (i = 0; no_semi_successors[i]; i++) - { - if (token_before_that == no_semi_successors[i]) - return (" "); - } - - return ("; "); -} -#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 == 0 || expanding_alias()) /* 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 = (char *)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; - } -} - -int -get_current_prompt_level () -{ - return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1); -} - -void -set_current_prompt_level (x) - int x; -{ - prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt; - current_prompt_string = *prompt_string_pointer; -} - -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: - - \a bell (ascii 07) - \d the date in Day Mon Date format - \e escape (ascii 033) - \h the hostname up to the first `.' - \H the hostname - \j the number of active jobs - \l the basename of the shell's tty device name - \n CRLF - \r CR - \s the name of the shell - \t the time in 24-hour hh:mm:ss format - \T the time in 12-hour hh:mm:ss format - \@ the time in 12-hour hh:mm am/pm format - \A the time in 24-hour hh:mm format - \D{fmt} the result of passing FMT to strftime(3) - \u your username - \v the version of bash (e.g., 2.00) - \V the release of bash, version + patchlevel (e.g., 2.00.0) - \w the current working directory - \W the last element of $PWD - \! the history number of this command - \# the command number of this command - \$ a $ or a # if you are root - \nnn character code nnn in octal - \\ a backslash - \[ begin a sequence of non-printing chars - \] end a sequence of non-printing chars -*/ -#define PROMPT_GROWTH 48 -char * -decode_prompt_string (string) - char *string; -{ - WORD_LIST *list; - char *result, *t; - struct dstack save_dstack; - int last_exit_value; -#if defined (PROMPT_STRING_DECODE) - int result_size, result_index; - int c, n; - char *temp, octal_string[4]; - struct tm *tm; - time_t the_time; - char timebuf[128]; - char *timefmt; - - result = (char *)xmalloc (result_size = PROMPT_GROWTH); - result[result_index = 0] = 0; - temp = (char *)NULL; - - 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': - strncpy (octal_string, string, 3); - octal_string[3] = '\0'; - - n = read_octal (octal_string); - temp = (char *)xmalloc (3); - - if (n == CTLESC || n == CTLNUL) - { - temp[0] = CTLESC; - temp[1] = n; - temp[2] = '\0'; - } - else if (n == -1) - { - temp[0] = '\\'; - temp[1] = '\0'; - } - else - { - temp[0] = n; - temp[1] = '\0'; - } - - for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++) - string++; - - c = 0; /* tested at add_string: */ - goto add_string; - - case 'd': - case 't': - case 'T': - case '@': - case 'A': - /* Make the current time/date into a string. */ - (void) time (&the_time); - tm = localtime (&the_time); - - if (c == 'd') - n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm); - else if (c == 't') - n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm); - else if (c == 'T') - n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm); - else if (c == '@') - n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm); - else if (c == 'A') - n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm); - - timebuf[sizeof(timebuf) - 1] = '\0'; - temp = savestring (timebuf); - goto add_string; - - case 'D': /* strftime format */ - if (string[1] != '{') /* } */ - goto not_escape; - - (void) time (&the_time); - tm = localtime (&the_time); - string += 2; /* skip { */ - timefmt = xmalloc (strlen (string) + 3); - for (t = timefmt; *string && *string != '}'; ) - *t++ = *string++; - *t = '\0'; - c = *string; /* tested at add_string */ - if (timefmt[0] == '\0') - { - timefmt[0] = '%'; - timefmt[1] = 'X'; /* locale-specific current time */ - timefmt[2] = '\0'; - } - n = strftime (timebuf, sizeof (timebuf), timefmt, tm); - free (timefmt); - - timebuf[sizeof(timebuf) - 1] = '\0'; - if (promptvars || posixly_correct) - /* Make sure that expand_prompt_string is called with a - second argument of Q_DOUBLE_QUOTES if we use this - function here. */ - temp = sh_backslash_quote_for_double_quotes (timebuf); - else - temp = savestring (timebuf); - goto add_string; - - case 'n': - temp = (char *)xmalloc (3); - temp[0] = no_line_editing ? '\n' : '\r'; - temp[1] = no_line_editing ? '\0' : '\n'; - temp[2] = '\0'; - goto add_string; - - case 's': - temp = base_pathname (shell_name); - temp = savestring (temp); - goto add_string; - - case 'v': - case 'V': - temp = (char *)xmalloc (16); - if (c == 'v') - strcpy (temp, dist_version); - else - sprintf (temp, "%s.%d", dist_version, patch_level); - goto add_string; - - case 'w': - case 'W': - { - /* Use the value of PWD because it is much more efficient. */ - char t_string[PATH_MAX], *t; - int tlen; - - temp = get_string_value ("PWD"); - - if (temp == 0) - { - if (getcwd (t_string, sizeof(t_string)) == 0) - { - t_string[0] = '.'; - tlen = 1; - } - else - tlen = strlen (t_string); - } - else - { - tlen = sizeof (t_string) - 1; - strncpy (t_string, temp, tlen); - } - t_string[tlen] = '\0'; - -#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0) -#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0) - /* Abbreviate \W as ~ if $PWD == $HOME */ - if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, temp) == 0)) - { - if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0) - { - t = strrchr (t_string, '/'); - if (t) - strcpy (t_string, t + 1); - } - } -#undef ROOT_PATH -#undef DOUBLE_SLASH_ROOT - else - /* polite_directory_format is guaranteed to return a string - no longer than PATH_MAX - 1 characters. */ - strcpy (t_string, polite_directory_format (t_string)); - - /* If we're going to be expanding the prompt string later, - quote the directory name. */ - if (promptvars || posixly_correct) - /* Make sure that expand_prompt_string is called with a - second argument of Q_DOUBLE_QUOTES if we use this - function here. */ - temp = sh_backslash_quote_for_double_quotes (t_string); - else - temp = savestring (t_string); - - goto add_string; - } - - case 'u': - if (current_user.user_name == 0) - get_current_user_info (); - temp = savestring (current_user.user_name); - goto add_string; - - case 'h': - case 'H': - temp = savestring (current_host_name); - if (c == 'h' && (t = (char *)strchr (temp, '.'))) - *t = '\0'; - goto add_string; - - case '#': - temp = itos (current_command_number); - goto add_string; - - case '!': -#if !defined (HISTORY) - temp = savestring ("1"); -#else /* HISTORY */ - temp = itos (history_number ()); -#endif /* HISTORY */ - goto add_string; - - case '$': - t = temp = (char *)xmalloc (3); - if ((promptvars || posixly_correct) && (current_user.euid != 0)) - *t++ = '\\'; - *t++ = current_user.euid == 0 ? '#' : '$'; - *t = '\0'; - goto add_string; - - case 'j': - temp = itos (count_all_jobs ()); - goto add_string; - - case 'l': -#if defined (HAVE_TTYNAME) - temp = (char *)ttyname (fileno (stdin)); - t = temp ? base_pathname (temp) : "tty"; - temp = savestring (t); -#else - temp = savestring ("tty"); -#endif /* !HAVE_TTYNAME */ - goto add_string; - -#if defined (READLINE) - case '[': - case ']': - if (no_line_editing) - { - string++; - break; - } - temp = (char *)xmalloc (3); - temp[0] = '\001'; - temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - temp[2] = '\0'; - goto add_string; -#endif /* READLINE */ - - case '\\': - case 'a': - case 'e': - case 'r': - temp = (char *)xmalloc (2); - if (c == 'a') - temp[0] = '\07'; - else if (c == 'e') - temp[0] = '\033'; - else if (c == 'r') - temp[0] = '\r'; - else /* (c == '\\') */ - temp[0] = c; - temp[1] = '\0'; - goto add_string; - - default: -not_escape: - temp = (char *)xmalloc (3); - temp[0] = '\\'; - temp[1] = c; - temp[2] = '\0'; - - add_string: - if (c) - string++; - result = - sub_append_string (temp, result, &result_index, &result_size); - temp = (char *)NULL; /* Freed in sub_append_string (). */ - result[result_index] = '\0'; - break; - } - } - else - { - RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); - result[result_index++] = c; - result[result_index] = '\0'; - } - } -#else /* !PROMPT_STRING_DECODE */ - result = savestring (string); -#endif /* !PROMPT_STRING_DECODE */ - - /* Save the delimiter stack and point `dstack' to temp space so any - command substitutions in the prompt string won't result in screwing - up the parser's quoting state. */ - save_dstack = dstack; - dstack = temp_dstack; - dstack.delimiter_depth = 0; - - /* Perform variable and parameter expansion and command substitution on - the prompt string. */ - if (promptvars || posixly_correct) - { - last_exit_value = last_command_exit_value; - list = expand_prompt_string (result, Q_DOUBLE_QUOTES); - free (result); - result = string_list (list); - dispose_words (list); - last_command_exit_value = last_exit_value; - } - else - { - t = dequote_string (result); - free (result); - result = t; - } - - dstack = save_dstack; - - return (result); -} - -/************************************************ - * * - * ERROR HANDLING * - * * - ************************************************/ - -/* Report a syntax error, and restart the parser. Call here for fatal - errors. */ -int -yyerror (msg) - const char *msg; -{ - report_syntax_error ((char *)NULL); - reset_parser (); - return (0); -} - -static char * -error_token_from_token (token) - int token; -{ - char *t; - - if (t = find_token_in_alist (token, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (token, other_token_alist, 0)) - return t; - - t = (char *)NULL; - /* This stuff is dicy and needs closer inspection */ - switch (current_token) - { - case WORD: - case ASSIGNMENT_WORD: - if (yylval.word) - t = savestring (yylval.word->word); - break; - case NUMBER: - t = itos (yylval.number); - break; - case ARITH_CMD: - if (yylval.word_list) - t = string_list (yylval.word_list); - break; - case ARITH_FOR_EXPRS: - if (yylval.word_list) - t = string_list_internal (yylval.word_list, " ; "); - break; - case COND_CMD: - t = (char *)NULL; /* punt */ - break; - } - - return t; -} - -static char * -error_token_from_text () -{ - char *msg, *t; - int token_end, i; - - t = shell_input_line; - i = shell_input_line_index; - token_end = 0; - msg = (char *)NULL; - - if (i && t[i] == '\0') - i--; - - while (i && (whitespace (t[i]) || t[i] == '\n')) - i--; - - if (i) - token_end = i + 1; - - while (i && (member (t[i], " \n\t;|&") == 0)) - i--; - - while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) - i++; - - /* Return our idea of the offending token. */ - if (token_end || (i == 0 && token_end == 0)) - { - if (token_end) - msg = substring (t, i, token_end); - else /* one-character token */ - { - msg = (char *)xmalloc (2); - msg[0] = t[i]; - msg[1] = '\0'; - } - } - - return (msg); -} - -static void -print_offending_line () -{ - char *msg; - int token_end; - - msg = savestring (shell_input_line); - token_end = strlen (msg); - while (token_end && msg[token_end - 1] == '\n') - msg[--token_end] = '\0'; - - parser_error (line_number, "`%s'", msg); - free (msg); -} - -/* 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; -{ - char *msg; - - if (message) - { - parser_error (line_number, "%s", message); - if (interactive && EOF_Reached) - EOF_Reached = 0; - last_command_exit_value = EX_USAGE; - return; - } - - /* If the line of input we're reading is not null, try to find the - objectionable token. First, try to figure out what token the - parser's complaining about by looking at current_token. */ - if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token))) - { - parser_error (line_number, _("syntax error near unexpected token `%s'"), msg); - free (msg); - - if (interactive == 0) - print_offending_line (); - - last_command_exit_value = EX_USAGE; - return; - } - - /* If looking at the current token doesn't prove fruitful, try to find the - offending token by analyzing the text of the input line near the current - input line index and report what we find. */ - if (shell_input_line && *shell_input_line) - { - msg = error_token_from_text (); - if (msg) - { - parser_error (line_number, _("syntax error near `%s'"), msg); - free (msg); - } - - /* If not interactive, print the line containing the error. */ - if (interactive == 0) - print_offending_line (); - } - else - { - msg = EOF_Reached ? _("syntax error: unexpected end of file") : _("syntax error"); - parser_error (line_number, "%s", msg); - /* When the shell is interactive, this file uses EOF_Reached - only for error reporting. Other mechanisms are used to - decide whether or not to exit. */ - if (interactive && EOF_Reached) - EOF_Reached = 0; - } - - last_command_exit_value = EX_USAGE; -} - -/* ??? 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.) */ -static void -discard_parser_constructs (error_p) - int error_p; -{ -} - -/************************************************ - * * - * EOF HANDLING * - * * - ************************************************/ - -/* 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 parsing state. */ - last_read_token = current_token = '\n'; - /* Reset the prompt string to be $PS1. */ - prompt_string_pointer = (char **)NULL; - prompt_again (); - 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; - } -} - -/************************************************ - * * - * STRING PARSING FUNCTIONS * - * * - ************************************************/ - -/* It's very important that these two functions treat the characters - between ( and ) identically. */ - -static WORD_LIST parse_string_error; - -/* Take a string and run it through the shell parser, returning the - resultant word list. Used by compound array assignment. */ -WORD_LIST * -parse_string_to_word_list (s, flags, whom) - char *s; - int flags; - const char *whom; -{ - WORD_LIST *wl; - int tok, orig_current_token, orig_line_number, orig_input_terminator; - int orig_line_count; - int old_echo_input, old_expand_aliases; -#if defined (HISTORY) - int old_remember_on_history, old_history_expansion_inhibited; -#endif - -#if defined (HISTORY) - old_remember_on_history = remember_on_history; -# if defined (BANG_HISTORY) - old_history_expansion_inhibited = history_expansion_inhibited; -# endif - bash_history_disable (); -#endif - - orig_line_number = line_number; - orig_line_count = current_command_line_count; - orig_input_terminator = shell_input_line_terminator; - old_echo_input = echo_input_at_read; - old_expand_aliases = expand_aliases; - - push_stream (1); - last_read_token = WORD; /* WORD to allow reserved words here */ - current_command_line_count = 0; - echo_input_at_read = expand_aliases = 0; - - with_input_from_string (s, whom); - wl = (WORD_LIST *)NULL; - - if (flags & 1) - parser_state |= PST_COMPASSIGN; - - while ((tok = read_token (READ)) != yacc_EOF) - { - if (tok == '\n' && *bash_input.location.string == '\0') - break; - if (tok == '\n') /* Allow newlines in compound assignments */ - continue; - if (tok != WORD && tok != ASSIGNMENT_WORD) - { - line_number = orig_line_number + line_number - 1; - orig_current_token = current_token; - current_token = tok; - yyerror ((char *)NULL); /* does the right thing */ - current_token = orig_current_token; - if (wl) - dispose_words (wl); - wl = &parse_string_error; - break; - } - wl = make_word_list (yylval.word, wl); - } - - last_read_token = '\n'; - pop_stream (); - -#if defined (HISTORY) - remember_on_history = old_remember_on_history; -# if defined (BANG_HISTORY) - history_expansion_inhibited = old_history_expansion_inhibited; -# endif /* BANG_HISTORY */ -#endif /* HISTORY */ - - echo_input_at_read = old_echo_input; - expand_aliases = old_expand_aliases; - - current_command_line_count = orig_line_count; - shell_input_line_terminator = orig_input_terminator; - - if (flags & 1) - parser_state &= ~PST_COMPASSIGN; - - if (wl == &parse_string_error) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - jump_to_top_level (FORCE_EOF); - else - jump_to_top_level (DISCARD); - } - - return (REVERSE_LIST (wl, WORD_LIST *)); -} - -static char * -parse_compound_assignment (retlenp) - int *retlenp; -{ - WORD_LIST *wl, *rl; - int tok, orig_line_number, orig_token_size; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - wl = (WORD_LIST *)NULL; /* ( */ - parser_state |= PST_COMPASSIGN; - - while ((tok = read_token (READ)) != ')') - { - if (tok == '\n') /* Allow newlines in compound assignments */ - { - if (SHOULD_PROMPT ()) - prompt_again (); - continue; - } - if (tok != WORD && tok != ASSIGNMENT_WORD) - { - current_token = tok; /* for error reporting */ - if (tok == yacc_EOF) /* ( */ - parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'")); - else - yyerror ((char *)NULL); /* does the right thing */ - if (wl) - dispose_words (wl); - wl = &parse_string_error; - break; - } - wl = make_word_list (yylval.word, wl); - } - - FREE (token); - token = saved_token; - token_buffer_size = orig_token_size; - - parser_state &= ~PST_COMPASSIGN; - - if (wl == &parse_string_error) - { - last_command_exit_value = EXECUTION_FAILURE; - last_read_token = '\n'; /* XXX */ - if (interactive_shell == 0 && posixly_correct) - jump_to_top_level (FORCE_EOF); - else - jump_to_top_level (DISCARD); - } - - last_read_token = WORD; - if (wl) - { - rl = REVERSE_LIST (wl, WORD_LIST *); - ret = string_list (rl); - dispose_words (rl); - } - else - ret = (char *)NULL; - - if (retlenp) - *retlenp = (ret && *ret) ? strlen (ret) : 0; - return ret; -} - -/************************************************ - * * - * SAVING AND RESTORING PARTIAL PARSE STATE * - * * - ************************************************/ - -sh_parser_state_t * -save_parser_state (ps) - sh_parser_state_t *ps; -{ -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - if (ps == 0) - ps = xmalloc (sizeof (sh_parser_state_t)); - if (ps == 0) - return ((sh_parser_state_t *)NULL); - - ps->parser_state = parser_state; - ps->token_state = save_token_state (); - - ps->input_line_terminator = shell_input_line_terminator; - ps->eof_encountered = eof_encountered; - - ps->current_command_line_count = current_command_line_count; - -#if defined (HISTORY) - ps->remember_on_history = remember_on_history; -# if defined (BANG_HISTORY) - ps->history_expansion_inhibited = history_expansion_inhibited; -# endif -#endif - - ps->last_command_exit_value = last_command_exit_value; -#if defined (ARRAY_VARS) - v = find_variable ("PIPESTATUS"); - if (v && array_p (v) && array_cell (v)) - ps->pipestatus = array_copy (array_cell (v)); - else - ps->pipestatus = (ARRAY *)NULL; -#endif - - ps->last_shell_builtin = last_shell_builtin; - ps->this_shell_builtin = this_shell_builtin; - - ps->expand_aliases = expand_aliases; - ps->echo_input_at_read = echo_input_at_read; - - return (ps); -} - -void -restore_parser_state (ps) - sh_parser_state_t *ps; -{ -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - if (ps == 0) - return; - - parser_state = ps->parser_state; - if (ps->token_state) - { - restore_token_state (ps->token_state); - free (ps->token_state); - } - - shell_input_line_terminator = ps->input_line_terminator; - eof_encountered = ps->eof_encountered; - - current_command_line_count = ps->current_command_line_count; - -#if defined (HISTORY) - remember_on_history = ps->remember_on_history; -# if defined (BANG_HISTORY) - history_expansion_inhibited = ps->history_expansion_inhibited; -# endif -#endif - - last_command_exit_value = ps->last_command_exit_value; -#if defined (ARRAY_VARS) - v = find_variable ("PIPESTATUS"); - if (v && array_p (v) && array_cell (v)) - { - array_dispose (array_cell (v)); - var_setarray (v, ps->pipestatus); - } -#endif - - last_shell_builtin = ps->last_shell_builtin; - this_shell_builtin = ps->this_shell_builtin; - - expand_aliases = ps->expand_aliases; - echo_input_at_read = ps->echo_input_at_read; -} - -/************************************************ - * * - * MULTIBYTE CHARACTER HANDLING * - * * - ************************************************/ - -#if defined (HANDLE_MULTIBYTE) -static void -set_line_mbstate () -{ - int i, previ, len, c; - mbstate_t mbs, prevs; - size_t mbclen; - - if (shell_input_line == NULL) - return; - len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */ - FREE (shell_input_line_property); - shell_input_line_property = (char *)xmalloc (len + 1); - - memset (&prevs, '\0', sizeof (mbstate_t)); - for (i = previ = 0; i < len; i++) - { - mbs = prevs; - - c = shell_input_line[i]; - if (c == EOF) - { - int j; - for (j = i; j < len; j++) - shell_input_line_property[j] = 1; - break; - } - - mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs); - if (mbclen == 1 || mbclen == (size_t)-1) - { - mbclen = 1; - previ = i + 1; - } - else if (mbclen == (size_t)-2) - mbclen = 0; - else if (mbclen > 1) - { - mbclen = 0; - previ = i + 1; - prevs = mbs; - } - else - { - /* XXX - what to do if mbrlen returns 0? (null wide character) */ - int j; - for (j = i; j < len; j++) - shell_input_line_property[j] = 1; - break; - } - - shell_input_line_property[i] = mbclen; - } -} -#endif /* HANDLE_MULTIBYTE */ diff --git a/po/bash.po.orig b/po/bash.po.orig deleted file mode 100644 index 023388d96..000000000 --- a/po/bash.po.orig +++ /dev/null @@ -1,5623 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#: array.c:695 array.c:755 array.c:879 bashhist.c:661 bashline.c:801 -#: bashline.c:1416 error.c:88 error.c:318 error.c:320 error.c:322 -#: execute_cmd.c:2005 execute_cmd.c:2007 execute_cmd.c:2195 execute_cmd.c:2441 -#: execute_cmd.c:2580 execute_cmd.c:3186 execute_cmd.c:3838 expr.c:1092 -#: expr.c:1093 general.c:132 jobs.c:1128 jobs.c:1143 jobs.c:2318 jobs.c:2319 -#: locale.c:64 locale.c:422 parse.y:1209 pcomplete.c:937 pcomplete.c:947 -#: pcomplete.c:1076 print_cmd.c:142 print_cmd.c:305 print_cmd.c:364 -#: print_cmd.c:368 print_cmd.c:374 print_cmd.c:378 print_cmd.c:548 -#: print_cmd.c:733 print_cmd.c:847 print_cmd.c:851 subst.c:1483 subst.c:1510 -#: subst.c:1734 subst.c:1754 subst.c:4238 subst.c:4274 subst.c:6391 -#: syntax.h:43 unwind_prot.c:173 variables.c:1631 variables.c:2381 -#: /usr/homes/chet/src/bash/src/parse.y:1209 builtins/common.c:144 -#: builtins/common.c:640 builtins/getopt.c:204 builtins/mkbuiltins.c:1067 -#: builtins/mkbuiltins.c:1070 builtins/mkbuiltins.c:1072 -#: builtins/mkbuiltins.c:1074 builtins/mkbuiltins.c:1079 -#: builtins/mkbuiltins.c:1084 builtins/mkbuiltins.c:1088 -#: builtins/mkbuiltins.c:1094 builtins/mkbuiltins.c:1100 -#: builtins/mkbuiltins.c:1108 builtins/mkbuiltins.c:1111 -#: builtins/mkbuiltins.c:1207 builtins/mkbuiltins.c:1208 -#: builtins/caller.def:127 builtins/caller.def:131 builtins/command.def:134 -#: builtins/complete.def:567 builtins/declare.def:238 builtins/declare.def:355 -#: builtins/declare.def:438 builtins/fc.def:338 builtins/getopts.def:310 -#: builtins/help.def:105 builtins/help.def:110 builtins/history.def:291 -#: builtins/printf.def:123 builtins/printf.def:726 builtins/pushd.def:330 -#: builtins/pushd.def:371 builtins/pushd.def:654 builtins/pushd.def:662 -#: builtins/pushd.def:665 builtins/pushd.def:675 builtins/pushd.def:679 -#: builtins/pushd.def:683 builtins/pushd.def:686 builtins/pushd.def:689 -#: builtins/pushd.def:698 builtins/pushd.def:702 builtins/pushd.def:706 -#: builtins/pushd.def:709 builtins/read.def:258 builtins/read.def:386 -#: builtins/read.def:595 builtins/setattr.def:353 builtins/setattr.def:396 -#: builtins/ulimit.def:111 builtins/umask.def:131 lib/sh/snprintf.c:394 -#: lib/sh/snprintf.c:1691 lib/sh/stringlist.c:235 lib/sh/stringvec.c:223 -#: lib/malloc/stats.c:99 -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2003-12-04 16:07-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: arrayfunc.c:43 -msgid "bad array subscript" -msgstr "" - -#: arrayfunc.c:304 -#, c-format -msgid "%s: cannot assign to non-numeric index" -msgstr "" - -#: bashhist.c:319 -#, c-format -msgid "%s: cannot create: %s" -msgstr "" - -#: bashline.c:2789 -msgid "bash_execute_unix_command: cannot find keymap for command" -msgstr "" - -#: bashline.c:2838 -#, c-format -msgid "%s: first non-whitespace character is not `\"'" -msgstr "" - -#: bashline.c:2867 braces.c:129 -#, c-format -msgid "no closing `%c' in %s" -msgstr "" - -#: bashline.c:2901 -#, c-format -msgid "%s: missing colon separator" -msgstr "" - -#: error.c:163 -#, c-format -msgid "last command: %s\n" -msgstr "" - -#: error.c:168 -#, c-format -msgid "Report this to %s\n" -msgstr "" - -#: error.c:171 -msgid "Stopping myself..." -msgstr "" - -#: error.c:258 -#, c-format -msgid "%s: warning: " -msgstr "" - -#: error.c:403 -msgid "unknown command error" -msgstr "" - -#: error.c:404 -msgid "bad command type" -msgstr "" - -#: error.c:405 -msgid "bad connector" -msgstr "" - -#: error.c:406 -msgid "bad jump" -msgstr "" - -#: error.c:444 -#, c-format -msgid "%s: unbound variable" -msgstr "" - -#: error.c:451 builtins/common.c:221 -#, c-format -msgid "%s: readonly variable" -msgstr "" - -#: eval.c:173 -msgid "timed out waiting for input: auto-logout\n" -msgstr "" - -#: execute_cmd.c:447 -msgid "close" -msgstr "" - -#: execute_cmd.c:447 -msgid "open" -msgstr "" - -#: execute_cmd.c:465 -#, c-format -msgid "cannot redirect standard input from /dev/null: %s" -msgstr "" - -#: execute_cmd.c:1035 -#, c-format -msgid "TIMEFORMAT: `%c': invalid format character" -msgstr "" - -#: execute_cmd.c:3520 -#, c-format -msgid "%s: restricted: cannot specify `/' in command names" -msgstr "" - -#: execute_cmd.c:3608 -#, c-format -msgid "%s: command not found" -msgstr "" - -#: execute_cmd.c:3820 shell.c:1393 builtins/evalfile.c:127 -#: builtins/hash.def:158 -#, c-format -msgid "%s: is a directory" -msgstr "" - -#: execute_cmd.c:3838 -#, c-format -msgid "%s: %s: bad interpreter" -msgstr "" - -#: execute_cmd.c:3875 shell.c:1403 builtins/evalfile.c:172 -#, c-format -msgid "%s: cannot execute binary file" -msgstr "" - -#: execute_cmd.c:3948 builtins/declare.def:306 -#, c-format -msgid "%s: readonly function" -msgstr "" - -#: execute_cmd.c:3987 -#, c-format -msgid "cannot duplicate fd %d to fd %d" -msgstr "" - -#: expr.c:238 -msgid "expression recursion level exceeded" -msgstr "" - -#: expr.c:262 -msgid "recursion stack underflow" -msgstr "" - -#: expr.c:373 -msgid "syntax error in expression" -msgstr "" - -#: expr.c:413 -msgid "attempted assignment to non-variable" -msgstr "" - -#: expr.c:434 expr.c:439 expr.c:749 -msgid "division by 0" -msgstr "" - -#: expr.c:465 -msgid "bug: bad expassign token" -msgstr "" - -#: expr.c:495 expr.c:510 builtins/let.def:92 builtins/let.def:117 -msgid "expression expected" -msgstr "" - -#: expr.c:507 -msgid "`:' expected for conditional expression" -msgstr "" - -#: expr.c:774 -msgid "exponent less than 0" -msgstr "" - -#: expr.c:818 -msgid "identifier expected after pre-increment or pre-decrement" -msgstr "" - -#: expr.c:846 -msgid "missing `)'" -msgstr "" - -#: expr.c:870 -msgid "syntax error: operand expected" -msgstr "" - -#: expr.c:1091 -#, c-format -msgid "%s%s%s: %s (error token is \"%s\")" -msgstr "" - -#: expr.c:1145 -msgid "bad number" -msgstr "" - -#: expr.c:1149 -msgid "invalid arithmetic base" -msgstr "" - -#: expr.c:1169 -msgid "value too great for base" -msgstr "" - -#: expr.c:1217 -#, c-format -msgid "%s: expression error\n" -msgstr "" - -#: general.c:58 -msgid "getcwd: cannot access parent directories" -msgstr "" - -#: general.c:227 general.c:232 builtins/common.c:193 -#, c-format -msgid "`%s': not a valid identifier" -msgstr "" - -#: input.c:229 -#, c-format -msgid "cannot allocate new file descriptor for bash input from fd %d" -msgstr "" - -#: input.c:237 -#, c-format -msgid "save_bash_input: buffer already exists for new fd %d" -msgstr "" - -#: jobs.c:692 -#, c-format -msgid "deleting stopped job %d with process group %ld" -msgstr "" - -#: jobs.c:1631 nojobs.c:646 -#, c-format -msgid "wait: pid %ld is not a child of this shell" -msgstr "" - -#: jobs.c:1814 -#, c-format -msgid "wait_for: No record of process %ld" -msgstr "" - -#: jobs.c:1957 -#, c-format -msgid "wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)" -msgstr "" - -#: jobs.c:2061 -#, c-format -msgid "wait_for_job: job %d is stopped" -msgstr "" - -#: jobs.c:2283 -#, c-format -msgid "%s: job has terminated" -msgstr "" - -#: jobs.c:2292 -#, c-format -msgid "%s: job %d already in background" -msgstr "" - -#: jobs.c:3036 -msgid "no job control in this shell" -msgstr "" - -#: jobs.c:3250 -#, c-format -msgid "tcsetpgrp(%d) failed: pid %ld to pgrp %ld" -msgstr "" - -#: mailcheck.c:381 -msgid "You have mail in $_" -msgstr "" - -#: mailcheck.c:406 -msgid "You have new mail in $_" -msgstr "" - -#: mailcheck.c:422 -#, c-format -msgid "The mail in %s has been read\n" -msgstr "" - -#: make_cmd.c:316 -msgid "syntax error: arithmetic expression required" -msgstr "" - -#: make_cmd.c:318 -msgid "syntax error: `;' unexpected" -msgstr "" - -#: make_cmd.c:558 -#, c-format -msgid "make_here_document: bad instruction type %d" -msgstr "" - -#: make_cmd.c:728 -#, c-format -msgid "make_redirection: redirection instruction `%d' out of range" -msgstr "" - -#: mksyntax.c:334 -#, c-format -msgid "%s: %s: cannot open: %s\n" -msgstr "" - -#: parse.y:1663 /usr/homes/chet/src/bash/src/parse.y:1663 -msgid "read_a_line: ignored null byte in input" -msgstr "" - -#: parse.y:1928 /usr/homes/chet/src/bash/src/parse.y:1928 -msgid "shell_getc: ignored null byte in input" -msgstr "" - -#: parse.y:2724 /usr/homes/chet/src/bash/src/parse.y:2724 -#, c-format -msgid "unexpected EOF while looking for matching `%c'" -msgstr "" - -#: parse.y:3009 /usr/homes/chet/src/bash/src/parse.y:3009 -msgid "unexpected EOF while looking for `]]'" -msgstr "" - -#: parse.y:3014 /usr/homes/chet/src/bash/src/parse.y:3014 -#, c-format -msgid "syntax error in conditional expression: unexpected token `%s'" -msgstr "" - -#: parse.y:3018 /usr/homes/chet/src/bash/src/parse.y:3018 -msgid "syntax error in conditional expression" -msgstr "" - -#: parse.y:3096 /usr/homes/chet/src/bash/src/parse.y:3096 -#, c-format -msgid "unexpected token `%s', expected `)'" -msgstr "" - -#: parse.y:3100 /usr/homes/chet/src/bash/src/parse.y:3100 -msgid "expected `)'" -msgstr "" - -#: parse.y:3128 /usr/homes/chet/src/bash/src/parse.y:3128 -#, c-format -msgid "unexpected argument `%s' to conditional unary operator" -msgstr "" - -#: parse.y:3132 /usr/homes/chet/src/bash/src/parse.y:3132 -msgid "unexpected argument to conditional unary operator" -msgstr "" - -#: parse.y:3160 /usr/homes/chet/src/bash/src/parse.y:3160 -msgid "-n" -msgstr "" - -#: parse.y:3169 /usr/homes/chet/src/bash/src/parse.y:3169 -#, c-format -msgid "unexpected token `%s', conditional binary operator expected" -msgstr "" - -#: parse.y:3173 /usr/homes/chet/src/bash/src/parse.y:3173 -msgid "conditional binary operator expected" -msgstr "" - -#: parse.y:3189 /usr/homes/chet/src/bash/src/parse.y:3189 -#, c-format -msgid "unexpected argument `%s' to conditional binary operator" -msgstr "" - -#: parse.y:3193 /usr/homes/chet/src/bash/src/parse.y:3193 -msgid "unexpected argument to conditional binary operator" -msgstr "" - -#: parse.y:3204 /usr/homes/chet/src/bash/src/parse.y:3204 -#, c-format -msgid "unexpected token `%c' in conditional command" -msgstr "" - -#: parse.y:3207 /usr/homes/chet/src/bash/src/parse.y:3207 -#, c-format -msgid "unexpected token `%s' in conditional command" -msgstr "" - -#: parse.y:3211 /usr/homes/chet/src/bash/src/parse.y:3211 -#, c-format -msgid "unexpected token %d in conditional command" -msgstr "" - -#: parse.y:4398 /usr/homes/chet/src/bash/src/parse.y:4398 -#, c-format -msgid "syntax error near unexpected token `%s'" -msgstr "" - -#: parse.y:4416 /usr/homes/chet/src/bash/src/parse.y:4416 -#, c-format -msgid "syntax error near `%s'" -msgstr "" - -#: parse.y:4426 /usr/homes/chet/src/bash/src/parse.y:4426 -msgid "syntax error: unexpected end of file" -msgstr "" - -#: parse.y:4426 /usr/homes/chet/src/bash/src/parse.y:4426 -msgid "syntax error" -msgstr "" - -#: parse.y:4488 /usr/homes/chet/src/bash/src/parse.y:4488 -#, c-format -msgid "Use \"%s\" to leave the shell.\n" -msgstr "" - -#: parse.y:4647 /usr/homes/chet/src/bash/src/parse.y:4647 -msgid "unexpected EOF while looking for matching `)'" -msgstr "" - -#: pcomplete.c:987 -#, c-format -msgid "completion: function `%s' not found" -msgstr "" - -#: pcomplete.c:1222 -msgid "ERROR: command_line_to_word_list returns NULL" -msgstr "" - -#: pcomplib.c:177 -#, c-format -msgid "progcomp_insert: %s: NULL COMPSPEC" -msgstr "" - -#: print_cmd.c:259 -#, c-format -msgid "print_command: bad connector `%d'" -msgstr "" - -#: print_cmd.c:1171 -#, c-format -msgid "cprintf: `%c': invalid format character" -msgstr "" - -#: redir.c:98 redir.c:133 -msgid "file descriptor out of range" -msgstr "" - -#: redir.c:140 -#, c-format -msgid "%s: ambiguous redirect" -msgstr "" - -#: redir.c:144 -#, c-format -msgid "%s: cannot overwrite existing file" -msgstr "" - -#: redir.c:149 -#, c-format -msgid "%s: restricted: cannot redirect output" -msgstr "" - -#: redir.c:154 -#, c-format -msgid "cannot create temp file for here document: %s" -msgstr "" - -#: redir.c:508 -msgid "/dev/(tcp|udp)/host/port not supported without networking" -msgstr "" - -#: redir.c:948 -msgid "redirection error: cannot duplicate fd" -msgstr "" - -#: shell.c:300 -msgid "could not find /tmp, please create!" -msgstr "" - -#: shell.c:304 -msgid "/tmp must be a valid directory name" -msgstr "" - -#: shell.c:463 shell.c:735 builtins/common.c:156 -#, c-format -msgid "%s: option requires an argument" -msgstr "" - -#: shell.c:748 builtins/common.c:179 -#, c-format -msgid "%s: invalid option" -msgstr "" - -#: shell.c:837 -#, c-format -msgid "%c%c: invalid option" -msgstr "" - -#: shell.c:1588 -msgid "I have no name!" -msgstr "" - -#: shell.c:1721 -#, c-format -msgid "GNU bash, version %s-(%s)\n" -msgstr "" - -#: shell.c:1722 -#, c-format -msgid "" -"Usage:\t%s [GNU long option] [option] ...\n" -"\t%s [GNU long option] [option] script-file ...\n" -msgstr "" - -#: shell.c:1724 -msgid "GNU long options:\n" -msgstr "" - -#: shell.c:1726 -#, c-format -msgid "\t--%s\n" -msgstr "" - -#: shell.c:1728 -msgid "Shell options:\n" -msgstr "" - -#: shell.c:1729 -msgid "\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n" -msgstr "" - -#: shell.c:1732 builtins/mkbuiltins.c:131 builtins/set.def:2 -msgid "set" -msgstr "" - -#: shell.c:1744 -#, c-format -msgid "\t-%s or -o option\n" -msgstr "" - -#: shell.c:1750 -#, c-format -msgid "Type `%s -c \"help set\"' for more information about shell options.\n" -msgstr "" - -#: shell.c:1751 -#, c-format -msgid "Type `%s -c help' for more information about shell builtin commands.\n" -msgstr "" - -#: shell.c:1752 -msgid "Use the `bashbug' command to report bugs.\n" -msgstr "" - -#: sig.c:483 -msgid "Bad code in sig.c: sigprocmask" -msgstr "" - -#: siglist.c:47 -msgid "Bogus signal" -msgstr "" - -#: siglist.c:50 -msgid "Hangup" -msgstr "" - -#: siglist.c:54 -msgid "Interrupt" -msgstr "" - -#: siglist.c:58 -msgid "Quit" -msgstr "" - -#: siglist.c:62 -msgid "Illegal instruction" -msgstr "" - -#: siglist.c:66 -msgid "BPT trace/trap" -msgstr "" - -#: siglist.c:74 -msgid "ABORT instruction" -msgstr "" - -#: siglist.c:78 -msgid "EMT instruction" -msgstr "" - -#: siglist.c:82 -msgid "Floating point exception" -msgstr "" - -#: siglist.c:86 -msgid "Killed" -msgstr "" - -#: siglist.c:90 -msgid "Bus error" -msgstr "" - -#: siglist.c:94 -msgid "Segmentation fault" -msgstr "" - -#: siglist.c:98 -msgid "Bad system call" -msgstr "" - -#: siglist.c:102 -msgid "Broken pipe" -msgstr "" - -#: siglist.c:106 -msgid "Alarm clock" -msgstr "" - -#: siglist.c:110 -msgid "Terminated" -msgstr "" - -#: siglist.c:114 -msgid "Urgent IO condition" -msgstr "" - -#: siglist.c:118 -msgid "Stopped (signal)" -msgstr "" - -#: siglist.c:126 -msgid "Continue" -msgstr "" - -#: siglist.c:134 -msgid "Child death or stop" -msgstr "" - -#: siglist.c:138 -msgid "Stopped (tty input)" -msgstr "" - -#: siglist.c:142 -msgid "Stopped (tty output)" -msgstr "" - -#: siglist.c:146 -msgid "I/O ready" -msgstr "" - -#: siglist.c:150 -msgid "CPU limit" -msgstr "" - -#: siglist.c:154 -msgid "File limit" -msgstr "" - -#: siglist.c:158 -msgid "Alarm (virtual)" -msgstr "" - -#: siglist.c:162 -msgid "Alarm (profile)" -msgstr "" - -#: siglist.c:166 -msgid "Window changed" -msgstr "" - -#: siglist.c:170 -msgid "Record lock" -msgstr "" - -#: siglist.c:174 -msgid "User signal 1" -msgstr "" - -#: siglist.c:178 -msgid "User signal 2" -msgstr "" - -#: siglist.c:182 -msgid "HFT input data pending" -msgstr "" - -#: siglist.c:186 -msgid "power failure imminent" -msgstr "" - -#: siglist.c:190 -msgid "system crash imminent" -msgstr "" - -#: siglist.c:194 -msgid "migrate process to another CPU" -msgstr "" - -#: siglist.c:198 -msgid "programming error" -msgstr "" - -#: siglist.c:202 -msgid "HFT monitor mode granted" -msgstr "" - -#: siglist.c:206 -msgid "HFT monitor mode retracted" -msgstr "" - -#: siglist.c:210 -msgid "HFT sound sequence has completed" -msgstr "" - -#: siglist.c:214 -msgid "Information request" -msgstr "" - -#: siglist.c:222 -msgid "Unknown Signal #" -msgstr "" - -#: siglist.c:224 -#, c-format -msgid "Unknown Signal #%d" -msgstr "" - -#: subst.c:666 subst.c:752 subst.c:865 subst.c:1107 subst.c:1370 -msgid "$(" -msgstr "" - -#: subst.c:876 -msgid "$[" -msgstr "" - -#: subst.c:876 -msgid "[" -msgstr "" - -#: subst.c:876 -msgid "]" -msgstr "" - -#: subst.c:1010 subst.c:1131 -#, c-format -msgid "bad substitution: no closing `%s' in %s" -msgstr "" - -#: subst.c:2006 -#, c-format -msgid "%s%s=(%s)\n" -msgstr "" - -#: subst.c:2009 variables.c:2123 -#, c-format -msgid "%s%s=%s\n" -msgstr "" - -#: subst.c:2019 -#, c-format -msgid "%s: cannot assign list to array member" -msgstr "" - -#: subst.c:3381 -msgid "sh-np" -msgstr "" - -#: subst.c:3449 -#, c-format -msgid "pid %ld: dev_fd_list:" -msgstr "" - -#: subst.c:3455 /usr/local/share/bison/bison.simple:719 -#: /usr/local/share/bison/bison.simple:864 -#, c-format -msgid " %d" -msgstr "" - -#: subst.c:3515 subst.c:3531 -msgid "cannot make pipe for process substitution" -msgstr "" - -#: subst.c:3562 -msgid "cannot make child for process substitution" -msgstr "" - -#: subst.c:3605 -#, c-format -msgid "cannot open named pipe %s for %s" -msgstr "" - -#: subst.c:3606 -msgid "reading" -msgstr "" - -#: subst.c:3606 -msgid "writing" -msgstr "" - -#: subst.c:3613 -#, c-format -msgid "cannout reset nodelay mode for fd %d" -msgstr "" - -#: subst.c:3623 -#, c-format -msgid "cannot duplicate named pipe %s as fd %d" -msgstr "" - -#: subst.c:3647 -msgid "process substitution" -msgstr "" - -#: subst.c:3697 -msgid "read_comsub: ignored null byte in input" -msgstr "" - -#: subst.c:3798 -msgid "cannot make pipe for command substitution" -msgstr "" - -#: subst.c:3827 -msgid "cannot make child for command substitution" -msgstr "" - -#: subst.c:3844 -msgid "command_substitute: cannot duplicate pipe as fd 1" -msgstr "" - -#: subst.c:3901 -msgid "command substitution" -msgstr "" - -#: subst.c:4279 -#, c-format -msgid "%s: parameter null or not set" -msgstr "" - -#: subst.c:4524 -#, c-format -msgid "%s: substring expression < 0" -msgstr "" - -#: subst.c:4966 subst.c:4983 -msgid "#%:-=?+/}" -msgstr "" - -#: subst.c:5033 -msgid "%:=+/" -msgstr "" - -#: subst.c:5204 -#, c-format -msgid "%s: bad substitution" -msgstr "" - -#: subst.c:5204 builtins/history.def:247 -msgid "??" -msgstr "" - -#: subst.c:5278 -#, c-format -msgid "$%s: cannot assign in this way" -msgstr "" - -#: subst.c:5792 -msgid "<(" -msgstr "" - -#: subst.c:5792 -msgid ">(" -msgstr "" - -#: subst.c:6647 -#, c-format -msgid "no match: %s" -msgstr "" - -#: syntax.h:26 -msgid "\\`$\"\n" -msgstr "" - -#: syntax.h:27 -msgid "\\`$" -msgstr "" - -#: syntax.h:29 -msgid "()<>;&|" -msgstr "" - -#: syntax.h:32 -msgid "\"`'" -msgstr "" - -#: syntax.h:35 -msgid "$<>" -msgstr "" - -#: syntax.h:41 -msgid "@*+?!" -msgstr "" - -#: syntax.h:45 -msgid "*?[]^" -msgstr "" - -#: test.c:152 -msgid "argument expected" -msgstr "" - -#: test.c:161 -#, c-format -msgid "%s: integer expression expected" -msgstr "" - -#: test.c:176 -msgid "/dev/fd/" -msgstr "" - -#: test.c:202 -msgid "/dev/std" -msgstr "" - -#: test.c:206 -msgid "out" -msgstr "" - -#: test.c:208 -msgid "err" -msgstr "" - -#: test.c:359 -msgid "`)' expected" -msgstr "" - -#: test.c:361 -#, c-format -msgid "`)' expected, found %s" -msgstr "" - -#: test.c:376 test.c:785 test.c:788 -#, c-format -msgid "%s: unary operator expected" -msgstr "" - -#: test.c:541 test.c:828 -#, c-format -msgid "%s: binary operator expected" -msgstr "" - -#: test.c:903 builtins/test.def:134 -msgid "missing `]'" -msgstr "" - -#: test.c:919 builtins/common.c:132 -msgid "too many arguments" -msgstr "" - -#: trap.c:171 -msgid "DEFAULT_SIG" -msgstr "" - -#: trap.c:173 -msgid "IGNORE_SIG" -msgstr "" - -#: trap.c:175 -msgid "IMPOSSIBLE_TRAP_HANDLER" -msgstr "" - -#: trap.c:179 builtins/caller.def:94 -msgid "NULL" -msgstr "" - -#: trap.c:192 -msgid "invalid signal number" -msgstr "" - -#: trap.c:222 builtins/common.c:638 builtins/trap.def:218 -msgid "SIG" -msgstr "" - -#: trap.c:307 -#, c-format -msgid "run_pending_traps: bad value in trap_list[%d]: %p" -msgstr "" - -#: trap.c:311 -#, c-format -msgid "" -"run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" -msgstr "" - -#: trap.c:347 -#, c-format -msgid "trap_handler: bad signal %d" -msgstr "" - -#: trap.c:673 -msgid "exit trap" -msgstr "" - -#: trap.c:781 -msgid "debug trap" -msgstr "" - -#: trap.c:800 -msgid "error trap" -msgstr "" - -#: trap.c:811 -msgid "return trap" -msgstr "" - -#: trap.c:821 -msgid "interrupt trap" -msgstr "" - -#: variables.c:287 -msgid "() {" -msgstr "" - -#: variables.c:309 -#, c-format -msgid "error importing function definition for `%s'" -msgstr "" - -#: variables.c:370 -msgid "NODE" -msgstr "" - -#: variables.c:383 -msgid "# " -msgstr "" - -#: variables.c:387 -msgid "+ " -msgstr "" - -#: variables.c:390 variables.c:2867 variables.c:3464 variables.c:3500 -#: variables.c:3632 variables.c:3735 -msgid "IFS" -msgstr "" - -#: variables.c:401 -msgid "600" -msgstr "" - -#: variables.c:401 -msgid "60" -msgstr "" - -#: variables.c:409 variables.c:3647 variables.c:3955 builtins/getopts.def:231 -msgid "OPTIND" -msgstr "" - -#: variables.c:411 variables.c:3646 variables.c:3976 -msgid "OPTERR" -msgstr "" - -#: variables.c:420 -msgid "BASH" -msgstr "" - -#: variables.c:430 -msgid "BASH_VERSION" -msgstr "" - -#: variables.c:436 -msgid "BASH_EXECUTION_STRING" -msgstr "" - -#: variables.c:452 -msgid "~/.sh_history" -msgstr "" - -#: variables.c:452 -msgid "~/.bash_history" -msgstr "" - -#: variables.c:457 -msgid "500" -msgstr "" - -#: variables.c:469 variables.c:3633 builtins/set.def:313 builtins/set.def:315 -#: builtins/set.def:316 -msgid "IGNOREEOF" -msgstr "" - -#: variables.c:471 variables.c:3669 builtins/set.def:191 builtins/set.def:311 -msgid "ignoreeof" -msgstr "" - -#: variables.c:527 -msgid "HOSTTYPE" -msgstr "" - -#: variables.c:528 -msgid "OSTYPE" -msgstr "" - -#: variables.c:529 -msgid "MACHTYPE" -msgstr "" - -#: variables.c:531 -msgid "HOSTNAME" -msgstr "" - -#: variables.c:660 variables.c:694 -msgid "SHLVL" -msgstr "" - -#: variables.c:669 -#, c-format -msgid "shell level (%d) too high, resetting to 1" -msgstr "" - -#: variables.c:734 -msgid "shell-init" -msgstr "" - -#: variables.c:758 variables.c:761 -msgid "PPID" -msgstr "" - -#: variables.c:772 variables.c:775 -msgid "UID" -msgstr "" - -#: variables.c:782 variables.c:785 -msgid "EUID" -msgstr "" - -#: variables.c:798 variables.c:800 -msgid "BASH_VERSINFO" -msgstr "" - -#: variables.c:893 -#, c-format -msgid "%s=" -msgstr "" - -#: variables.c:1087 variables.c:1093 -msgid "SECONDS" -msgstr "" - -#: variables.c:1395 -msgid "BASH_COMMAND" -msgstr "" - -#: variables.c:1396 -msgid "BASH_SUBSHELL" -msgstr "" - -#: variables.c:1398 -msgid "RANDOM" -msgstr "" - -#: variables.c:1399 -msgid "LINENO" -msgstr "" - -#: variables.c:1402 -msgid "HISTCMD" -msgstr "" - -#: variables.c:1406 -msgid "COMP_WORDBREAKS" -msgstr "" - -#: variables.c:1410 -msgid "DIRSTACK" -msgstr "" - -#: variables.c:1414 -msgid "GROUPS" -msgstr "" - -#: variables.c:1417 variables.c:3554 variables.c:3578 builtins/evalfile.c:101 -msgid "BASH_ARGC" -msgstr "" - -#: variables.c:1418 variables.c:3553 variables.c:3577 builtins/evalfile.c:100 -msgid "BASH_ARGV" -msgstr "" - -#: variables.c:1609 -msgid "make_local_variable: no function context at current scope" -msgstr "" - -#: variables.c:2708 -msgid "all_local_variables: no function context at current scope" -msgstr "" - -#: variables.c:2922 variables.c:2931 -#, c-format -msgid "invalid character %d in exportstr for %s" -msgstr "" - -#: variables.c:2937 -#, c-format -msgid "no `=' in exportstr for %s" -msgstr "" - -#: variables.c:3071 -msgid ") {" -msgstr "" - -#: variables.c:3222 -msgid "_=" -msgstr "" - -#: variables.c:3242 -msgid "_GNU_nonoption_argv_flags_" -msgstr "" - -#: variables.c:3362 -msgid "pop_var_context: head of shell_variables not a function context" -msgstr "" - -#: variables.c:3375 -msgid "pop_var_context: no global_variables context" -msgstr "" - -#: variables.c:3441 -msgid "pop_scope: head of shell_variables not a temporary environment scope" -msgstr "" - -#: variables.c:3625 builtins/history.def:282 -msgid "HISTTIMEFORMAT" -msgstr "" - -#: variables.c:3635 -msgid "LANG" -msgstr "" - -#: variables.c:3636 -msgid "LC_ALL" -msgstr "" - -#: variables.c:3654 -msgid "TERMCAP" -msgstr "" - -#: variables.c:3655 -msgid "TERMINFO" -msgstr "" - -#: variables.c:3662 lib/sh/strftime.c:185 lib/sh/strftime.c:187 -msgid "TZ" -msgstr "" - -#: variables.c:3867 -msgid "ignorespace" -msgstr "" - -#: variables.c:3869 -msgid "ignoredups" -msgstr "" - -#: variables.c:3871 -msgid "ignoreboth" -msgstr "" - -#: variables.c:3873 -msgid "erasedups" -msgstr "" - -#: version.c:60 version.c:62 -#, c-format -msgid "%s.%d(%d)-%s" -msgstr "" - -#: version.c:66 version.c:68 -#, c-format -msgid "%s.%d(%d)" -msgstr "" - -#: version.c:78 -#, c-format -msgid "GNU bash, version %s (%s)\n" -msgstr "" - -#: version.c:80 -msgid "Copyright (C) 2003 Free Software Foundation, Inc.\n" -msgstr "" - -#: xmalloc.c:91 -#, c-format -msgid "xmalloc: cannot allocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:93 -#, c-format -msgid "xmalloc: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:113 -#, c-format -msgid "xrealloc: cannot reallocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:115 -#, c-format -msgid "xrealloc: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:149 -#, c-format -msgid "xmalloc: %s:%d: cannot allocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:151 -#, c-format -msgid "xmalloc: %s:%d: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:173 -#, c-format -msgid "xrealloc: %s:%d: cannot reallocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:175 -#, c-format -msgid "xrealloc: %s:%d: cannot allocate %lu bytes" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "error" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "$undefined." -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "IF" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "THEN" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "ELSE" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "ELIF" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "FI" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:469 -msgid "CASE" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "ESAC" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "FOR" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "SELECT" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "WHILE" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "UNTIL" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "DO" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 -msgid "DONE" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:470 builtins/mkbuiltins.c:425 -msgid "FUNCTION" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "COND_START" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "COND_END" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "COND_ERROR" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "IN" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "BANG" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "TIME" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:471 -msgid "TIMEOPT" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:472 -msgid "WORD" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:472 -msgid "ASSIGNMENT_WORD" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:472 -msgid "NUMBER" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:472 -msgid "ARITH_CMD" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:472 -msgid "ARITH_FOR_EXPRS" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:473 -msgid "COND_CMD" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:473 -msgid "AND_AND" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:473 -msgid "OR_OR" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:473 -msgid "GREATER_GREATER" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:473 -msgid "LESS_LESS" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:474 -msgid "LESS_AND" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:474 -msgid "LESS_LESS_LESS" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:474 -msgid "GREATER_AND" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:474 -msgid "SEMI_SEMI" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:475 -msgid "LESS_LESS_MINUS" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:475 -msgid "AND_GREATER" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:475 -msgid "LESS_GREATER" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:475 -msgid "GREATER_BAR" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:475 -msgid "'&'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "';'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'\\n'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "yacc_EOF" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'|'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'>'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'<'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'-'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'{'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:476 -msgid "'}'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:477 -msgid "'('" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:477 -msgid "')'" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:477 -msgid "inputunit" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:477 -msgid "word_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:477 -msgid "redirection" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:478 -msgid "simple_command_element" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:478 -msgid "redirection_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:478 -msgid "simple_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:479 builtins/command.def:2 -#: builtins/complete.def:82 -msgid "command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:479 -msgid "shell_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:479 -msgid "for_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:479 -msgid "arith_for_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:480 -msgid "select_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:480 -msgid "case_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:480 -msgid "function_def" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:480 -msgid "function_body" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:481 -msgid "subshell" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:481 -msgid "if_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:481 -msgid "group_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:481 -msgid "arith_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:482 -msgid "cond_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:482 -msgid "elif_clause" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:482 -msgid "case_clause" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:482 -msgid "pattern_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:483 -msgid "case_clause_sequence" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:483 -msgid "pattern" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:483 -msgid "list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:483 -msgid "compound_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:483 -msgid "list0" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:484 -msgid "list1" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:484 -msgid "simple_list_terminator" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:484 -msgid "list_terminator" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:484 -msgid "newline_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:485 -msgid "simple_list" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:485 -msgid "simple_list1" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:485 -msgid "pipeline_command" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:485 -msgid "pipeline" -msgstr "" - -#: /usr/homes/chet/src/bash/src/parse.y:486 -msgid "timespec" -msgstr "" - -#: /usr/local/share/bison/bison.simple:156 -msgid "syntax error: cannot back up" -msgstr "" - -#: /usr/local/share/bison/bison.simple:442 -msgid "Starting parse\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:492 -#: /usr/local/share/bison/bison.simple:499 -#: /usr/local/share/bison/bison.simple:924 -msgid "parser stack overflow" -msgstr "" - -#: /usr/local/share/bison/bison.simple:538 -#, c-format -msgid "Stack size increased to %lu\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:545 -#, c-format -msgid "Entering state %d\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:572 -msgid "Reading a token: " -msgstr "" - -#: /usr/local/share/bison/bison.simple:583 -msgid "Now at end of input.\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:594 -#, c-format -msgid "Next token is %d (%s" -msgstr "" - -#: /usr/local/share/bison/bison.simple:633 -#, c-format -msgid "Shifting token %d (%s), " -msgstr "" - -#: /usr/local/share/bison/bison.simple:695 -#, c-format -msgid "Reducing via rule %d (line %d), " -msgstr "" - -#: /usr/local/share/bison/bison.simple:701 -#, c-format -msgid " -> %s\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:717 -msgid "state stack now" -msgstr "" - -#: /usr/local/share/bison/bison.simple:769 -#: /usr/local/share/bison/bison.simple:774 -msgid "parse error, unexpected " -msgstr "" - -#: /usr/local/share/bison/bison.simple:785 -msgid ", expecting " -msgstr "" - -#: /usr/local/share/bison/bison.simple:785 -msgid " or " -msgstr "" - -#: /usr/local/share/bison/bison.simple:795 -msgid "parse error; also virtual memory exhausted" -msgstr "" - -#: /usr/local/share/bison/bison.simple:799 -msgid "parse error" -msgstr "" - -#: /usr/local/share/bison/bison.simple:816 -#, c-format -msgid "Discarding token %d (%s).\n" -msgstr "" - -#: /usr/local/share/bison/bison.simple:862 -msgid "Error: state stack now" -msgstr "" - -#: /usr/local/share/bison/bison.simple:895 -msgid "Shifting error token, " -msgstr "" - -#: builtins/common.c:102 -#, c-format -msgid "line %d: " -msgstr "" - -#: builtins/common.c:119 -#, c-format -msgid "%s: usage: " -msgstr "" - -#: builtins/common.c:163 -#, c-format -msgid "%s: numeric argument required" -msgstr "" - -#: builtins/common.c:170 -#, c-format -msgid "%s: not found" -msgstr "" - -#: builtins/common.c:186 -#, c-format -msgid "%s: invalid option name" -msgstr "" - -#: builtins/common.c:200 -#, c-format -msgid "%s: invalid number" -msgstr "" - -#: builtins/common.c:207 -#, c-format -msgid "%s: invalid signal specification" -msgstr "" - -#: builtins/common.c:214 -#, c-format -msgid "`%s': not a pid or valid job spec" -msgstr "" - -#: builtins/common.c:229 -#, c-format -msgid "%s: %s out of range" -msgstr "" - -#: builtins/common.c:229 builtins/common.c:231 -msgid "argument" -msgstr "" - -#: builtins/common.c:231 -#, c-format -msgid "%s out of range" -msgstr "" - -#: builtins/common.c:239 -#, c-format -msgid "%s: no such job" -msgstr "" - -#: builtins/common.c:247 -#, c-format -msgid "%s: no job control" -msgstr "" - -#: builtins/common.c:249 -msgid "no job control" -msgstr "" - -#: builtins/common.c:259 -#, c-format -msgid "%s: restricted" -msgstr "" - -#: builtins/common.c:269 -#, c-format -msgid "%s: not a shell builtin" -msgstr "" - -#: builtins/common.c:417 -msgid "`'" -msgstr "" - -#: builtins/common.c:480 -#, c-format -msgid "%s: could not get current directory: %s: %s\n" -msgstr "" - -#: builtins/common.c:547 builtins/common.c:549 -#, c-format -msgid "%s: ambiguous job spec" -msgstr "" - -#: builtins/common.c:631 builtins/common.c:680 builtins/trap.def:214 -msgid "SIGJUNK" -msgstr "" - -#: builtins/common.c:631 builtins/common.c:680 -msgid "Unknown" -msgstr "" - -#: builtins/common.c:644 -#, c-format -msgid "%2d) %s" -msgstr "" - -#: builtins/evalfile.c:132 -#, c-format -msgid "%s: not a regular file" -msgstr "" - -#: builtins/evalfile.c:140 -#, c-format -msgid "%s: file is too large" -msgstr "" - -#: builtins/evalfile.c:178 builtins/evalfile.c:237 -msgid "_evalfile" -msgstr "" - -#: builtins/evalfile.c:204 builtins/mkbuiltins.c:130 builtins/source.def:2 -#: builtins/source.def:143 builtins/source.def:170 -msgid "source" -msgstr "" - -#: builtins/evalstring.c:76 builtins/evalstring.c:103 -#: builtins/evalstring.c:287 -msgid "parse_and_execute_top" -msgstr "" - -#: builtins/evalstring.c:181 builtins/evalstring.c:189 -#: builtins/evalstring.c:223 builtins/evalstring.c:272 -msgid "pe_dispose" -msgstr "" - -#: builtins/evalstring.c:205 -msgid "parse_and_execute" -msgstr "" - -#: builtins/getopt.c:108 -#, c-format -msgid "%s: illegal option -- %c\n" -msgstr "" - -#: builtins/getopt.c:109 -#, c-format -msgid "%s: option requires an argument -- %c\n" -msgstr "" - -#: builtins/getopt.c:231 -msgid "sh_getopt_debug_restore_state: resetting nextchar" -msgstr "" - -#: builtins/getopt.c:254 -msgid "abc:d:0123456789" -msgstr "" - -#: builtins/getopt.c:271 -msgid "digits occur in two different argv-elements.\n" -msgstr "" - -#: builtins/getopt.c:273 -#, c-format -msgid "option %c\n" -msgstr "" - -#: builtins/getopt.c:277 -msgid "option a\n" -msgstr "" - -#: builtins/getopt.c:281 -msgid "option b\n" -msgstr "" - -#: builtins/getopt.c:285 -#, c-format -msgid "option c with value `%s'\n" -msgstr "" - -#: builtins/getopt.c:292 -#, c-format -msgid "?? sh_getopt returned character code 0%o ??\n" -msgstr "" - -#: builtins/getopt.c:298 -msgid "non-option ARGV-elements: " -msgstr "" - -#: builtins/mkbuiltins.c:47 -msgid "builtins.texi" -msgstr "" - -#: builtins/mkbuiltins.c:130 builtins/break.def:2 -msgid "break" -msgstr "" - -#: builtins/mkbuiltins.c:130 builtins/break.def:2 -msgid "continue" -msgstr "" - -#: builtins/mkbuiltins.c:130 builtins/eval.def:2 builtins/eval.def:52 -msgid "eval" -msgstr "" - -#: builtins/mkbuiltins.c:130 builtins/exec.def:2 -msgid "exec" -msgstr "" - -#: builtins/mkbuiltins.c:131 builtins/mkbuiltins.c:138 -#: builtins/complete.def:86 builtins/setattr.def:2 -msgid "export" -msgstr "" - -#: builtins/mkbuiltins.c:131 builtins/mkbuiltins.c:138 builtins/setattr.def:2 -msgid "readonly" -msgstr "" - -#: builtins/mkbuiltins.c:131 builtins/return.def:2 -msgid "return" -msgstr "" - -#: builtins/mkbuiltins.c:131 builtins/shift.def:2 -msgid "shift" -msgstr "" - -#: builtins/mkbuiltins.c:131 builtins/set.def:2 -msgid "unset" -msgstr "" - -#: builtins/mkbuiltins.c:138 builtins/alias.def:2 builtins/complete.def:78 -#: builtins/type.def:228 -msgid "alias" -msgstr "" - -#: builtins/mkbuiltins.c:138 builtins/declare.def:2 -msgid "declare" -msgstr "" - -#: builtins/mkbuiltins.c:138 builtins/declare.def:2 -msgid "local" -msgstr "" - -#: builtins/mkbuiltins.c:138 -msgid "typeset" -msgstr "" - -#: builtins/mkbuiltins.c:194 -msgid "-externfile" -msgstr "" - -#: builtins/mkbuiltins.c:196 -msgid "-structfile" -msgstr "" - -#: builtins/mkbuiltins.c:198 -msgid "-noproduction" -msgstr "" - -#: builtins/mkbuiltins.c:200 -msgid "-document" -msgstr "" - -#: builtins/mkbuiltins.c:202 -msgid "-D" -msgstr "" - -#: builtins/mkbuiltins.c:218 -msgid "-documentonly" -msgstr "" - -#: builtins/mkbuiltins.c:223 -msgid "-H" -msgstr "" - -#: builtins/mkbuiltins.c:230 -#, c-format -msgid "%s: Unknown flag %s.\n" -msgstr "" - -#: builtins/mkbuiltins.c:245 -#, c-format -msgid "mk-%ld" -msgstr "" - -#: builtins/mkbuiltins.c:266 -#, c-format -msgid "@c Table of builtins created with %s.\n" -msgstr "" - -#: builtins/mkbuiltins.c:268 -msgid "@ftable @asis\n" -msgstr "" - -#: builtins/mkbuiltins.c:305 -msgid "@end ftable\n" -msgstr "" - -#: builtins/mkbuiltins.c:423 -msgid "BUILTIN" -msgstr "" - -#: builtins/mkbuiltins.c:424 -msgid "DOCNAME" -msgstr "" - -#: builtins/mkbuiltins.c:426 -msgid "SHORT_DOC" -msgstr "" - -#: builtins/mkbuiltins.c:428 -msgid "COMMENT" -msgstr "" - -#: builtins/mkbuiltins.c:429 -msgid "DEPENDS_ON" -msgstr "" - -#: builtins/mkbuiltins.c:430 -msgid "PRODUCES" -msgstr "" - -#: builtins/mkbuiltins.c:431 -msgid "END" -msgstr "" - -#: builtins/mkbuiltins.c:500 -#, c-format -msgid "mkbuiltins: %s: skipping zero-length file\n" -msgstr "" - -#: builtins/mkbuiltins.c:551 -#, c-format -msgid "Unknown directive `%s'" -msgstr "" - -#: builtins/mkbuiltins.c:577 -#, c-format -msgid "#line %d \"%s\"\n" -msgstr "" - -#: builtins/mkbuiltins.c:580 -#, c-format -msgid "#line %d \"%s%s\"\n" -msgstr "" - -#: builtins/mkbuiltins.c:582 builtins/mkbuiltins.c:954 -msgid "./" -msgstr "" - -#: builtins/mkbuiltins.c:703 -#, c-format -msgid "%s requires an argument" -msgstr "" - -#: builtins/mkbuiltins.c:715 -#, c-format -msgid "%s must be inside of a $BUILTIN block" -msgstr "" - -#: builtins/mkbuiltins.c:740 -msgid "(implied LONGDOC)" -msgstr "" - -#: builtins/mkbuiltins.c:766 -#, c-format -msgid "%s found before $END" -msgstr "" - -#: builtins/mkbuiltins.c:812 -msgid "syntax error: no current builtin for $FUNCTION directive" -msgstr "" - -#: builtins/mkbuiltins.c:816 -#, c-format -msgid "%s already has a function (%s)" -msgstr "" - -#: builtins/mkbuiltins.c:836 -#, c-format -msgid "%s already had a docname (%s)" -msgstr "" - -#: builtins/mkbuiltins.c:856 -#, c-format -msgid "%s already has short documentation (%s)" -msgstr "" - -#: builtins/mkbuiltins.c:910 -#, c-format -msgid "%s already has a %s definition" -msgstr "" - -#: builtins/mkbuiltins.c:923 -#, c-format -msgid "/* %s, created from %s. */\n" -msgstr "" - -#: builtins/mkbuiltins.c:955 -#, c-format -msgid "%s:%d:" -msgstr "" - -#: builtins/mkbuiltins.c:1010 -msgid "mkbuiltins: out of virtual memory\n" -msgstr "" - -#: builtins/mkbuiltins.c:1066 -msgid "/* builtins.c -- the built in shell commands. */" -msgstr "" - -#: builtins/mkbuiltins.c:1068 -msgid "/* This file is manufactured by ./mkbuiltins, and should not be" -msgstr "" - -#: builtins/mkbuiltins.c:1069 -msgid " edited by hand. See the source to mkbuiltins for details. */" -msgstr "" - -#: builtins/mkbuiltins.c:1071 -msgid "/* Copyright (C) 1987-2002 Free Software Foundation, Inc." -msgstr "" - -#: builtins/mkbuiltins.c:1073 -msgid " This file is part of GNU Bash, the Bourne Again SHell." -msgstr "" - -#: builtins/mkbuiltins.c:1075 -msgid " Bash is free software; you can redistribute it and/or modify it" -msgstr "" - -#: builtins/mkbuiltins.c:1076 -msgid " under the terms of the GNU General Public License as published by" -msgstr "" - -#: builtins/mkbuiltins.c:1077 -msgid " the Free Software Foundation; either version 2, or (at your option)" -msgstr "" - -#: builtins/mkbuiltins.c:1078 -msgid " any later version." -msgstr "" - -#: builtins/mkbuiltins.c:1080 -msgid " Bash is distributed in the hope that it will be useful, but WITHOUT" -msgstr "" - -#: builtins/mkbuiltins.c:1081 -msgid " ANY WARRANTY; without even the implied warranty of MERCHANTABILITY" -msgstr "" - -#: builtins/mkbuiltins.c:1082 -msgid " or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public" -msgstr "" - -#: builtins/mkbuiltins.c:1083 -msgid " License for more details." -msgstr "" - -#: builtins/mkbuiltins.c:1085 -msgid " You should have received a copy of the GNU General Public License" -msgstr "" - -#: builtins/mkbuiltins.c:1086 -msgid " along with Bash; see the file COPYING. If not, write to the Free" -msgstr "" - -#: builtins/mkbuiltins.c:1087 -msgid "" -" Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */" -msgstr "" - -#: builtins/mkbuiltins.c:1089 -msgid "/* The list of shell builtins. Each element is name, function, flags," -msgstr "" - -#: builtins/mkbuiltins.c:1090 -msgid "" -" long-doc, short-doc. The long-doc field contains a pointer to an array" -msgstr "" - -#: builtins/mkbuiltins.c:1091 -msgid "" -" of help lines. The function takes a WORD_LIST *; the first word in the" -msgstr "" - -#: builtins/mkbuiltins.c:1092 -msgid " list is the first arg to the command. The list has already had word" -msgstr "" - -#: builtins/mkbuiltins.c:1093 -msgid " expansion performed." -msgstr "" - -#: builtins/mkbuiltins.c:1095 -msgid " Functions which need to look at only the simple commands (e.g." -msgstr "" - -#: builtins/mkbuiltins.c:1096 -msgid " the enable_builtin ()), should ignore entries where" -msgstr "" - -#: builtins/mkbuiltins.c:1097 -msgid "" -" (array[i].function == (sh_builtin_func_t *)NULL). Such entries are for" -msgstr "" - -#: builtins/mkbuiltins.c:1098 -msgid "" -" the list of shell reserved control structures, like `if' and `while'." -msgstr "" - -#: builtins/mkbuiltins.c:1099 -msgid " The end of the list is denoted with a NULL name field. */" -msgstr "" - -#: builtins/mkbuiltins.c:1101 -msgid "#include \"../builtins.h\"" -msgstr "" - -#: builtins/mkbuiltins.c:1106 -msgid "" -" { (char *)0x0, (sh_builtin_func_t *)0x0, 0, (char **)0x0, (char *)0x0 }" -msgstr "" - -#: builtins/mkbuiltins.c:1107 -msgid "};" -msgstr "" - -#: builtins/mkbuiltins.c:1109 -msgid "struct builtin *shell_builtins = static_shell_builtins;" -msgstr "" - -#: builtins/mkbuiltins.c:1110 -msgid "struct builtin *current_builtin;" -msgstr "" - -#: builtins/mkbuiltins.c:1112 -msgid "int num_shell_builtins =" -msgstr "" - -#: builtins/mkbuiltins.c:1113 -msgid "\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;" -msgstr "" - -#: builtins/mkbuiltins.c:1130 -#, c-format -msgid "#include \"%s\"\n" -msgstr "" - -#: builtins/mkbuiltins.c:1131 builtins/mkbuiltins.c:1138 -msgid "builtext.h" -msgstr "" - -#: builtins/mkbuiltins.c:1132 -msgid "" -"\n" -"struct builtin static_shell_builtins[] = {\n" -msgstr "" - -#: builtins/mkbuiltins.c:1137 -#, c-format -msgid "/* %s - The list of builtins found in libbuiltins.a. */\n" -msgstr "" - -#: builtins/mkbuiltins.c:1188 -#, c-format -msgid "extern int %s __P((WORD_LIST *));\n" -msgstr "" - -#: builtins/mkbuiltins.c:1191 -#, c-format -msgid "extern char * const %s_doc[];\n" -msgstr "" - -#: builtins/mkbuiltins.c:1198 -#, c-format -msgid " { \"%s\", " -msgstr "" - -#: builtins/mkbuiltins.c:1201 -#, c-format -msgid "%s, " -msgstr "" - -#: builtins/mkbuiltins.c:1203 -msgid "(sh_builtin_func_t *)0x0, " -msgstr "" - -#: builtins/mkbuiltins.c:1205 -#, c-format -msgid "%s%s%s, %s_doc,\n" -msgstr "" - -#: builtins/mkbuiltins.c:1206 -msgid "BUILTIN_ENABLED | STATIC_BUILTIN" -msgstr "" - -#: builtins/mkbuiltins.c:1207 -msgid " | SPECIAL_BUILTIN" -msgstr "" - -#: builtins/mkbuiltins.c:1208 -msgid " | ASSIGNMENT_BUILTIN" -msgstr "" - -#: builtins/mkbuiltins.c:1212 -#, c-format -msgid " \"%s\", (char *)NULL },\n" -msgstr "" - -#: builtins/mkbuiltins.c:1235 -#, c-format -msgid "@item %s\n" -msgstr "" - -#: builtins/mkbuiltins.c:1263 -#, c-format -msgid "char * const %s_doc[] =" -msgstr "" - -#: builtins/mkbuiltins.c:1269 lib/sh/mailstat.c:126 -#, c-format -msgid "%s/%s" -msgstr "" - -#: builtins/mkbuiltins.c:1299 -msgid "#if " -msgstr "" - -#: builtins/mkbuiltins.c:1306 -#, c-format -msgid "!defined (%s)" -msgstr "" - -#: builtins/mkbuiltins.c:1308 -#, c-format -msgid "defined (%s)" -msgstr "" - -#: builtins/mkbuiltins.c:1330 -msgid "#endif /* " -msgstr "" - -#: builtins/mkbuiltins.c:1340 -msgid " */\n" -msgstr "" - -#: builtins/mkbuiltins.c:1360 -msgid "" -" {\n" -"#if defined (HELP_BUILTIN)\n" -msgstr "" - -#: builtins/mkbuiltins.c:1373 -msgid " \"" -msgstr "" - -#: builtins/mkbuiltins.c:1387 -#, c-format -msgid "\\%c" -msgstr "" - -#: builtins/mkbuiltins.c:1391 builtins/mkbuiltins.c:1410 -#, c-format -msgid "%c" -msgstr "" - -#: builtins/mkbuiltins.c:1395 -msgid "\",\n" -msgstr "" - -#: builtins/mkbuiltins.c:1406 -#, c-format -msgid "@%c" -msgstr "" - -#: builtins/mkbuiltins.c:1420 -msgid "" -"#endif /* HELP_BUILTIN */\n" -" (char *)NULL\n" -"};\n" -msgstr "" - -#: builtins/mkbuiltins.c:1432 -msgid "helpfiles" -msgstr "" - -#: builtins/mkbuiltins.c:1435 -msgid "write_helpfiles: helpfiles: cannot create directory\n" -msgstr "" - -#: builtins/mkbuiltins.c:1439 -msgid "helpfiles/" -msgstr "" - -#: builtins/mkbuiltins.c:1446 -#, c-format -msgid "helpfiles/%s" -msgstr "" - -#: builtins/mkbuiltins.c:1451 -#, c-format -msgid "write_helpfiles: cannot open %s\n" -msgstr "" - -#: builtins/alias.def:2 -msgid "unalias" -msgstr "" - -#: builtins/alias.def:73 -msgid "p" -msgstr "" - -#: builtins/alias.def:160 -msgid "a" -msgstr "" - -#: builtins/alias.def:210 -msgid "alias " -msgstr "" - -#: builtins/bind.def:2 -msgid "bind" -msgstr "" - -#: builtins/bind.def:121 builtins/bind.def:265 -msgid "bind_builtin" -msgstr "" - -#: builtins/bind.def:127 -msgid "lvpVPsSf:q:u:m:r:x:" -msgstr "" - -#: builtins/bind.def:192 -#, c-format -msgid "`%s': invalid keymap name" -msgstr "" - -#: builtins/bind.def:231 -#, c-format -msgid "%s: cannot read: %s" -msgstr "" - -#: builtins/bind.def:246 -#, c-format -msgid "`%s': cannot unbind" -msgstr "" - -#: builtins/bind.def:281 builtins/bind.def:311 -#, c-format -msgid "`%s': unknown function name" -msgstr "" - -#: builtins/bind.def:289 -#, c-format -msgid "%s is not bound to any keys.\n" -msgstr "" - -#: builtins/bind.def:293 -#, c-format -msgid "%s can be invoked via " -msgstr "" - -#: builtins/bind.def:295 -#, c-format -msgid "\"%s\"%s" -msgstr "" - -#: builtins/bind.def:295 builtins/help.def:106 -msgid ", " -msgstr "" - -#: builtins/bind.def:295 -msgid ".\n" -msgstr "" - -#: builtins/bind.def:297 -msgid "...\n" -msgstr "" - -#: builtins/break.def:71 builtins/break.def:106 -msgid "loop count" -msgstr "" - -#: builtins/break.def:126 -msgid "only meaningful in a `for', `while', or `until' loop" -msgstr "" - -#: builtins/builtin.def:2 builtins/complete.def:81 builtins/type.def:294 -msgid "builtin" -msgstr "" - -#: builtins/caller.def:2 builtins/caller.def:138 -msgid "caller" -msgstr "" - -#: builtins/caller.def:31 -msgid "$line $filename" -msgstr "" - -#: builtins/caller.def:32 -msgid "$line $subroutine $filename" -msgstr "" - -#: builtins/caller.def:70 -msgid "1 NULL\n" -msgstr "" - -#: builtins/caller.def:94 -#, c-format -msgid "%s %s\n" -msgstr "" - -#: builtins/caller.def:110 -#, c-format -msgid "%s %s %s\n" -msgstr "" - -#: builtins/caller.def:126 -msgid "Returns the context of the current subroutine call." -msgstr "" - -#: builtins/caller.def:128 -msgid "Without EXPR, returns returns \"$line $filename\". With EXPR," -msgstr "" - -#: builtins/caller.def:129 -msgid "returns \"$line $subroutine $filename\"; this extra information" -msgstr "" - -#: builtins/caller.def:130 -msgid "can be used used to provide a stack trace." -msgstr "" - -#: builtins/caller.def:132 -msgid "The value of EXPR indicates how many call frames to go back before the" -msgstr "" - -#: builtins/caller.def:133 -msgid "current one; the top frame is frame 0." -msgstr "" - -#: builtins/caller.def:142 -msgid "caller [EXPR]" -msgstr "" - -#: builtins/cd.def:2 builtins/cd.def:96 builtins/cd.def:130 -msgid "cd" -msgstr "" - -#: builtins/cd.def:2 builtins/cd.def:338 -msgid "pwd" -msgstr "" - -#: builtins/cd.def:105 -msgid "OLDPWD=" -msgstr "" - -#: builtins/cd.def:112 -msgid "PWD=" -msgstr "" - -#: builtins/cd.def:160 builtins/cd.def:318 -msgid "LP" -msgstr "" - -#: builtins/cd.def:187 -msgid "HOME not set" -msgstr "" - -#: builtins/cd.def:199 -msgid "OLDPWD not set" -msgstr "" - -#: builtins/cd.def:210 -msgid "CDPATH" -msgstr "" - -#: builtins/cd.def:349 -#, c-format -msgid "write error: %s" -msgstr "" - -#: builtins/cd.def:378 -msgid "chdir" -msgstr "" - -#: builtins/command.def:29 -msgid "command ls" -msgstr "" - -#: builtins/command.def:73 -msgid "pvV" -msgstr "" - -#: builtins/command.def:120 builtins/command.def:160 -msgid "command_builtin" -msgstr "" - -#: builtins/complete.def:2 -msgid "complete" -msgstr "" - -#: builtins/complete.def:2 builtins/complete.def:589 -msgid "compgen" -msgstr "" - -#: builtins/complete.def:79 builtins/complete.def:458 -msgid "arrayvar" -msgstr "" - -#: builtins/complete.def:80 builtins/complete.def:459 -msgid "binding" -msgstr "" - -#: builtins/complete.def:83 -msgid "directory" -msgstr "" - -#: builtins/complete.def:84 builtins/complete.def:460 -msgid "disabled" -msgstr "" - -#: builtins/complete.def:85 builtins/complete.def:461 -msgid "enabled" -msgstr "" - -#: builtins/complete.def:87 builtins/type.def:315 builtins/type.def:335 -#: builtins/type.def:380 -msgid "file" -msgstr "" - -#: builtins/complete.def:89 builtins/complete.def:463 -msgid "helptopic" -msgstr "" - -#: builtins/complete.def:90 builtins/complete.def:464 -msgid "hostname" -msgstr "" - -#: builtins/complete.def:91 -msgid "group" -msgstr "" - -#: builtins/complete.def:92 -msgid "job" -msgstr "" - -#: builtins/complete.def:93 builtins/set.def:193 builtins/type.def:249 -msgid "keyword" -msgstr "" - -#: builtins/complete.def:94 builtins/complete.def:465 -msgid "running" -msgstr "" - -#: builtins/complete.def:95 -msgid "service" -msgstr "" - -#: builtins/complete.def:96 builtins/complete.def:466 -msgid "setopt" -msgstr "" - -#: builtins/complete.def:97 builtins/complete.def:467 -msgid "shopt" -msgstr "" - -#: builtins/complete.def:98 builtins/complete.def:468 -msgid "signal" -msgstr "" - -#: builtins/complete.def:99 builtins/complete.def:469 -msgid "stopped" -msgstr "" - -#: builtins/complete.def:100 -msgid "user" -msgstr "" - -#: builtins/complete.def:101 builtins/set.def:787 -msgid "variable" -msgstr "" - -#: builtins/complete.def:110 builtins/complete.def:434 -msgid "bashdefault" -msgstr "" - -#: builtins/complete.def:111 builtins/complete.def:435 -msgid "default" -msgstr "" - -#: builtins/complete.def:112 builtins/complete.def:436 -msgid "dirnames" -msgstr "" - -#: builtins/complete.def:113 builtins/complete.def:437 -msgid "filenames" -msgstr "" - -#: builtins/complete.def:114 builtins/complete.def:438 -msgid "nospace" -msgstr "" - -#: builtins/complete.def:115 builtins/complete.def:439 -msgid "plusdirs" -msgstr "" - -#: builtins/complete.def:170 -msgid "abcdefgjko:prsuvA:G:W:P:S:X:F:C:" -msgstr "" - -#: builtins/complete.def:183 -msgid "-r" -msgstr "" - -#: builtins/complete.def:250 -#, c-format -msgid "%s: invalid action name" -msgstr "" - -#: builtins/complete.def:380 builtins/complete.def:523 -#, c-format -msgid "%s: no completion specification" -msgstr "" - -#: builtins/complete.def:392 builtins/complete.def:400 -#, c-format -msgid "%s %s " -msgstr "" - -#: builtins/complete.def:412 -#, c-format -msgid "-A %s " -msgstr "" - -#: builtins/complete.def:418 -#, c-format -msgid "-o %s " -msgstr "" - -#: builtins/complete.def:429 -msgid "complete " -msgstr "" - -#: builtins/complete.def:444 -msgid "-a" -msgstr "" - -#: builtins/complete.def:445 -msgid "-b" -msgstr "" - -#: builtins/complete.def:447 -msgid "-d" -msgstr "" - -#: builtins/complete.def:448 -msgid "-e" -msgstr "" - -#: builtins/complete.def:449 -msgid "-f" -msgstr "" - -#: builtins/complete.def:450 -msgid "-g" -msgstr "" - -#: builtins/complete.def:451 -msgid "-j" -msgstr "" - -#: builtins/complete.def:452 -msgid "-k" -msgstr "" - -#: builtins/complete.def:453 builtins/shopt.def:325 -msgid "-s" -msgstr "" - -#: builtins/complete.def:454 builtins/shopt.def:325 -msgid "-u" -msgstr "" - -#: builtins/complete.def:455 -msgid "-v" -msgstr "" - -#: builtins/complete.def:474 -msgid "-G" -msgstr "" - -#: builtins/complete.def:475 -msgid "-W" -msgstr "" - -#: builtins/complete.def:476 -msgid "-P" -msgstr "" - -#: builtins/complete.def:477 -msgid "-S" -msgstr "" - -#: builtins/complete.def:478 -msgid "-X" -msgstr "" - -#: builtins/complete.def:481 -msgid "-F" -msgstr "" - -#: builtins/complete.def:482 -msgid "-C" -msgstr "" - -#: builtins/complete.def:570 -msgid "warning: -F option may not work as you expect" -msgstr "" - -#: builtins/complete.def:572 -msgid "warning: -C option may not work as you expect" -msgstr "" - -#: builtins/declare.def:104 -msgid "can only be used in a function" -msgstr "" - -#: builtins/declare.def:110 -msgid "+afiprtxF" -msgstr "" - -#: builtins/declare.def:112 -msgid "+fiprtxF" -msgstr "" - -#: builtins/declare.def:294 -msgid "cannot use `-f' to make functions" -msgstr "" - -#: builtins/declare.def:319 -#, c-format -msgid "%s %d %s\n" -msgstr "" - -#: builtins/declare.def:388 -#, c-format -msgid "%s: cannot destroy array variables in this way" -msgstr "" - -#: builtins/echo.def:2 -msgid "echo" -msgstr "" - -#: builtins/echo.def:65 -msgid "neE" -msgstr "" - -#: builtins/echo.def:67 -msgid "n" -msgstr "" - -#: builtins/enable.def:2 -msgid "enable" -msgstr "" - -#: builtins/enable.def:104 -msgid "adnpsf:" -msgstr "" - -#: builtins/enable.def:126 builtins/enable.def:134 -msgid "dynamic loading not available" -msgstr "" - -#: builtins/enable.def:227 -#, c-format -msgid "enable %s\n" -msgstr "" - -#: builtins/enable.def:230 -#, c-format -msgid "enable -n %s\n" -msgstr "" - -#: builtins/enable.def:301 -#, c-format -msgid "cannot open shared object %s: %s" -msgstr "" - -#: builtins/enable.def:319 -msgid "_struct" -msgstr "" - -#: builtins/enable.def:324 -#, c-format -msgid "cannot find %s in shared object %s: %s" -msgstr "" - -#: builtins/enable.def:448 -#, c-format -msgid "%s: not dynamically loaded" -msgstr "" - -#: builtins/enable.def:463 -#, c-format -msgid "%s: cannot delete: %s" -msgstr "" - -#: builtins/exec.def:100 -msgid "cla:" -msgstr "" - -#: builtins/exec.def:204 -#, c-format -msgid "%s: cannot execute: %s" -msgstr "" - -#: builtins/exit.def:61 -msgid "logout\n" -msgstr "" - -#: builtins/exit.def:61 -msgid "exit\n" -msgstr "" - -#: builtins/exit.def:81 -msgid "not login shell: use `exit'" -msgstr "" - -#: builtins/exit.def:109 -msgid "There are stopped jobs.\n" -msgstr "" - -#: builtins/exit.def:145 -msgid "~/.bash_logout" -msgstr "" - -#: builtins/fc.def:2 builtins/fc.def:269 builtins/fc.def:370 -msgid "fc" -msgstr "" - -#: builtins/fc.def:157 -msgid "${FCEDIT:-${EDITOR:-vi}}" -msgstr "" - -#: builtins/fc.def:181 -msgid ":e:lnrs" -msgstr "" - -#: builtins/fc.def:252 -msgid "no command found" -msgstr "" - -#: builtins/fc.def:317 -msgid "history specification" -msgstr "" - -#: builtins/fc.def:335 -msgid "bash-fc" -msgstr "" - -#: builtins/fc.def:338 -#, c-format -msgid "cannot open temp file %s" -msgstr "" - -#: builtins/fc.def:350 -#, c-format -msgid "\t%c" -msgstr "" - -#: builtins/fc.def:363 builtins/fc.def:368 -#, c-format -msgid "%s %s" -msgstr "" - -#: builtins/fc.def:386 builtins/fc.def:394 -msgid "fc builtin" -msgstr "" - -#: builtins/fg_bg.def:123 builtins/jobs.def:264 -msgid "current" -msgstr "" - -#: builtins/fg_bg.def:131 -#, c-format -msgid "job %%%d started without job control" -msgstr "" - -#: builtins/getopts.def:2 -msgid "getopts" -msgstr "" - -#: builtins/getopts.def:248 builtins/getopts.def:255 builtins/getopts.def:282 -#: lib/sh/strftime.c:235 lib/sh/strftime.c:242 lib/sh/strftime.c:250 -#: lib/sh/strftime.c:257 -msgid "?" -msgstr "" - -#: builtins/getopts.def:261 builtins/getopts.def:264 builtins/getopts.def:278 -#: builtins/getopts.def:283 builtins/getopts.def:288 -msgid "OPTARG" -msgstr "" - -#: builtins/hash.def:2 -msgid "hash" -msgstr "" - -#: builtins/hash.def:82 -msgid "hashing disabled" -msgstr "" - -#: builtins/hash.def:89 -msgid "dlp:rt" -msgstr "" - -#: builtins/hash.def:118 -msgid "-t" -msgstr "" - -#: builtins/hash.def:127 -#, c-format -msgid "%s: hash table empty\n" -msgstr "" - -#: builtins/hash.def:210 -#, c-format -msgid "%4d\t%s\n" -msgstr "" - -#: builtins/hash.def:218 builtins/hash.def:257 -#, c-format -msgid "builtin hash -p %s %s\n" -msgstr "" - -#: builtins/hash.def:230 -msgid "hits\tcommand\n" -msgstr "" - -#: builtins/hash.def:261 -#, c-format -msgid "%s\t" -msgstr "" - -#: builtins/help.def:80 builtins/help.def:105 -msgid "s" -msgstr "" - -#: builtins/help.def:105 -#, c-format -msgid "Shell commands matching keyword%s `" -msgstr "" - -#: builtins/help.def:107 -msgid "" -"'\n" -"\n" -msgstr "" - -#: builtins/help.def:121 -#, c-format -msgid "%s: %s\n" -msgstr "" - -#: builtins/help.def:133 -#, c-format -msgid "" -"no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." -msgstr "" - -#: builtins/help.def:159 -#, c-format -msgid "%s: cannot open: %s" -msgstr "" - -#: builtins/help.def:167 -#, c-format -msgid " %s\n" -msgstr "" - -#: builtins/help.def:177 -msgid "" -"These shell commands are defined internally. Type `help' to see this list.\n" -"Type `help name' to find out more about the function `name'.\n" -"Use `info bash' to find out more about the shell in general.\n" -"Use `man -k' or `info' to find out more about commands not in this list.\n" -"\n" -"A star (*) next to a name means that the command is disabled.\n" -"\n" -msgstr "" - -#: builtins/history.def:2 builtins/set.def:189 -msgid "history" -msgstr "" - -#: builtins/history.def:106 -msgid "acd:npsrw" -msgstr "" - -#: builtins/history.def:147 -msgid "cannot use more than one of -anrw" -msgstr "" - -#: builtins/history.def:179 -msgid "history position" -msgstr "" - -#: builtins/history.def:289 -#, c-format -msgid "%5d%c %s%s\n" -msgstr "" - -#: builtins/history.def:389 -#, c-format -msgid "%s: history expansion failed" -msgstr "" - -#: builtins/inlib.def:2 -msgid "inlib" -msgstr "" - -#: builtins/inlib.def:67 -#, c-format -msgid "%s: inlib failed" -msgstr "" - -#: builtins/jobs.def:2 -msgid "jobs" -msgstr "" - -#: builtins/jobs.def:2 -msgid "disown" -msgstr "" - -#: builtins/jobs.def:85 -msgid "lpnxrs" -msgstr "" - -#: builtins/jobs.def:101 -msgid "no other options allowed with `-x'" -msgstr "" - -#: builtins/jobs.def:185 builtins/jobs.def:197 -msgid "jobs_builtin" -msgstr "" - -#: builtins/jobs.def:224 -msgid "ahr" -msgstr "" - -#: builtins/kill.def:2 -msgid "kill" -msgstr "" - -#: builtins/kill.def:186 -#, c-format -msgid "%s: arguments must be process or job IDs" -msgstr "" - -#: builtins/kill.def:247 -msgid "Unknown error" -msgstr "" - -#: builtins/kill.def:248 -#, c-format -msgid "(%ld) - %s" -msgstr "" - -#: builtins/let.def:2 -msgid "let" -msgstr "" - -#: builtins/printf.def:2 -msgid "printf" -msgstr "" - -#: builtins/printf.def:66 -msgid "lld" -msgstr "" - -#: builtins/printf.def:68 -msgid "ld" -msgstr "" - -#: builtins/printf.def:103 -msgid "#'-+ 0" -msgstr "" - -#: builtins/printf.def:104 -msgid "hjlLtz" -msgstr "" - -#: builtins/printf.def:119 -msgid "L" -msgstr "" - -#: builtins/printf.def:248 -#, c-format -msgid "`%s': missing format character" -msgstr "" - -#: builtins/printf.def:346 builtins/printf.def:373 -msgid "" -msgstr "" - -#: builtins/printf.def:355 builtins/printf.def:378 -msgid "l" -msgstr "" - -#: builtins/printf.def:407 -#, c-format -msgid "`%c': invalid format character" -msgstr "" - -#: builtins/printf.def:427 -#, c-format -msgid "warning: %s: %s" -msgstr "" - -#: builtins/printf.def:504 -#, c-format -msgid "format parsing problem: %s" -msgstr "" - -#: builtins/printf.def:600 -msgid "missing hex digit for \\x" -msgstr "" - -#: builtins/pushd.def:2 builtins/pushd.def:171 builtins/pushd.def:230 -#: builtins/pushd.def:263 builtins/pushd.def:715 -msgid "pushd" -msgstr "" - -#: builtins/pushd.def:2 builtins/pushd.def:724 -msgid "popd" -msgstr "" - -#: builtins/pushd.def:2 builtins/pushd.def:432 builtins/pushd.def:733 -msgid "dirs" -msgstr "" - -#: builtins/pushd.def:167 -msgid "no other directory" -msgstr "" - -#: builtins/pushd.def:434 -msgid "" -msgstr "" - -#: builtins/pushd.def:436 builtins/pushd.def:455 -#, c-format -msgid "%2d %s" -msgstr "" - -#: builtins/pushd.def:463 -#, c-format -msgid "" -"\n" -"%2d %s" -msgstr "" - -#: builtins/pushd.def:478 -msgid "directory stack empty" -msgstr "" - -#: builtins/pushd.def:480 -msgid "directory stack index" -msgstr "" - -#: builtins/pushd.def:625 -msgid "dirstack" -msgstr "" - -#: builtins/pushd.def:651 -msgid "Display the list of currently remembered directories. Directories" -msgstr "" - -#: builtins/pushd.def:652 -msgid "find their way onto the list with the `pushd' command; you can get" -msgstr "" - -#: builtins/pushd.def:653 -msgid "back up through the list with the `popd' command." -msgstr "" - -#: builtins/pushd.def:655 -msgid "The -l flag specifies that `dirs' should not print shorthand versions" -msgstr "" - -#: builtins/pushd.def:656 -msgid "of directories which are relative to your home directory. This means" -msgstr "" - -#: builtins/pushd.def:657 -msgid "that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag" -msgstr "" - -#: builtins/pushd.def:658 -msgid "causes `dirs' to print the directory stack with one entry per line," -msgstr "" - -#: builtins/pushd.def:659 -msgid "prepending the directory name with its position in the stack. The -p" -msgstr "" - -#: builtins/pushd.def:660 -msgid "flag does the same thing, but the stack position is not prepended." -msgstr "" - -#: builtins/pushd.def:661 -msgid "The -c flag clears the directory stack by deleting all of the elements." -msgstr "" - -#: builtins/pushd.def:663 -msgid "+N displays the Nth entry counting from the left of the list shown by" -msgstr "" - -#: builtins/pushd.def:664 builtins/pushd.def:667 -msgid " dirs when invoked without options, starting with zero." -msgstr "" - -#: builtins/pushd.def:666 -msgid "" -"-N displays the Nth entry counting from the right of the list shown by" -msgstr "" - -#: builtins/pushd.def:672 -msgid "Adds a directory to the top of the directory stack, or rotates" -msgstr "" - -#: builtins/pushd.def:673 -msgid "the stack, making the new top of the stack the current working" -msgstr "" - -#: builtins/pushd.def:674 -msgid "directory. With no arguments, exchanges the top two directories." -msgstr "" - -#: builtins/pushd.def:676 -msgid "+N Rotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins/pushd.def:677 -msgid " from the left of the list shown by `dirs', starting with" -msgstr "" - -#: builtins/pushd.def:678 builtins/pushd.def:682 -msgid " zero) is at the top." -msgstr "" - -#: builtins/pushd.def:680 -msgid "-N Rotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins/pushd.def:681 -msgid " from the right of the list shown by `dirs', starting with" -msgstr "" - -#: builtins/pushd.def:684 -msgid "-n suppress the normal change of directory when adding directories" -msgstr "" - -#: builtins/pushd.def:685 -msgid " to the stack, so only the stack is manipulated." -msgstr "" - -#: builtins/pushd.def:687 -msgid "dir adds DIR to the directory stack at the top, making it the" -msgstr "" - -#: builtins/pushd.def:688 -msgid " new current working directory." -msgstr "" - -#: builtins/pushd.def:690 builtins/pushd.def:710 -msgid "You can see the directory stack with the `dirs' command." -msgstr "" - -#: builtins/pushd.def:695 -msgid "Removes entries from the directory stack. With no arguments," -msgstr "" - -#: builtins/pushd.def:696 -msgid "removes the top directory from the stack, and cd's to the new" -msgstr "" - -#: builtins/pushd.def:697 -msgid "top directory." -msgstr "" - -#: builtins/pushd.def:699 -msgid "+N removes the Nth entry counting from the left of the list" -msgstr "" - -#: builtins/pushd.def:700 -msgid " shown by `dirs', starting with zero. For example: `popd +0'" -msgstr "" - -#: builtins/pushd.def:701 -msgid " removes the first directory, `popd +1' the second." -msgstr "" - -#: builtins/pushd.def:703 -msgid "-N removes the Nth entry counting from the right of the list" -msgstr "" - -#: builtins/pushd.def:704 -msgid " shown by `dirs', starting with zero. For example: `popd -0'" -msgstr "" - -#: builtins/pushd.def:705 -msgid " removes the last directory, `popd -1' the next to last." -msgstr "" - -#: builtins/pushd.def:707 -msgid "-n suppress the normal change of directory when removing directories" -msgstr "" - -#: builtins/pushd.def:708 -msgid " from the stack, so only the stack is manipulated." -msgstr "" - -#: builtins/pushd.def:719 -msgid "pushd [+N | -N] [-n] [dir]" -msgstr "" - -#: builtins/pushd.def:728 -msgid "popd [+N | -N] [-n]" -msgstr "" - -#: builtins/pushd.def:737 -msgid "dirs [-clpv] [+N] [-N]" -msgstr "" - -#: builtins/read.def:2 -msgid "read" -msgstr "" - -#: builtins/read.def:178 -msgid "ersa:d:n:p:t:u:" -msgstr "" - -#: builtins/read.def:205 -#, c-format -msgid "%s: invalid timeout specification" -msgstr "" - -#: builtins/read.def:228 -#, c-format -msgid "%s: invalid file descriptor specification" -msgstr "" - -#: builtins/read.def:235 -#, c-format -msgid "%d: invalid file descriptor: %s" -msgstr "" - -#: builtins/read.def:272 builtins/read.def:317 builtins/read.def:491 -msgid "read_builtin" -msgstr "" - -#: builtins/read.def:461 -#, c-format -msgid "read error: %d: %s" -msgstr "" - -#: builtins/reserved.def:123 -msgid "let EXPRESSION" -msgstr "" - -#: builtins/return.def:61 -msgid "can only `return' from a function or sourced script" -msgstr "" - -#: builtins/set.def:161 builtins/shopt.def:170 -msgid "on" -msgstr "" - -#: builtins/set.def:162 builtins/shopt.def:171 -msgid "off" -msgstr "" - -#: builtins/set.def:174 -msgid "allexport" -msgstr "" - -#: builtins/set.def:176 -msgid "braceexpand" -msgstr "" - -#: builtins/set.def:181 -msgid "errexit" -msgstr "" - -#: builtins/set.def:182 -msgid "errtrace" -msgstr "" - -#: builtins/set.def:183 -msgid "functrace" -msgstr "" - -#: builtins/set.def:184 -msgid "hashall" -msgstr "" - -#: builtins/set.def:186 -msgid "histexpand" -msgstr "" - -#: builtins/set.def:192 -msgid "interactive-comments" -msgstr "" - -#: builtins/set.def:194 -msgid "monitor" -msgstr "" - -#: builtins/set.def:195 -msgid "noclobber" -msgstr "" - -#: builtins/set.def:196 -msgid "noexec" -msgstr "" - -#: builtins/set.def:197 -msgid "noglob" -msgstr "" - -#: builtins/set.def:199 -msgid "nolog" -msgstr "" - -#: builtins/set.def:202 -msgid "notify" -msgstr "" - -#: builtins/set.def:204 -msgid "nounset" -msgstr "" - -#: builtins/set.def:205 -msgid "onecmd" -msgstr "" - -#: builtins/set.def:206 -msgid "physical" -msgstr "" - -#: builtins/set.def:207 -msgid "pipefail" -msgstr "" - -#: builtins/set.def:209 -msgid "privileged" -msgstr "" - -#: builtins/set.def:212 -msgid "vi" -msgstr "" - -#: builtins/set.def:214 -msgid "xtrace" -msgstr "" - -#: builtins/set.def:252 builtins/shopt.def:56 -#, c-format -msgid "%-15s\t%s\n" -msgstr "" - -#: builtins/set.def:262 builtins/shopt.def:414 -#, c-format -msgid "set %co %s\n" -msgstr "" - -#: builtins/set.def:313 -msgid "10" -msgstr "" - -#: builtins/set.def:345 -msgid "editing-mode" -msgstr "" - -#: builtins/set.def:493 builtins/set.def:505 builtins/set.def:541 -msgid "SHELLOPTS" -msgstr "" - -#: builtins/set.def:722 -msgid "fv" -msgstr "" - -#: builtins/set.def:742 -msgid "cannot simultaneously unset a function and a variable" -msgstr "" - -#: builtins/set.def:779 -#, c-format -msgid "%s: cannot unset" -msgstr "" - -#: builtins/set.def:786 -#, c-format -msgid "%s: cannot unset: readonly %s" -msgstr "" - -#: builtins/set.def:797 -#, c-format -msgid "%s: not an array variable" -msgstr "" - -#: builtins/setattr.def:98 -msgid "afnp" -msgstr "" - -#: builtins/setattr.def:100 -msgid "fnp" -msgstr "" - -#: builtins/setattr.def:164 -#, c-format -msgid "%s: not a function" -msgstr "" - -#: builtins/setattr.def:201 -msgid "-ra" -msgstr "" - -#: builtins/setattr.def:332 -#, c-format -msgid "declare -%s " -msgstr "" - -#: builtins/setattr.def:334 -#, c-format -msgid "%s -%s " -msgstr "" - -#: builtins/shift.def:65 builtins/shift.def:71 -msgid "shift count" -msgstr "" - -#: builtins/shopt.def:115 -msgid "cdable_vars" -msgstr "" - -#: builtins/shopt.def:116 -msgid "cdspell" -msgstr "" - -#: builtins/shopt.def:117 -msgid "checkhash" -msgstr "" - -#: builtins/shopt.def:118 -msgid "checkwinsize" -msgstr "" - -#: builtins/shopt.def:120 -msgid "cmdhist" -msgstr "" - -#: builtins/shopt.def:122 -msgid "dotglob" -msgstr "" - -#: builtins/shopt.def:123 -msgid "execfail" -msgstr "" - -#: builtins/shopt.def:124 -msgid "expand_aliases" -msgstr "" - -#: builtins/shopt.def:126 -msgid "extdebug" -msgstr "" - -#: builtins/shopt.def:129 -msgid "extglob" -msgstr "" - -#: builtins/shopt.def:131 -msgid "extquote" -msgstr "" - -#: builtins/shopt.def:132 -msgid "failglob" -msgstr "" - -#: builtins/shopt.def:134 -msgid "force_fignore" -msgstr "" - -#: builtins/shopt.def:135 -msgid "gnu_errfmt" -msgstr "" - -#: builtins/shopt.def:136 -msgid "histreedit" -msgstr "" - -#: builtins/shopt.def:139 -msgid "histappend" -msgstr "" - -#: builtins/shopt.def:142 -msgid "histverify" -msgstr "" - -#: builtins/shopt.def:143 -msgid "hostcomplete" -msgstr "" - -#: builtins/shopt.def:145 -msgid "huponexit" -msgstr "" - -#: builtins/shopt.def:146 -msgid "interactive_comments" -msgstr "" - -#: builtins/shopt.def:148 -msgid "lithist" -msgstr "" - -#: builtins/shopt.def:150 -msgid "login_shell" -msgstr "" - -#: builtins/shopt.def:151 -msgid "mailwarn" -msgstr "" - -#: builtins/shopt.def:153 -msgid "no_empty_cmd_completion" -msgstr "" - -#: builtins/shopt.def:155 -msgid "nocaseglob" -msgstr "" - -#: builtins/shopt.def:156 -msgid "nullglob" -msgstr "" - -#: builtins/shopt.def:158 -msgid "progcomp" -msgstr "" - -#: builtins/shopt.def:160 -msgid "promptvars" -msgstr "" - -#: builtins/shopt.def:162 -msgid "restricted_shell" -msgstr "" - -#: builtins/shopt.def:164 -msgid "shift_verbose" -msgstr "" - -#: builtins/shopt.def:165 -msgid "sourcepath" -msgstr "" - -#: builtins/shopt.def:166 -msgid "xpg_echo" -msgstr "" - -#: builtins/shopt.def:196 -msgid "psuoq" -msgstr "" - -#: builtins/shopt.def:224 -msgid "cannot set and unset shell options simultaneously" -msgstr "" - -#: builtins/shopt.def:289 -#, c-format -msgid "%s: invalid shell option name" -msgstr "" - -#: builtins/shopt.def:325 -#, c-format -msgid "shopt %s %s\n" -msgstr "" - -#: builtins/source.def:116 -msgid "filename argument required" -msgstr "" - -#: builtins/source.def:136 -#, c-format -msgid "%s: file not found" -msgstr "" - -#: builtins/suspend.def:2 -msgid "suspend" -msgstr "" - -#: builtins/suspend.def:77 -msgid "f" -msgstr "" - -#: builtins/suspend.def:92 -msgid "cannot suspend" -msgstr "" - -#: builtins/suspend.def:102 -msgid "cannot suspend a login shell" -msgstr "" - -#: builtins/test.def:2 builtins/test.def:98 -msgid "test" -msgstr "" - -#: builtins/times.def:2 -msgid "times" -msgstr "" - -#: builtins/times.def:109 -msgid "" -"0.00 0.00\n" -"0.00 0.00\n" -msgstr "" - -#: builtins/trap.def:39 -msgid "kill -signal $$" -msgstr "" - -#: builtins/trap.def:94 -msgid "lp" -msgstr "" - -#: builtins/trap.def:215 -#, c-format -msgid "trap -- %s %d\n" -msgstr "" - -#: builtins/trap.def:219 builtins/trap.def:221 builtins/trap.def:224 -#, c-format -msgid "trap -- %s %s\n" -msgstr "" - -#: builtins/type.def:2 builtins/type.def:127 -msgid "type" -msgstr "" - -#: builtins/type.def:127 -msgid "-type" -msgstr "" - -#: builtins/type.def:132 -msgid "path" -msgstr "" - -#: builtins/type.def:132 -msgid "-path" -msgstr "" - -#: builtins/type.def:137 -msgid "all" -msgstr "" - -#: builtins/type.def:137 -msgid "-all" -msgstr "" - -#: builtins/type.def:145 -msgid "afptP" -msgstr "" - -#: builtins/type.def:230 -#, c-format -msgid "%s is aliased to `%s'\n" -msgstr "" - -#: builtins/type.def:234 -#, c-format -msgid "alias %s=%s\n" -msgstr "" - -#: builtins/type.def:251 -#, c-format -msgid "%s is a shell keyword\n" -msgstr "" - -#: builtins/type.def:271 -#, c-format -msgid "%s is a function\n" -msgstr "" - -#: builtins/type.def:296 -#, c-format -msgid "%s is a shell builtin\n" -msgstr "" - -#: builtins/type.def:317 builtins/type.def:382 -#, c-format -msgid "%s is %s\n" -msgstr "" - -#: builtins/type.def:337 -#, c-format -msgid "%s is hashed (%s)\n" -msgstr "" - -#: builtins/ulimit.def:2 -msgid "ulimit" -msgstr "" - -#: builtins/ulimit.def:111 -#, c-format -msgid "%ld%s" -msgstr "" - -#: builtins/ulimit.def:195 -msgid "core file size" -msgstr "" - -#: builtins/ulimit.def:195 builtins/ulimit.def:200 -msgid "blocks" -msgstr "" - -#: builtins/ulimit.def:198 -msgid "data seg size" -msgstr "" - -#: builtins/ulimit.def:198 builtins/ulimit.def:202 builtins/ulimit.def:205 -#: builtins/ulimit.def:210 builtins/ulimit.def:217 builtins/ulimit.def:220 -msgid "kbytes" -msgstr "" - -#: builtins/ulimit.def:200 -msgid "file size" -msgstr "" - -#: builtins/ulimit.def:202 -msgid "max locked memory" -msgstr "" - -#: builtins/ulimit.def:205 -msgid "max memory size" -msgstr "" - -#: builtins/ulimit.def:207 -msgid "open files" -msgstr "" - -#: builtins/ulimit.def:208 -msgid "pipe size" -msgstr "" - -#: builtins/ulimit.def:208 -msgid "512 bytes" -msgstr "" - -#: builtins/ulimit.def:210 -msgid "stack size" -msgstr "" - -#: builtins/ulimit.def:213 -msgid "cpu time" -msgstr "" - -#: builtins/ulimit.def:213 -msgid "seconds" -msgstr "" - -#: builtins/ulimit.def:215 -msgid "max user processes" -msgstr "" - -#: builtins/ulimit.def:217 -msgid "virtual memory" -msgstr "" - -#: builtins/ulimit.def:220 -msgid "swap size" -msgstr "" - -#: builtins/ulimit.def:328 builtins/ulimit.def:401 builtins/ulimit.def:674 -msgid "unlimited" -msgstr "" - -#: builtins/ulimit.def:330 -#, c-format -msgid "%s: invalid limit argument" -msgstr "" - -#: builtins/ulimit.def:356 -#, c-format -msgid "`%c': bad command" -msgstr "" - -#: builtins/ulimit.def:385 builtins/ulimit.def:649 -#, c-format -msgid "%s: cannot get limit: %s" -msgstr "" - -#: builtins/ulimit.def:397 builtins/ulimit.def:676 -msgid "hard" -msgstr "" - -#: builtins/ulimit.def:399 builtins/ulimit.def:678 -msgid "soft" -msgstr "" - -#: builtins/ulimit.def:411 -msgid "limit" -msgstr "" - -#: builtins/ulimit.def:423 builtins/ulimit.def:716 -#, c-format -msgid "%s: cannot modify limit: %s" -msgstr "" - -#: builtins/ulimit.def:667 -#, c-format -msgid "(%s, -%c) " -msgstr "" - -#: builtins/ulimit.def:669 -#, c-format -msgid "(-%c) " -msgstr "" - -#: builtins/ulimit.def:671 -#, c-format -msgid "%-18s %16s" -msgstr "" - -#: builtins/umask.def:2 -msgid "umask" -msgstr "" - -#: builtins/umask.def:80 -msgid "Sp" -msgstr "" - -#: builtins/umask.def:110 -msgid "octal number" -msgstr "" - -#: builtins/umask.def:131 -#, c-format -msgid "umask%s " -msgstr "" - -#: builtins/umask.def:131 -msgid " -S" -msgstr "" - -#: builtins/umask.def:135 -#, c-format -msgid "%04lo\n" -msgstr "" - -#: builtins/umask.def:178 -#, c-format -msgid "u=%s,g=%s,o=%s\n" -msgstr "" - -#: builtins/umask.def:194 -msgid "agou" -msgstr "" - -#: builtins/umask.def:224 -#, c-format -msgid "`%c': invalid symbolic mode operator" -msgstr "" - -#: builtins/umask.def:229 -msgid "rwx" -msgstr "" - -#: builtins/umask.def:277 -#, c-format -msgid "`%c': invalid symbolic mode character" -msgstr "" - -#: lib/sh/clock.c:79 lib/sh/timeval.c:143 -#, c-format -msgid "%ldm%d.%03ds" -msgstr "" - -#: lib/sh/fmtulong.c:55 lib/sh/snprintf.c:167 -msgid "0123456789abcdef" -msgstr "" - -#: lib/sh/fmtulong.c:56 lib/sh/snprintf.c:168 -msgid "0123456789ABCDEF" -msgstr "" - -#: lib/sh/fmtulong.c:99 -msgid "invalid base" -msgstr "" - -#: lib/sh/getcwd.c:75 -msgid "../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.." -msgstr "" - -#: lib/sh/getcwd.c:304 -msgid "cwd: getcwd" -msgstr "" - -#: lib/sh/inet_aton.c:59 -msgid "@(#)inet_addr.c\t8.1 (Berkeley) 6/17/93" -msgstr "" - -#: lib/sh/inet_aton.c:60 -msgid "$Id: inet_addr.c,v 1.5 1996/08/14 03:48:37 drepper Exp $" -msgstr "" - -#: lib/sh/mailstat.c:95 -#, c-format -msgid "%s/cur" -msgstr "" - -#: lib/sh/mailstat.c:101 -#, c-format -msgid "%s/tmp" -msgstr "" - -#: lib/sh/mailstat.c:107 -#, c-format -msgid "%s/new" -msgstr "" - -#: lib/sh/mailstat.c:126 -msgid "cur" -msgstr "" - -#: lib/sh/mailstat.c:126 -msgid "new" -msgstr "" - -#: lib/sh/mailstat.c:127 -#, c-format -msgid "%s/" -msgstr "" - -#: lib/sh/makepath.c:77 -msgid "sh_makepath" -msgstr "" - -#: lib/sh/mktime.c:330 -#, c-format -msgid "%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d" -msgstr "" - -#: lib/sh/mktime.c:345 -msgid "mktime (" -msgstr "" - -#: lib/sh/mktime.c:347 -msgid "" -")\n" -"yields (" -msgstr "" - -#: lib/sh/mktime.c:349 -#, c-format -msgid ") == %ld, should be %ld\n" -msgstr "" - -#: lib/sh/mktime.c:367 -#, c-format -msgid "%d-%d-%d%c" -msgstr "" - -#: lib/sh/mktime.c:370 -#, c-format -msgid "%d:%d:%d%c" -msgstr "" - -#: lib/sh/mktime.c:380 -#, c-format -msgid "mktime returns %ld == " -msgstr "" - -#: lib/sh/mktime.c:410 -#, c-format -msgid "" -"Usage:\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n" -"\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n" -"\t%s FROM BY TO - # Do not test those values (for benchmark).\n" -msgstr "" - -#: lib/sh/netopen.c:128 -msgid "tcp" -msgstr "" - -#: lib/sh/netopen.c:128 -msgid "udp" -msgstr "" - -#: lib/sh/netopen.c:156 -#, c-format -msgid "%s: host unknown" -msgstr "" - -#: lib/sh/netopen.c:163 -#, c-format -msgid "%s: invalid service" -msgstr "" - -#: lib/sh/netopen.c:176 lib/sh/netopen.c:234 -msgid "socket" -msgstr "" - -#: lib/sh/netopen.c:183 lib/sh/netopen.c:246 -msgid "connect" -msgstr "" - -#: lib/sh/netopen.c:294 -#, c-format -msgid "%s: bad network path specification" -msgstr "" - -#: lib/sh/netopen.c:334 -msgid "network operations not supported" -msgstr "" - -#: lib/sh/pathphys.c:269 -msgid "sh_realpath" -msgstr "" - -#: lib/sh/shmatch.c:95 lib/sh/shmatch.c:96 -msgid "BASH_REMATCH" -msgstr "" - -#: lib/sh/snprintf.c:402 -msgid "" -msgstr "" - -#: lib/sh/snprintf.c:892 -msgid "INF" -msgstr "" - -#: lib/sh/snprintf.c:892 -msgid "NAN" -msgstr "" - -#: lib/sh/snprintf.c:893 -msgid "inf" -msgstr "" - -#: lib/sh/snprintf.c:893 -msgid "nan" -msgstr "" - -#: lib/sh/snprintf.c:1646 -msgid "out of virtual memory\n" -msgstr "" - -#: lib/sh/snprintf.c:1695 lib/sh/snprintf.c:1697 lib/sh/snprintf.c:1699 -msgid "abcde\n" -msgstr "" - -#: lib/sh/snprintf.c:1696 -#, c-format -msgid "snprintf returns %d with NULL first argument and size of 0\n" -msgstr "" - -#: lib/sh/snprintf.c:1698 -#, c-format -msgid "snprintf returns %d with non-NULL first argument and size of 0\n" -msgstr "" - -#: lib/sh/snprintf.c:1700 -#, c-format -msgid "snprintf returns %d with NULL first argument and non-zero size\n" -msgstr "" - -#: lib/sh/snprintf.c:1710 -#, c-format -msgid "/%%ld %%ld/, 336, 336\n" -msgstr "" - -#: lib/sh/snprintf.c:1711 lib/sh/snprintf.c:1712 lib/sh/snprintf.c:1713 -#, c-format -msgid "/%ld %ld/\n" -msgstr "" - -#: lib/sh/snprintf.c:1717 -#, c-format -msgid "/%%d/, 336\n" -msgstr "" - -#: lib/sh/snprintf.c:1718 lib/sh/snprintf.c:1719 lib/sh/snprintf.c:1720 -#, c-format -msgid "/%d/\n" -msgstr "" - -#: lib/sh/snprintf.c:1724 -#, c-format -msgid "/%%2d/, 336\n" -msgstr "" - -#: lib/sh/snprintf.c:1725 lib/sh/snprintf.c:1726 lib/sh/snprintf.c:1727 -#, c-format -msgid "/%2d/\n" -msgstr "" - -#: lib/sh/snprintf.c:1731 -#, c-format -msgid "/%%10d/, 336\n" -msgstr "" - -#: lib/sh/snprintf.c:1732 lib/sh/snprintf.c:1733 lib/sh/snprintf.c:1734 -#, c-format -msgid "/%10d/\n" -msgstr "" - -#: lib/sh/snprintf.c:1738 -#, c-format -msgid "/%%-10d/, 336\n" -msgstr "" - -#: lib/sh/snprintf.c:1739 lib/sh/snprintf.c:1740 lib/sh/snprintf.c:1741 -#, c-format -msgid "/%-10d/\n" -msgstr "" - -#: lib/sh/snprintf.c:1748 -#, c-format -msgid "/%%f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1749 lib/sh/snprintf.c:1750 lib/sh/snprintf.c:1751 -#, c-format -msgid "/%f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1755 -#, c-format -msgid "/%%e/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1756 lib/sh/snprintf.c:1757 lib/sh/snprintf.c:1758 -#, c-format -msgid "/%e/\n" -msgstr "" - -#: lib/sh/snprintf.c:1762 -#, c-format -msgid "/%%4.2f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1763 lib/sh/snprintf.c:1764 lib/sh/snprintf.c:1765 -#, c-format -msgid "/%4.2f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1769 -#, c-format -msgid "/%%3.1f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1770 lib/sh/snprintf.c:1771 lib/sh/snprintf.c:1772 -#, c-format -msgid "/%3.1f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1776 -#, c-format -msgid "/%%10.3f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1777 lib/sh/snprintf.c:1778 lib/sh/snprintf.c:1779 -#, c-format -msgid "/%10.3f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1783 -#, c-format -msgid "/%%10.3e/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1784 lib/sh/snprintf.c:1785 lib/sh/snprintf.c:1786 -#, c-format -msgid "/%10.3e/\n" -msgstr "" - -#: lib/sh/snprintf.c:1790 -#, c-format -msgid "/%%+4.2f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1791 lib/sh/snprintf.c:1792 lib/sh/snprintf.c:1793 -#, c-format -msgid "/%+4.2f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1797 -#, c-format -msgid "/%%010.2f/, 1234.56\n" -msgstr "" - -#: lib/sh/snprintf.c:1798 lib/sh/snprintf.c:1799 lib/sh/snprintf.c:1800 -#, c-format -msgid "/%010.2f/\n" -msgstr "" - -#: lib/sh/snprintf.c:1804 -msgid "Outstanding acting !" -msgstr "" - -#: lib/sh/snprintf.c:1807 -#, c-format -msgid "/%%2s/, \"%s\"\n" -msgstr "" - -#: lib/sh/snprintf.c:1808 lib/sh/snprintf.c:1809 lib/sh/snprintf.c:1810 -#, c-format -msgid "/%2s/\n" -msgstr "" - -#: lib/sh/snprintf.c:1814 -#, c-format -msgid "/%%22s/ %s\n" -msgstr "" - -#: lib/sh/snprintf.c:1815 lib/sh/snprintf.c:1816 lib/sh/snprintf.c:1817 -#, c-format -msgid "/%22s/\n" -msgstr "" - -#: lib/sh/snprintf.c:1821 -#, c-format -msgid "/%%22.5s/ %s\n" -msgstr "" - -#: lib/sh/snprintf.c:1822 lib/sh/snprintf.c:1823 lib/sh/snprintf.c:1824 -#, c-format -msgid "/%22.5s/\n" -msgstr "" - -#: lib/sh/snprintf.c:1828 -#, c-format -msgid "/%%-22.5s/ %s\n" -msgstr "" - -#: lib/sh/snprintf.c:1829 lib/sh/snprintf.c:1830 lib/sh/snprintf.c:1831 -#, c-format -msgid "/%-22.5s/\n" -msgstr "" - -#: lib/sh/snprintf.c:1837 -#, c-format -msgid "%%x %%X %%#x, 31, 31, 31\n" -msgstr "" - -#: lib/sh/snprintf.c:1838 lib/sh/snprintf.c:1839 lib/sh/snprintf.c:1840 -#, c-format -msgid "%x %X %#x\n" -msgstr "" - -#: lib/sh/snprintf.c:1844 -#, c-format -msgid "**%%d**%% d**%% d**, 42, 42, -42\n" -msgstr "" - -#: lib/sh/snprintf.c:1845 lib/sh/snprintf.c:1846 lib/sh/snprintf.c:1847 -#, c-format -msgid "**%d**% d**% d**\n" -msgstr "" - -#: lib/sh/snprintf.c:1853 -#, c-format -msgid "/%%g/, 31.4\n" -msgstr "" - -#: lib/sh/snprintf.c:1854 lib/sh/snprintf.c:1855 lib/sh/snprintf.c:1856 -#: lib/sh/snprintf.c:1975 lib/sh/snprintf.c:1976 lib/sh/snprintf.c:1977 -#: lib/sh/snprintf.c:1982 lib/sh/snprintf.c:1983 lib/sh/snprintf.c:1984 -#, c-format -msgid "/%g/\n" -msgstr "" - -#: lib/sh/snprintf.c:1860 -#, c-format -msgid "/%%.6g/, 31.4\n" -msgstr "" - -#: lib/sh/snprintf.c:1861 lib/sh/snprintf.c:1862 lib/sh/snprintf.c:1863 -#, c-format -msgid "/%.6g/\n" -msgstr "" - -#: lib/sh/snprintf.c:1867 -#, c-format -msgid "/%%.1G/, 31.4\n" -msgstr "" - -#: lib/sh/snprintf.c:1868 lib/sh/snprintf.c:1869 lib/sh/snprintf.c:1870 -#: lib/sh/snprintf.c:1875 lib/sh/snprintf.c:1876 lib/sh/snprintf.c:1877 -#, c-format -msgid "/%.1G/\n" -msgstr "" - -#: lib/sh/snprintf.c:1874 -#, c-format -msgid "/%%.1G/, 3100000000.4\n" -msgstr "" - -#: lib/sh/snprintf.c:1881 -#, c-format -msgid "abc%%n\n" -msgstr "" - -#: lib/sh/snprintf.c:1882 lib/sh/snprintf.c:1883 lib/sh/snprintf.c:1885 -#, c-format -msgid "abc%n" -msgstr "" - -#: lib/sh/snprintf.c:1884 lib/sh/snprintf.c:1886 -#, c-format -msgid "" -"%d\n" -"\n" -msgstr "" - -#: lib/sh/snprintf.c:1888 -#, c-format -msgid "%%*.*s --> 10.10\n" -msgstr "" - -#: lib/sh/snprintf.c:1889 lib/sh/snprintf.c:1890 lib/sh/snprintf.c:1891 -#, c-format -msgid "%*.*s\n" -msgstr "" - -#: lib/sh/snprintf.c:1895 -#, c-format -msgid "%%%%%%%%\n" -msgstr "" - -#: lib/sh/snprintf.c:1896 lib/sh/snprintf.c:1897 lib/sh/snprintf.c:1898 -#, c-format -msgid "%%%%\n" -msgstr "" - -#: lib/sh/snprintf.c:1902 -msgid "Hello this is a too big string for the buffer" -msgstr "" - -#: lib/sh/snprintf.c:1904 -#, c-format -msgid "<%%>, %s\n" -msgstr "" - -#: lib/sh/snprintf.c:1907 lib/sh/snprintf.c:1908 lib/sh/snprintf.c:1915 -#: lib/sh/snprintf.c:1922 lib/sh/snprintf.c:1930 lib/sh/snprintf.c:1939 -#: lib/sh/snprintf.c:1948 lib/sh/snprintf.c:1955 -#, c-format -msgid "<%s>\n" -msgstr "" - -#: lib/sh/snprintf.c:1909 lib/sh/snprintf.c:1916 lib/sh/snprintf.c:1923 -#: lib/sh/snprintf.c:1931 lib/sh/snprintf.c:1940 lib/sh/snprintf.c:1949 -#: lib/sh/snprintf.c:1956 -#, c-format -msgid "" -"<%s>\n" -"\n" -msgstr "" - -#: lib/sh/snprintf.c:1911 -#, c-format -msgid "<%%p> vsnprintf\n" -msgstr "" - -#: lib/sh/snprintf.c:1912 lib/sh/snprintf.c:1913 -#, c-format -msgid "%p" -msgstr "" - -#: lib/sh/snprintf.c:1914 -#, c-format -msgid "<%p>\n" -msgstr "" - -#: lib/sh/snprintf.c:1918 -#, c-format -msgid "<%%lu> LONG_MAX+1\n" -msgstr "" - -#: lib/sh/snprintf.c:1919 lib/sh/snprintf.c:1920 -#, c-format -msgid "%lu" -msgstr "" - -#: lib/sh/snprintf.c:1921 -#, c-format -msgid "<%lu>\n" -msgstr "" - -#: lib/sh/snprintf.c:1926 -#, c-format -msgid "<%%llu> LLONG_MAX+1\n" -msgstr "" - -#: lib/sh/snprintf.c:1927 lib/sh/snprintf.c:1928 -#, c-format -msgid "%llu" -msgstr "" - -#: lib/sh/snprintf.c:1929 -#, c-format -msgid "<%llu>\n" -msgstr "" - -#: lib/sh/snprintf.c:1935 -#, c-format -msgid "<%%6.2LE> 42.42\n" -msgstr "" - -#: lib/sh/snprintf.c:1936 lib/sh/snprintf.c:1937 -#, c-format -msgid "%6.2LE" -msgstr "" - -#: lib/sh/snprintf.c:1938 -#, c-format -msgid "<%6.2LE>\n" -msgstr "" - -#: lib/sh/snprintf.c:1944 -#, c-format -msgid "<%%6.2A> 42.42\n" -msgstr "" - -#: lib/sh/snprintf.c:1945 lib/sh/snprintf.c:1946 -#, c-format -msgid "%6.2A" -msgstr "" - -#: lib/sh/snprintf.c:1947 -#, c-format -msgid "<%6.2A>\n" -msgstr "" - -#: lib/sh/snprintf.c:1951 -#, c-format -msgid "<%%6.2LA> 42.42\n" -msgstr "" - -#: lib/sh/snprintf.c:1952 lib/sh/snprintf.c:1953 -#, c-format -msgid "%6.2LA" -msgstr "" - -#: lib/sh/snprintf.c:1954 -#, c-format -msgid "<%6.2LA>\n" -msgstr "" - -#: lib/sh/snprintf.c:1959 -#, c-format -msgid "<%%.10240f> DBL_MAX\n" -msgstr "" - -#: lib/sh/snprintf.c:1960 lib/sh/snprintf.c:1961 -#, c-format -msgid "%.10240f" -msgstr "" - -#: lib/sh/snprintf.c:1962 -#, c-format -msgid "<%.10240f>\n" -msgstr "" - -#: lib/sh/snprintf.c:1963 lib/sh/snprintf.c:1970 -#, c-format -msgid "<%d> <%s>\n" -msgstr "" - -#: lib/sh/snprintf.c:1964 lib/sh/snprintf.c:1971 -#, c-format -msgid "" -"<%d> <%s>\n" -"\n" -msgstr "" - -#: lib/sh/snprintf.c:1966 -#, c-format -msgid "<%%.10240Lf> LDBL_MAX\n" -msgstr "" - -#: lib/sh/snprintf.c:1967 lib/sh/snprintf.c:1968 -#, c-format -msgid "%.10240Lf" -msgstr "" - -#: lib/sh/snprintf.c:1969 -#, c-format -msgid "<%.10240Lf>\n" -msgstr "" - -#: lib/sh/snprintf.c:1974 -#, c-format -msgid "/%%g/, 421.2345\n" -msgstr "" - -#: lib/sh/snprintf.c:1981 -#, c-format -msgid "/%%g/, 4214.2345\n" -msgstr "" - -#: lib/sh/snprintf.c:1988 -#, c-format -msgid "/%%.5g/, 4214.2345\n" -msgstr "" - -#: lib/sh/snprintf.c:1989 lib/sh/snprintf.c:1990 lib/sh/snprintf.c:1991 -#, c-format -msgid "/%.5g/\n" -msgstr "" - -#: lib/sh/snprintf.c:1995 -#, c-format -msgid "/%%.4g/, 4214.2345\n" -msgstr "" - -#: lib/sh/snprintf.c:1996 lib/sh/snprintf.c:1997 lib/sh/snprintf.c:1998 -#, c-format -msgid "/%.4g/\n" -msgstr "" - -#: lib/sh/snprintf.c:2002 -#, c-format -msgid "/%%'ld %%'ld/, 12345, 1234567\n" -msgstr "" - -#: lib/sh/snprintf.c:2003 lib/sh/snprintf.c:2004 lib/sh/snprintf.c:2005 -#: lib/sh/snprintf.c:2010 lib/sh/snprintf.c:2011 lib/sh/snprintf.c:2012 -#: lib/sh/snprintf.c:2017 lib/sh/snprintf.c:2018 lib/sh/snprintf.c:2019 -#, c-format -msgid "/%'ld %'ld/\n" -msgstr "" - -#: lib/sh/snprintf.c:2009 -#, c-format -msgid "/%%'ld %%'ld/, 336, 3336\n" -msgstr "" - -#: lib/sh/snprintf.c:2016 -#, c-format -msgid "/%%'ld %%'ld/, -42786, -142786\n" -msgstr "" - -#: lib/sh/snprintf.c:2023 -#, c-format -msgid "/%%'f %%'f/, 421.2345, 421234.56789\n" -msgstr "" - -#: lib/sh/snprintf.c:2024 lib/sh/snprintf.c:2025 lib/sh/snprintf.c:2026 -#: lib/sh/snprintf.c:2031 lib/sh/snprintf.c:2032 lib/sh/snprintf.c:2033 -#, c-format -msgid "/%'f %'f/\n" -msgstr "" - -#: lib/sh/snprintf.c:2030 -#, c-format -msgid "/%%'f %%'f/, -421.2345, -421234.56789\n" -msgstr "" - -#: lib/sh/snprintf.c:2037 -#, c-format -msgid "/%%'g %%'g/, 421.2345, 421234.56789\n" -msgstr "" - -#: lib/sh/snprintf.c:2038 lib/sh/snprintf.c:2039 lib/sh/snprintf.c:2040 -#: lib/sh/snprintf.c:2045 lib/sh/snprintf.c:2046 lib/sh/snprintf.c:2047 -#, c-format -msgid "/%'g %'g/\n" -msgstr "" - -#: lib/sh/snprintf.c:2044 -#, c-format -msgid "/%%'g %%'g/, -421.2345, -421234.56789\n" -msgstr "" - -#: lib/sh/snprintf.c:2052 -#, c-format -msgid "/%%'g/, 4213455.8392\n" -msgstr "" - -#: lib/sh/snprintf.c:2053 lib/sh/snprintf.c:2054 lib/sh/snprintf.c:2055 -#, c-format -msgid "/%'g/\n" -msgstr "" - -#: lib/sh/strerror.c:49 -msgid "Unknown system error " -msgstr "" - -#: lib/sh/strftime.c:153 -msgid "Sun" -msgstr "" - -#: lib/sh/strftime.c:153 -msgid "Mon" -msgstr "" - -#: lib/sh/strftime.c:153 -msgid "Tue" -msgstr "" - -#: lib/sh/strftime.c:153 -msgid "Wed" -msgstr "" - -#: lib/sh/strftime.c:154 -msgid "Thu" -msgstr "" - -#: lib/sh/strftime.c:154 -msgid "Fri" -msgstr "" - -#: lib/sh/strftime.c:154 -msgid "Sat" -msgstr "" - -#: lib/sh/strftime.c:157 -msgid "Sunday" -msgstr "" - -#: lib/sh/strftime.c:157 -msgid "Monday" -msgstr "" - -#: lib/sh/strftime.c:157 -msgid "Tuesday" -msgstr "" - -#: lib/sh/strftime.c:157 -msgid "Wednesday" -msgstr "" - -#: lib/sh/strftime.c:158 -msgid "Thursday" -msgstr "" - -#: lib/sh/strftime.c:158 -msgid "Friday" -msgstr "" - -#: lib/sh/strftime.c:158 -msgid "Saturday" -msgstr "" - -#: lib/sh/strftime.c:161 -msgid "Jan" -msgstr "" - -#: lib/sh/strftime.c:161 -msgid "Feb" -msgstr "" - -#: lib/sh/strftime.c:161 -msgid "Mar" -msgstr "" - -#: lib/sh/strftime.c:161 -msgid "Apr" -msgstr "" - -#: lib/sh/strftime.c:161 lib/sh/strftime.c:166 -msgid "May" -msgstr "" - -#: lib/sh/strftime.c:161 -msgid "Jun" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Jul" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Aug" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Sep" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Oct" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Nov" -msgstr "" - -#: lib/sh/strftime.c:162 -msgid "Dec" -msgstr "" - -#: lib/sh/strftime.c:165 -msgid "January" -msgstr "" - -#: lib/sh/strftime.c:165 -msgid "February" -msgstr "" - -#: lib/sh/strftime.c:165 -msgid "March" -msgstr "" - -#: lib/sh/strftime.c:165 -msgid "April" -msgstr "" - -#: lib/sh/strftime.c:166 -msgid "June" -msgstr "" - -#: lib/sh/strftime.c:166 -msgid "July" -msgstr "" - -#: lib/sh/strftime.c:166 -msgid "August" -msgstr "" - -#: lib/sh/strftime.c:166 -msgid "September" -msgstr "" - -#: lib/sh/strftime.c:167 -msgid "October" -msgstr "" - -#: lib/sh/strftime.c:167 -msgid "November" -msgstr "" - -#: lib/sh/strftime.c:167 -msgid "December" -msgstr "" - -#: lib/sh/strftime.c:169 -msgid "AM" -msgstr "" - -#: lib/sh/strftime.c:169 -msgid "PM" -msgstr "" - -#: lib/sh/strftime.c:270 -msgid "%A %B %d %T %Y" -msgstr "" - -#: lib/sh/strftime.c:275 lib/sh/strftime.c:280 lib/sh/strftime.c:321 -#: lib/sh/strftime.c:329 lib/sh/strftime.c:338 lib/sh/strftime.c:347 -#: lib/sh/strftime.c:352 lib/sh/strftime.c:393 lib/sh/strftime.c:413 -#: lib/sh/strftime.c:417 lib/sh/strftime.c:426 lib/sh/strftime.c:440 -#, c-format -msgid "%02d" -msgstr "" - -#: lib/sh/strftime.c:284 -msgid "%m/%d/%y" -msgstr "" - -#: lib/sh/strftime.c:288 lib/sh/strftime.c:519 lib/sh/strftime.c:528 -#, c-format -msgid "%2d" -msgstr "" - -#: lib/sh/strftime.c:296 -msgid "%Y-%m-%d" -msgstr "" - -#: lib/sh/strftime.c:342 -#, c-format -msgid "%03d" -msgstr "" - -#: lib/sh/strftime.c:373 -msgid "%I:%M:%S %p" -msgstr "" - -#: lib/sh/strftime.c:386 lib/malloc/stats.c:181 -#, c-format -msgid "%ld" -msgstr "" - -#: lib/sh/strftime.c:430 -msgid "%A %B %d %Y" -msgstr "" - -#: lib/sh/strftime.c:495 -#, c-format -msgid "%02d%02d" -msgstr "" - -#: lib/sh/strftime.c:544 -#, c-format -msgid "%2d-%3.3s-%4d" -msgstr "" - -#: lib/sh/strftime.c:786 -#, c-format -msgid "(%%A) full weekday name, var length (Sunday..Saturday) %A" -msgstr "" - -#: lib/sh/strftime.c:787 -msgid "(%%B) full month name, var length (January..December) %B" -msgstr "" - -#: lib/sh/strftime.c:788 -#, c-format -msgid "(%%C) Century %C" -msgstr "" - -#: lib/sh/strftime.c:789 -msgid "(%%D) date (%%m/%%d/%%y) %D" -msgstr "" - -#: lib/sh/strftime.c:790 -#, c-format -msgid "(%%E) Locale extensions (ignored) %E" -msgstr "" - -#: lib/sh/strftime.c:791 -#, c-format -msgid "(%%F) full month name, var length (January..December) %F" -msgstr "" - -#: lib/sh/strftime.c:792 -msgid "(%%H) hour (24-hour clock, 00..23) %H" -msgstr "" - -#: lib/sh/strftime.c:793 -msgid "(%%I) hour (12-hour clock, 01..12) %I" -msgstr "" - -#: lib/sh/strftime.c:794 -msgid "(%%M) minute (00..59) %M" -msgstr "" - -#: lib/sh/strftime.c:795 -msgid "(%%N) Emporer/Era Name %N" -msgstr "" - -#: lib/sh/strftime.c:796 -msgid "(%%O) Locale extensions (ignored) %O" -msgstr "" - -#: lib/sh/strftime.c:797 -msgid "(%%R) time, 24-hour (%%H:%%M) %R" -msgstr "" - -#: lib/sh/strftime.c:798 -#, c-format -msgid "(%%S) second (00..60) %S" -msgstr "" - -#: lib/sh/strftime.c:799 -msgid "(%%T) time, 24-hour (%%H:%%M:%%S) %T" -msgstr "" - -#: lib/sh/strftime.c:800 -msgid "(%%U) week of year, Sunday as first day of week (00..53) %U" -msgstr "" - -#: lib/sh/strftime.c:801 -msgid "(%%V) week of year according to ISO 8601 %V" -msgstr "" - -#: lib/sh/strftime.c:802 -msgid "(%%W) week of year, Monday as first day of week (00..53) %W" -msgstr "" - -#: lib/sh/strftime.c:803 -msgid "(%%X) appropriate locale time representation (%H:%M:%S) %X" -msgstr "" - -#: lib/sh/strftime.c:804 -msgid "(%%Y) year with century (1970...) %Y" -msgstr "" - -#: lib/sh/strftime.c:805 -msgid "(%%Z) timezone (EDT), or blank if timezone not determinable %Z" -msgstr "" - -#: lib/sh/strftime.c:806 -#, c-format -msgid "(%%a) locale's abbreviated weekday name (Sun..Sat) %a" -msgstr "" - -#: lib/sh/strftime.c:807 -msgid "(%%b) locale's abbreviated month name (Jan..Dec) %b" -msgstr "" - -#: lib/sh/strftime.c:808 -msgid "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c" -msgstr "" - -#: lib/sh/strftime.c:809 -#, c-format -msgid "(%%d) day of the month (01..31) %d" -msgstr "" - -#: lib/sh/strftime.c:810 -#, c-format -msgid "(%%e) day of the month, blank-padded ( 1..31) %e" -msgstr "" - -#: lib/sh/strftime.c:811 -msgid "(%%h) should be same as (%%b) %h" -msgstr "" - -#: lib/sh/strftime.c:812 -msgid "(%%j) day of the year (001..366) %j" -msgstr "" - -#: lib/sh/strftime.c:813 -msgid "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k" -msgstr "" - -#: lib/sh/strftime.c:814 -msgid "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l" -msgstr "" - -#: lib/sh/strftime.c:815 -#, c-format -msgid "(%%m) month (01..12) %m" -msgstr "" - -#: lib/sh/strftime.c:816 -#, c-format -msgid "(%%o) Emporer/Era Year %o" -msgstr "" - -#: lib/sh/strftime.c:817 -#, c-format -msgid "(%%p) locale's AM or PM based on 12-hour clock %p" -msgstr "" - -#: lib/sh/strftime.c:818 -msgid "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r" -msgstr "" - -#: lib/sh/strftime.c:819 -#, c-format -msgid "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u" -msgstr "" - -#: lib/sh/strftime.c:820 -msgid "(%%v) VMS date (dd-bbb-YYYY) %v" -msgstr "" - -#: lib/sh/strftime.c:821 -msgid "(%%w) day of week (0..6, Sunday == 0) %w" -msgstr "" - -#: lib/sh/strftime.c:822 -#, c-format -msgid "(%%x) appropriate locale date representation %x" -msgstr "" - -#: lib/sh/strftime.c:823 -msgid "(%%y) last two digits of year (00..99) %y" -msgstr "" - -#: lib/sh/strftime.c:824 -msgid "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z" -msgstr "" - -#: lib/sh/stringlist.c:235 -#, c-format -msgid "%s%s\n" -msgstr "" - -#: lib/sh/strtoimax.c:38 lib/sh/strtoimax.c:45 lib/sh/strtoumax.c:38 -#: lib/sh/strtoumax.c:45 -msgid "this configure-time declaration test was not run" -msgstr "" - -#: lib/sh/strtoimax.c:83 -#, c-format -msgid "sizeof intmax_t: %d\n" -msgstr "" - -#: lib/sh/strtoimax.c:86 -#, c-format -msgid "sizeof long long: %d\n" -msgstr "" - -#: lib/sh/strtoimax.c:88 -#, c-format -msgid "sizeof long: %d\n" -msgstr "" - -#: lib/sh/strtoimax.c:98 -#, c-format -msgid "%lld %lld %ld\n" -msgstr "" - -#: lib/sh/strtoumax.c:83 -#, c-format -msgid "sizeof uintmax_t: %d\n" -msgstr "" - -#: lib/sh/strtoumax.c:86 -#, c-format -msgid "sizeof unsigned long long: %d\n" -msgstr "" - -#: lib/sh/strtoumax.c:88 -#, c-format -msgid "sizeof unsigned long: %d\n" -msgstr "" - -#: lib/sh/strtoumax.c:98 -#, c-format -msgid "%llu %llu %lu\n" -msgstr "" - -#: lib/sh/tmpfile.c:46 -msgid "shtmp" -msgstr "" - -#: lib/sh/tmpfile.c:73 -msgid "/var/tmp" -msgstr "" - -#: lib/sh/tmpfile.c:77 -msgid "/usr/tmp" -msgstr "" - -#: lib/sh/tmpfile.c:92 -msgid "TMPDIR" -msgstr "" - -#: lib/sh/tmpfile.c:122 lib/sh/tmpfile.c:167 -#, c-format -msgid "%s/%s.XXXXXX" -msgstr "" - -#: lib/sh/tmpfile.c:135 lib/sh/tmpfile.c:184 -#, c-format -msgid "%s/%s-%lu" -msgstr "" - -#: lib/sh/tmpfile.c:212 -msgid "w+" -msgstr "" - -#: lib/malloc/alloca.c:446 -#, c-format -msgid "%011o %011o %011o\n" -msgstr "" - -#: lib/malloc/alloca.c:467 -#, c-format -msgid "%011o %011o\n" -msgstr "" - -#: lib/malloc/i386-alloca.s:1 -msgid "alloca.s" -msgstr "" - -#: lib/malloc/imalloc.h:52 -msgid "x" -msgstr "" - -#: lib/malloc/malloc.c:298 -#, c-format -msgid "malloc: failed assertion: %s\n" -msgstr "" - -#: lib/malloc/malloc.c:314 -#, c-format -msgid "" -"\r\n" -"malloc: %s:%d: assertion botched\r\n" -msgstr "" - -#: lib/malloc/malloc.c:355 -msgid "bcoalesce: CHAIN(mp2) != mp1" -msgstr "" - -#: lib/malloc/malloc.c:604 -msgid "malloc_debug_dummy\n" -msgstr "" - -#: lib/malloc/malloc.c:740 -msgid "malloc: block on free list clobbered" -msgstr "" - -#: lib/malloc/malloc.c:766 lib/malloc/malloc.c:768 lib/malloc/malloc.c:773 -msgid "malloc" -msgstr "" - -#: lib/malloc/malloc.c:817 -msgid "free: called with already freed block argument" -msgstr "" - -#: lib/malloc/malloc.c:820 -msgid "free: called with unallocated block argument" -msgstr "" - -#: lib/malloc/malloc.c:839 -msgid "free: underflow detected; mh_nbytes out of range" -msgstr "" - -#: lib/malloc/malloc.c:845 -msgid "free: start and end chunk sizes differ" -msgstr "" - -#: lib/malloc/malloc.c:942 -msgid "realloc: called with unallocated block argument" -msgstr "" - -#: lib/malloc/malloc.c:957 -msgid "realloc: underflow detected; mh_nbytes out of range" -msgstr "" - -#: lib/malloc/malloc.c:963 -msgid "realloc: start and end chunk sizes differ" -msgstr "" - -#: lib/malloc/malloc.c:1009 lib/malloc/malloc.c:1011 lib/malloc/malloc.c:1016 -msgid "realloc" -msgstr "" - -#: lib/malloc/memtest.c:125 lib/malloc/memtest.c:138 -msgid "malloc-test: " -msgstr "" - -#: lib/malloc/stats.c:99 -#, c-format -msgid "" -"Memory allocation statistics: %s\n" -" size\tfree\tin use\ttotal\tmorecore lesscore split\tcoalesce\n" -msgstr "" - -#: lib/malloc/stats.c:104 -#, c-format -msgid "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n" -msgstr "" - -#: lib/malloc/stats.c:108 -#, c-format -msgid "" -"\n" -"Total bytes in use: %lu, total bytes free: %lu\n" -msgstr "" - -#: lib/malloc/stats.c:110 -#, c-format -msgid "" -"\n" -"Total bytes requested by application: %lu\n" -msgstr "" - -#: lib/malloc/stats.c:111 -#, c-format -msgid "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n" -msgstr "" - -#: lib/malloc/stats.c:113 -#, c-format -msgid "Total sbrks: %d, total bytes via sbrk: %d\n" -msgstr "" - -#: lib/malloc/stats.c:115 -#, c-format -msgid "Total blocks split: %d, total block coalesces: %d\n" -msgstr "" - -#: lib/malloc/stats.c:134 -msgid "/var/tmp/maltrace/stats." -msgstr "" - -#: lib/malloc/stats.c:172 -#, c-format -msgid "%s%ld" -msgstr "" - -#: lib/malloc/table.c:152 -#, c-format -msgid "malloc: %p: %s: last %s from %s:%d\n" -msgstr "" - -#: lib/malloc/table.c:154 lib/malloc/table.c:155 lib/malloc/table.c:239 -#: lib/malloc/watch.c:46 -msgid "allocated" -msgstr "" - -#: lib/malloc/table.c:154 lib/malloc/table.c:222 lib/malloc/table.c:237 -msgid "free" -msgstr "" - -#: lib/malloc/table.c:155 lib/malloc/watch.c:48 -msgid "freed" -msgstr "" - -#: lib/malloc/table.c:175 -msgid "register_alloc: alloc table is full with FIND_ALLOC?\n" -msgstr "" - -#: lib/malloc/table.c:182 -#, c-format -msgid "register_alloc: %p already in table as allocated?\n" -msgstr "" - -#: lib/malloc/table.c:211 -#, c-format -msgid "register_free: %p not in allocation table?\n" -msgstr "" - -#: lib/malloc/table.c:218 -#, c-format -msgid "register_free: %p already in table as free?\n" -msgstr "" - -#: lib/malloc/table.c:241 -msgid "undetermined?" -msgstr "" - -#: lib/malloc/table.c:255 -#, c-format -msgid "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n" -msgstr "" - -#: lib/malloc/trace.c:51 -#, c-format -msgid "alloc: %s: %p (%d bytes) from '%s:%d'\n" -msgstr "" - -#: lib/malloc/trace.c:54 -#, c-format -msgid "alloc:%p:%d:%s:%d\n" -msgstr "" - -#: lib/malloc/trace.c:69 -#, c-format -msgid "free: %p (%d bytes) from '%s:%d'\n" -msgstr "" - -#: lib/malloc/trace.c:72 -#, c-format -msgid "free:%p:%d:%s:%d\n" -msgstr "" - -#: lib/malloc/trace.c:107 -msgid "/var/tmp/maltrace/trace." -msgstr "" - -#: lib/malloc/watch.c:50 -msgid "requesting resize" -msgstr "" - -#: lib/malloc/watch.c:52 -msgid "just resized" -msgstr "" - -#: lib/malloc/watch.c:54 -msgid "bug: unknown operation" -msgstr "" - -#: lib/malloc/watch.c:56 -#, c-format -msgid "malloc: watch alert: %p %s " -msgstr "" - -#: lib/malloc/watch.c:58 -#, c-format -msgid "(size %lu) " -msgstr "" - -#: lib/malloc/watch.c:59 -#, c-format -msgid "from '%s:%d'\n" -msgstr "" - -#: lib/malloc/x386-alloca.s:10 -msgid "masm" -msgstr "" - -#: lib/malloc/xmalloc.c:55 -#, c-format -msgid "%s: out of virtual memory\n" -msgstr "" - -#: lib/malloc/xmalloc.c:70 -msgid "xmalloc" -msgstr "" - -#: lib/malloc/xmalloc.c:84 -msgid "xrealloc" -msgstr "" diff --git a/po/bash.pot~ b/po/bash.pot~ deleted file mode 100644 index 1dd995c98..000000000 --- a/po/bash.pot~ +++ /dev/null @@ -1,4174 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Free Software Foundation, Inc. -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#: builtins/caller.def:128 builtins/caller.def:132 builtins/pushd.def:655 -#: builtins/pushd.def:663 builtins/pushd.def:666 builtins/pushd.def:676 -#: builtins/pushd.def:680 builtins/pushd.def:684 builtins/pushd.def:687 -#: builtins/pushd.def:690 builtins/pushd.def:699 builtins/pushd.def:703 -#: builtins/pushd.def:707 builtins/pushd.def:710 builtins.c:321 builtins.c:325 -#: builtins.c:390 builtins.c:392 builtins.c:401 builtins.c:404 builtins.c:408 -#: builtins.c:445 builtins.c:487 builtins.c:491 builtins.c:498 builtins.c:509 -#: builtins.c:513 builtins.c:552 builtins.c:555 builtins.c:559 builtins.c:562 -#: builtins.c:630 builtins.c:637 builtins.c:692 builtins.c:713 builtins.c:718 -#: builtins.c:722 builtins.c:745 builtins.c:835 builtins.c:919 builtins.c:921 -#: builtins.c:943 builtins.c:946 builtins.c:948 builtins.c:950 builtins.c:952 -#: builtins.c:954 builtins.c:957 builtins.c:966 builtins.c:968 builtins.c:973 -#: builtins.c:976 builtins.c:1019 builtins.c:1024 builtins.c:1028 -#: builtins.c:1032 builtins.c:1034 builtins.c:1047 builtins.c:1062 -#: builtins.c:1226 builtins.c:1231 builtins.c:1305 builtins.c:1309 -#: builtins.c:1313 builtins.c:1316 builtins.c:1319 builtins.c:1331 -#: builtins.c:1335 builtins.c:1339 builtins.c:1342 builtins.c:1354 -#: builtins.c:1362 builtins.c:1365 -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: bug-bash@gnu.org\n" -"POT-Creation-Date: 2003-12-22 15:34-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: arrayfunc.c:45 -msgid "bad array subscript" -msgstr "" - -#: arrayfunc.c:306 -#, c-format -msgid "%s: cannot assign to non-numeric index" -msgstr "" - -#: bashhist.c:321 -#, c-format -msgid "%s: cannot create: %s" -msgstr "" - -#: bashline.c:2791 -msgid "bash_execute_unix_command: cannot find keymap for command" -msgstr "" - -#: bashline.c:2840 -#, c-format -msgid "%s: first non-whitespace character is not `\"'" -msgstr "" - -#: bashline.c:2869 -#, c-format -msgid "no closing `%c' in %s" -msgstr "" - -#: bashline.c:2903 -#, c-format -msgid "%s: missing colon separator" -msgstr "" - -#: builtins/alias.def:123 -#, c-format -msgid "`%s': invalid alias name" -msgstr "" - -#: builtins/bind.def:194 -#, c-format -msgid "`%s': invalid keymap name" -msgstr "" - -#: builtins/bind.def:233 -#, c-format -msgid "%s: cannot read: %s" -msgstr "" - -#: builtins/bind.def:248 -#, c-format -msgid "`%s': cannot unbind" -msgstr "" - -#: builtins/bind.def:283 -#, c-format -msgid "`%s': unknown function name" -msgstr "" - -#: builtins/bind.def:291 -#, c-format -msgid "%s is not bound to any keys.\n" -msgstr "" - -#: builtins/bind.def:295 -#, c-format -msgid "%s can be invoked via " -msgstr "" - -#: builtins/break.def:128 -msgid "only meaningful in a `for', `while', or `until' loop" -msgstr "" - -#: builtins/caller.def:127 builtins.c:320 -msgid "Returns the context of the current subroutine call." -msgstr "" - -#: builtins/caller.def:129 builtins.c:322 -msgid "Without EXPR, returns returns \"$line $filename\". With EXPR," -msgstr "" - -#: builtins/caller.def:130 builtins.c:323 -msgid "returns \"$line $subroutine $filename\"; this extra information" -msgstr "" - -#: builtins/caller.def:131 builtins.c:324 -msgid "can be used used to provide a stack trace." -msgstr "" - -#: builtins/caller.def:133 builtins.c:326 -msgid "The value of EXPR indicates how many call frames to go back before the" -msgstr "" - -#: builtins/caller.def:134 builtins.c:327 -msgid "current one; the top frame is frame 0." -msgstr "" - -#: builtins/cd.def:188 -msgid "HOME not set" -msgstr "" - -#: builtins/cd.def:200 -msgid "OLDPWD not set" -msgstr "" - -#: builtins/cd.def:357 -#, c-format -msgid "write error: %s" -msgstr "" - -#: builtins/common.c:133 test.c:921 -msgid "too many arguments" -msgstr "" - -#: builtins/common.c:157 shell.c:465 shell.c:737 -#, c-format -msgid "%s: option requires an argument" -msgstr "" - -#: builtins/common.c:164 -#, c-format -msgid "%s: numeric argument required" -msgstr "" - -#: builtins/common.c:171 -#, c-format -msgid "%s: not found" -msgstr "" - -#: builtins/common.c:180 shell.c:750 -#, c-format -msgid "%s: invalid option" -msgstr "" - -#: builtins/common.c:187 -#, c-format -msgid "%s: invalid option name" -msgstr "" - -#: builtins/common.c:194 general.c:229 general.c:234 -#, c-format -msgid "`%s': not a valid identifier" -msgstr "" - -#: builtins/common.c:201 -#, c-format -msgid "%s: invalid number" -msgstr "" - -#: builtins/common.c:208 -#, c-format -msgid "%s: invalid signal specification" -msgstr "" - -#: builtins/common.c:215 -#, c-format -msgid "`%s': not a pid or valid job spec" -msgstr "" - -#: builtins/common.c:222 error.c:453 -#, c-format -msgid "%s: readonly variable" -msgstr "" - -#: builtins/common.c:230 -#, c-format -msgid "%s: %s out of range" -msgstr "" - -#: builtins/common.c:230 builtins/common.c:232 -msgid "argument" -msgstr "" - -#: builtins/common.c:232 -#, c-format -msgid "%s out of range" -msgstr "" - -#: builtins/common.c:240 -#, c-format -msgid "%s: no such job" -msgstr "" - -#: builtins/common.c:248 -#, c-format -msgid "%s: no job control" -msgstr "" - -#: builtins/common.c:250 -msgid "no job control" -msgstr "" - -#: builtins/common.c:260 -#, c-format -msgid "%s: restricted" -msgstr "" - -#: builtins/common.c:262 -msgid "restricted" -msgstr "" - -#: builtins/common.c:270 -#, c-format -msgid "%s: not a shell builtin" -msgstr "" - -#: builtins/common.c:486 -#, c-format -msgid "%s: could not get current directory: %s: %s\n" -msgstr "" - -#: builtins/common.c:553 builtins/common.c:555 -#, c-format -msgid "%s: ambiguous job spec" -msgstr "" - -#: builtins/complete.def:251 -#, c-format -msgid "%s: invalid action name" -msgstr "" - -#: builtins/complete.def:381 builtins/complete.def:524 -#, c-format -msgid "%s: no completion specification" -msgstr "" - -#: builtins/complete.def:571 -msgid "warning: -F option may not work as you expect" -msgstr "" - -#: builtins/complete.def:573 -msgid "warning: -C option may not work as you expect" -msgstr "" - -#: builtins/declare.def:105 -msgid "can only be used in a function" -msgstr "" - -#: builtins/declare.def:295 -msgid "cannot use `-f' to make functions" -msgstr "" - -#: builtins/declare.def:307 execute_cmd.c:3949 -#, c-format -msgid "%s: readonly function" -msgstr "" - -#: builtins/declare.def:389 -#, c-format -msgid "%s: cannot destroy array variables in this way" -msgstr "" - -#: builtins/enable.def:128 builtins/enable.def:136 -msgid "dynamic loading not available" -msgstr "" - -#: builtins/enable.def:303 -#, c-format -msgid "cannot open shared object %s: %s" -msgstr "" - -#: builtins/enable.def:326 -#, c-format -msgid "cannot find %s in shared object %s: %s" -msgstr "" - -#: builtins/enable.def:450 -#, c-format -msgid "%s: not dynamically loaded" -msgstr "" - -#: builtins/enable.def:465 -#, c-format -msgid "%s: cannot delete: %s" -msgstr "" - -#: builtins/evalfile.c:128 execute_cmd.c:3821 shell.c:1395 -#, c-format -msgid "%s: is a directory" -msgstr "" - -#: builtins/evalfile.c:133 -#, c-format -msgid "%s: not a regular file" -msgstr "" - -#: builtins/evalfile.c:141 -#, c-format -msgid "%s: file is too large" -msgstr "" - -#: builtins/exec.def:205 -#, c-format -msgid "%s: cannot execute: %s" -msgstr "" - -#: builtins/exit.def:83 -msgid "not login shell: use `exit'" -msgstr "" - -#: builtins/exit.def:111 -msgid "There are stopped jobs.\n" -msgstr "" - -#: builtins/fc.def:252 -msgid "no command found" -msgstr "" - -#: builtins/fc.def:317 -msgid "history specification" -msgstr "" - -#: builtins/fc.def:338 -#, c-format -msgid "%s: cannot open temp file: %s" -msgstr "" - -#: builtins/fg_bg.def:133 -#, c-format -msgid "job %d started without job control" -msgstr "" - -#: builtins/getopt.c:109 -#, c-format -msgid "%s: illegal option -- %c\n" -msgstr "" - -#: builtins/getopt.c:110 -#, c-format -msgid "%s: option requires an argument -- %c\n" -msgstr "" - -#: builtins/hash.def:83 -msgid "hashing disabled" -msgstr "" - -#: builtins/hash.def:128 -#, c-format -msgid "%s: hash table empty\n" -msgstr "" - -#: builtins/help.def:108 -msgid "Shell commands matching keywords `" -msgstr "" - -#: builtins/help.def:110 -msgid "Shell commands matching keyword `" -msgstr "" - -#: builtins/help.def:138 -#, c-format -msgid "" -"no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." -msgstr "" - -#: builtins/help.def:164 -#, c-format -msgid "%s: cannot open: %s" -msgstr "" - -#: builtins/help.def:182 -msgid "" -"These shell commands are defined internally. Type `help' to see this list.\n" -"Type `help name' to find out more about the function `name'.\n" -"Use `info bash' to find out more about the shell in general.\n" -"Use `man -k' or `info' to find out more about commands not in this list.\n" -"\n" -"A star (*) next to a name means that the command is disabled.\n" -"\n" -msgstr "" - -#: builtins/history.def:148 -msgid "cannot use more than one of -anrw" -msgstr "" - -#: builtins/history.def:180 -msgid "history position" -msgstr "" - -#: builtins/history.def:390 -#, c-format -msgid "%s: history expansion failed" -msgstr "" - -#: builtins/jobs.def:99 -msgid "no other options allowed with `-x'" -msgstr "" - -#: builtins/kill.def:187 -#, c-format -msgid "%s: arguments must be process or job IDs" -msgstr "" - -#: builtins/kill.def:248 -msgid "Unknown error" -msgstr "" - -#: builtins/let.def:94 builtins/let.def:119 expr.c:496 expr.c:511 -msgid "expression expected" -msgstr "" - -#: builtins/printf.def:249 -#, c-format -msgid "`%s': missing format character" -msgstr "" - -#: builtins/printf.def:408 -#, c-format -msgid "`%c': invalid format character" -msgstr "" - -#: builtins/printf.def:601 -msgid "missing hex digit for \\x" -msgstr "" - -#: builtins/pushd.def:168 -msgid "no other directory" -msgstr "" - -#: builtins/pushd.def:435 -msgid "" -msgstr "" - -#: builtins/pushd.def:652 builtins.c:1351 -msgid "Display the list of currently remembered directories. Directories" -msgstr "" - -#: builtins/pushd.def:653 builtins.c:1352 -msgid "find their way onto the list with the `pushd' command; you can get" -msgstr "" - -#: builtins/pushd.def:654 builtins.c:1353 -msgid "back up through the list with the `popd' command." -msgstr "" - -#: builtins/pushd.def:656 builtins.c:1355 -msgid "The -l flag specifies that `dirs' should not print shorthand versions" -msgstr "" - -#: builtins/pushd.def:657 builtins.c:1356 -msgid "of directories which are relative to your home directory. This means" -msgstr "" - -#: builtins/pushd.def:658 builtins.c:1357 -msgid "that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag" -msgstr "" - -#: builtins/pushd.def:659 builtins.c:1358 -msgid "causes `dirs' to print the directory stack with one entry per line," -msgstr "" - -#: builtins/pushd.def:660 builtins.c:1359 -msgid "prepending the directory name with its position in the stack. The -p" -msgstr "" - -#: builtins/pushd.def:661 builtins.c:1360 -msgid "flag does the same thing, but the stack position is not prepended." -msgstr "" - -#: builtins/pushd.def:662 builtins.c:1361 -msgid "The -c flag clears the directory stack by deleting all of the elements." -msgstr "" - -#: builtins/pushd.def:664 -msgid "+N displays the Nth entry counting from the left of the list shown by" -msgstr "" - -#: builtins/pushd.def:665 builtins/pushd.def:668 -msgid " dirs when invoked without options, starting with zero." -msgstr "" - -#: builtins/pushd.def:667 -msgid "" -"-N displays the Nth entry counting from the right of the list shown by" -msgstr "" - -#: builtins/pushd.def:673 builtins.c:1302 -msgid "Adds a directory to the top of the directory stack, or rotates" -msgstr "" - -#: builtins/pushd.def:674 builtins.c:1303 -msgid "the stack, making the new top of the stack the current working" -msgstr "" - -#: builtins/pushd.def:675 builtins.c:1304 -msgid "directory. With no arguments, exchanges the top two directories." -msgstr "" - -#: builtins/pushd.def:677 -msgid "+N Rotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins/pushd.def:678 -msgid " from the left of the list shown by `dirs', starting with" -msgstr "" - -#: builtins/pushd.def:679 builtins/pushd.def:683 -msgid " zero) is at the top." -msgstr "" - -#: builtins/pushd.def:681 -msgid "-N Rotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins/pushd.def:682 -msgid " from the right of the list shown by `dirs', starting with" -msgstr "" - -#: builtins/pushd.def:685 -msgid "-n suppress the normal change of directory when adding directories" -msgstr "" - -#: builtins/pushd.def:686 -msgid " to the stack, so only the stack is manipulated." -msgstr "" - -#: builtins/pushd.def:688 -msgid "dir adds DIR to the directory stack at the top, making it the" -msgstr "" - -#: builtins/pushd.def:689 -msgid " new current working directory." -msgstr "" - -#: builtins/pushd.def:691 builtins/pushd.def:711 builtins.c:1320 -#: builtins.c:1343 -msgid "You can see the directory stack with the `dirs' command." -msgstr "" - -#: builtins/pushd.def:696 builtins.c:1328 -msgid "Removes entries from the directory stack. With no arguments," -msgstr "" - -#: builtins/pushd.def:697 builtins.c:1329 -msgid "removes the top directory from the stack, and cd's to the new" -msgstr "" - -#: builtins/pushd.def:698 builtins.c:1330 -msgid "top directory." -msgstr "" - -#: builtins/pushd.def:700 -msgid "+N removes the Nth entry counting from the left of the list" -msgstr "" - -#: builtins/pushd.def:701 -msgid " shown by `dirs', starting with zero. For example: `popd +0'" -msgstr "" - -#: builtins/pushd.def:702 -msgid " removes the first directory, `popd +1' the second." -msgstr "" - -#: builtins/pushd.def:704 -msgid "-N removes the Nth entry counting from the right of the list" -msgstr "" - -#: builtins/pushd.def:705 -msgid " shown by `dirs', starting with zero. For example: `popd -0'" -msgstr "" - -#: builtins/pushd.def:706 -msgid " removes the last directory, `popd -1' the next to last." -msgstr "" - -#: builtins/pushd.def:708 -msgid "-n suppress the normal change of directory when removing directories" -msgstr "" - -#: builtins/pushd.def:709 -msgid " from the stack, so only the stack is manipulated." -msgstr "" - -#: builtins/read.def:207 -#, c-format -msgid "%s: invalid timeout specification" -msgstr "" - -#: builtins/read.def:230 -#, c-format -msgid "%s: invalid file descriptor specification" -msgstr "" - -#: builtins/read.def:237 -#, c-format -msgid "%d: invalid file descriptor: %s" -msgstr "" - -#: builtins/read.def:463 -#, c-format -msgid "read error: %d: %s" -msgstr "" - -#: builtins/return.def:63 -msgid "can only `return' from a function or sourced script" -msgstr "" - -#: builtins/set.def:743 -msgid "cannot simultaneously unset a function and a variable" -msgstr "" - -#: builtins/set.def:780 -#, c-format -msgid "%s: cannot unset" -msgstr "" - -#: builtins/set.def:787 -#, c-format -msgid "%s: cannot unset: readonly %s" -msgstr "" - -#: builtins/set.def:798 -#, c-format -msgid "%s: not an array variable" -msgstr "" - -#: builtins/setattr.def:165 -#, c-format -msgid "%s: not a function" -msgstr "" - -#: builtins/shift.def:66 builtins/shift.def:72 -msgid "shift count" -msgstr "" - -#: builtins/shopt.def:226 -msgid "cannot set and unset shell options simultaneously" -msgstr "" - -#: builtins/shopt.def:291 -#, c-format -msgid "%s: invalid shell option name" -msgstr "" - -#: builtins/source.def:117 -msgid "filename argument required" -msgstr "" - -#: builtins/source.def:137 -#, c-format -msgid "%s: file not found" -msgstr "" - -#: builtins/suspend.def:93 -msgid "cannot suspend" -msgstr "" - -#: builtins/suspend.def:103 -msgid "cannot suspend a login shell" -msgstr "" - -#: builtins/type.def:231 -#, c-format -msgid "%s is aliased to `%s'\n" -msgstr "" - -#: builtins/type.def:252 -#, c-format -msgid "%s is a shell keyword\n" -msgstr "" - -#: builtins/type.def:272 -#, c-format -msgid "%s is a function\n" -msgstr "" - -#: builtins/type.def:297 -#, c-format -msgid "%s is a shell builtin\n" -msgstr "" - -#: builtins/type.def:318 -#, c-format -msgid "%s is %s\n" -msgstr "" - -#: builtins/type.def:338 -#, c-format -msgid "%s is hashed (%s)\n" -msgstr "" - -#: builtins/ulimit.def:332 -#, c-format -msgid "%s: invalid limit argument" -msgstr "" - -#: builtins/ulimit.def:358 -#, c-format -msgid "`%c': bad command" -msgstr "" - -#: builtins/ulimit.def:387 -#, c-format -msgid "%s: cannot get limit: %s" -msgstr "" - -#: builtins/ulimit.def:425 -#, c-format -msgid "%s: cannot modify limit: %s" -msgstr "" - -#: builtins/umask.def:112 -msgid "octal number" -msgstr "" - -#: builtins/umask.def:226 -#, c-format -msgid "`%c': invalid symbolic mode operator" -msgstr "" - -#: builtins/umask.def:279 -#, c-format -msgid "`%c': invalid symbolic mode character" -msgstr "" - -#: error.c:165 -#, c-format -msgid "last command: %s\n" -msgstr "" - -#: error.c:173 -msgid "Aborting..." -msgstr "" - -#: error.c:260 -#, c-format -msgid "%s: warning: " -msgstr "" - -#: error.c:405 -msgid "unknown command error" -msgstr "" - -#: error.c:406 -msgid "bad command type" -msgstr "" - -#: error.c:407 -msgid "bad connector" -msgstr "" - -#: error.c:408 -msgid "bad jump" -msgstr "" - -#: error.c:446 -#, c-format -msgid "%s: unbound variable" -msgstr "" - -#: eval.c:175 -msgid "timed out waiting for input: auto-logout\n" -msgstr "" - -#: execute_cmd.c:466 -#, c-format -msgid "cannot redirect standard input from /dev/null: %s" -msgstr "" - -#: execute_cmd.c:1036 -#, c-format -msgid "TIMEFORMAT: `%c': invalid format character" -msgstr "" - -#: execute_cmd.c:3521 -#, c-format -msgid "%s: restricted: cannot specify `/' in command names" -msgstr "" - -#: execute_cmd.c:3609 -#, c-format -msgid "%s: command not found" -msgstr "" - -#: execute_cmd.c:3839 -#, c-format -msgid "%s: %s: bad interpreter" -msgstr "" - -#: execute_cmd.c:3876 -#, c-format -msgid "%s: cannot execute binary file" -msgstr "" - -#: execute_cmd.c:3988 -#, c-format -msgid "cannot duplicate fd %d to fd %d" -msgstr "" - -#: expr.c:239 -msgid "expression recursion level exceeded" -msgstr "" - -#: expr.c:263 -msgid "recursion stack underflow" -msgstr "" - -#: expr.c:374 -msgid "syntax error in expression" -msgstr "" - -#: expr.c:414 -msgid "attempted assignment to non-variable" -msgstr "" - -#: expr.c:435 expr.c:440 expr.c:750 -msgid "division by 0" -msgstr "" - -#: expr.c:466 -msgid "bug: bad expassign token" -msgstr "" - -#: expr.c:508 -msgid "`:' expected for conditional expression" -msgstr "" - -#: expr.c:775 -msgid "exponent less than 0" -msgstr "" - -#: expr.c:819 -msgid "identifier expected after pre-increment or pre-decrement" -msgstr "" - -#: expr.c:847 -msgid "missing `)'" -msgstr "" - -#: expr.c:871 -msgid "syntax error: operand expected" -msgstr "" - -#: expr.c:1146 -msgid "invalid number" -msgstr "" - -#: expr.c:1150 -msgid "invalid arithmetic base" -msgstr "" - -#: expr.c:1170 -msgid "value too great for base" -msgstr "" - -#: general.c:60 -msgid "getcwd: cannot access parent directories" -msgstr "" - -#: input.c:231 -#, c-format -msgid "cannot allocate new file descriptor for bash input from fd %d" -msgstr "" - -#: input.c:239 -#, c-format -msgid "save_bash_input: buffer already exists for new fd %d" -msgstr "" - -#: jobs.c:693 -#, c-format -msgid "deleting stopped job %d with process group %ld" -msgstr "" - -#: jobs.c:1001 -#, c-format -msgid "describe_pid: %ld: no such pid" -msgstr "" - -#: jobs.c:1632 nojobs.c:648 -#, c-format -msgid "wait: pid %ld is not a child of this shell" -msgstr "" - -#: jobs.c:1815 -#, c-format -msgid "wait_for: No record of process %ld" -msgstr "" - -#: jobs.c:2062 -#, c-format -msgid "wait_for_job: job %d is stopped" -msgstr "" - -#: jobs.c:2284 -#, c-format -msgid "%s: job has terminated" -msgstr "" - -#: jobs.c:2293 -#, c-format -msgid "%s: job %d already in background" -msgstr "" - -#: jobs.c:3037 -msgid "no job control in this shell" -msgstr "" - -#: lib/malloc/malloc.c:298 -#, c-format -msgid "malloc: failed assertion: %s\n" -msgstr "" - -#: lib/malloc/malloc.c:314 -#, c-format -msgid "" -"\r\n" -"malloc: %s:%d: assertion botched\r\n" -msgstr "" - -#: lib/malloc/malloc.c:740 -msgid "malloc: block on free list clobbered" -msgstr "" - -#: lib/malloc/malloc.c:817 -msgid "free: called with already freed block argument" -msgstr "" - -#: lib/malloc/malloc.c:820 -msgid "free: called with unallocated block argument" -msgstr "" - -#: lib/malloc/malloc.c:839 -msgid "free: underflow detected; mh_nbytes out of range" -msgstr "" - -#: lib/malloc/malloc.c:845 -msgid "free: start and end chunk sizes differ" -msgstr "" - -#: lib/malloc/malloc.c:942 -msgid "realloc: called with unallocated block argument" -msgstr "" - -#: lib/malloc/malloc.c:957 -msgid "realloc: underflow detected; mh_nbytes out of range" -msgstr "" - -#: lib/malloc/malloc.c:963 -msgid "realloc: start and end chunk sizes differ" -msgstr "" - -#: lib/malloc/table.c:175 -msgid "register_alloc: alloc table is full with FIND_ALLOC?\n" -msgstr "" - -#: lib/malloc/table.c:182 -#, c-format -msgid "register_alloc: %p already in table as allocated?\n" -msgstr "" - -#: lib/malloc/table.c:218 -#, c-format -msgid "register_free: %p already in table as free?\n" -msgstr "" - -#: lib/malloc/watch.c:46 -msgid "allocated" -msgstr "" - -#: lib/malloc/watch.c:48 -msgid "freed" -msgstr "" - -#: lib/malloc/watch.c:50 -msgid "requesting resize" -msgstr "" - -#: lib/malloc/watch.c:52 -msgid "just resized" -msgstr "" - -#: lib/malloc/watch.c:54 -msgid "bug: unknown operation" -msgstr "" - -#: lib/malloc/watch.c:56 -#, c-format -msgid "malloc: watch alert: %p %s " -msgstr "" - -#: lib/sh/fmtulong.c:101 -msgid "invalid base" -msgstr "" - -#: lib/sh/netopen.c:158 -#, c-format -msgid "%s: host unknown" -msgstr "" - -#: lib/sh/netopen.c:165 -#, c-format -msgid "%s: invalid service" -msgstr "" - -#: lib/sh/netopen.c:296 -#, c-format -msgid "%s: bad network path specification" -msgstr "" - -#: lib/sh/netopen.c:336 -msgid "network operations not supported" -msgstr "" - -#: mailcheck.c:382 -msgid "You have mail in $_" -msgstr "" - -#: mailcheck.c:407 -msgid "You have new mail in $_" -msgstr "" - -#: mailcheck.c:423 -#, c-format -msgid "The mail in %s has been read\n" -msgstr "" - -#: make_cmd.c:318 -msgid "syntax error: arithmetic expression required" -msgstr "" - -#: make_cmd.c:320 -msgid "syntax error: `;' unexpected" -msgstr "" - -#: make_cmd.c:321 -#, c-format -msgid "syntax error: `((%s))'" -msgstr "" - -#: make_cmd.c:560 -#, c-format -msgid "make_here_document: bad instruction type %d" -msgstr "" - -#: make_cmd.c:730 -#, c-format -msgid "make_redirection: redirection instruction `%d' out of range" -msgstr "" - -#: parse.y:2726 -#, c-format -msgid "unexpected EOF while looking for matching `%c'" -msgstr "" - -#: parse.y:3011 -msgid "unexpected EOF while looking for `]]'" -msgstr "" - -#: parse.y:3016 -#, c-format -msgid "syntax error in conditional expression: unexpected token `%s'" -msgstr "" - -#: parse.y:3020 -msgid "syntax error in conditional expression" -msgstr "" - -#: parse.y:3098 -#, c-format -msgid "unexpected token `%s', expected `)'" -msgstr "" - -#: parse.y:3102 -msgid "expected `)'" -msgstr "" - -#: parse.y:3130 -#, c-format -msgid "unexpected argument `%s' to conditional unary operator" -msgstr "" - -#: parse.y:3134 -msgid "unexpected argument to conditional unary operator" -msgstr "" - -#: parse.y:3171 -#, c-format -msgid "unexpected token `%s', conditional binary operator expected" -msgstr "" - -#: parse.y:3175 -msgid "conditional binary operator expected" -msgstr "" - -#: parse.y:3191 -#, c-format -msgid "unexpected argument `%s' to conditional binary operator" -msgstr "" - -#: parse.y:3195 -msgid "unexpected argument to conditional binary operator" -msgstr "" - -#: parse.y:3206 -#, c-format -msgid "unexpected token `%c' in conditional command" -msgstr "" - -#: parse.y:3209 -#, c-format -msgid "unexpected token `%s' in conditional command" -msgstr "" - -#: parse.y:3213 -#, c-format -msgid "unexpected token %d in conditional command" -msgstr "" - -#: parse.y:4400 -#, c-format -msgid "syntax error near unexpected token `%s'" -msgstr "" - -#: parse.y:4418 -#, c-format -msgid "syntax error near `%s'" -msgstr "" - -#: parse.y:4428 -msgid "syntax error: unexpected end of file" -msgstr "" - -#: parse.y:4428 -msgid "syntax error" -msgstr "" - -#: parse.y:4490 -#, c-format -msgid "Use \"%s\" to leave the shell.\n" -msgstr "" - -#: parse.y:4649 -msgid "unexpected EOF while looking for matching `)'" -msgstr "" - -#: pcomplete.c:988 -#, c-format -msgid "completion: function `%s' not found" -msgstr "" - -#: pcomplib.c:179 -#, c-format -msgid "progcomp_insert: %s: NULL COMPSPEC" -msgstr "" - -#: print_cmd.c:260 -#, c-format -msgid "print_command: bad connector `%d'" -msgstr "" - -#: print_cmd.c:1172 -#, c-format -msgid "cprintf: `%c': invalid format character" -msgstr "" - -#: redir.c:99 -msgid "file descriptor out of range" -msgstr "" - -#: redir.c:141 -#, c-format -msgid "%s: ambiguous redirect" -msgstr "" - -#: redir.c:145 -#, c-format -msgid "%s: cannot overwrite existing file" -msgstr "" - -#: redir.c:150 -#, c-format -msgid "%s: restricted: cannot redirect output" -msgstr "" - -#: redir.c:155 -#, c-format -msgid "cannot create temp file for here document: %s" -msgstr "" - -#: redir.c:509 -msgid "/dev/(tcp|udp)/host/port not supported without networking" -msgstr "" - -#: redir.c:949 -msgid "redirection error: cannot duplicate fd" -msgstr "" - -#: shell.c:302 -msgid "could not find /tmp, please create!" -msgstr "" - -#: shell.c:306 -msgid "/tmp must be a valid directory name" -msgstr "" - -#: shell.c:839 -#, c-format -msgid "%c%c: invalid option" -msgstr "" - -#: shell.c:1590 -msgid "I have no name!" -msgstr "" - -#: shell.c:1725 -#, c-format -msgid "" -"Usage:\t%s [GNU long option] [option] ...\n" -"\t%s [GNU long option] [option] script-file ...\n" -msgstr "" - -#: shell.c:1727 -msgid "GNU long options:\n" -msgstr "" - -#: shell.c:1731 -msgid "Shell options:\n" -msgstr "" - -#: shell.c:1732 -msgid "\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n" -msgstr "" - -#: shell.c:1747 -#, c-format -msgid "\t-%s or -o option\n" -msgstr "" - -#: shell.c:1753 -#, c-format -msgid "Type `%s -c \"help set\"' for more information about shell options.\n" -msgstr "" - -#: shell.c:1754 -#, c-format -msgid "Type `%s -c help' for more information about shell builtin commands.\n" -msgstr "" - -#: shell.c:1755 -msgid "Use the `bashbug' command to report bugs.\n" -msgstr "" - -#: sig.c:485 -#, c-format -msgid "sigprocmask: %d: invalid operation" -msgstr "" - -#: subst.c:1011 -#, c-format -msgid "bad substitution: no closing `%s' in %s" -msgstr "" - -#: subst.c:2020 -#, c-format -msgid "%s: cannot assign list to array member" -msgstr "" - -#: subst.c:3516 subst.c:3532 -msgid "cannot make pipe for process substitution" -msgstr "" - -#: subst.c:3563 -msgid "cannot make child for process substitution" -msgstr "" - -#: subst.c:3608 -#, c-format -msgid "cannot open named pipe %s for reading" -msgstr "" - -#: subst.c:3610 -#, c-format -msgid "cannot open named pipe %s for writing" -msgstr "" - -#: subst.c:3618 -#, c-format -msgid "cannout reset nodelay mode for fd %d" -msgstr "" - -#: subst.c:3628 -#, c-format -msgid "cannot duplicate named pipe %s as fd %d" -msgstr "" - -#: subst.c:3803 -msgid "cannot make pipe for command substitution" -msgstr "" - -#: subst.c:3832 -msgid "cannot make child for command substitution" -msgstr "" - -#: subst.c:3849 -msgid "command_substitute: cannot duplicate pipe as fd 1" -msgstr "" - -#: subst.c:4284 -#, c-format -msgid "%s: parameter null or not set" -msgstr "" - -#: subst.c:4529 -#, c-format -msgid "%s: substring expression < 0" -msgstr "" - -#: subst.c:5209 -#, c-format -msgid "%s: bad substitution" -msgstr "" - -#: subst.c:5283 -#, c-format -msgid "$%s: cannot assign in this way" -msgstr "" - -#: subst.c:6652 -#, c-format -msgid "no match: %s" -msgstr "" - -#: test.c:154 -msgid "argument expected" -msgstr "" - -#: test.c:163 -#, c-format -msgid "%s: integer expression expected" -msgstr "" - -#: test.c:361 -msgid "`)' expected" -msgstr "" - -#: test.c:363 -#, c-format -msgid "`)' expected, found %s" -msgstr "" - -#: test.c:378 test.c:787 test.c:790 -#, c-format -msgid "%s: unary operator expected" -msgstr "" - -#: test.c:543 test.c:830 -#, c-format -msgid "%s: binary operator expected" -msgstr "" - -#: test.c:905 -msgid "missing `]'" -msgstr "" - -#: trap.c:194 -msgid "invalid signal number" -msgstr "" - -#: trap.c:309 -#, c-format -msgid "run_pending_traps: bad value in trap_list[%d]: %p" -msgstr "" - -#: trap.c:313 -#, c-format -msgid "" -"run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" -msgstr "" - -#: trap.c:349 -#, c-format -msgid "trap_handler: bad signal %d" -msgstr "" - -#: variables.c:310 -#, c-format -msgid "error importing function definition for `%s'" -msgstr "" - -#: variables.c:670 -#, c-format -msgid "shell level (%d) too high, resetting to 1" -msgstr "" - -#: variables.c:1610 -msgid "make_local_variable: no function context at current scope" -msgstr "" - -#: variables.c:2709 -msgid "all_local_variables: no function context at current scope" -msgstr "" - -#: variables.c:2923 variables.c:2932 -#, c-format -msgid "invalid character %d in exportstr for %s" -msgstr "" - -#: variables.c:2938 -#, c-format -msgid "no `=' in exportstr for %s" -msgstr "" - -#: variables.c:3363 -msgid "pop_var_context: head of shell_variables not a function context" -msgstr "" - -#: variables.c:3376 -msgid "pop_var_context: no global_variables context" -msgstr "" - -#: variables.c:3442 -msgid "pop_scope: head of shell_variables not a temporary environment scope" -msgstr "" - -#: version.c:82 -msgid "Copyright (C) 2004 Free Software Foundation, Inc.\n" -msgstr "" - -#: xmalloc.c:93 -#, c-format -msgid "xmalloc: cannot allocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:95 -#, c-format -msgid "xmalloc: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:115 -#, c-format -msgid "xrealloc: cannot reallocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:117 -#, c-format -msgid "xrealloc: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:151 -#, c-format -msgid "xmalloc: %s:%d: cannot allocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:153 -#, c-format -msgid "xmalloc: %s:%d: cannot allocate %lu bytes" -msgstr "" - -#: xmalloc.c:175 -#, c-format -msgid "xrealloc: %s:%d: cannot reallocate %lu bytes (%lu bytes allocated)" -msgstr "" - -#: xmalloc.c:177 -#, c-format -msgid "xrealloc: %s:%d: cannot allocate %lu bytes" -msgstr "" - -#: builtins.c:244 -msgid "`alias' with no arguments or with the -p option prints the list" -msgstr "" - -#: builtins.c:245 -msgid "of aliases in the form alias NAME=VALUE on standard output." -msgstr "" - -#: builtins.c:246 -msgid "Otherwise, an alias is defined for each NAME whose VALUE is given." -msgstr "" - -#: builtins.c:247 -msgid "A trailing space in VALUE causes the next word to be checked for" -msgstr "" - -#: builtins.c:248 -msgid "alias substitution when the alias is expanded. Alias returns" -msgstr "" - -#: builtins.c:249 -msgid "true unless a NAME is given for which no alias has been defined." -msgstr "" - -#: builtins.c:257 -msgid "" -"Remove NAMEs from the list of defined aliases. If the -a option is given," -msgstr "" - -#: builtins.c:258 -msgid "then remove all alias definitions." -msgstr "" - -#: builtins.c:266 -msgid "Bind a key sequence to a Readline function or a macro, or set" -msgstr "" - -#: builtins.c:267 -msgid "a Readline variable. The non-option argument syntax is equivalent" -msgstr "" - -#: builtins.c:268 -msgid "to that found in ~/.inputrc, but must be passed as a single argument:" -msgstr "" - -#: builtins.c:269 -msgid "bind '\"\\C-x\\C-r\": re-read-init-file'." -msgstr "" - -#: builtins.c:270 -msgid "bind accepts the following options:" -msgstr "" - -#: builtins.c:271 -msgid "" -" -m keymap Use `keymap' as the keymap for the duration of this" -msgstr "" - -#: builtins.c:272 -msgid " command. Acceptable keymap names are emacs," -msgstr "" - -#: builtins.c:273 -msgid "" -" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move," -msgstr "" - -#: builtins.c:274 -msgid " vi-command, and vi-insert." -msgstr "" - -#: builtins.c:275 -msgid " -l List names of functions." -msgstr "" - -#: builtins.c:276 -msgid " -P List function names and bindings." -msgstr "" - -#: builtins.c:277 -msgid " -p List functions and bindings in a form that can be" -msgstr "" - -#: builtins.c:278 -msgid " reused as input." -msgstr "" - -#: builtins.c:279 -msgid " -r keyseq Remove the binding for KEYSEQ." -msgstr "" - -#: builtins.c:280 -msgid " -x keyseq:shell-command\tCause SHELL-COMMAND to be executed when" -msgstr "" - -#: builtins.c:281 -msgid "\t\t\t\tKEYSEQ is entered." -msgstr "" - -#: builtins.c:282 -msgid " -f filename Read key bindings from FILENAME." -msgstr "" - -#: builtins.c:283 -msgid " -q function-name Query about which keys invoke the named function." -msgstr "" - -#: builtins.c:284 -msgid "" -" -u function-name Unbind all keys which are bound to the named function." -msgstr "" - -#: builtins.c:285 -msgid " -V List variable names and values" -msgstr "" - -#: builtins.c:286 -msgid " -v List variable names and values in a form that can" -msgstr "" - -#: builtins.c:287 -msgid " be reused as input." -msgstr "" - -#: builtins.c:288 -msgid "" -" -S List key sequences that invoke macros and their values" -msgstr "" - -#: builtins.c:289 -msgid "" -" -s List key sequences that invoke macros and their values" -msgstr "" - -#: builtins.c:290 -msgid " in a form that can be reused as input." -msgstr "" - -#: builtins.c:297 -msgid "Exit from within a FOR, WHILE or UNTIL loop. If N is specified," -msgstr "" - -#: builtins.c:298 -msgid "break N levels." -msgstr "" - -#: builtins.c:304 -msgid "Resume the next iteration of the enclosing FOR, WHILE or UNTIL loop." -msgstr "" - -#: builtins.c:305 -msgid "If N is specified, resume at the N-th enclosing loop." -msgstr "" - -#: builtins.c:311 -msgid "Run a shell builtin. This is useful when you wish to rename a" -msgstr "" - -#: builtins.c:312 -msgid "shell builtin to be a function, but need the functionality of the" -msgstr "" - -#: builtins.c:313 -msgid "builtin within the function itself." -msgstr "" - -#: builtins.c:334 -msgid "Change the current directory to DIR. The variable $HOME is the" -msgstr "" - -#: builtins.c:335 -msgid "default DIR. The variable CDPATH defines the search path for" -msgstr "" - -#: builtins.c:336 -msgid "the directory containing DIR. Alternative directory names in CDPATH" -msgstr "" - -#: builtins.c:337 -msgid "are separated by a colon (:). A null directory name is the same as" -msgstr "" - -#: builtins.c:338 -msgid "the current directory, i.e. `.'. If DIR begins with a slash (/)," -msgstr "" - -#: builtins.c:339 -msgid "then CDPATH is not used. If the directory is not found, and the" -msgstr "" - -#: builtins.c:340 -msgid "shell option `cdable_vars' is set, then try the word as a variable" -msgstr "" - -#: builtins.c:341 -msgid "name. If that variable has a value, then cd to the value of that" -msgstr "" - -#: builtins.c:342 -msgid "variable. The -P option says to use the physical directory structure" -msgstr "" - -#: builtins.c:343 -msgid "" -"instead of following symbolic links; the -L option forces symbolic links" -msgstr "" - -#: builtins.c:344 -msgid "to be followed." -msgstr "" - -#: builtins.c:350 -msgid "Print the current working directory. With the -P option, pwd prints" -msgstr "" - -#: builtins.c:351 -msgid "the physical directory, without any symbolic links; the -L option" -msgstr "" - -#: builtins.c:352 -msgid "makes pwd follow symbolic links." -msgstr "" - -#: builtins.c:358 -msgid "No effect; the command does nothing. A zero exit code is returned." -msgstr "" - -#: builtins.c:364 -msgid "Return a successful result." -msgstr "" - -#: builtins.c:370 -msgid "Return an unsuccessful result." -msgstr "" - -#: builtins.c:376 -msgid "Runs COMMAND with ARGS ignoring shell functions. If you have a shell" -msgstr "" - -#: builtins.c:377 -msgid "function called `ls', and you wish to call the command `ls', you can" -msgstr "" - -#: builtins.c:378 -msgid "say \"command ls\". If the -p option is given, a default value is used" -msgstr "" - -#: builtins.c:379 -msgid "for PATH that is guaranteed to find all of the standard utilities. If" -msgstr "" - -#: builtins.c:380 -msgid "the -V or -v option is given, a string is printed describing COMMAND." -msgstr "" - -#: builtins.c:381 -msgid "The -V option produces a more verbose description." -msgstr "" - -#: builtins.c:387 -msgid "Declare variables and/or give them attributes. If no NAMEs are" -msgstr "" - -#: builtins.c:388 -msgid "given, then display the values of variables instead. The -p option" -msgstr "" - -#: builtins.c:389 -msgid "will display the attributes and values of each NAME." -msgstr "" - -#: builtins.c:391 -msgid "The flags are:" -msgstr "" - -#: builtins.c:393 -msgid " -a\tto make NAMEs arrays (if supported)" -msgstr "" - -#: builtins.c:394 -msgid " -f\tto select from among function names only" -msgstr "" - -#: builtins.c:395 -msgid "" -" -F\tto display function names (and line number and source file name if" -msgstr "" - -#: builtins.c:396 -msgid "\tdebugging) without definitions" -msgstr "" - -#: builtins.c:397 -msgid " -i\tto make NAMEs have the `integer' attribute" -msgstr "" - -#: builtins.c:398 -msgid " -r\tto make NAMEs readonly" -msgstr "" - -#: builtins.c:399 -msgid " -t\tto make NAMEs have the `trace' attribute" -msgstr "" - -#: builtins.c:400 -msgid " -x\tto make NAMEs export" -msgstr "" - -#: builtins.c:402 -msgid "Variables with the integer attribute have arithmetic evaluation (see" -msgstr "" - -#: builtins.c:403 -msgid "`let') done when the variable is assigned to." -msgstr "" - -#: builtins.c:405 -msgid "When displaying values of variables, -f displays a function's name" -msgstr "" - -#: builtins.c:406 -msgid "and definition. The -F option restricts the display to function" -msgstr "" - -#: builtins.c:407 -msgid "name only." -msgstr "" - -#: builtins.c:409 -msgid "Using `+' instead of `-' turns off the given attribute instead. When" -msgstr "" - -#: builtins.c:410 -msgid "used in a function, makes NAMEs local, as with the `local' command." -msgstr "" - -#: builtins.c:416 -msgid "Obsolete. See `declare'." -msgstr "" - -#: builtins.c:422 -msgid "Create a local variable called NAME, and give it VALUE. LOCAL" -msgstr "" - -#: builtins.c:423 -msgid "can only be used within a function; it makes the variable NAME" -msgstr "" - -#: builtins.c:424 -msgid "have a visible scope restricted to that function and its children." -msgstr "" - -#: builtins.c:431 -msgid "Output the ARGs. If -n is specified, the trailing newline is" -msgstr "" - -#: builtins.c:432 -msgid "suppressed. If the -e option is given, interpretation of the" -msgstr "" - -#: builtins.c:433 -msgid "following backslash-escaped characters is turned on:" -msgstr "" - -#: builtins.c:434 -msgid "\t\\a\talert (bell)" -msgstr "" - -#: builtins.c:435 -msgid "\t\\b\tbackspace" -msgstr "" - -#: builtins.c:436 -msgid "\t\\c\tsuppress trailing newline" -msgstr "" - -#: builtins.c:437 -msgid "\t\\E\tescape character" -msgstr "" - -#: builtins.c:438 -msgid "\t\\f\tform feed" -msgstr "" - -#: builtins.c:439 -msgid "\t\\n\tnew line" -msgstr "" - -#: builtins.c:440 -msgid "\t\\r\tcarriage return" -msgstr "" - -#: builtins.c:441 -msgid "\t\\t\thorizontal tab" -msgstr "" - -#: builtins.c:442 -msgid "\t\\v\tvertical tab" -msgstr "" - -#: builtins.c:443 -msgid "\t\\\\\tbackslash" -msgstr "" - -#: builtins.c:444 -msgid "\t\\num\tthe character whose ASCII code is NUM (octal)." -msgstr "" - -#: builtins.c:446 -msgid "You can explicitly turn off the interpretation of the above characters" -msgstr "" - -#: builtins.c:447 -msgid "with the -E option." -msgstr "" - -#: builtins.c:455 -msgid "" -"Output the ARGs. If -n is specified, the trailing newline is suppressed." -msgstr "" - -#: builtins.c:462 -msgid "Enable and disable builtin shell commands. This allows" -msgstr "" - -#: builtins.c:463 -msgid "you to use a disk command which has the same name as a shell" -msgstr "" - -#: builtins.c:464 -msgid "builtin without specifying a full pathname. If -n is used, the" -msgstr "" - -#: builtins.c:465 -msgid "NAMEs become disabled; otherwise NAMEs are enabled. For example," -msgstr "" - -#: builtins.c:466 -msgid "to use the `test' found in $PATH instead of the shell builtin" -msgstr "" - -#: builtins.c:467 -msgid "version, type `enable -n test'. On systems supporting dynamic" -msgstr "" - -#: builtins.c:468 -msgid "loading, the -f option may be used to load new builtins from the" -msgstr "" - -#: builtins.c:469 -msgid "shared object FILENAME. The -d option will delete a builtin" -msgstr "" - -#: builtins.c:470 -msgid "previously loaded with -f. If no non-option names are given, or" -msgstr "" - -#: builtins.c:471 -msgid "the -p option is supplied, a list of builtins is printed. The" -msgstr "" - -#: builtins.c:472 -msgid "-a option means to print every builtin with an indication of whether" -msgstr "" - -#: builtins.c:473 -msgid "" -"or not it is enabled. The -s option restricts the output to the POSIX.2" -msgstr "" - -#: builtins.c:474 -msgid "" -"`special' builtins. The -n option displays a list of all disabled builtins." -msgstr "" - -#: builtins.c:480 -msgid "Read ARGs as input to the shell and execute the resulting command(s)." -msgstr "" - -#: builtins.c:486 -msgid "Getopts is used by shell procedures to parse positional parameters." -msgstr "" - -#: builtins.c:488 -msgid "OPTSTRING contains the option letters to be recognized; if a letter" -msgstr "" - -#: builtins.c:489 -msgid "is followed by a colon, the option is expected to have an argument," -msgstr "" - -#: builtins.c:490 -msgid "which should be separated from it by white space." -msgstr "" - -#: builtins.c:492 -msgid "Each time it is invoked, getopts will place the next option in the" -msgstr "" - -#: builtins.c:493 -msgid "shell variable $name, initializing name if it does not exist, and" -msgstr "" - -#: builtins.c:494 -msgid "the index of the next argument to be processed into the shell" -msgstr "" - -#: builtins.c:495 -msgid "variable OPTIND. OPTIND is initialized to 1 each time the shell or" -msgstr "" - -#: builtins.c:496 -msgid "a shell script is invoked. When an option requires an argument," -msgstr "" - -#: builtins.c:497 -msgid "getopts places that argument into the shell variable OPTARG." -msgstr "" - -#: builtins.c:499 -msgid "getopts reports errors in one of two ways. If the first character" -msgstr "" - -#: builtins.c:500 -msgid "of OPTSTRING is a colon, getopts uses silent error reporting. In" -msgstr "" - -#: builtins.c:501 -msgid "this mode, no error messages are printed. If an invalid option is" -msgstr "" - -#: builtins.c:502 -msgid "seen, getopts places the option character found into OPTARG. If a" -msgstr "" - -#: builtins.c:503 -msgid "required argument is not found, getopts places a ':' into NAME and" -msgstr "" - -#: builtins.c:504 -msgid "sets OPTARG to the option character found. If getopts is not in" -msgstr "" - -#: builtins.c:505 -msgid "silent mode, and an invalid option is seen, getopts places '?' into" -msgstr "" - -#: builtins.c:506 -msgid "NAME and unsets OPTARG. If a required argument is not found, a '?'" -msgstr "" - -#: builtins.c:507 -msgid "is placed in NAME, OPTARG is unset, and a diagnostic message is" -msgstr "" - -#: builtins.c:508 -msgid "printed." -msgstr "" - -#: builtins.c:510 -msgid "If the shell variable OPTERR has the value 0, getopts disables the" -msgstr "" - -#: builtins.c:511 -msgid "printing of error messages, even if the first character of" -msgstr "" - -#: builtins.c:512 -msgid "OPTSTRING is not a colon. OPTERR has the value 1 by default." -msgstr "" - -#: builtins.c:514 -msgid "Getopts normally parses the positional parameters ($0 - $9), but if" -msgstr "" - -#: builtins.c:515 -msgid "more arguments are given, they are parsed instead." -msgstr "" - -#: builtins.c:521 -msgid "Exec FILE, replacing this shell with the specified program." -msgstr "" - -#: builtins.c:522 -msgid "If FILE is not specified, the redirections take effect in this" -msgstr "" - -#: builtins.c:523 -msgid "shell. If the first argument is `-l', then place a dash in the" -msgstr "" - -#: builtins.c:524 -msgid "zeroth arg passed to FILE, as login does. If the `-c' option" -msgstr "" - -#: builtins.c:525 -msgid "is supplied, FILE is executed with a null environment. The `-a'" -msgstr "" - -#: builtins.c:526 -msgid "option means to make set argv[0] of the executed process to NAME." -msgstr "" - -#: builtins.c:527 -msgid "If the file cannot be executed and the shell is not interactive," -msgstr "" - -#: builtins.c:528 -msgid "then the shell exits, unless the shell option `execfail' is set." -msgstr "" - -#: builtins.c:534 -msgid "Exit the shell with a status of N. If N is omitted, the exit status" -msgstr "" - -#: builtins.c:535 -msgid "is that of the last command executed." -msgstr "" - -#: builtins.c:541 -msgid "Logout of a login shell." -msgstr "" - -#: builtins.c:548 -msgid "" -"fc is used to list or edit and re-execute commands from the history list." -msgstr "" - -#: builtins.c:549 -msgid "FIRST and LAST can be numbers specifying the range, or FIRST can be a" -msgstr "" - -#: builtins.c:550 -msgid "string, which means the most recent command beginning with that" -msgstr "" - -#: builtins.c:551 -msgid "string." -msgstr "" - -#: builtins.c:553 -msgid "" -" -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR," -msgstr "" - -#: builtins.c:554 -msgid " then vi." -msgstr "" - -#: builtins.c:556 -msgid " -l means list lines instead of editing." -msgstr "" - -#: builtins.c:557 -msgid " -n means no line numbers listed." -msgstr "" - -#: builtins.c:558 -msgid "" -" -r means reverse the order of the lines (making it newest listed first)." -msgstr "" - -#: builtins.c:560 -msgid "With the `fc -s [pat=rep ...] [command]' format, the command is" -msgstr "" - -#: builtins.c:561 -msgid "re-executed after the substitution OLD=NEW is performed." -msgstr "" - -#: builtins.c:563 -msgid "A useful alias to use with this is r='fc -s', so that typing `r cc'" -msgstr "" - -#: builtins.c:564 -msgid "runs the last command beginning with `cc' and typing `r' re-executes" -msgstr "" - -#: builtins.c:565 -msgid "the last command." -msgstr "" - -#: builtins.c:573 -msgid "Place JOB_SPEC in the foreground, and make it the current job. If" -msgstr "" - -#: builtins.c:574 -msgid "JOB_SPEC is not present, the shell's notion of the current job is" -msgstr "" - -#: builtins.c:575 -msgid "used." -msgstr "" - -#: builtins.c:583 -msgid "Place JOB_SPEC in the background, as if it had been started with" -msgstr "" - -#: builtins.c:584 -msgid "`&'. If JOB_SPEC is not present, the shell's notion of the current" -msgstr "" - -#: builtins.c:585 -msgid "job is used." -msgstr "" - -#: builtins.c:592 -msgid "For each NAME, the full pathname of the command is determined and" -msgstr "" - -#: builtins.c:593 -msgid "remembered. If the -p option is supplied, PATHNAME is used as the" -msgstr "" - -#: builtins.c:594 -msgid "full pathname of NAME, and no path search is performed. The -r" -msgstr "" - -#: builtins.c:595 -msgid "option causes the shell to forget all remembered locations. The -d" -msgstr "" - -#: builtins.c:596 -msgid "option causes the shell to forget the remembered location of each NAME." -msgstr "" - -#: builtins.c:597 -msgid "If the -t option is supplied the full pathname to which each NAME" -msgstr "" - -#: builtins.c:598 -msgid "corresponds is printed. If multiple NAME arguments are supplied with" -msgstr "" - -#: builtins.c:599 -msgid "-t, the NAME is printed before the hashed full pathname. The -l option" -msgstr "" - -#: builtins.c:600 -msgid "causes output to be displayed in a format that may be reused as input." -msgstr "" - -#: builtins.c:601 -msgid "" -"If no arguments are given, information about remembered commands is " -"displayed." -msgstr "" - -#: builtins.c:608 -msgid "Display helpful information about builtin commands. If PATTERN is" -msgstr "" - -#: builtins.c:609 -msgid "specified, gives detailed help on all commands matching PATTERN," -msgstr "" - -#: builtins.c:610 -msgid "otherwise a list of the builtins is printed. The -s option" -msgstr "" - -#: builtins.c:611 -msgid "restricts the output for each builtin command matching PATTERN to" -msgstr "" - -#: builtins.c:612 -msgid "a short usage synopsis." -msgstr "" - -#: builtins.c:620 -msgid "Display the history list with line numbers. Lines listed with" -msgstr "" - -#: builtins.c:621 -msgid "with a `*' have been modified. Argument of N says to list only" -msgstr "" - -#: builtins.c:622 -msgid "the last N lines. The `-c' option causes the history list to be" -msgstr "" - -#: builtins.c:623 -msgid "cleared by deleting all of the entries. The `-d' option deletes" -msgstr "" - -#: builtins.c:624 -msgid "the history entry at offset OFFSET. The `-w' option writes out the" -msgstr "" - -#: builtins.c:625 -msgid "current history to the history file; `-r' means to read the file and" -msgstr "" - -#: builtins.c:626 -msgid "append the contents to the history list instead. `-a' means" -msgstr "" - -#: builtins.c:627 -msgid "to append history lines from this session to the history file." -msgstr "" - -#: builtins.c:628 -msgid "Argument `-n' means to read all history lines not already read" -msgstr "" - -#: builtins.c:629 -msgid "from the history file and append them to the history list." -msgstr "" - -#: builtins.c:631 -msgid "If FILENAME is given, then that is used as the history file else" -msgstr "" - -#: builtins.c:632 -msgid "if $HISTFILE has a value, that is used, else ~/.bash_history." -msgstr "" - -#: builtins.c:633 -msgid "If the -s option is supplied, the non-option ARGs are appended to" -msgstr "" - -#: builtins.c:634 -msgid "the history list as a single entry. The -p option means to perform" -msgstr "" - -#: builtins.c:635 -msgid "history expansion on each ARG and display the result, without storing" -msgstr "" - -#: builtins.c:636 -msgid "anything in the history list." -msgstr "" - -#: builtins.c:638 -msgid "If the $HISTTIMEFORMAT variable is set and not null, its value is used" -msgstr "" - -#: builtins.c:639 -msgid "as a format string for strftime(3) to print the time stamp associated" -msgstr "" - -#: builtins.c:640 -msgid "" -"with each displayed history entry. No time stamps are printed otherwise." -msgstr "" - -#: builtins.c:648 -msgid "Lists the active jobs. The -l option lists process id's in addition" -msgstr "" - -#: builtins.c:649 -msgid "to the normal information; the -p option lists process id's only." -msgstr "" - -#: builtins.c:650 -msgid "If -n is given, only processes that have changed status since the last" -msgstr "" - -#: builtins.c:651 -msgid "notification are printed. JOBSPEC restricts output to that job. The" -msgstr "" - -#: builtins.c:652 -msgid "-r and -s options restrict output to running and stopped jobs only," -msgstr "" - -#: builtins.c:653 -msgid "respectively. Without options, the status of all active jobs is" -msgstr "" - -#: builtins.c:654 -msgid "printed. If -x is given, COMMAND is run after all job specifications" -msgstr "" - -#: builtins.c:655 -msgid "" -"that appear in ARGS have been replaced with the process ID of that job's" -msgstr "" - -#: builtins.c:656 -msgid "process group leader." -msgstr "" - -#: builtins.c:664 -msgid "" -"By default, removes each JOBSPEC argument from the table of active jobs." -msgstr "" - -#: builtins.c:665 -msgid "" -"If the -h option is given, the job is not removed from the table, but is" -msgstr "" - -#: builtins.c:666 -msgid "marked so that SIGHUP is not sent to the job if the shell receives a" -msgstr "" - -#: builtins.c:667 -msgid "" -"SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all" -msgstr "" - -#: builtins.c:668 -msgid "" -"jobs from the job table; the -r option means to remove only running jobs." -msgstr "" - -#: builtins.c:675 -msgid "Send the processes named by PID (or JOB) the signal SIGSPEC. If" -msgstr "" - -#: builtins.c:676 -msgid "SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l'" -msgstr "" - -#: builtins.c:677 -msgid "lists the signal names; if arguments follow `-l' they are assumed to" -msgstr "" - -#: builtins.c:678 -msgid "be signal numbers for which names should be listed. Kill is a shell" -msgstr "" - -#: builtins.c:679 -msgid "builtin for two reasons: it allows job IDs to be used instead of" -msgstr "" - -#: builtins.c:680 -msgid "process IDs, and, if you have reached the limit on processes that" -msgstr "" - -#: builtins.c:681 -msgid "you can create, you don't have to start a process to kill another one." -msgstr "" - -#: builtins.c:687 -msgid "Each ARG is an arithmetic expression to be evaluated. Evaluation" -msgstr "" - -#: builtins.c:688 -msgid "is done in fixed-width integers with no check for overflow, though" -msgstr "" - -#: builtins.c:689 -msgid "division by 0 is trapped and flagged as an error. The following" -msgstr "" - -#: builtins.c:690 -msgid "list of operators is grouped into levels of equal-precedence operators." -msgstr "" - -#: builtins.c:691 -msgid "The levels are listed in order of decreasing precedence." -msgstr "" - -#: builtins.c:693 -msgid "\tid++, id--\tvariable post-increment, post-decrement" -msgstr "" - -#: builtins.c:694 -msgid "\t++id, --id\tvariable pre-increment, pre-decrement" -msgstr "" - -#: builtins.c:695 -msgid "\t-, +\t\tunary minus, plus" -msgstr "" - -#: builtins.c:696 -msgid "\t!, ~\t\tlogical and bitwise negation" -msgstr "" - -#: builtins.c:697 -msgid "\t**\t\texponentiation" -msgstr "" - -#: builtins.c:698 -msgid "\t*, /, %\t\tmultiplication, division, remainder" -msgstr "" - -#: builtins.c:699 -msgid "\t+, -\t\taddition, subtraction" -msgstr "" - -#: builtins.c:700 -msgid "\t<<, >>\t\tleft and right bitwise shifts" -msgstr "" - -#: builtins.c:701 -msgid "\t<=, >=, <, >\tcomparison" -msgstr "" - -#: builtins.c:702 -msgid "\t==, !=\t\tequality, inequality" -msgstr "" - -#: builtins.c:703 -msgid "\t&\t\tbitwise AND" -msgstr "" - -#: builtins.c:704 -msgid "\t^\t\tbitwise XOR" -msgstr "" - -#: builtins.c:705 -msgid "\t|\t\tbitwise OR" -msgstr "" - -#: builtins.c:706 -msgid "\t&&\t\tlogical AND" -msgstr "" - -#: builtins.c:707 -msgid "\t||\t\tlogical OR" -msgstr "" - -#: builtins.c:708 -msgid "\texpr ? expr : expr" -msgstr "" - -#: builtins.c:709 -msgid "\t\t\tconditional operator" -msgstr "" - -#: builtins.c:710 -msgid "\t=, *=, /=, %=," -msgstr "" - -#: builtins.c:711 -msgid "\t+=, -=, <<=, >>=," -msgstr "" - -#: builtins.c:712 -msgid "\t&=, ^=, |=\tassignment" -msgstr "" - -#: builtins.c:714 -msgid "Shell variables are allowed as operands. The name of the variable" -msgstr "" - -#: builtins.c:715 -msgid "is replaced by its value (coerced to a fixed-width integer) within" -msgstr "" - -#: builtins.c:716 -msgid "an expression. The variable need not have its integer attribute" -msgstr "" - -#: builtins.c:717 -msgid "turned on to be used in an expression." -msgstr "" - -#: builtins.c:719 -msgid "Operators are evaluated in order of precedence. Sub-expressions in" -msgstr "" - -#: builtins.c:720 -msgid "parentheses are evaluated first and may override the precedence" -msgstr "" - -#: builtins.c:721 -msgid "rules above." -msgstr "" - -#: builtins.c:723 -msgid "If the last ARG evaluates to 0, let returns 1; 0 is returned" -msgstr "" - -#: builtins.c:724 -msgid "otherwise." -msgstr "" - -#: builtins.c:730 -msgid "" -"One line is read from the standard input, or from file descriptor FD if the" -msgstr "" - -#: builtins.c:731 -msgid "" -"-u option is supplied, and the first word is assigned to the first NAME," -msgstr "" - -#: builtins.c:732 -msgid "" -"the second word to the second NAME, and so on, with leftover words assigned" -msgstr "" - -#: builtins.c:733 -msgid "" -"to the last NAME. Only the characters found in $IFS are recognized as word" -msgstr "" - -#: builtins.c:734 -msgid "" -"delimiters. If no NAMEs are supplied, the line read is stored in the REPLY" -msgstr "" - -#: builtins.c:735 -msgid "variable. If the -r option is given, this signifies `raw' input, and" -msgstr "" - -#: builtins.c:736 -msgid "backslash escaping is disabled. The -d option causes read to continue" -msgstr "" - -#: builtins.c:737 -msgid "" -"until the first character of DELIM is read, rather than newline. If the -p" -msgstr "" - -#: builtins.c:738 -msgid "" -"option is supplied, the string PROMPT is output without a trailing newline" -msgstr "" - -#: builtins.c:739 -msgid "" -"before attempting to read. If -a is supplied, the words read are assigned" -msgstr "" - -#: builtins.c:740 -msgid "" -"to sequential indices of ARRAY, starting at zero. If -e is supplied and" -msgstr "" - -#: builtins.c:741 -msgid "" -"the shell is interactive, readline is used to obtain the line. If -n is" -msgstr "" - -#: builtins.c:742 -msgid "supplied with a non-zero NCHARS argument, read returns after NCHARS" -msgstr "" - -#: builtins.c:743 -msgid "characters have been read. The -s option causes input coming from a" -msgstr "" - -#: builtins.c:744 -msgid "terminal to not be echoed." -msgstr "" - -#: builtins.c:746 -msgid "" -"The -t option causes read to time out and return failure if a complete line" -msgstr "" - -#: builtins.c:747 -msgid "" -"of input is not read within TIMEOUT seconds. If the TMOUT variable is set," -msgstr "" - -#: builtins.c:748 -msgid "" -"its value is the default timeout. The return code is zero, unless end-of-" -"file" -msgstr "" - -#: builtins.c:749 -msgid "" -"is encountered, read times out, or an invalid file descriptor is supplied as" -msgstr "" - -#: builtins.c:750 -msgid "the argument to -u." -msgstr "" - -#: builtins.c:756 -msgid "Causes a function to exit with the return value specified by N. If N" -msgstr "" - -#: builtins.c:757 -msgid "is omitted, the return status is that of the last command." -msgstr "" - -#: builtins.c:763 -msgid " -a Mark variables which are modified or created for export." -msgstr "" - -#: builtins.c:764 -msgid " -b Notify of job termination immediately." -msgstr "" - -#: builtins.c:765 -msgid " -e Exit immediately if a command exits with a non-zero status." -msgstr "" - -#: builtins.c:766 -msgid " -f Disable file name generation (globbing)." -msgstr "" - -#: builtins.c:767 -msgid " -h Remember the location of commands as they are looked up." -msgstr "" - -#: builtins.c:768 -msgid " -k All assignment arguments are placed in the environment for a" -msgstr "" - -#: builtins.c:769 -msgid " command, not just those that precede the command name." -msgstr "" - -#: builtins.c:770 -msgid " -m Job control is enabled." -msgstr "" - -#: builtins.c:771 -msgid " -n Read commands but do not execute them." -msgstr "" - -#: builtins.c:772 -msgid " -o option-name" -msgstr "" - -#: builtins.c:773 -msgid " Set the variable corresponding to option-name:" -msgstr "" - -#: builtins.c:774 -msgid " allexport same as -a" -msgstr "" - -#: builtins.c:775 -msgid " braceexpand same as -B" -msgstr "" - -#: builtins.c:777 -msgid " emacs use an emacs-style line editing interface" -msgstr "" - -#: builtins.c:779 -msgid " errexit same as -e" -msgstr "" - -#: builtins.c:780 -msgid " errtrace same as -E" -msgstr "" - -#: builtins.c:781 -msgid " functrace same as -T" -msgstr "" - -#: builtins.c:782 -msgid " hashall same as -h" -msgstr "" - -#: builtins.c:784 -msgid " histexpand same as -H" -msgstr "" - -#: builtins.c:787 -msgid " history enable command history" -msgstr "" - -#: builtins.c:789 -msgid " ignoreeof the shell will not exit upon reading EOF" -msgstr "" - -#: builtins.c:790 -msgid " interactive-comments" -msgstr "" - -#: builtins.c:791 -msgid "" -" allow comments to appear in interactive commands" -msgstr "" - -#: builtins.c:792 -msgid " keyword same as -k" -msgstr "" - -#: builtins.c:793 -msgid " monitor same as -m" -msgstr "" - -#: builtins.c:794 -msgid " noclobber same as -C" -msgstr "" - -#: builtins.c:795 -msgid " noexec same as -n" -msgstr "" - -#: builtins.c:796 -msgid " noglob same as -f" -msgstr "" - -#: builtins.c:797 -msgid " nolog currently accepted but ignored" -msgstr "" - -#: builtins.c:798 -msgid " notify same as -b" -msgstr "" - -#: builtins.c:799 -msgid " nounset same as -u" -msgstr "" - -#: builtins.c:800 -msgid " onecmd same as -t" -msgstr "" - -#: builtins.c:801 -msgid " physical same as -P" -msgstr "" - -#: builtins.c:802 -msgid "" -" pipefail the return value of a pipeline is the status of" -msgstr "" - -#: builtins.c:803 -msgid "" -" the last command to exit with a non-zero status," -msgstr "" - -#: builtins.c:804 -msgid "" -" or zero if no command exited with a non-zero status" -msgstr "" - -#: builtins.c:805 -msgid " posix change the behavior of bash where the default" -msgstr "" - -#: builtins.c:806 -msgid " operation differs from the 1003.2 standard to" -msgstr "" - -#: builtins.c:807 -msgid " match the standard" -msgstr "" - -#: builtins.c:808 -msgid " privileged same as -p" -msgstr "" - -#: builtins.c:809 -msgid " verbose same as -v" -msgstr "" - -#: builtins.c:811 -msgid " vi use a vi-style line editing interface" -msgstr "" - -#: builtins.c:813 -msgid " xtrace same as -x" -msgstr "" - -#: builtins.c:814 -msgid "" -" -p Turned on whenever the real and effective user ids do not match." -msgstr "" - -#: builtins.c:815 -msgid " Disables processing of the $ENV file and importing of shell" -msgstr "" - -#: builtins.c:816 -msgid "" -" functions. Turning this option off causes the effective uid and" -msgstr "" - -#: builtins.c:817 -msgid " gid to be set to the real uid and gid." -msgstr "" - -#: builtins.c:818 -msgid " -t Exit after reading and executing one command." -msgstr "" - -#: builtins.c:819 -msgid " -u Treat unset variables as an error when substituting." -msgstr "" - -#: builtins.c:820 -msgid " -v Print shell input lines as they are read." -msgstr "" - -#: builtins.c:821 -msgid " -x Print commands and their arguments as they are executed." -msgstr "" - -#: builtins.c:823 -msgid " -B the shell will perform brace expansion" -msgstr "" - -#: builtins.c:825 -msgid " -C If set, disallow existing regular files to be overwritten" -msgstr "" - -#: builtins.c:826 -msgid " by redirection of output." -msgstr "" - -#: builtins.c:827 -msgid " -E If set, the ERR trap is inherited by shell functions." -msgstr "" - -#: builtins.c:829 -msgid " -H Enable ! style history substitution. This flag is on" -msgstr "" - -#: builtins.c:830 -msgid " by default." -msgstr "" - -#: builtins.c:832 -msgid " -P If set, do not follow symbolic links when executing commands" -msgstr "" - -#: builtins.c:833 -msgid " such as cd which change the current directory." -msgstr "" - -#: builtins.c:834 -msgid " -T If set, the DEBUG trap is inherited by shell functions." -msgstr "" - -#: builtins.c:836 -msgid "Using + rather than - causes these flags to be turned off. The" -msgstr "" - -#: builtins.c:837 -msgid "flags can also be used upon invocation of the shell. The current" -msgstr "" - -#: builtins.c:838 -msgid "set of flags may be found in $-. The remaining n ARGs are positional" -msgstr "" - -#: builtins.c:839 -msgid "parameters and are assigned, in order, to $1, $2, .. $n. If no" -msgstr "" - -#: builtins.c:840 -msgid "ARGs are given, all shell variables are printed." -msgstr "" - -#: builtins.c:846 -msgid "For each NAME, remove the corresponding variable or function. Given" -msgstr "" - -#: builtins.c:847 -msgid "the `-v', unset will only act on variables. Given the `-f' flag," -msgstr "" - -#: builtins.c:848 -msgid "unset will only act on functions. With neither flag, unset first" -msgstr "" - -#: builtins.c:849 -msgid "tries to unset a variable, and if that fails, then tries to unset a" -msgstr "" - -#: builtins.c:850 -msgid "function. Some variables cannot be unset; also see readonly." -msgstr "" - -#: builtins.c:856 -msgid "NAMEs are marked for automatic export to the environment of" -msgstr "" - -#: builtins.c:857 -msgid "subsequently executed commands. If the -f option is given," -msgstr "" - -#: builtins.c:858 -msgid "the NAMEs refer to functions. If no NAMEs are given, or if `-p'" -msgstr "" - -#: builtins.c:859 -msgid "is given, a list of all names that are exported in this shell is" -msgstr "" - -#: builtins.c:860 -msgid "printed. An argument of `-n' says to remove the export property" -msgstr "" - -#: builtins.c:861 -msgid "from subsequent NAMEs. An argument of `--' disables further option" -msgstr "" - -#: builtins.c:862 builtins.c:874 -msgid "processing." -msgstr "" - -#: builtins.c:868 -msgid "The given NAMEs are marked readonly and the values of these NAMEs may" -msgstr "" - -#: builtins.c:869 -msgid "not be changed by subsequent assignment. If the -f option is given," -msgstr "" - -#: builtins.c:870 -msgid "then functions corresponding to the NAMEs are so marked. If no" -msgstr "" - -#: builtins.c:871 -msgid "arguments are given, or if `-p' is given, a list of all readonly names" -msgstr "" - -#: builtins.c:872 -msgid "is printed. The `-a' option means to treat each NAME as" -msgstr "" - -#: builtins.c:873 -msgid "an array variable. An argument of `--' disables further option" -msgstr "" - -#: builtins.c:880 -msgid "The positional parameters from $N+1 ... are renamed to $1 ... If N is" -msgstr "" - -#: builtins.c:881 -msgid "not given, it is assumed to be 1." -msgstr "" - -#: builtins.c:887 builtins.c:896 -msgid "Read and execute commands from FILENAME and return. The pathnames" -msgstr "" - -#: builtins.c:888 builtins.c:897 -msgid "in $PATH are used to find the directory containing FILENAME. If any" -msgstr "" - -#: builtins.c:889 builtins.c:898 -msgid "ARGUMENTS are supplied, they become the positional parameters when" -msgstr "" - -#: builtins.c:890 builtins.c:899 -msgid "FILENAME is executed." -msgstr "" - -#: builtins.c:906 -msgid "Suspend the execution of this shell until it receives a SIGCONT" -msgstr "" - -#: builtins.c:907 -msgid "signal. The `-f' if specified says not to complain about this" -msgstr "" - -#: builtins.c:908 -msgid "being a login shell if it is; just suspend anyway." -msgstr "" - -#: builtins.c:915 -msgid "Exits with a status of 0 (true) or 1 (false) depending on" -msgstr "" - -#: builtins.c:916 -msgid "the evaluation of EXPR. Expressions may be unary or binary. Unary" -msgstr "" - -#: builtins.c:917 -msgid "expressions are often used to examine the status of a file. There" -msgstr "" - -#: builtins.c:918 -msgid "are string operators as well, and numeric comparison operators." -msgstr "" - -#: builtins.c:920 -msgid "File operators:" -msgstr "" - -#: builtins.c:922 -msgid " -a FILE True if file exists." -msgstr "" - -#: builtins.c:923 -msgid " -b FILE True if file is block special." -msgstr "" - -#: builtins.c:924 -msgid " -c FILE True if file is character special." -msgstr "" - -#: builtins.c:925 -msgid " -d FILE True if file is a directory." -msgstr "" - -#: builtins.c:926 -msgid " -e FILE True if file exists." -msgstr "" - -#: builtins.c:927 -msgid " -f FILE True if file exists and is a regular file." -msgstr "" - -#: builtins.c:928 -msgid " -g FILE True if file is set-group-id." -msgstr "" - -#: builtins.c:929 -msgid " -h FILE True if file is a symbolic link." -msgstr "" - -#: builtins.c:930 -msgid " -L FILE True if file is a symbolic link." -msgstr "" - -#: builtins.c:931 -msgid " -k FILE True if file has its `sticky' bit set." -msgstr "" - -#: builtins.c:932 -msgid " -p FILE True if file is a named pipe." -msgstr "" - -#: builtins.c:933 -msgid " -r FILE True if file is readable by you." -msgstr "" - -#: builtins.c:934 -msgid " -s FILE True if file exists and is not empty." -msgstr "" - -#: builtins.c:935 -msgid " -S FILE True if file is a socket." -msgstr "" - -#: builtins.c:936 -msgid " -t FD True if FD is opened on a terminal." -msgstr "" - -#: builtins.c:937 -msgid " -u FILE True if the file is set-user-id." -msgstr "" - -#: builtins.c:938 -msgid " -w FILE True if the file is writable by you." -msgstr "" - -#: builtins.c:939 -msgid " -x FILE True if the file is executable by you." -msgstr "" - -#: builtins.c:940 -msgid " -O FILE True if the file is effectively owned by you." -msgstr "" - -#: builtins.c:941 -msgid " -G FILE True if the file is effectively owned by your group." -msgstr "" - -#: builtins.c:942 -msgid "" -" -N FILE True if the file has been modified since it was last read." -msgstr "" - -#: builtins.c:944 -msgid " FILE1 -nt FILE2 True if file1 is newer than file2 (according to" -msgstr "" - -#: builtins.c:945 -msgid " modification date)." -msgstr "" - -#: builtins.c:947 -msgid " FILE1 -ot FILE2 True if file1 is older than file2." -msgstr "" - -#: builtins.c:949 -msgid " FILE1 -ef FILE2 True if file1 is a hard link to file2." -msgstr "" - -#: builtins.c:951 -msgid "String operators:" -msgstr "" - -#: builtins.c:953 -msgid " -z STRING True if string is empty." -msgstr "" - -#: builtins.c:955 -msgid " -n STRING" -msgstr "" - -#: builtins.c:956 -msgid " STRING True if string is not empty." -msgstr "" - -#: builtins.c:958 -msgid " STRING1 = STRING2" -msgstr "" - -#: builtins.c:959 -msgid " True if the strings are equal." -msgstr "" - -#: builtins.c:960 -msgid " STRING1 != STRING2" -msgstr "" - -#: builtins.c:961 -msgid " True if the strings are not equal." -msgstr "" - -#: builtins.c:962 -msgid " STRING1 < STRING2" -msgstr "" - -#: builtins.c:963 -msgid "" -" True if STRING1 sorts before STRING2 lexicographically." -msgstr "" - -#: builtins.c:964 -msgid " STRING1 > STRING2" -msgstr "" - -#: builtins.c:965 -msgid "" -" True if STRING1 sorts after STRING2 lexicographically." -msgstr "" - -#: builtins.c:967 -msgid "Other operators:" -msgstr "" - -#: builtins.c:969 -msgid " -o OPTION True if the shell option OPTION is enabled." -msgstr "" - -#: builtins.c:970 -msgid " ! EXPR True if expr is false." -msgstr "" - -#: builtins.c:971 -msgid " EXPR1 -a EXPR2 True if both expr1 AND expr2 are true." -msgstr "" - -#: builtins.c:972 -msgid " EXPR1 -o EXPR2 True if either expr1 OR expr2 is true." -msgstr "" - -#: builtins.c:974 -msgid " arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne," -msgstr "" - -#: builtins.c:975 -msgid " -lt, -le, -gt, or -ge." -msgstr "" - -#: builtins.c:977 -msgid "Arithmetic binary operators return true if ARG1 is equal, not-equal," -msgstr "" - -#: builtins.c:978 -msgid "less-than, less-than-or-equal, greater-than, or greater-than-or-equal" -msgstr "" - -#: builtins.c:979 -msgid "than ARG2." -msgstr "" - -#: builtins.c:985 -msgid "This is a synonym for the \"test\" builtin, but the last" -msgstr "" - -#: builtins.c:986 -msgid "argument must be a literal `]', to match the opening `['." -msgstr "" - -#: builtins.c:992 -msgid "Print the accumulated user and system times for processes run from" -msgstr "" - -#: builtins.c:993 -msgid "the shell." -msgstr "" - -#: builtins.c:999 -msgid "The command ARG is to be read and executed when the shell receives" -msgstr "" - -#: builtins.c:1000 -msgid "signal(s) SIGNAL_SPEC. If ARG is absent all specified signals are" -msgstr "" - -#: builtins.c:1001 -msgid "reset to their original values. If ARG is the null string each" -msgstr "" - -#: builtins.c:1002 -msgid "SIGNAL_SPEC is ignored by the shell and by the commands it invokes." -msgstr "" - -#: builtins.c:1003 -msgid "If a SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from" -msgstr "" - -#: builtins.c:1004 -msgid "the shell. If a SIGNAL_SPEC is DEBUG, ARG is executed after every" -msgstr "" - -#: builtins.c:1005 -msgid "command. If ARG is `-p' then the trap commands associated with" -msgstr "" - -#: builtins.c:1006 -msgid "each SIGNAL_SPEC are displayed. If no arguments are supplied or if" -msgstr "" - -#: builtins.c:1007 -msgid "only `-p' is given, trap prints the list of commands associated with" -msgstr "" - -#: builtins.c:1008 -msgid "" -"each signal number. Each SIGNAL_SPEC is either a signal name in " -msgstr "" - -#: builtins.c:1009 -msgid "or a signal number. `trap -l' prints a list of signal names and their" -msgstr "" - -#: builtins.c:1010 -msgid "corresponding numbers. Note that a signal can be sent to the shell" -msgstr "" - -#: builtins.c:1011 -msgid "with \"kill -signal $$\"." -msgstr "" - -#: builtins.c:1017 -msgid "For each NAME, indicate how it would be interpreted if used as a" -msgstr "" - -#: builtins.c:1018 -msgid "command name." -msgstr "" - -#: builtins.c:1020 -msgid "If the -t option is used, `type' outputs a single word which is one of" -msgstr "" - -#: builtins.c:1021 -msgid "`alias', `keyword', `function', `builtin', `file' or `', if NAME is an" -msgstr "" - -#: builtins.c:1022 -msgid "alias, shell reserved word, shell function, shell builtin, disk file," -msgstr "" - -#: builtins.c:1023 -msgid "or unfound, respectively." -msgstr "" - -#: builtins.c:1025 -msgid "If the -p flag is used, `type' either returns the name of the disk" -msgstr "" - -#: builtins.c:1026 -msgid "file that would be executed, or nothing if `type -t NAME' would not" -msgstr "" - -#: builtins.c:1027 -msgid "return `file'." -msgstr "" - -#: builtins.c:1029 -msgid "If the -a flag is used, `type' displays all of the places that contain" -msgstr "" - -#: builtins.c:1030 -msgid "an executable named `file'. This includes aliases, builtins, and" -msgstr "" - -#: builtins.c:1031 -msgid "functions, if and only if the -p flag is not also used." -msgstr "" - -#: builtins.c:1033 -msgid "The -f flag suppresses shell function lookup." -msgstr "" - -#: builtins.c:1035 -msgid "The -P flag forces a PATH search for each NAME, even if it is an alias," -msgstr "" - -#: builtins.c:1036 -msgid "builtin, or function, and returns the name of the disk file that would" -msgstr "" - -#: builtins.c:1037 -msgid "be executed." -msgstr "" - -#: builtins.c:1044 -msgid "Ulimit provides control over the resources available to processes" -msgstr "" - -#: builtins.c:1045 -msgid "started by the shell, on systems that allow such control. If an" -msgstr "" - -#: builtins.c:1046 -msgid "option is given, it is interpreted as follows:" -msgstr "" - -#: builtins.c:1048 -msgid " -S\tuse the `soft' resource limit" -msgstr "" - -#: builtins.c:1049 -msgid " -H\tuse the `hard' resource limit" -msgstr "" - -#: builtins.c:1050 -msgid " -a\tall current limits are reported" -msgstr "" - -#: builtins.c:1051 -msgid " -c\tthe maximum size of core files created" -msgstr "" - -#: builtins.c:1052 -msgid " -d\tthe maximum size of a process's data segment" -msgstr "" - -#: builtins.c:1053 -msgid " -f\tthe maximum size of files created by the shell" -msgstr "" - -#: builtins.c:1054 -msgid " -l\tthe maximum size a process may lock into memory" -msgstr "" - -#: builtins.c:1055 -msgid " -m\tthe maximum resident set size" -msgstr "" - -#: builtins.c:1056 -msgid " -n\tthe maximum number of open file descriptors" -msgstr "" - -#: builtins.c:1057 -msgid " -p\tthe pipe buffer size" -msgstr "" - -#: builtins.c:1058 -msgid " -s\tthe maximum stack size" -msgstr "" - -#: builtins.c:1059 -msgid " -t\tthe maximum amount of cpu time in seconds" -msgstr "" - -#: builtins.c:1060 -msgid " -u\tthe maximum number of user processes" -msgstr "" - -#: builtins.c:1061 -msgid " -v\tthe size of virtual memory" -msgstr "" - -#: builtins.c:1063 -msgid "If LIMIT is given, it is the new value of the specified resource;" -msgstr "" - -#: builtins.c:1064 -msgid "the special LIMIT values `soft', `hard', and `unlimited' stand for" -msgstr "" - -#: builtins.c:1065 -msgid "" -"the current soft limit, the current hard limit, and no limit, respectively." -msgstr "" - -#: builtins.c:1066 -msgid "Otherwise, the current value of the specified resource is printed." -msgstr "" - -#: builtins.c:1067 -msgid "If no option is given, then -f is assumed. Values are in 1024-byte" -msgstr "" - -#: builtins.c:1068 -msgid "increments, except for -t, which is in seconds, -p, which is in" -msgstr "" - -#: builtins.c:1069 -msgid "increments of 512 bytes, and -u, which is an unscaled number of" -msgstr "" - -#: builtins.c:1070 -msgid "processes." -msgstr "" - -#: builtins.c:1077 -msgid "The user file-creation mask is set to MODE. If MODE is omitted, or if" -msgstr "" - -#: builtins.c:1078 -msgid "`-S' is supplied, the current value of the mask is printed. The `-S'" -msgstr "" - -#: builtins.c:1079 -msgid "option makes the output symbolic; otherwise an octal number is output." -msgstr "" - -#: builtins.c:1080 -msgid "If `-p' is supplied, and MODE is omitted, the output is in a form" -msgstr "" - -#: builtins.c:1081 -msgid "that may be used as input. If MODE begins with a digit, it is" -msgstr "" - -#: builtins.c:1082 -msgid "interpreted as an octal number, otherwise it is a symbolic mode string" -msgstr "" - -#: builtins.c:1083 -msgid "like that accepted by chmod(1)." -msgstr "" - -#: builtins.c:1090 builtins.c:1102 -msgid "Wait for the specified process and report its termination status. If" -msgstr "" - -#: builtins.c:1091 builtins.c:1103 -msgid "N is not given, all currently active child processes are waited for," -msgstr "" - -#: builtins.c:1092 -msgid "and the return code is zero. N may be a process ID or a job" -msgstr "" - -#: builtins.c:1093 -msgid "specification; if a job spec is given, all processes in the job's" -msgstr "" - -#: builtins.c:1094 -msgid "pipeline are waited for." -msgstr "" - -#: builtins.c:1104 -msgid "and the return code is zero. N is a process ID; if it is not given," -msgstr "" - -#: builtins.c:1105 -msgid "all child processes of the shell are waited for." -msgstr "" - -#: builtins.c:1112 -msgid "The `for' loop executes a sequence of commands for each member in a" -msgstr "" - -#: builtins.c:1113 -msgid "list of items. If `in WORDS ...;' is not present, then `in \"$@\"' is" -msgstr "" - -#: builtins.c:1114 -msgid "assumed. For each element in WORDS, NAME is set to that element, and" -msgstr "" - -#: builtins.c:1115 -msgid "the COMMANDS are executed." -msgstr "" - -#: builtins.c:1121 -msgid "Equivalent to" -msgstr "" - -#: builtins.c:1122 -msgid "\t(( EXP1 ))" -msgstr "" - -#: builtins.c:1123 -msgid "\twhile (( EXP2 )); do" -msgstr "" - -#: builtins.c:1124 -msgid "\t\tCOMMANDS" -msgstr "" - -#: builtins.c:1125 -msgid "\t\t(( EXP3 ))" -msgstr "" - -#: builtins.c:1126 -msgid "\tdone" -msgstr "" - -#: builtins.c:1127 -msgid "EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is" -msgstr "" - -#: builtins.c:1128 -msgid "omitted, it behaves as if it evaluates to 1." -msgstr "" - -#: builtins.c:1134 -msgid "The WORDS are expanded, generating a list of words. The" -msgstr "" - -#: builtins.c:1135 -msgid "set of expanded words is printed on the standard error, each" -msgstr "" - -#: builtins.c:1136 -msgid "preceded by a number. If `in WORDS' is not present, `in \"$@\"'" -msgstr "" - -#: builtins.c:1137 -msgid "is assumed. The PS3 prompt is then displayed and a line read" -msgstr "" - -#: builtins.c:1138 -msgid "from the standard input. If the line consists of the number" -msgstr "" - -#: builtins.c:1139 -msgid "corresponding to one of the displayed words, then NAME is set" -msgstr "" - -#: builtins.c:1140 -msgid "to that word. If the line is empty, WORDS and the prompt are" -msgstr "" - -#: builtins.c:1141 -msgid "redisplayed. If EOF is read, the command completes. Any other" -msgstr "" - -#: builtins.c:1142 -msgid "value read causes NAME to be set to null. The line read is saved" -msgstr "" - -#: builtins.c:1143 -msgid "in the variable REPLY. COMMANDS are executed after each selection" -msgstr "" - -#: builtins.c:1144 -msgid "until a break command is executed." -msgstr "" - -#: builtins.c:1150 -msgid "Execute PIPELINE and print a summary of the real time, user CPU time," -msgstr "" - -#: builtins.c:1151 -msgid "and system CPU time spent executing PIPELINE when it terminates." -msgstr "" - -#: builtins.c:1152 -msgid "The return status is the return status of PIPELINE. The `-p' option" -msgstr "" - -#: builtins.c:1153 -msgid "prints the timing summary in a slightly different format. This uses" -msgstr "" - -#: builtins.c:1154 -msgid "the value of the TIMEFORMAT variable as the output format." -msgstr "" - -#: builtins.c:1160 -msgid "Selectively execute COMMANDS based upon WORD matching PATTERN. The" -msgstr "" - -#: builtins.c:1161 -msgid "`|' is used to separate multiple patterns." -msgstr "" - -#: builtins.c:1167 -msgid "" -"The if COMMANDS are executed. If the exit status is zero, then the then" -msgstr "" - -#: builtins.c:1168 -msgid "" -"COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed" -msgstr "" - -#: builtins.c:1169 -msgid "" -"in turn, and if the exit status is zero, the corresponding then COMMANDS" -msgstr "" - -#: builtins.c:1170 -msgid "" -"are executed and the if command completes. Otherwise, the else COMMANDS" -msgstr "" - -#: builtins.c:1171 -msgid "" -"are executed, if present. The exit status is the exit status of the last" -msgstr "" - -#: builtins.c:1172 -msgid "command executed, or zero if no condition tested true." -msgstr "" - -#: builtins.c:1178 builtins.c:1185 -msgid "Expand and execute COMMANDS as long as the final command in the" -msgstr "" - -#: builtins.c:1179 -msgid "`while' COMMANDS has an exit status of zero." -msgstr "" - -#: builtins.c:1186 -msgid "`until' COMMANDS has an exit status which is not zero." -msgstr "" - -#: builtins.c:1192 -msgid "Create a simple command invoked by NAME which runs COMMANDS." -msgstr "" - -#: builtins.c:1193 -msgid "Arguments on the command line along with NAME are passed to the" -msgstr "" - -#: builtins.c:1194 -msgid "function as $0 .. $n." -msgstr "" - -#: builtins.c:1200 -msgid "Run a set of commands in a group. This is one way to redirect an" -msgstr "" - -#: builtins.c:1201 -msgid "entire set of commands." -msgstr "" - -#: builtins.c:1207 -msgid "This is similar to the `fg' command. Resume a stopped or background" -msgstr "" - -#: builtins.c:1208 -msgid "job. If you specifiy DIGITS, then that job is used. If you specify" -msgstr "" - -#: builtins.c:1209 -msgid "WORD, then the job whose name begins with WORD is used. Following the" -msgstr "" - -#: builtins.c:1210 -msgid "job specification with a `&' places the job in the background." -msgstr "" - -#: builtins.c:1216 -msgid "The EXPRESSION is evaluated according to the rules for arithmetic" -msgstr "" - -#: builtins.c:1217 -msgid "evaluation. Equivalent to \"let EXPRESSION\"." -msgstr "" - -#: builtins.c:1223 -msgid "" -"Returns a status of 0 or 1 depending on the evaluation of the conditional" -msgstr "" - -#: builtins.c:1224 -msgid "" -"expression EXPRESSION. Expressions are composed of the same primaries used" -msgstr "" - -#: builtins.c:1225 -msgid "" -"by the `test' builtin, and may be combined using the following operators" -msgstr "" - -#: builtins.c:1227 -msgid "\t( EXPRESSION )\tReturns the value of EXPRESSION" -msgstr "" - -#: builtins.c:1228 -msgid "\t! EXPRESSION\tTrue if EXPRESSION is false; else false" -msgstr "" - -#: builtins.c:1229 -msgid "\tEXPR1 && EXPR2\tTrue if both EXPR1 and EXPR2 are true; else false" -msgstr "" - -#: builtins.c:1230 -msgid "\tEXPR1 || EXPR2\tTrue if either EXPR1 or EXPR2 is true; else false" -msgstr "" - -#: builtins.c:1232 -msgid "" -"When the `==' and `!=' operators are used, the string to the right of the" -msgstr "" - -#: builtins.c:1233 -msgid "operator is used as a pattern and pattern matching is performed. The" -msgstr "" - -#: builtins.c:1234 -msgid "&& and || operators do not evaluate EXPR2 if EXPR1 is sufficient to" -msgstr "" - -#: builtins.c:1235 -msgid "determine the expression's value." -msgstr "" - -#: builtins.c:1241 -msgid "BASH_VERSION Version information for this Bash." -msgstr "" - -#: builtins.c:1242 -msgid "CDPATH A colon separated list of directories to search" -msgstr "" - -#: builtins.c:1243 -msgid "\t\twhen the argument to `cd' is not found in the current" -msgstr "" - -#: builtins.c:1244 -msgid "\t\tdirectory." -msgstr "" - -#: builtins.c:1245 -msgid "GLOBIGNORE\tA colon-separated list of patterns describing filenames to" -msgstr "" - -#: builtins.c:1246 -msgid "\t\tbe ignored by pathname expansion." -msgstr "" - -#: builtins.c:1248 -msgid "" -"HISTFILE The name of the file where your command history is stored." -msgstr "" - -#: builtins.c:1249 -msgid "HISTFILESIZE The maximum number of lines this file can contain." -msgstr "" - -#: builtins.c:1250 -msgid "HISTSIZE The maximum number of history lines that a running" -msgstr "" - -#: builtins.c:1251 -msgid "\t\tshell can access." -msgstr "" - -#: builtins.c:1253 -msgid "HOME The complete pathname to your login directory." -msgstr "" - -#: builtins.c:1254 -msgid "HOSTNAME\tThe name of the current host." -msgstr "" - -#: builtins.c:1255 -msgid "HOSTTYPE The type of CPU this version of Bash is running under." -msgstr "" - -#: builtins.c:1256 -msgid "IGNOREEOF Controls the action of the shell on receipt of an EOF" -msgstr "" - -#: builtins.c:1257 -msgid "\t\tcharacter as the sole input. If set, then the value" -msgstr "" - -#: builtins.c:1258 -msgid "\t\tof it is the number of EOF characters that can be seen" -msgstr "" - -#: builtins.c:1259 -msgid "\t\tin a row on an empty line before the shell will exit" -msgstr "" - -#: builtins.c:1260 -msgid "\t\t(default 10). When unset, EOF signifies the end of input." -msgstr "" - -#: builtins.c:1261 -msgid "MACHTYPE\tA string describing the current system Bash is running on." -msgstr "" - -#: builtins.c:1262 -msgid "MAILCHECK\tHow often, in seconds, Bash checks for new mail." -msgstr "" - -#: builtins.c:1263 -msgid "MAILPATH\tA colon-separated list of filenames which Bash checks" -msgstr "" - -#: builtins.c:1264 -msgid "\t\tfor new mail." -msgstr "" - -#: builtins.c:1265 -msgid "OSTYPE\t\tThe version of Unix this version of Bash is running on." -msgstr "" - -#: builtins.c:1266 -msgid "PATH A colon-separated list of directories to search when" -msgstr "" - -#: builtins.c:1267 -msgid "\t\tlooking for commands." -msgstr "" - -#: builtins.c:1268 -msgid "PROMPT_COMMAND A command to be executed before the printing of each" -msgstr "" - -#: builtins.c:1269 -msgid "\t\tprimary prompt." -msgstr "" - -#: builtins.c:1270 -msgid "PS1 The primary prompt string." -msgstr "" - -#: builtins.c:1271 -msgid "PS2 The secondary prompt string." -msgstr "" - -#: builtins.c:1272 -msgid "PWD\t\tThe full pathname of the current directory." -msgstr "" - -#: builtins.c:1273 -msgid "SHELLOPTS\tA colon-separated list of enabled shell options." -msgstr "" - -#: builtins.c:1274 -msgid "TERM The name of the current terminal type." -msgstr "" - -#: builtins.c:1275 -msgid "TIMEFORMAT\tThe output format for timing statistics displayed by the" -msgstr "" - -#: builtins.c:1276 -msgid "\t\t`time' reserved word." -msgstr "" - -#: builtins.c:1277 -msgid "auto_resume Non-null means a command word appearing on a line by" -msgstr "" - -#: builtins.c:1278 -msgid "\t\titself is first looked for in the list of currently" -msgstr "" - -#: builtins.c:1279 -msgid "\t\tstopped jobs. If found there, that job is foregrounded." -msgstr "" - -#: builtins.c:1280 -msgid "\t\tA value of `exact' means that the command word must" -msgstr "" - -#: builtins.c:1281 -msgid "\t\texactly match a command in the list of stopped jobs. A" -msgstr "" - -#: builtins.c:1282 -msgid "\t\tvalue of `substring' means that the command word must" -msgstr "" - -#: builtins.c:1283 -msgid "\t\tmatch a substring of the job. Any other value means that" -msgstr "" - -#: builtins.c:1284 -msgid "\t\tthe command must be a prefix of a stopped job." -msgstr "" - -#: builtins.c:1287 -msgid "histchars Characters controlling history expansion and quick" -msgstr "" - -#: builtins.c:1288 -msgid "\t\tsubstitution. The first character is the history" -msgstr "" - -#: builtins.c:1289 -msgid "\t\tsubstitution character, usually `!'. The second is" -msgstr "" - -#: builtins.c:1290 -msgid "\t\tthe `quick substitution' character, usually `^'. The" -msgstr "" - -#: builtins.c:1291 -msgid "\t\tthird is the `history comment' character, usually `#'." -msgstr "" - -#: builtins.c:1293 -msgid "HISTIGNORE\tA colon-separated list of patterns used to decide which" -msgstr "" - -#: builtins.c:1294 -msgid "\t\tcommands should be saved on the history list." -msgstr "" - -#: builtins.c:1306 -msgid "+N\tRotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins.c:1307 -msgid "\tfrom the left of the list shown by `dirs', starting with" -msgstr "" - -#: builtins.c:1308 builtins.c:1312 -msgid "\tzero) is at the top." -msgstr "" - -#: builtins.c:1310 -msgid "-N\tRotates the stack so that the Nth directory (counting" -msgstr "" - -#: builtins.c:1311 -msgid "\tfrom the right of the list shown by `dirs', starting with" -msgstr "" - -#: builtins.c:1314 -msgid "-n\tsuppress the normal change of directory when adding directories" -msgstr "" - -#: builtins.c:1315 -msgid "\tto the stack, so only the stack is manipulated." -msgstr "" - -#: builtins.c:1317 -msgid "dir\tadds DIR to the directory stack at the top, making it the" -msgstr "" - -#: builtins.c:1318 -msgid "\tnew current working directory." -msgstr "" - -#: builtins.c:1332 -msgid "+N\tremoves the Nth entry counting from the left of the list" -msgstr "" - -#: builtins.c:1333 -msgid "\tshown by `dirs', starting with zero. For example: `popd +0'" -msgstr "" - -#: builtins.c:1334 -msgid "\tremoves the first directory, `popd +1' the second." -msgstr "" - -#: builtins.c:1336 -msgid "-N\tremoves the Nth entry counting from the right of the list" -msgstr "" - -#: builtins.c:1337 -msgid "\tshown by `dirs', starting with zero. For example: `popd -0'" -msgstr "" - -#: builtins.c:1338 -msgid "\tremoves the last directory, `popd -1' the next to last." -msgstr "" - -#: builtins.c:1340 -msgid "-n\tsuppress the normal change of directory when removing directories" -msgstr "" - -#: builtins.c:1341 -msgid "\tfrom the stack, so only the stack is manipulated." -msgstr "" - -#: builtins.c:1363 -msgid "+N\tdisplays the Nth entry counting from the left of the list shown by" -msgstr "" - -#: builtins.c:1364 builtins.c:1367 -msgid "\tdirs when invoked without options, starting with zero." -msgstr "" - -#: builtins.c:1366 -msgid "-N\tdisplays the Nth entry counting from the right of the list shown by" -msgstr "" - -#: builtins.c:1374 -msgid "Toggle the values of variables controlling optional behavior." -msgstr "" - -#: builtins.c:1375 -msgid "The -s flag means to enable (set) each OPTNAME; the -u flag" -msgstr "" - -#: builtins.c:1376 -msgid "unsets each OPTNAME. The -q flag suppresses output; the exit" -msgstr "" - -#: builtins.c:1377 -msgid "status indicates whether each OPTNAME is set or unset. The -o" -msgstr "" - -#: builtins.c:1378 -msgid "option restricts the OPTNAMEs to those defined for use with" -msgstr "" - -#: builtins.c:1379 -msgid "`set -o'. With no options, or with the -p option, a list of all" -msgstr "" - -#: builtins.c:1380 -msgid "settable options is displayed, with an indication of whether or" -msgstr "" - -#: builtins.c:1381 -msgid "not each is set." -msgstr "" - -#: builtins.c:1387 -msgid "printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT" -msgstr "" - -#: builtins.c:1388 -msgid "is a character string which contains three types of objects: plain" -msgstr "" - -#: builtins.c:1389 -msgid "" -"characters, which are simply copied to standard output, character escape" -msgstr "" - -#: builtins.c:1390 -msgid "sequences which are converted and copied to the standard output, and" -msgstr "" - -#: builtins.c:1391 -msgid "" -"format specifications, each of which causes printing of the next successive" -msgstr "" - -#: builtins.c:1392 -msgid "argument. In addition to the standard printf(1) formats, %b means to" -msgstr "" - -#: builtins.c:1393 -msgid "expand backslash escape sequences in the corresponding argument, and %q" -msgstr "" - -#: builtins.c:1394 -msgid "means to quote the argument in a way that can be reused as shell input." -msgstr "" - -#: builtins.c:1401 -msgid "For each NAME, specify how arguments are to be completed." -msgstr "" - -#: builtins.c:1402 -msgid "If the -p option is supplied, or if no options are supplied, existing" -msgstr "" - -#: builtins.c:1403 -msgid "completion specifications are printed in a way that allows them to be" -msgstr "" - -#: builtins.c:1404 -msgid "reused as input. The -r option removes a completion specification for" -msgstr "" - -#: builtins.c:1405 -msgid "each NAME, or, if no NAMEs are supplied, all completion specifications." -msgstr "" - -#: builtins.c:1413 -msgid "Display the possible completions depending on the options. Intended" -msgstr "" - -#: builtins.c:1414 -msgid "" -"to be used from within a shell function generating possible completions." -msgstr "" - -#: builtins.c:1415 -msgid "If the optional WORD argument is supplied, matches against WORD are" -msgstr "" - -#: builtins.c:1416 -msgid "generated." -msgstr "" diff --git a/print_cmd.c~ b/print_cmd.c~ deleted file mode 100644 index e63c45744..000000000 --- a/print_cmd.c~ +++ /dev/null @@ -1,1282 +0,0 @@ -/* print_command -- A way to make readable commands from a command tree. */ - -/* Copyright (C) 1989-2004 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include /* use <...> so we pick it up from the build directory */ -#include "builtins/common.h" - -#if !HAVE_DECL_PRINTF -extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */ -#endif - -extern int indirection_level; - -static int indentation; -static int indentation_amount = 4; - -#if defined (PREFER_STDARG) -typedef void PFUNC __P((const char *, ...)); - -static void cprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -static void xprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -#else -#define PFUNC VFunction -static void cprintf (); -static void xprintf (); -#endif - -static void reset_locals __P((void)); -static void newline __P((char *)); -static void indent __P((int)); -static void semicolon __P((void)); -static void the_printed_command_resize __P((int)); - -static void make_command_string_internal __P((COMMAND *)); -static void _print_word_list __P((WORD_LIST *, char *, PFUNC *)); -static void command_print_word_list __P((WORD_LIST *, char *)); -static void print_case_clauses __P((PATTERN_LIST *)); -static void print_redirection_list __P((REDIRECT *)); -static void print_redirection __P((REDIRECT *)); - -static void print_for_command __P((FOR_COM *)); -#if defined (ARITH_FOR_COMMAND) -static void print_arith_for_command __P((ARITH_FOR_COM *)); -#endif -#if defined (SELECT_COMMAND) -static void print_select_command __P((SELECT_COM *)); -#endif -static void print_group_command __P((GROUP_COM *)); -static void print_case_command __P((CASE_COM *)); -static void print_while_command __P((WHILE_COM *)); -static void print_until_command __P((WHILE_COM *)); -static void print_until_or_while __P((WHILE_COM *, char *)); -static void print_if_command __P((IF_COM *)); -#if defined (COND_COMMAND) -static void print_cond_node __P((COND_COM *)); -#endif -static void print_function_def __P((FUNCTION_DEF *)); - -#define PRINTED_COMMAND_INITIAL_SIZE 64 -#define PRINTED_COMMAND_GROW_SIZE 128 - -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; -static int skip_this_indent; -static int was_heredoc; - -/* 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; - -/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */ -static char indirection_string[100]; - -/* 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 = was_heredoc = 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 == 0) - cprintf (""); - else - { - if (skip_this_indent) - skip_this_indent--; - else - indent (indentation); - - if (command->flags & CMD_TIME_PIPELINE) - { - cprintf ("time "); - if (command->flags & CMD_TIME_POSIX) - cprintf ("-p "); - } - - if (command->flags & CMD_INVERT_RETURN) - cprintf ("! "); - - switch (command->type) - { - case cm_for: - print_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - print_arith_for_command (command->value.ArithFor); - break; -#endif - -#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; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - print_arith_command (command->value.Arith->exp); - break; -#endif - -#if defined (COND_COMMAND) - case cm_cond: - print_cond_command (command->value.Cond); - break; -#endif - - 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 ';': - if (was_heredoc == 0) - cprintf (";"); - else - was_heredoc = 0; - - 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; - - case cm_subshell: - cprintf ("( "); - skip_this_indent++; - make_command_string_internal (command->value.Subshell->command); - cprintf (" )"); - break; - - default: - command_error ("print_command", CMDERR_BADTYPE, command->type, 0); - break; - } - - - if (command->redirects) - { - cprintf (" "); - print_redirection_list (command->redirects); - } - } -} - -static void -_print_word_list (list, separator, pfunc) - WORD_LIST *list; - char *separator; - PFUNC *pfunc; -{ - WORD_LIST *w; - - for (w = list; w; w = w->next) - (*pfunc) ("%s%s", w->word->word, w->next ? separator : ""); -} - -void -print_word_list (list, separator) - WORD_LIST *list; - char *separator; -{ - _print_word_list (list, separator, xprintf); -} - -/* Return a string denoting what our indirection level is. */ - -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); - - change_flag ('x', FLAG_OFF); - ps4 = decode_prompt_string (ps4); - change_flag ('x', FLAG_ON); - - if (ps4 == 0 || *ps4 == '\0') - return (indirection_string); - - 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); -} - -void -xtrace_print_assignment (name, value, assign_list, xflags) - char *name, *value; - int assign_list, xflags; -{ - char *nval; - - if (xflags) - fprintf (stderr, "%s", indirection_level_string ()); - - /* VALUE should not be NULL when this is called. */ - if (*value == '\0 || assign_list) - nval = value; - else if (sh_contains_shell_metas (value)) - nval = sh_single_quote (value); - else if (ansic_shouldquote (value)) - nval = ansic_quote (value, 0, (int *)0); - else - nval = value; - - if (assign_list) - fprintf (stderr, "%s=(%s)\n", name, nval); - else - fprintf (stderr, "%s=%s\n", name, nval); - - if (nval != value) - FREE (nval); - - fflush (stderr); -} - -/* A function to print the words of a simple command when set -x is on. */ -void -xtrace_print_word_list (list, xtflags) - WORD_LIST *list; - int xtflags; -{ - WORD_LIST *w; - char *t, *x; - - if (xtflags) - fprintf (stderr, "%s", indirection_level_string ()); - - for (w = list; w; w = w->next) - { - t = w->word->word; - if (t == 0 || *t == '\0') - fprintf (stderr, "''%s", w->next ? " " : ""); - else if (sh_contains_shell_metas (t)) - { - x = sh_single_quote (t); - fprintf (stderr, "%s%s", x, w->next ? " " : ""); - free (x); - } - else if (ansic_shouldquote (t)) - { - x = ansic_quote (t, 0, (int *)0); - fprintf (stderr, "%s%s", x, w->next ? " " : ""); - free (x); - } - else - fprintf (stderr, "%s%s", t, w->next ? " " : ""); - } - fprintf (stderr, "\n"); -} - -static void -command_print_word_list (list, separator) - WORD_LIST *list; - char *separator; -{ - _print_word_list (list, separator, cprintf); -} - -void -print_for_command_head (for_command) - FOR_COM *for_command; -{ - cprintf ("for %s in ", for_command->name->word); - command_print_word_list (for_command->map_list, " "); -} - -void -xtrace_print_for_command_head (for_command) - FOR_COM *for_command; -{ - fprintf (stderr, "%s", indirection_level_string ()); - fprintf (stderr, "for %s in ", for_command->name->word); - xtrace_print_word_list (for_command->map_list, 0); -} - -static void -print_for_command (for_command) - FOR_COM *for_command; -{ - print_for_command_head (for_command); - - cprintf (";"); - newline ("do\n"); - indentation += indentation_amount; - make_command_string_internal (for_command->action); - semicolon (); - indentation -= indentation_amount; - newline ("done"); -} - -#if defined (ARITH_FOR_COMMAND) -static void -print_arith_for_command (arith_for_command) - ARITH_FOR_COM *arith_for_command; -{ - cprintf ("for (("); - command_print_word_list (arith_for_command->init, " "); - cprintf (" ; "); - command_print_word_list (arith_for_command->test, " "); - cprintf (" ; "); - command_print_word_list (arith_for_command->step, " "); - cprintf ("))"); - newline ("do\n"); - indentation += indentation_amount; - make_command_string_internal (arith_for_command->action); - semicolon (); - indentation -= indentation_amount; - newline ("done"); -} -#endif /* ARITH_FOR_COMMAND */ - -#if defined (SELECT_COMMAND) -void -print_select_command_head (select_command) - SELECT_COM *select_command; -{ - cprintf ("select %s in ", select_command->name->word); - command_print_word_list (select_command->map_list, " "); -} - -void -xtrace_print_select_command_head (select_command) - SELECT_COM *select_command; -{ - fprintf (stderr, "%s", indirection_level_string ()); - fprintf (stderr, "select %s in ", select_command->name->word); - xtrace_print_word_list (select_command->map_list, 0); -} - -static void -print_select_command (select_command) - SELECT_COM *select_command; -{ - print_select_command_head (select_command); - - 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 == 0) - skip_this_indent++; - else - { - /* This is a group command { ... } inside of a function - definition, and should be printed as a multiline group - command, using the current indentation. */ - cprintf ("\n"); - indentation += indentation_amount; - } - - make_command_string_internal (group_command->command); - - if (inside_function_def) - { - cprintf ("\n"); - indentation -= indentation_amount; - indent (indentation); - } - else - { - semicolon (); - cprintf (" "); - } - - cprintf ("}"); - - group_command_nesting--; -} - -void -print_case_command_head (case_command) - CASE_COM *case_command; -{ - cprintf ("case %s in ", case_command->word->word); -} - -void -xtrace_print_case_command_head (case_command) - CASE_COM *case_command; -{ - fprintf (stderr, "%s", indirection_level_string ()); - fprintf (stderr, "case %s in\n", case_command->word->word); -} - -static void -print_case_command (case_command) - CASE_COM *case_command; -{ - print_case_command_head (case_command); - - 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"); -} - -#if defined (DPAREN_ARITHMETIC) -void -print_arith_command (arith_cmd_list) - WORD_LIST *arith_cmd_list; -{ - cprintf ("(("); - command_print_word_list (arith_cmd_list, " "); - cprintf ("))"); -} -#endif - -#if defined (COND_COMMAND) -static void -print_cond_node (cond) - COND_COM *cond; -{ - if (cond->flags & CMD_INVERT_RETURN) - cprintf ("! "); - - if (cond->type == COND_EXPR) - { - cprintf ("( "); - print_cond_node (cond->left); - cprintf (" )"); - } - else if (cond->type == COND_AND) - { - print_cond_node (cond->left); - cprintf (" && "); - print_cond_node (cond->right); - } - else if (cond->type == COND_OR) - { - print_cond_node (cond->left); - cprintf (" || "); - print_cond_node (cond->right); - } - else if (cond->type == COND_UNARY) - { - cprintf ("%s", cond->op->word); - cprintf (" "); - print_cond_node (cond->left); - } - else if (cond->type == COND_BINARY) - { - print_cond_node (cond->left); - cprintf (" "); - cprintf ("%s", cond->op->word); - cprintf (" "); - print_cond_node (cond->right); - } - else if (cond->type == COND_TERM) - { - cprintf ("%s", cond->op->word); /* need to add quoting here */ - } -} - -void -print_cond_command (cond) - COND_COM *cond; -{ - cprintf ("[[ "); - print_cond_node (cond); - cprintf (" ]]"); -} - -#ifdef DEBUG -void -debug_print_cond_command (cond) - COND_COM *cond; -{ - fprintf (stderr, "DEBUG: "); - command_string_index = 0; - print_cond_command (cond); - fprintf (stderr, "%s\n", the_printed_command); -} -#endif - -void -xtrace_print_cond_term (type, invert, op, arg1, arg2) - int type, invert; - WORD_DESC *op; - char *arg1, *arg2; -{ - command_string_index = 0; - fprintf (stderr, "%s", indirection_level_string ()); - fprintf (stderr, "[[ "); - if (invert) - fprintf (stderr, "! "); - - if (type == COND_UNARY) - { - fprintf (stderr, "%s ", op->word); - fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''"); - } - else if (type == COND_BINARY) - { - fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''"); - fprintf (stderr, " %s ", op->word); - fprintf (stderr, "%s", (arg2 && *arg2) ? arg2 : "''"); - } - - fprintf (stderr, " ]]\n"); -} -#endif /* COND_COMMAND */ - -#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND) -/* A function to print the words of an arithmetic command when set -x is on. */ -void -xtrace_print_arith_cmd (list) - WORD_LIST *list; -{ - WORD_LIST *w; - - fprintf (stderr, "%s", indirection_level_string ()); - fprintf (stderr, "(( "); - for (w = list; w; w = w->next) - fprintf (stderr, "%s%s", w->word->word, w->next ? " " : ""); - fprintf (stderr, " ))\n"); -} -#endif - -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; -{ - REDIRECT *heredocs, *hdtail, *newredir; - - heredocs = (REDIRECT *)NULL; - hdtail = heredocs; - - was_heredoc = 0; - while (redirects) - { - /* Defer printing the here documents until we've printed the - rest of the redirections. */ - if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until) - { - newredir = copy_redirect (redirects); - newredir->next = (REDIRECT *)NULL; - if (heredocs) - { - hdtail->next = newredir; - hdtail = newredir; - } - else - hdtail = heredocs = newredir; - } - else if (redirects->instruction == r_duplicating_output_word && redirects->redirector == 1) - { - /* Temporarily translate it as the execution code does. */ - redirects->instruction = r_err_and_out; - print_redirection (redirects); - redirects->instruction = r_duplicating_output_word; - } - else - print_redirection (redirects); - - redirects = redirects->next; - if (redirects) - cprintf (" "); - } - - /* Now that we've printed all the other redirections (on one line), - print the here documents. */ - if (heredocs) - { - cprintf (" "); - for (hdtail = heredocs; hdtail; hdtail = hdtail->next) - { - print_redirection (hdtail); - cprintf ("\n"); - } - dispose_redirects (heredocs); - was_heredoc = 1; - } -} - -static void -print_redirection (redirect) - REDIRECT *redirect; -{ - int kill_leading, redirector, redir_fd; - WORD_DESC *redirectee; - - kill_leading = 0; - redirectee = redirect->redirectee.filename; - redirector = redirect->redirector; - 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->flags & W_QUOTED) - { - char *x; - x = sh_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_reading_string: - if (redirector != 0) - cprintf ("%d", redirector); - if (ansic_shouldquote (redirect->redirectee.filename->word)) - { - char *x; - x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0); - cprintf ("<<< %s", x); - free (x); - } - else - cprintf ("<<< %s", redirect->redirectee.filename->word); - 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_move_input: - cprintf ("%d<&%d-", redirector, redir_fd); - break; - - case r_move_output: - cprintf ("%d>&%d-", redirector, redir_fd); - break; - - case r_move_input_word: - cprintf ("%d<&%s-", redirector, redirectee->word); - break; - - case r_move_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; -{ - COMMAND *cmdcopy; - REDIRECT *func_redirects; - - func_redirects = NULL; - cprintf ("function %s () \n", func->name->word); - add_unwind_protect (reset_locals, 0); - - indent (indentation); - cprintf ("{ \n"); - - inside_function_def++; - indentation += indentation_amount; - - cmdcopy = copy_command (func->command); - if (cmdcopy->type == cm_group) - { - func_redirects = cmdcopy->redirects; - cmdcopy->redirects = (REDIRECT *)NULL; - } - make_command_string_internal (cmdcopy->type == cm_group - ? cmdcopy->value.Group->command - : cmdcopy); - - remove_unwind_protect (); - indentation -= indentation_amount; - inside_function_def--; - - if (func_redirects) - { /* { */ - newline ("} "); - print_redirection_list (func_redirects); - cmdcopy->redirects = func_redirects; - } - else - newline ("}"); - - dispose_command (cmdcopy); -} - -/* 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, old_amount; - COMMAND *cmdcopy; - REDIRECT *func_redirects; - - old_indent = indentation; - old_amount = indentation_amount; - command_string_index = was_heredoc = 0; - - if (name && *name) - cprintf ("%s ", name); - - cprintf ("() "); - - if (multi_line == 0) - { - indentation = 1; - indentation_amount = 0; - } - else - { - cprintf ("\n"); - indentation += indentation_amount; - } - - inside_function_def++; - - cprintf (multi_line ? "{ \n" : "{ "); - - cmdcopy = copy_command (command); - /* Take any redirections specified in the function definition (which should - apply to the function as a whole) and save them for printing later. */ - func_redirects = (REDIRECT *)NULL; - if (cmdcopy->type == cm_group) - { - func_redirects = cmdcopy->redirects; - cmdcopy->redirects = (REDIRECT *)NULL; - } - make_command_string_internal (cmdcopy->type == cm_group - ? cmdcopy->value.Group->command - : cmdcopy); - - indentation = old_indent; - indentation_amount = old_amount; - inside_function_def--; - - if (func_redirects) - { /* { */ - newline ("} "); - print_redirection_list (func_redirects); - cmdcopy->redirects = func_redirects; - } - else - 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 - } - - dispose_command (cmdcopy); - - return (result); -} - -static void -newline (string) - char *string; -{ - cprintf ("\n"); - indent (indentation); - if (string && *string) - cprintf ("%s", string); -} - -static char *indentation_string; -static int indentation_size; - -static void -indent (amount) - int amount; -{ - register int i; - - RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16); - - for (i = 0; amount > 0; amount--) - indentation_string[i++] = ' '; - indentation_string[i] = '\0'; - cprintf (indentation_string); -} - -static void -semicolon () -{ - if (command_string_index > 0 && - (the_printed_command[command_string_index - 1] == '&' || - the_printed_command[command_string_index - 1] == '\n')) - return; - cprintf (";"); -} - -/* How to make the string. */ -static void -#if defined (PREFER_STDARG) -cprintf (const char *control, ...) -#else -cprintf (control, va_alist) - const char *control; - va_dcl -#endif -{ - register const char *s; - char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (int) + 1]; - int digit_arg, arg_len, c; - va_list args; - - SH_VA_START (args, control); - - arg_len = strlen (control); - the_printed_command_resize (arg_len + 1); - - char_arg[1] = '\0'; - s = control; - while (s && *s) - { - c = *s++; - argp = (char *)NULL; - if (c != '%' || !*s) - { - char_arg[0] = c; - argp = char_arg; - 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': - /* Represent an out-of-range file descriptor with an out-of-range - integer value. We can do this because the only use of `%d' in - the calls to cprintf is to output a file descriptor number for - a redirection. */ - digit_arg = va_arg (args, int); - if (digit_arg < 0) - { - sprintf (intbuf, "%u", (unsigned)-1); - argp = intbuf; - } - else - argp = inttostr (digit_arg, intbuf, sizeof (intbuf)); - arg_len = strlen (argp); - break; - - case 'c': - char_arg[0] = va_arg (args, int); - argp = char_arg; - arg_len = 1; - break; - - default: - programming_error (_("cprintf: `%c': invalid format character"), c); - /*NOTREACHED*/ - } - } - - if (argp && arg_len) - { - the_printed_command_resize (arg_len + 1); - FASTCOPY (argp, the_printed_command + command_string_index, arg_len); - command_string_index += arg_len; - } - } - - the_printed_command[command_string_index] = '\0'; -} - -/* 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 == 0) - { - the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1); - the_printed_command = (char *)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; - - /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */ - new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1); - the_printed_command_size = new; - - the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size); - } -} - -#if defined (HAVE_VPRINTF) -/* ``If vprintf is available, you may assume that vfprintf and vsprintf are - also available.'' */ - -static void -#if defined (PREFER_STDARG) -xprintf (const char *format, ...) -#else -xprintf (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - SH_VA_START (args, format); - - vfprintf (stdout, format, args); - va_end (args); -} - -#else - -static void -xprintf (format, arg1, arg2, arg3, arg4, arg5) - const char *format; -{ - printf (format, arg1, arg2, arg3, arg4, arg5); -} - -#endif /* !HAVE_VPRINTF */ diff --git a/shell.c~ b/shell.c~ deleted file mode 100644 index 9be750336..000000000 --- a/shell.c~ +++ /dev/null @@ -1,1786 +0,0 @@ -/* shell.c -- GNU's idea of the POSIX shell specification. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. - - Birthdate: - Sunday, January 10th, 1988. - Initial author: Brian Fox -*/ -#define INSTALL_DEBUG_MODE - -#include "config.h" - -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#include "posixtime.h" -#include "bashansi.h" -#include -#include -#include -#include "filecntl.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" - -#define NEED_SH_SETLINEBUF_DECL /* used in externs.h */ - -#include "shell.h" -#include "flags.h" -#include "trap.h" -#include "mailcheck.h" -#include "builtins.h" -#include "builtins/common.h" - -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif /* JOB_CONTROL */ - -#include "input.h" -#include "execute_cmd.h" -#include "findcmd.h" - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include -#endif - -#include -#include - -#if defined (__OPENNT) -# include -#endif - -#if !defined (HAVE_GETPW_DECLS) -extern struct passwd *getpwuid (); -#endif /* !HAVE_GETPW_DECLS */ - -#if !defined (errno) -extern int errno; -#endif - -#if defined (NO_MAIN_ENV_ARG) -extern char **environ; /* used if no third argument to main() */ -#endif - -extern char *dist_version, *release_status; -extern int patch_level, build_version; -extern int shell_level; -extern int subshell_environment; -extern int last_command_exit_value; -extern int line_number; -extern char *primary_prompt, *secondary_prompt; -extern int expand_aliases; -extern char *this_command_name; -extern int array_needs_making; - -/* Non-zero means that this shell has already been run; i.e. you should - call shell_reinitialize () if you need to start afresh. */ -int shell_initialized = 0; - -COMMAND *global_command = (COMMAND *)NULL; - -/* Information about the current user. */ -struct user_info current_user = -{ - (uid_t)-1, (uid_t)-1, (gid_t)-1, (gid_t)-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" (or -l) 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; - -/* Non-zero means to send a SIGHUP to all jobs when an interactive login - shell exits. */ -int hup_on_exit = 0; - -/* Tells what state the shell was in when it started: - 0 = non-interactive shell script - 1 = interactive - 2 = -c command - 3 = wordexp evaluation - 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; - -/* Non-zero is the recursion depth for commands. */ -int indirection_level = 0; - -/* The name of this shell, as taken from argv[0]. */ -char *shell_name = (char *)NULL; - -/* time in seconds when the shell was started */ -time_t shell_start_time; - -/* Are we running in an emacs shell window? */ -int running_under_emacs; - -/* The name of the .(shell)rc file. */ -static char *bashrc_file = "~/.bashrc"; - -/* Non-zero means to act more like the Bourne shell on startup. */ -static int act_like_sh; - -/* Non-zero if this shell is being run by `su'. */ -static int su_shell; - -/* Non-zero if we have already expanded and sourced $ENV. */ -static int sourced_env; - -/* Is this shell running setuid? */ -static int running_setuid; - -/* Values for the long-winded argument names. */ -static int debugging; /* Do debugging things. */ -static int no_rc; /* Don't execute ~/.bashrc */ -static int no_profile; /* Don't execute .profile */ -static int do_version; /* Display interesting version info. */ -static int make_login_shell; /* Make this shell be a `-bash' shell. */ -static int want_initial_help; /* --help option */ - -int debugging_mode = 0; /* In debugging mode with --debugger */ -int no_line_editing = 0; /* Don't do fancy line editing. */ -int posixly_correct = 0; /* Non-zero means posix.2 superset. */ -int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ -int dump_po_strings; /* Dump strings in $"..." in po format */ -int wordexp_only = 0; /* Do word expansion only */ -int protected_mode = 0; /* No command substitution with --wordexp */ - -/* 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 }, -#if defined (DEBUGGER) - { "debugger", Int, &debugging_mode, (char **)0x0 }, -#endif - { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 }, - { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, - { "help", Int, &want_initial_help, (char **)0x0 }, - { "init-file", Charp, (int *)0x0, &bashrc_file }, - { "login", Int, &make_login_shell, (char **)0x0 }, - { "noediting", Int, &no_line_editing, (char **)0x0 }, - { "noprofile", Int, &no_profile, (char **)0x0 }, - { "norc", Int, &no_rc, (char **)0x0 }, - { "posix", Int, &posixly_correct, (char **)0x0 }, - { "protected", Int, &protected_mode, (char **)0x0 }, - { "rcfile", Charp, (int *)0x0, &bashrc_file }, -#if defined (RESTRICTED_SHELL) - { "restricted", Int, &restricted, (char **)0x0 }, -#endif - { "verbose", Int, &echo_input_at_read, (char **)0x0 }, - { "version", Int, &do_version, (char **)0x0 }, - { "wordexp", Int, &wordexp_only, (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. */ -procenv_t 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 - -/* The following two variables are not static so they can show up in $-. */ -int read_from_stdin; /* -s flag supplied */ -int want_pending_command; /* -c flag supplied */ - -/* This variable is not static so it can be bound to $BASH_EXECUTION_STRING */ -char *command_execution_string; /* argument to -c option */ - -int malloc_trace_at_exit = 0; - -static int shell_reinitialized = 0; - -static FILE *default_input; - -static STRING_INT_ALIST *shopt_alist; -static int shopt_ind = 0, shopt_len = 0; - -static int parse_long_options __P((char **, int, int)); -static int parse_shell_options __P((char **, int, int)); -static int bind_args __P((char **, int, int, int)); - -static void start_debugger __P((void)); - -static void add_shopt_to_alist __P((char *, int)); -static void run_shopt_alist __P((void)); - -static void execute_env_file __P((char *)); -static void run_startup_files __P((void)); -static int open_shell_script __P((char *)); -static void set_bash_input __P((void)); -static int run_one_command __P((char *)); -static int run_wordexp __P((char *)); - -static int uidget __P((void)); - -static void init_interactive __P((void)); -static void init_noninteractive __P((void)); - -static void set_shell_name __P((char *)); -static void shell_initialize __P((void)); -static void shell_reinitialize __P((void)); - -static void show_shell_usage __P((FILE *, int)); - -#ifdef __CYGWIN__ -static void -_cygwin32_check_tmp () -{ - struct stat sb; - - if (stat ("/tmp", &sb) < 0) - internal_warning (_("could not find /tmp, please create!")); - else - { - if (S_ISDIR (sb.st_mode) == 0) - internal_warning (_("/tmp must be a valid directory name")); - } -} -#endif /* __CYGWIN__ */ - -#if defined (NO_MAIN_ENV_ARG) -/* systems without third argument to main() */ -int -main (argc, argv) - int argc; - char **argv; -#else /* !NO_MAIN_ENV_ARG */ -int -main (argc, argv, env) - int argc; - char **argv, **env; -#endif /* !NO_MAIN_ENV_ARG */ -{ - register int i; - int code, old_errexit_flag; -#if defined (RESTRICTED_SHELL) - int saverst; -#endif - volatile int locally_skip_execution; - volatile int arg_index, top_level_arg_index; -#ifdef __OPENNT - char **env; - - env = environ; -#endif /* __OPENNT */ - - USE_VAR(argc); - USE_VAR(argv); - USE_VAR(env); - USE_VAR(code); - USE_VAR(old_errexit_flag); -#if defined (RESTRICTED_SHELL) - USE_VAR(saverst); -#endif - - /* Catch early SIGINTs. */ - code = setjmp (top_level); - if (code) - exit (2); - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# if 1 - malloc_set_register (1); -# endif -#endif - - check_dev_tty (); - -#ifdef __CYGWIN__ - _cygwin32_check_tmp (); -#endif /* __CYGWIN__ */ - - /* Wait forever if we are debugging a login shell. */ - while (debugging_login_shell); - - set_default_locale (); - - running_setuid = uidget (); - - if (getenv ("POSIXLY_CORRECT") || getenv ("POSIX_PEDANTIC")) - posixly_correct = 1; - -#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; - } - - shell_reinitialized = 0; - - /* Initialize `local' variables for all `invocations' of main (). */ - arg_index = 1; - command_execution_string = (char *)NULL; - want_pending_command = locally_skip_execution = 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); - } - - shell_environment = env; - set_shell_name (argv[0]); - shell_start_time = NOW; /* NOW now defined in general.h */ - - /* Parse argument flags from the input line. */ - - /* Find full word arguments first. */ - arg_index = parse_long_options (argv, arg_index, argc); - - if (want_initial_help) - { - show_shell_usage (stdout, 1); - exit (EXECUTION_SUCCESS); - } - - if (do_version) - { - show_shell_version (1); - exit (EXECUTION_SUCCESS); - } - - /* All done with full word options; do standard shell option parsing.*/ - this_command_name = shell_name; /* for error reporting */ - arg_index = parse_shell_options (argv, arg_index, argc); - - /* If user supplied the "--login" (or -l) flag, then set and invert - LOGIN_SHELL. */ - if (make_login_shell) - { - login_shell++; - login_shell = -login_shell; - } - - set_login_shell (login_shell != 0); - - if (dump_po_strings) - dump_translatable_strings = 1; - - if (dump_translatable_strings) - read_but_dont_execute = 1; - - if (running_setuid && privileged_mode == 0) - disable_priv_mode (); - - /* Need to get the argument to a -c option processed in the - above loop. The next arg is a command to execute, and the - following args are $0...$n respectively. */ - if (want_pending_command) - { - command_execution_string = argv[arg_index]; - if (command_execution_string == 0) - { - report_error (_("%s: option requires an argument"), "-c"); - exit (EX_BADUSAGE); - } - arg_index++; - } - this_command_name = (char *)NULL; - - cmd_init(); /* initialize the command object caches */ - - /* 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 */ - (!command_execution_string && /* No -c command and ... */ - wordexp_only == 0 && /* No --wordexp 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. */ - init_interactive (); - else - init_noninteractive (); - -#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 */ - - /* If we're in a strict Posix.2 mode, turn on interactive comments, - alias expansion in non-interactive shells, and other Posix.2 things. */ - if (posixly_correct) - { - bind_variable ("POSIXLY_CORRECT", "y"); - sv_strict_posix ("POSIXLY_CORRECT"); - } - - /* Now we run the shopt_alist and process the options. */ - if (shopt_alist) - run_shopt_alist (); - - /* From here on in, the shell must be a normal functioning shell. - Variables from the environment are expected to be set, etc. */ - shell_initialize (); - - set_default_locale_vars (); - - if (interactive_shell) - { - char *term, *emacs; - - term = get_string_value ("TERM"); - no_line_editing |= term && (STREQ (term, "emacs")); - emacs = get_string_value ("EMACS"); - running_under_emacs = emacs ? ((strmatch ("*term*", emacs, 0) == 0) ? 2 : 1) - : 0; -#if 0 - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0'; -#else - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); -#endif - } - - top_level_arg_index = arg_index; - old_errexit_flag = exit_immediately_on_error; - - /* 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. */ - code = setjmp (top_level); - if (code) - { - if (code == EXITPROG || code == ERREXIT) - exit_shell (last_command_exit_value); - else - { -#if defined (JOB_CONTROL) - /* Reset job control, since run_startup_files turned it off. */ - set_job_control (interactive_shell); -#endif - /* Reset value of `set -e', since it's turned off before running - the startup files. */ - exit_immediately_on_error += old_errexit_flag; - locally_skip_execution++; - } - } - - arg_index = top_level_arg_index; - - /* Execute the start-up scripts. */ - - if (interactive_shell == 0) - { - unbind_variable ("PS1"); - unbind_variable ("PS2"); - interactive = 0; -#if 0 - /* This has already been done by init_noninteractive */ - expand_aliases = posixly_correct; -#endif - } - else - { - change_flag ('i', FLAG_ON); - interactive = 1; - } - -#if defined (RESTRICTED_SHELL) - /* Set restricted_shell based on whether the basename of $0 indicates that - the shell should be restricted or if the `-r' option was supplied at - startup. */ - restricted_shell = shell_is_restricted (shell_name); - - /* If the `-r' option is supplied at invocation, make sure that the shell - is not in restricted mode when running the startup files. */ - saverst = restricted; - restricted = 0; -#endif - - /* The startup files are run with `set -e' temporarily disabled. */ - if (locally_skip_execution == 0 && running_setuid == 0) - { - old_errexit_flag = exit_immediately_on_error; - exit_immediately_on_error = 0; - - run_startup_files (); - exit_immediately_on_error += old_errexit_flag; - } - - /* If we are invoked as `sh', turn on Posix mode. */ - if (act_like_sh) - { - bind_variable ("POSIXLY_CORRECT", "y"); - sv_strict_posix ("POSIXLY_CORRECT"); - } - -#if defined (RESTRICTED_SHELL) - /* Turn on the restrictions after executing the startup files. This - means that `bash -r' or `set -r' invoked from a startup file will - turn on the restrictions after the startup files are executed. */ - restricted = saverst || restricted; - if (shell_reinitialized == 0) - maybe_make_restricted (shell_name); -#endif /* RESTRICTED_SHELL */ - - if (wordexp_only) - { - startup_state = 3; - last_command_exit_value = run_wordexp (argv[arg_index]); - exit_shell (last_command_exit_value); - } - - if (command_execution_string) - { - arg_index = bind_args (argv, arg_index, argc, 0); - startup_state = 2; - - if (debugging_mode) - start_debugger (); - -#if defined (ONESHOT) - executing = 1; - run_one_command (command_execution_string); - exit_shell (last_command_exit_value); -#else /* ONESHOT */ - with_input_from_string (command_execution_string, "-c"); - goto read_and_execute; -#endif /* !ONESHOT */ - } - - /* Get possible input filename and set up default_buffered_input or - default_input as appropriate. */ - if (arg_index != argc && read_from_stdin == 0) - { - open_shell_script (argv[arg_index]); - arg_index++; - } - else if (interactive == 0) - /* In this mode, bash is reading a script from stdin, which is a - pipe or redirected file. */ -#if defined (BUFFERED_INPUT) - default_buffered_input = fileno (stdin); /* == 0 */ -#else - setbuf (default_input, (char *)NULL); -#endif /* !BUFFERED_INPUT */ - - set_bash_input (); - - /* Bind remaining args to $1 ... $n */ - arg_index = bind_args (argv, arg_index, argc, 1); - - if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0) - start_debugger (); - - /* 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. */ - bash_initialize_history (); - /* Don't load the history from the history file if we've already - saved some lines in this session (e.g., by putting `history -s xx' - into one of the startup files). */ - if (shell_initialized == 0 && history_lines_this_session == 0) - load_history (); -#endif /* HISTORY */ - - /* Initialize terminal state for interactive shells after the - .bash_profile and .bashrc are interpreted. */ - get_tty_state (); - } - -#if !defined (ONESHOT) - read_and_execute: -#endif /* !ONESHOT */ - - shell_initialized = 1; - - /* Read commands until exit condition. */ - reader_loop (); - exit_shell (last_command_exit_value); -} - -static int -parse_long_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index, longarg, i; - char *arg_string; - - arg_index = arg_start; - while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && - (*arg_string == '-')) - { - longarg = 0; - - /* Make --login equivalent to -login. */ - if (arg_string[1] == '-' && arg_string[2]) - { - longarg = 1; - arg_string++; - } - - for (i = 0; long_args[i].name; i++) - { - if (STREQ (arg_string + 1, long_args[i].name)) - { - if (long_args[i].type == Int) - *long_args[i].int_value = 1; - else if (argv[++arg_index] == 0) - { - report_error (_("%s: option requires an argument"), long_args[i].name); - exit (EX_BADUSAGE); - } - else - *long_args[i].char_value = argv[arg_index]; - - break; - } - } - if (long_args[i].name == 0) - { - if (longarg) - { - report_error (_("%s: invalid option"), argv[arg_index]); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - break; /* No such argument. Maybe flag arg. */ - } - - arg_index++; - } - - return (arg_index); -} - -static int -parse_shell_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index; - int arg_character, on_or_off, next_arg, i; - char *o_option, *arg_string; - - arg_index = arg_start; - while (arg_index != arg_end && (arg_string = argv[arg_index]) && - (*arg_string == '-' || *arg_string == '+')) - { - /* There are flag arguments, so parse them. */ - next_arg = arg_index + 1; - - /* A single `-' signals the end of options. From the 4.3 BSD sh. - An option `--' means the same thing; this is the standard - getopt(3) meaning. */ - if (arg_string[0] == '-' && - (arg_string[1] == '\0' || - (arg_string[1] == '-' && arg_string[2] == '\0'))) - return (next_arg); - - i = 1; - on_or_off = arg_string[0]; - while (arg_character = arg_string[i++]) - { - switch (arg_character) - { - case 'c': - want_pending_command = 1; - break; - - case 'l': - make_login_shell = 1; - break; - - case 's': - read_from_stdin = 1; - break; - - case 'o': - o_option = argv[next_arg]; - if (o_option == 0) - { - list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); - break; - } - if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - next_arg++; - break; - - case 'O': - /* Since some of these can be overridden by the normal - interactive/non-interactive shell initialization or - initializing posix mode, we save the options and process - them after initialization. */ - o_option = argv[next_arg]; - if (o_option == 0) - { - shopt_listopt (o_option, (on_or_off == '-') ? 0 : 1); - break; - } - add_shopt_to_alist (o_option, on_or_off); - next_arg++; - break; - - case 'D': - dump_translatable_strings = 1; - break; - - default: - if (change_flag (arg_character, on_or_off) == FLAG_ERROR) - { - report_error (_("%c%c: invalid option"), on_or_off, arg_character); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - } - } - /* Can't do just a simple increment anymore -- what about - "bash -abouo emacs ignoreeof -hP"? */ - arg_index = next_arg; - } - - return (arg_index); -} - -/* Exit the shell with status S. */ -void -exit_shell (s) - int s; -{ - /* Do trap[0] if defined. Allow it to override the exit status - passed to us. */ - if (signal_is_trapped (0)) - s = run_exit_trap (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (HISTORY) - if (interactive_shell) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (JOB_CONTROL) - /* If the user has run `shopt -s huponexit', hangup all jobs when we exit - an interactive login shell. ksh does this unconditionally. */ - if (interactive_shell && login_shell && hup_on_exit) - hangup_all_jobs (); - - /* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. Don't do this if we're - in a subshell and calling exit_shell after, for example, a failed - word expansion. */ - if (subshell_environment == 0) - end_job_control (); -#endif /* JOB_CONTROL */ - - /* Always return the exit status of the last command to our parent. */ - sh_exit (s); -} - -/* A wrapper for exit that (optionally) can do other things, like malloc - statistics tracing. */ -void -sh_exit (s) - int s; -{ -#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC) - if (malloc_trace_at_exit) - trace_malloc_stats (get_name_for_error (), (char *)NULL); -#endif - - exit (s); -} - -/* 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 interactive shells only. (section 4.56.5.3) */ - -/* 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 -*/ - -static void -execute_env_file (env_file) - char *env_file; -{ - char *fn; - - if (env_file && *env_file) - { - fn = expand_string_unsplit_to_string (env_file, Q_DOUBLE_QUOTES); - if (fn && *fn) - maybe_execute_file (fn, 1); - FREE (fn); - } -} - -static void -run_startup_files () -{ -#if defined (JOB_CONTROL) - int old_job_control; -#endif - int sourced_login, run_by_ssh; - - /* get the rshd/sshd case out of the way first. */ - if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && - act_like_sh == 0 && command_execution_string) - { -#ifdef SSH_SOURCE_BASHRC - run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) || - (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); -#else - run_by_ssh = 0; -#endif - - /* If we were run by sshd or we think we were run by rshd, execute - ~/.bashrc if we are a top-level shell. */ - if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - return; - } - } - -#if defined (JOB_CONTROL) - /* Startup files should be run without job control enabled. */ - old_job_control = interactive_shell ? set_job_control (0) : 0; -#endif - - sourced_login = 0; - - /* A shell begun with the --login (or -l) flag that is not in posix mode - runs the login shell startup files, no matter whether or not it is - interactive. If NON_INTERACTIVE_LOGIN_SHELLS is defined, run the - startup files if argv[0][0] == '-' as well. */ -#if defined (NON_INTERACTIVE_LOGIN_SHELLS) - if (login_shell && posixly_correct == 0) -#else - if (login_shell < 0 && posixly_correct == 0) -#endif - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - - sourced_login = 1; - } - - /* A non-interactive shell not named `sh' and not in posix mode reads and - executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd' - and `-su' as the name of the shell, we want to read the startup files. - No other non-interactive shells read any startup files. */ - if (interactive_shell == 0 && !(su_shell && login_shell)) - { - if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 && - sourced_env++ == 0) - execute_env_file (get_string_value ("BASH_ENV")); - return; - } - - /* Interactive shell or `-su' shell. */ - if (posixly_correct == 0) /* bash, sh */ - { - if (login_shell && sourced_login++ == 0) - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - } - - /* bash */ - if (act_like_sh == 0 && no_rc == 0) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - } - /* sh */ - else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - else /* bash --posix, sh --posix */ - { - /* bash and sh */ - if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - -#if defined (JOB_CONTROL) - set_job_control (old_job_control); -#endif -} - -#if defined (RESTRICTED_SHELL) -/* Return 1 if the shell should be a restricted one based on NAME or the - value of `restricted'. Don't actually do anything, just return a - boolean value. */ -int -shell_is_restricted (name) - char *name; -{ - char *temp; - - if (restricted) - return 1; - temp = base_pathname (name); - return (STREQ (temp, RESTRICTED_SHELL_NAME)); -} - -/* Perhaps make this shell a `restricted' one, based on NAME. If the - basename of NAME is "rbash", then this shell is restricted. The - name of the restricted shell is a configurable option, see config.h. - In a restricted shell, PATH, SHELL, ENV, and BASH_ENV are read-only - and non-unsettable. - Do this also if `restricted' is already set to 1; maybe the shell was - started with -r. */ -int -maybe_make_restricted (name) - char *name; -{ - char *temp; - - temp = base_pathname (name); - if (*temp == '-') - temp++; - if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) - { - set_var_read_only ("PATH"); - set_var_read_only ("SHELL"); - set_var_read_only ("ENV"); - set_var_read_only ("BASH_ENV"); - restricted = 1; - } - return (restricted); -} -#endif /* RESTRICTED_SHELL */ - -/* Fetch the current set of uids and gids and return 1 if we're running - setuid or setgid. */ -static int -uidget () -{ - uid_t u; - - u = getuid (); - if (current_user.uid != u) - { - FREE (current_user.user_name); - FREE (current_user.shell); - FREE (current_user.home_dir); - current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL; - } - current_user.uid = u; - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); - - /* See whether or not we are running setuid or setgid. */ - return (current_user.uid != current_user.euid) || - (current_user.gid != current_user.egid); -} - -void -disable_priv_mode () -{ - setuid (current_user.uid); - setgid (current_user.gid); - current_user.euid = current_user.uid; - current_user.egid = current_user.gid; -} - -static int -run_wordexp (words) - char *words; -{ - int code, nw, nb; - WORD_LIST *wl, *tl, *result; - - code = setjmp (top_level); - - if (code != NOT_JUMPED) - { - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - return last_command_exit_value = 127; - case ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_wordexp", CMDERR_BADJUMP, code, 0); - } - } - - /* Run it through the parser to get a list of words and expand them */ - if (words && *words) - { - with_input_from_string (words, "--wordexp"); - if (parse_command () != 0) - return (126); - if (global_command == 0) - { - printf ("0\n0\n"); - return (0); - } - if (global_command->type != cm_simple) - return (126); - wl = global_command->value.Simple->words; - if (protected_mode) - for (tl = wl; tl; tl = tl->next) - tl->word->flags |= W_NOCOMSUB; - result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0; - } - else - result = (WORD_LIST *)0; - - last_command_exit_value = 0; - - if (result == 0) - { - printf ("0\n0\n"); - return (0); - } - - /* Count up the number of words and bytes, and print them. Don't count - the trailing NUL byte. */ - for (nw = nb = 0, wl = result; wl; wl = wl->next) - { - nw++; - nb += strlen (wl->word->word); - } - printf ("%u\n%u\n", nw, nb); - /* Print each word on a separate line. This will have to be changed when - the interface to glibc is completed. */ - for (wl = result; wl; wl = wl->next) - printf ("%s\n", wl->word->word); - - return (0); -} - -#if defined (ONESHOT) -/* Run one command, given as the argument to the -c option. Tell - parse_and_execute not to fork for a simple command. */ -static int -run_one_command (command) - char *command; -{ - 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 ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_one_command", CMDERR_BADJUMP, code, 0); - } - } - return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST)); -} -#endif /* ONESHOT */ - -static int -bind_args (argv, arg_start, arg_end, start_index) - char **argv; - int arg_start, arg_end, start_index; -{ - register int i; - WORD_LIST *args; - - for (i = arg_start, args = (WORD_LIST *)NULL; i != arg_end; i++) - args = make_word_list (make_word (argv[i]), args); - if (args) - { - args = REVERSE_LIST (args, WORD_LIST *); - if (start_index == 0) /* bind to $0...$n for sh -c command */ - { - /* Posix.2 4.56.3 says that the first argument after sh -c command - becomes $0, and the rest of the arguments become $1...$n */ - shell_name = savestring (args->word->word); - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (args->word->word); - remember_args (args->next, 1); - push_args (args->next); /* BASH_ARGV and BASH_ARGC */ - } - else /* bind to $1...$n for shell script */ - { - remember_args (args, 1); - push_args (args); /* BASH_ARGV and BASH_ARGC */ - } - - dispose_words (args); - } - - return (i); -} - -void -unbind_args () -{ - remember_args ((WORD_LIST *)NULL, 1); - pop_args (); /* Reset BASH_ARGV and BASH_ARGC */ -} - -static void -start_debugger () -{ -#if defined (DEBUGGER) && defined (DEBUGGER_START_FILE) - int old_errexit; - - old_errexit = exit_immediately_on_error; - exit_immediately_on_error = 0; - - maybe_execute_file (DEBUGGER_START_FILE, 1); - function_trace_mode = 1; - - exit_immediately_on_error += old_errexit; -#endif -} - -static int -open_shell_script (script_name) - char *script_name; -{ - int fd, e, fd_is_tty; - char *filename, *path_filename, *t; - char sample[80]; - int sample_len; - struct stat sb; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; -#endif - - filename = savestring (script_name); - - fd = open (filename, O_RDONLY); - if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) - { - e = errno; - /* If it's not in the current directory, try looking through PATH - for it. */ - path_filename = find_path_file (script_name); - if (path_filename) - { - free (filename); - filename = path_filename; - fd = open (filename, O_RDONLY); - } - else - errno = e; - } - - if (fd < 0) - { - e = errno; - file_error (filename); - exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); - } - - free (dollar_vars[0]); - dollar_vars[0] = savestring (script_name); - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); - - array_push (bash_source_a, filename); - if (bash_lineno_a) - { - t = itos (executing_line_number ()); - array_push (bash_lineno_a, t); - free (t); - } - array_push (funcname_a, "main"); -#endif - -#ifdef HAVE_DEV_FD - fd_is_tty = isatty (fd); -#else - fd_is_tty = 0; -#endif - - /* Only do this with non-tty file descriptors we can seek on. */ - if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) - { - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), - and report an error and exit if it is. */ - sample_len = read (fd, sample, sizeof (sample)); - if (sample_len < 0) - { - e = errno; - if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode)) - internal_error (_("%s: is a directory"), filename); - else - { - errno = e; - file_error (filename); - } - exit (EX_NOEXEC); - } - else if (sample_len > 0 && (check_binary_file (sample, sample_len))) - { - internal_error ("%s: cannot execute binary file", filename); - exit (EX_BINARY_FILE); - } - /* Now rewind the file back to the beginning. */ - lseek (fd, 0L, 0); - } - - /* Open the script. But try to move the file descriptor to a randomly - large one, in the hopes that any descriptors used by the script will - not match with ours. */ - fd = move_to_high_fd (fd, 0, -1); - -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (fd, O_TEXT); -#endif - -#if defined (BUFFERED_INPUT) - default_buffered_input = fd; - SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ - default_input = fdopen (fd, "r"); - - if (default_input == 0) - { - file_error (filename); - exit (EX_NOTFOUND); - } - - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); -#endif /* !BUFFERED_INPUT */ - - /* Just about the only way for this code to be executed is if something - like `bash -i /dev/stdin' is executed. */ - if (interactive_shell && fd_is_tty) - { - dup2 (fd, 0); - close (fd); - fd = 0; -#if defined (BUFFERED_INPUT) - default_buffered_input = 0; -#else - fclose (default_input); - default_input = stdin; -#endif - } - else if (forced_interactive && fd_is_tty == 0) - /* But if a script is called with something like `bash -i scriptname', - we need to do a non-interactive setup here, since we didn't do it - before. */ - init_noninteractive (); - - free (filename); - return (fd); -} - -/* Initialize the input routines for the parser. */ -static void -set_bash_input () -{ - /* Make sure the fd from which we are reading input is not in - no-delay mode. */ -#if defined (BUFFERED_INPUT) - if (interactive == 0) - sh_unset_nodelay_mode (default_buffered_input); - else -#endif /* !BUFFERED_INPUT */ - sh_unset_nodelay_mode (fileno (stdin)); - - /* with_input_from_stdin really means `with_input_from_readline' */ - if (interactive && no_line_editing == 0) - with_input_from_stdin (); - else -#if defined (BUFFERED_INPUT) - { - if (interactive == 0) - 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 */ -} - -/* Close the current shell script input source and forget about it. This is - extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO - is non-zero, we close default_buffered_input even if it's the standard - input (fd 0). */ -void -unset_bash_input (check_zero) - int check_zero; -{ -#if defined (BUFFERED_INPUT) - if ((check_zero && default_buffered_input >= 0) || - (check_zero == 0 && default_buffered_input > 0)) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - } -#else /* !BUFFERED_INPUT */ - if (default_input) - { - fclose (default_input); - default_input = (FILE *)NULL; - } -#endif /* !BUFFERED_INPUT */ -} - - -#if !defined (PROGRAM) -# define PROGRAM "bash" -#endif - -static void -set_shell_name (argv0) - char *argv0; -{ - /* Here's a hack. If the name of this shell is "sh", then don't do - any startup files; just try to be more like /bin/sh. */ - shell_name = base_pathname (argv0); - - if (*shell_name == '-') - { - shell_name++; - login_shell++; - } - - if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') - act_like_sh++; - if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') - su_shell++; - - shell_name = argv0; - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (shell_name); - - /* A program may start an interactive shell with - "execl ("/bin/bash", "-", NULL)". - If so, default the name of this shell to our name. */ - if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) - shell_name = PROGRAM; -} - -static void -init_interactive () -{ - interactive_shell = startup_state = interactive = 1; - expand_aliases = 1; -} - -static void -init_noninteractive () -{ -#if defined (HISTORY) - bash_history_reinit (0); -#endif /* HISTORY */ - interactive_shell = startup_state = interactive = 0; - expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */ - no_line_editing = 1; -#if defined (JOB_CONTROL) - set_job_control (0); -#endif /* JOB_CONTROL */ -} - -void -get_current_user_info () -{ - struct passwd *entry; - - /* Don't fetch this more than once. */ - if (current_user.user_name == 0) - { - entry = getpwuid (current_user.uid); - if (entry) - { - current_user.user_name = savestring (entry->pw_name); - current_user.shell = (entry->pw_shell && entry->pw_shell[0]) - ? savestring (entry->pw_shell) - : savestring ("/bin/sh"); - current_user.home_dir = savestring (entry->pw_dir); - } - else - { - current_user.user_name = _("I have no name!"); - current_user.user_name = savestring (current_user.user_name); - current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring ("/"); - } - endpwent (); - } -} - -/* Do whatever is necessary to initialize the shell. - Put new initializations in here. */ -static void -shell_initialize () -{ - char hostname[256]; - - /* Line buffer output for stderr and stdout. */ - if (shell_initialized == 0) - { - sh_setlinebuf (stderr); - sh_setlinebuf (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 (0); - - /* It's highly unlikely that this will change. */ - if (current_host_name == 0) - { - /* Initialize current_host_name. */ - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; - else - current_host_name = savestring (hostname); - } - - /* Initialize the stuff in current_user that comes from the password - file. We don't need to do this right away if the shell is not - interactive. */ - if (interactive_shell) - get_current_user_info (); - - /* Initialize our interface to the tilde expander. */ - tilde_initialize (); - - /* Initialize internal and environment variables. Don't import shell - functions from the environment if we are running in privileged or - restricted mode or if the shell is running setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid); -#else - initialize_shell_variables (shell_environment, privileged_mode||running_setuid); -#endif - - /* Initialize the data structures for storing and running jobs. */ - initialize_job_control (0); - - /* Initialize input streams to null. */ - initialize_bash_input (); - - initialize_flags (); - - /* Initialize the shell options. Don't import the shell options - from the environment variable $SHELLOPTS if we are running in - privileged or restricted mode or if the shell is running setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_options (privileged_mode||restricted||running_setuid); -#else - initialize_shell_options (privileged_mode||running_setuid); -#endif -} - -/* 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; - expand_aliases = 0; - -#if defined (HISTORY) - bash_history_reinit (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_contexts (shell_variables); - delete_all_variables (shell_functions); - - shell_reinitialized = 1; -} - -static void -show_shell_usage (fp, extra) - FILE *fp; - int extra; -{ - int i; - char *set_opts, *s, *t; - - if (extra) - fprintf (fp, "GNU bash, version %s-(%s)\n", shell_version_string (), MACHTYPE); - fprintf (fp, _("Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n"), - shell_name, shell_name); - fputs (_("GNU long options:\n"), fp); - for (i = 0; long_args[i].name; i++) - fprintf (fp, "\t--%s\n", long_args[i].name); - - fputs (_("Shell options:\n"), fp); - fputs (_("\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"), fp); - - for (i = 0, set_opts = 0; shell_builtins[i].name; i++) - if (STREQ (shell_builtins[i].name, "set")) - set_opts = savestring (shell_builtins[i].short_doc); - if (set_opts) - { - s = xstrchr (set_opts, '['); - if (s == 0) - s = set_opts; - while (*++s == '-') - ; - t = xstrchr (s, ']'); - if (t) - *t = '\0'; - fprintf (fp, _("\t-%s or -o option\n"), s); - free (set_opts); - } - - if (extra) - { - fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name); - fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name); - fprintf (fp, _("Use the `bashbug' command to report bugs.\n")); - } -} - -static void -add_shopt_to_alist (opt, on_or_off) - char *opt; - int on_or_off; -{ - if (shopt_ind >= shopt_len) - { - shopt_len += 8; - shopt_alist = (STRING_INT_ALIST *)xrealloc (shopt_alist, shopt_len * sizeof (shopt_alist[0])); - } - shopt_alist[shopt_ind].word = opt; - shopt_alist[shopt_ind].token = on_or_off; - shopt_ind++; -} - -static void -run_shopt_alist () -{ - register int i; - - for (i = 0; i < shopt_ind; i++) - if (shopt_setopt (shopt_alist[i].word, (shopt_alist[i].token == '-')) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - free (shopt_alist); - shopt_alist = 0; - shopt_ind = shopt_len = 0; -} diff --git a/stringlib.c~ b/stringlib.c~ deleted file mode 100644 index 97280cf5a..000000000 --- a/stringlib.c~ +++ /dev/null @@ -1,284 +0,0 @@ -/* stringlib.c - Miscellaneous string functions. */ - -/* Copyright (C) 1996-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include -#include "chartypes.h" - -#include "shell.h" -#include "pathexp.h" - -#include - -#if defined (EXTENDED_GLOB) -# include -#endif - -/* **************************************************************** */ -/* */ -/* Functions to manage arrays of strings */ -/* */ -/* **************************************************************** */ - -/* Find STRING in ALIST, a list of string key/int value pairs. If FLAGS - is 1, STRING is treated as a pattern and matched using strmatch. */ -int -find_string_in_alist (string, alist, flags) - char *string; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - int r; - - for (i = r = 0; alist[i].word; i++) - { -#if defined (EXTENDED_GLOB) - if (flags) - r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; - else -#endif - r = STREQ (string, alist[i].word); - - if (r) - return (alist[i].token); - } - return -1; -} - -/* Find TOKEN in ALIST, a list of string/int value pairs. Return the - corresponding string. Allocates memory for the returned - string. FLAGS is currently ignored, but reserved. */ -char * -find_token_in_alist (token, alist, flags) - int token; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - - for (i = 0; alist[i].word; i++) - { - if (alist[i].token == token) - return (savestring (alist[i].word)); - } - return ((char *)NULL); -} - -int -find_index_in_alist (string, alist, flags) - char *string; - STRING_INT_ALIST *alist; - int flags; -{ - register int i; - int r; - - for (i = r = 0; alist[i].word; i++) - { -#if defined (EXTENDED_GLOB) - if (flags) - r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH; - else -#endif - r = STREQ (string, alist[i].word); - - if (r) - return (i); - } - - return -1; -} - -/* **************************************************************** */ -/* */ -/* String Management 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; - register char *result; - - len = end - start; - result = (char *)xmalloc (len + 1); - strncpy (result, string + start, len); - result[len] = '\0'; - return (result); -} - -/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero, - replace all occurrences, otherwise replace only the first. - This returns a new string; the caller should free it. */ -char * -strsub (string, pat, rep, global) - char *string, *pat, *rep; - int global; -{ - int patlen, replen, templen, tempsize, repl, i; - char *temp, *r; - - patlen = strlen (pat); - replen = strlen (rep); - for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; ) - { - if (repl && STREQN (string + i, pat, patlen)) - { - if (replen) - RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); - - for (r = rep; *r; ) - temp[templen++] = *r++; - - i += patlen ? patlen : 1; /* avoid infinite recursion */ - repl = global != 0; - } - else - { - RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16); - temp[templen++] = string[i++]; - } - } - temp[templen] = 0; - return (temp); -} - -/* Replace all instances of C in STRING with TEXT. TEXT may be empty or - NULL. If DO_GLOB is non-zero, we quote the replacement text for - globbing. Backslash may be used to quote C. */ -char * -strcreplace (string, c, text, do_glob) - char *string; - int c; - char *text; - int do_glob; -{ - char *ret, *p, *r, *t; - int len, rlen, ind, tlen; - - len = STRLEN (text); - rlen = len + strlen (string) + 2; - ret = (char *)xmalloc (rlen); - - for (p = string, r = ret; p && *p; ) - { - if (*p == c) - { - if (len) - { - ind = r - ret; - if (do_glob && (glob_pattern_p (text) || strchr (text, '\\'))) - { - t = quote_globbing_chars (text); - tlen = strlen (t); - RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); - r = ret + ind; /* in case reallocated */ - strcpy (r, t); - r += tlen; - free (t); - } - else - { - RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen); - r = ret + ind; /* in case reallocated */ - strcpy (r, text); - r += len; - } - } - p++; - continue; - } - - if (*p == '\\' && p[1] == c) - p++; - - ind = r - ret; - RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen); - r = ret + ind; /* in case reallocated */ - *r++ = *p++; - } - *r = '\0'; - - return ret; -} - -#ifdef INCLUDE_UNUSED -/* 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'; - } -} -#endif - -/* 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, len, newlines_only) - char *string; - int len; - int newlines_only; -{ - while (len >= 0) - { - if ((newlines_only && string[len] == '\n') || - (!newlines_only && whitespace (string[len]))) - len--; - else - break; - } - string[len + 1] = '\0'; -} - -/* A wrapper for bcopy that can be prototyped in general.h */ -void -xbcopy (s, d, n) - char *s, *d; - int n; -{ - FASTCOPY (s, d, n); -} diff --git a/subst.c.new b/subst.c.new deleted file mode 100644 index da6174ead..000000000 --- a/subst.c.new +++ /dev/null @@ -1,7293 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, and - globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the string extraction functions. */ -#define EX_NOALLOC 0x01 /* just skip; don't return substring */ -#define EX_VARNAME 0x02 /* variable name; for string_extract () */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -unsigned char ifs_firstc; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment; -extern int subshell_level; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static char expand_param_error, expand_param_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *dequote_escapes __P((char *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); -static char *remove_quoted_escapes __P((char *)); -static char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -static int do_assignment_internal __P((const char *, int)); - -static char *string_extract_verbatim __P((char *, int *, char *)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static unsigned char *mb_getcharlens __P((char *, int)); - -static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -static wchar_t *wcsdup __P((wchar_t *)); -static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern __P((char *, char *, int)); - -static int match_pattern_char __P((char *, char *)); -static int match_upattern __P((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_pattern_wchar __P((wchar_t *, wchar_t *)); -static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); - -static char *parameter_brace_expand_word __P((char *, int, int)); -static char *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static char *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, char *, int)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, char *, int)); - -static char *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static char *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (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 freeing 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 = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* 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) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* 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. If (flags & EX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & EX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & EX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - - temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[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: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - 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++; - i++; - 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; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ - else - ret = extract_dollar_brace_string (string, &si, 1, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j++] = string[si]; - - i = si + 1; - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, sindex, charlist) - char *string; - int *sindex; - char *charlist; -{ - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - for (i = *sindex; c = string[i]; i++) - { - if (c == CTLESC) - { - i++; - continue; - } - - if (MEMBER (c, charlist)) - break; - } - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", 0)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & EX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - 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 of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ - i = si + 1; - continue; - } - - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - report_error ("bad substitution: no closing `%s' in %s", "}", string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)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 - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims) - char *string; - int start; - char *delims; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (member (c, delims)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - d2 = (char *)xmalloc (strlen (delims) + 1); - for (i = ts = 0; delims[i]; i++) - { - if (whitespace(delims[i]) == 0) - d2[ts++] = delims[i]; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitspace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - while (1) - { - te = skip_to_delim (string, ts, d); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING, add an additional null argument and set the current - word pointer to that. */ - if (cwp && cw == -1 && sentinel >= slen) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* 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. */ -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 == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* 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 = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - 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 sep[2]; - - sep[0] = ifs_firstc; - sep[1] = '\0'; - - return (string_list_internal (list, sep)); -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, sep[2]; - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; - - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) - ? quote_list (list) - : list_quote_escapes (list); - return (string_list_internal (tlist, 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! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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. */ - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - current_word = string_extract_verbatim (string, &sindex, separators); - if (current_word == 0) - 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)) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* 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++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (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. This is never called with SEPARATORS != $IFS; - it should be simplified. - - 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, whitesep; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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) && isifs (*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; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (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]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (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) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -/* 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) - const char *string; - int expand; -{ - int offset; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni, assign_list = 0; -#endif - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - name[offset] = 0; - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) - { - assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); - } - else -#endif - - /* Perform tilde expansion. */ - if (expand && temp[0]) - { - temp = (xstrchr (temp, '~') && unquoted_member ('~', temp)) - ? bash_tilde_expand (temp, 1) - : savestring (temp); - - value = expand_string_if_necessary (temp, 0, expand_string_unsplit); - free (temp); - } - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { -#if defined (ARRAY_VARS) - if (assign_list) - fprintf (stderr, "%s%s=(%s)\n", indirection_level_string (), name, value); - else -#endif - fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value); - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - -#if defined (ARRAY_VARS) - if (t = xstrchr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - entry = assign_array_from_string (name, value); - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value); - - stupidly_hack_special_variables (name); - - if (entry) - VUNSETATTR (entry, att_invisible); - - /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ -int -do_assignment (string) - const 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. */ -int -do_assignment_no_expand (string) - const char *string; -{ - return do_assignment_internal (string, 0); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* 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; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#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 * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - slen = strlen (string); - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - 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 & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is nonzero, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. The - caller is responsible for removing the backslashes if the unquoted - words is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - if (xstrchr (w->word, '~') && unquoted_member ('~', w->word)) - { - p = bash_tilde_expand (w->word, 0); - free (w->word); - w->word = p; - } - - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* 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, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - 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 == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - -/* 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 - substitution, 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 == 0 || *string == '\0') - 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); -} - -/* 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; - - td.flags = 0; - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* 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. */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or 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. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - s = string; - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, s)); - - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)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. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quoted quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 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) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - free (t); - w->word->flags |= W_QUOTED; - } - return list; -} - -static WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -static char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* 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 () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -static char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - i++; - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* 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; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -#if 0 /* Currently unused */ -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -#endif -#endif - -/* 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_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register int len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (savestring (param)); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) -static wchar_t * -wcsdup (ws) - wchar_t *ws; -{ - wchar_t *ret; - size_t len; - - len = wcslen (ws); - ret = xmalloc ((len + 1) * sizeof (wchar_t)); - if (ret == 0) - return ret; - return (wcscpy (ret, ws)); -} - -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc; - int n, n1; - wchar_t *ret; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wcsdup (wparam)); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - char *xret; - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - return (remove_upattern (param, pattern, op)); - n = xdupmbstowcs (&wparam, NULL, param); - if (n == (size_t)-1) - { - free (wpattern); - return (remove_upattern (param, pattern, op)); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - return (remove_upattern (param, pattern, op)); -} - -/* Return 1 of the first character of STRING could match the first - character of pattern PAT. Used to avoid n2 calls to strmatch(). */ -static int -match_pattern_char (pat, string) - char *pat, *string; -{ - char c; - - if (*string == 0) - return (0); - - switch (c = *pat++) - { - default: - return (*string == c); - case '\\': - return (*string == *pat); - case '?': - return (*pat == LPAREN ? 1 : (*string != '\0')); - case '*': - return (1); - case '+': - case '!': - case '@': - return (*pat == LPAREN ? 1 : (*string == c)); - case '[': - return (*string != '\0'); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len; - register char *p, *p1; - char *end; - - len = STRLEN (string); - end = string + len; - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { - for (p1 = end; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - - for (p = end; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - } - - return (0); - - case MATCH_END: - for (p = string; p <= end; p++) - { - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } - - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) -/* Return 1 of the first character of WSTRING could match the first - character of pattern WPAT. Wide character version. */ -static int -match_pattern_wchar (wpat, wstring) - wchar_t *wpat, *wstring; -{ - wchar_t wc; - - if (*wstring == 0) - return (0); - - switch (wc = *wpat++) - { - default: - return (*wstring == wc); - case L'\\': - return (*wstring == *wpat); - case L'?': - return (*wpat == LPAREN ? 1 : (*wstring != L'\0')); - case L'*': - return (1); - case L'+': - case L'!': - case L'@': - return (*wpat == LPAREN ? 1 : (*wstring == wc)); - case L'[': - return (*wstring != L'\0'); - } -} - -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { - if (match_pattern_wchar (wpat, wstring + n)) - { - for (n1 = wstrlen; n1 >= n; n1--) - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring) == 0) - return (0); - - for (n = wstrlen; n >= 0; n--) - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; - } - - return (0); - - case MATCH_END: - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } - } - - return (0); - } - - return (0); -} -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; -#endif - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value); - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - FREE (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (a, pattern, patspec, varname, quoted) - ARRAY *a; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - list = array_to_word_list (a); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) - char *varname, *value, *patstr; - int rtype, quoted; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - pattern = getpattern (patstr, quoted, 1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * 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, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : 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_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : 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; -{ - return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL)); -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#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 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#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; -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 = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - 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 %ld: dev_fd_list:", (long)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, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - 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 || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - 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]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (!pathname) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - 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) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - 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_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannout reset nodelay mode for fd %d"), fd); - 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) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - 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", (SEVAL_NONINT|SEVAL_NOHIST)); - -#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 */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted) - int fd, quoted; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = 0; - -#ifdef __CYGWIN__ - setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ -#endif - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - 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, istring_index - 1, 1); - - return istring; -} - -/* Perform command substitution on STRING. This returns a string, - possibly quoted. */ -char * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp; - char *istring; - int result, fildes[2], function_value, pflags, rc; - - istring = (char *)NULL; - - /* 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); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = 125; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = interactive ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif - - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((char *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - 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; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - istring = read_comsub (fildes[0], quoted); - - close (fildes[0]); - - current_command_subst_pid = pid; - 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) && last_command_exit_signal == 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. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ -#if 0 - if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) -#else - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) -#endif - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - return (istring); - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *t, c; - ARRAY *array; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_p (var) ? array_num_elements (array) : 1); - - ind = array_expand_index (t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - - len = STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -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; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = xstrchr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - 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, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - /* Handle multiple digit arguments, as in ${11}. */ - - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp = array_value (name, quoted, &atype); - if (atype == 0 && temp) - temp = quote_escapes (temp); - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = quote_escapes (temp); - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - return (temp); -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static char * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - - t = parameter_brace_expand_word (name, var_is_special, quoted); - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (t); - temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - return temp; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static char * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* XXX - Should we tilde expand in an assignment context if C is `='? */ - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) - { - hasdol = 0; - t = string_extract_double_quoted (temp, &hasdol, 1); - free (temp); - temp = t; - } - - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. We use string_list_dollar_star instead. */ - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); - - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - return (temp); - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1); - else -#endif /* ARRAY_VARS */ - 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; -{ - WORD_LIST *l; - char *temp; - - if (value && *value) - { - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - l = expand_string (temp, 0); - FREE (temp); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - 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] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = STRLEN (t); - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (value, substr, vtype, e1p, e2p) - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = strlen (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. */ - len = array_max_index (a); /* arrays index from 0 to n - 1 */ - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p >= len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - if (*e2p < 0) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, varp, valp) - char *varname, *value; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - if (v && array_p (v)) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = (char *)array_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else - return -1; - } - else if ((v = find_variable (varname)) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif - *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - slen = STRLEN (string); - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, substr, quoted) - char *varname, *value, *substr; - int quoted; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - if (r <= 0) - return ((r == 0) ? &expand_param_error : (char *)NULL); - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str; - int rsize, rptr, l, replen, mtype; - - mtype = mflags & MATCH_TYPEMASK; - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = strlen (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rep, replen); - rptr += replen; - } - str = e; /* e == end of match */ - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - e++, str++; /* avoid infinite recursion on zero-length match */ - } - - /* Now copy the unmatched portion of the input string */ - if (*str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret, *tt; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = make_bare_word (ret); - dispose_word (params->word); - params->word = w; - FREE (ret); - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, patsub, quoted) - char *varname, *value, *patsub; - int quoted; -{ - int vtype, mflags, starsub; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - -#if 0 - /* Expand PAT and REP for command, variable and parameter, arithmetic, - and process substitution. Also perform quote removal. Do not - perform word splitting or filename generation. */ - pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); -#else - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); -#endif - - if (rep) - { - if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - p = pat; - if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = array_patsub (array_cell (v), p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static char * -parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub; - char *name, *value, *temp, *temp1; - int t_index, sindex, c; - intmax_t number; - - value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = 0; - - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && - (string[t_index] == '-' || - string[t_index] == '?' || - string[t_index] == '#')) || - (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) - { - t_index++; - free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xmalloc (3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' && string[sindex] != RBRACE) - want_patsub = 1; - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* 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. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - - *indexp = sindex; - return ((number < 0) ? &expand_param_error : itos (number)); - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (x); - free (xlist); - free (temp1); - *indexp = sindex; - return (temp); - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - free (temp1); - *indexp = sindex; - return (temp); - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - temp = parameter_brace_expand_word (name, var_is_special, quoted); - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, 0); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_param_error; - - case RBRACE: - if (var_is_set == 0 && unbound_vars_is_error) - { - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted); - free (temp); - free (value); - temp = temp1; - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_param_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - } - free (value); - } - - break; - } - free (name); - return (temp); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static char * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - - /* 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': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - temp = temp1 ? quote_escapes (temp1) : (char *)NULL; - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ - temp = string_list_dollar_star (list); - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* 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 '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, quoted); - - dispose_words (list); - break; - - case LBRACE: - temp = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - return (temp); - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (temp && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - temp = (char *)NULL; - } - - } - - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_param_fatal); - } - else - return (&expand_param_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - - /* Do initial variable expansion. */ - temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = quote_escapes (temp); - } - else -#endif - temp = quote_escapes (value_cell (var)); - free (temp1); - - goto return0; - } - - temp = (char *)NULL; - - if (unbound_vars_is_error) - err_unboundvar (temp1); - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_param_fatal - : &expand_param_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - return (temp); -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal 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 contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - 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, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - int had_quoted_null; - int has_dollar_at; - int tflag; - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - string_size = strlen (string); - - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - temp = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return ((temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - if (expanded_something) - *expanded_something = 1; - - temp = string_extract (string, &sindex, "`", 0); - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - temp1 = command_substitute (temp, quoted); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = make_word (temp); /* XXX */ - free (temp); - temp = (char *)NULL; - - has_dollar_at = 0; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL); - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - dispose_words (list); -#if 1 - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* HOWEVER, this fails if the string contains a literal - CTLNUL or CTLNUL is contained in the (non-null) expansion - of some variable. I'm not sure what to do about this - yet. There has to be some way to indicate the difference - between the two. An auxiliary data structure might be - necessary. */ - if (QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ -#endif - } - } - 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 == 0 && quoted_state == PARTIALLY_QUOTED) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - 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. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - 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 == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1) - sindex--; - - if (MB_CUR_MAX > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* 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. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* 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_bare_word (t); - free (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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = v ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - - ifs_firstc = ifs_value ? *ifs_value : 0; -} - -char * -getifs () -{ - return ifs_value; -} - -/* 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, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & 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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* 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 SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (!tlist) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_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->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_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->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_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->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_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); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* 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_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - 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. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - report_error (_("no match: %s"), tlist->word->word); - jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = 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 `xstrchr', 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 (xstrchr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = make_word (temp_string); - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - output_list = make_word_list (w, output_list); - free (expansions[eindex]); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && - (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) && - (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))) - { - tlist->word->word = bash_tilde_expand (temp_string, 1); - free (temp_string); - } - else if (temp_string[0] == '~') - { - tlist->word->word = bash_tilde_expand (temp_string, 0); - free (temp_string); - } - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = 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); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_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 ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_assign_func_t *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 (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/subst.c.orig b/subst.c.orig deleted file mode 100644 index 011930b36..000000000 --- a/subst.c.orig +++ /dev/null @@ -1,7376 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, and - globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the string extraction functions. */ -#define EX_NOALLOC 0x01 /* just skip; don't return substring */ -#define EX_VARNAME 0x02 /* variable name; for string_extract () */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -unsigned char ifs_firstc; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment; -extern int subshell_level; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static char expand_param_error, expand_param_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *dequote_escapes __P((char *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); -static char *remove_quoted_escapes __P((char *)); -static char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -static int do_assignment_internal __P((const char *, int)); - -static char *string_extract_verbatim __P((char *, int *, char *)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static unsigned char *mb_getcharlens __P((char *, int)); - -static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -# if !defined (HAVE_WCSDUP) -static wchar_t *wcsdup __P((wchar_t *)); -# endif -static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern __P((char *, char *, int)); - -static int match_pattern_char __P((char *, char *)); -static int match_upattern __P((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_pattern_wchar __P((wchar_t *, wchar_t *)); -static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); - -static char *parameter_brace_expand_word __P((char *, int, int)); -static char *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static char *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, char *, int)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, char *, int)); - -static char *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static char *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (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 freeing 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 = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* 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) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* 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. If (flags & EX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & EX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & EX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - - temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[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: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - 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++; - i++; - 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; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - int free_ret = 1; - - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ - else - ret = extract_dollar_brace_string (string, &si, 1, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error - is set. */ - if (ret == 0 && no_longjmp_on_fatal_error) - { - free_ret = 0; - ret = string + i + 2; - } - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j++] = string[si]; - - i = si + 1; - if (free_ret) - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, sindex, charlist) - char *string; - int *sindex; - char *charlist; -{ - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - for (i = *sindex; c = string[i]; i++) - { - if (c == CTLESC) - { - i++; - continue; - } - - if (MEMBER (c, charlist)) - break; - } - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", 0)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & EX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - 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 of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ - i = si + 1; - continue; - } - - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - report_error ("bad substitution: no closing `%s' in %s", "}", string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)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 - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims) - char *string; - int start; - char *delims; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (member (c, delims)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - d2 = (char *)xmalloc (strlen (delims) + 1); - for (i = ts = 0; delims[i]; i++) - { - if (whitespace(delims[i]) == 0) - d2[ts++] = delims[i]; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitspace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - while (1) - { - te = skip_to_delim (string, ts, d); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING, add an additional null argument and set the current - word pointer to that. */ - if (cwp && cw == -1 && sentinel >= slen) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* 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. */ -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 == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* 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 = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - 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 sep[2]; - - sep[0] = ifs_firstc; - sep[1] = '\0'; - - return (string_list_internal (list, sep)); -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, sep[2]; - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; - - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) - ? quote_list (list) - : list_quote_escapes (list); - return (string_list_internal (tlist, 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! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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. */ - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - current_word = string_extract_verbatim (string, &sindex, separators); - if (current_word == 0) - 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)) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* 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++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (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. This is never called with SEPARATORS != $IFS; - it should be simplified. - - 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, whitesep; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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) && isifs (*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; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (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]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (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) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -/* 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) - const char *string; - int expand; -{ - int offset; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - int assign_list = 0; - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - name[offset] = 0; - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) - { - assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); - } - else -#endif - - /* Perform tilde expansion. */ - if (expand && temp[0]) - { - temp = (xstrchr (temp, '~') && unquoted_member ('~', temp)) - ? bash_tilde_expand (temp, 1) - : savestring (temp); - - value = expand_string_if_necessary (temp, 0, expand_string_unsplit); - free (temp); - } - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - xtrace_print_assignment (name, value, assign_list, 1); - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - -#if defined (ARRAY_VARS) - if (t = xstrchr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - entry = assign_array_from_string (name, value); - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value); - - stupidly_hack_special_variables (name); - - if (entry) - VUNSETATTR (entry, att_invisible); - - /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ -int -do_assignment (string) - const 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. */ -int -do_assignment_no_expand (string) - const char *string; -{ - return do_assignment_internal (string, 0); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* 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; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') -#if 0 - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h); -#else - { - if (quoted & Q_DOUBLE_QUOTES) - ret = string_list_dollar_star (quote_list (h)); - else if (quoted & Q_HERE_DOCUMENT) - ret = string_list (quote_list (h)); - else - ret = string_list (h); - } -#endif - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#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 * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - slen = strlen (string); - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - 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 & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is nonzero, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. The - caller is responsible for removing the backslashes if the unquoted - words is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - if (xstrchr (w->word, '~') && unquoted_member ('~', w->word)) - { - p = bash_tilde_expand (w->word, 0); - free (w->word); - w->word = p; - } - - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* 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, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - 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 == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - -/* 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 - substitution, 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 == 0 || *string == '\0') - 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); -} - -/* 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; - - td.flags = 0; - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* 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. */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or 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. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - s = string; - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, s)); - - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)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. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quoted quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 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) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - free (t); - w->word->flags |= W_QUOTED; - } - return list; -} - -static WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -static char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* 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 () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -static char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - i++; - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* 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; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -#if 0 /* Currently unused */ -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -#endif -#endif - -/* 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_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register int len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (savestring (param)); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) - -#if !defined (HAVE_WCSDUP) -static wchar_t * -wcsdup (ws) - wchar_t *ws; -{ - wchar_t *ret; - size_t len; - - len = wcslen (ws); - ret = xmalloc ((len + 1) * sizeof (wchar_t)); - if (ret == 0) - return ret; - return (wcscpy (ret, ws)); -} -#endif /* !HAVE_WCSDUP */ - -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc; - int n, n1; - wchar_t *ret; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wcsdup (wparam)); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - char *xret; - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - return (remove_upattern (param, pattern, op)); - n = xdupmbstowcs (&wparam, NULL, param); - if (n == (size_t)-1) - { - free (wpattern); - return (remove_upattern (param, pattern, op)); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - return (remove_upattern (param, pattern, op)); -} - -/* Return 1 of the first character of STRING could match the first - character of pattern PAT. Used to avoid n2 calls to strmatch(). */ -static int -match_pattern_char (pat, string) - char *pat, *string; -{ - char c; - - if (*string == 0) - return (0); - - switch (c = *pat++) - { - default: - return (*string == c); - case '\\': - return (*string == *pat); - case '?': - return (*pat == LPAREN ? 1 : (*string != '\0')); - case '*': - return (1); - case '+': - case '!': - case '@': - return (*pat == LPAREN ? 1 : (*string == c)); - case '[': - return (*string != '\0'); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len; - register char *p, *p1; - char *end; - - len = STRLEN (string); - end = string + len; - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { - for (p1 = end; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - - for (p = end; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - } - - return (0); - - case MATCH_END: - for (p = string; p <= end; p++) - { - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } - - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) -/* Return 1 of the first character of WSTRING could match the first - character of pattern WPAT. Wide character version. */ -static int -match_pattern_wchar (wpat, wstring) - wchar_t *wpat, *wstring; -{ - wchar_t wc; - - if (*wstring == 0) - return (0); - - switch (wc = *wpat++) - { - default: - return (*wstring == wc); - case L'\\': - return (*wstring == *wpat); - case L'?': - return (*wpat == LPAREN ? 1 : (*wstring != L'\0')); - case L'*': - return (1); - case L'+': - case L'!': - case L'@': - return (*wpat == LPAREN ? 1 : (*wstring == wc)); - case L'[': - return (*wstring != L'\0'); - } -} - -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { - if (match_pattern_wchar (wpat, wstring + n)) - { - for (n1 = wstrlen; n1 >= n; n1--) - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring) == 0) - return (0); - - for (n = wstrlen; n >= 0; n--) - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; - } - - return (0); - - case MATCH_END: - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } - } - - return (0); - } - - return (0); -} -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; -#endif - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value); - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - FREE (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') -#if 0 - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); -#else - tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l); -#endif - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (a, pattern, patspec, varname, quoted) - ARRAY *a; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - list = array_to_word_list (a); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) - char *varname, *value, *patstr; - int rtype, quoted; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - pattern = getpattern (patstr, quoted, 1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * 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, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : 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_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : 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; -{ - return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL)); -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#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 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#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; -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 = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - 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 %ld: dev_fd_list:", (long)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, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - 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 || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - 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]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (!pathname) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - 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) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - 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_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannout reset nodelay mode for fd %d"), fd); - 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) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - 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", (SEVAL_NONINT|SEVAL_NOHIST)); - -#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 */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted) - int fd, quoted; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = 0; - -#ifdef __CYGWIN__ - setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ -#endif - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - 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, istring_index - 1, 1); - - return istring; -} - -/* Perform command substitution on STRING. This returns a string, - possibly quoted. */ -char * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp; - char *istring; - int result, fildes[2], function_value, pflags, rc; - - istring = (char *)NULL; - - /* 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); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = 125; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = interactive ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif - - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((char *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - 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; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - istring = read_comsub (fildes[0], quoted); - - close (fildes[0]); - - current_command_subst_pid = pid; - 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) && last_command_exit_signal == 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. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ -#if 0 - if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) -#else - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) -#endif - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - return (istring); - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *t, c; - ARRAY *array; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_p (var) ? array_num_elements (array) : 1); - - ind = array_expand_index (t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - - len = STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -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; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = xstrchr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - 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, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - /* Handle multiple digit arguments, as in ${11}. */ - - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - if (tt) - temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (tt) - : quote_escapes (tt); - else - temp = (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp = array_value (name, quoted, &atype); - if (atype == 0 && temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - return (temp); -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static char * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - - t = parameter_brace_expand_word (name, var_is_special, quoted); - /* Have to dequote here if necessary */ - if (t) - { - temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - ? dequote_string (t) - : dequote_escapes (t); - free (t); - t = temp; - } - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (t); - temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - return temp; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static char * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* XXX - Should we tilde expand in an assignment context if C is `='? */ - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) - { - hasdol = 0; - t = string_extract_double_quoted (temp, &hasdol, 1); - free (temp); - temp = t; - } - - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. We use string_list_dollar_star instead. */ - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); - - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - return (temp); - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1); - else -#endif /* ARRAY_VARS */ - 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; -{ - WORD_LIST *l; - char *temp; - - if (value && *value) - { - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - l = expand_string (temp, 0); - FREE (temp); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - 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] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = STRLEN (t); - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (value, substr, vtype, e1p, e2p) - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = strlen (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. */ - len = array_max_index (a); /* arrays index from 0 to n - 1 */ - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p >= len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - if (*e2p < 0) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, quoted, varp, valp) - char *varname, *value; - int quoted; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - if (v && array_p (v)) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = (char *)array_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else - return -1; - } - else if ((v = find_variable (varname)) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif -#if 1 - { - if (value && vtype == VT_VARIABLE) - { - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - *valp = value; - } -#else - *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; -#endif - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - slen = STRLEN (string); - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, substr, quoted) - char *varname, *value, *substr; - int quoted; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - if (r <= 0) - return ((r == 0) ? &expand_param_error : (char *)NULL); - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str; - int rsize, rptr, l, replen, mtype; - - mtype = mflags & MATCH_TYPEMASK; - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = strlen (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rep, replen); - rptr += replen; - } - str = e; /* e == end of match */ - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - e++, str++; /* avoid infinite recursion on zero-length match */ - } - - /* Now copy the unmatched portion of the input string */ - if (*str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret, *tt; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = make_bare_word (ret); - dispose_word (params->word); - params->word = w; - FREE (ret); - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, patsub, quoted) - char *varname, *value, *patsub; - int quoted; -{ - int vtype, mflags, starsub; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - -#if 0 - /* Expand PAT and REP for command, variable and parameter, arithmetic, - and process substitution. Also perform quote removal. Do not - perform word splitting or filename generation. */ - pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); -#else - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); -#endif - - if (rep) - { - if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - p = pat; - if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = array_patsub (array_cell (v), p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static char * -parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub; - char *name, *value, *temp, *temp1; - int t_index, sindex, c; - intmax_t number; - - value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = 0; - - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && - (string[t_index] == '-' || - string[t_index] == '?' || - string[t_index] == '#')) || - (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) - { - t_index++; - free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xmalloc (3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' && string[sindex] != RBRACE) - want_patsub = 1; - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* 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. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - - *indexp = sindex; - return ((number < 0) ? &expand_param_error : itos (number)); - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (x); - free (xlist); - free (temp1); - *indexp = sindex; - return (temp); - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - free (temp1); - *indexp = sindex; - return (temp); - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - temp = parameter_brace_expand_word (name, var_is_special, quoted); - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, 0); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_param_error; - - case RBRACE: - if (var_is_set == 0 && unbound_vars_is_error) - { - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted); - free (temp); - free (value); - temp = temp1; - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_param_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - } - free (value); - } - - break; - } - free (name); - return (temp); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static char * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - - /* 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': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } -#if 1 - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (char *)NULL; -#else - temp = temp1 ? quote_escapes (temp1) : (char *)NULL; -#endif - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ -#if 0 - temp = string_list_dollar_star (list); -#else - temp = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); -#endif - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* 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 '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, quoted); - - dispose_words (list); - break; - - case LBRACE: - temp = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - return (temp); - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (temp && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - temp = (char *)NULL; - } - - } - - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_param_fatal); - } - else - return (&expand_param_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - - /* Do initial variable expansion. */ - temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - else if (unbound_vars_is_error) - goto unbound_variable; - } - else -#endif - { - temp = value_cell (var); - - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - } - - free (temp1); - - goto return0; - } - - temp = (char *)NULL; - -unbound_variable: - if (unbound_vars_is_error) - err_unboundvar (temp1); - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_param_fatal - : &expand_param_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - return (temp); -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal 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 contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - 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, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - int had_quoted_null; - int has_dollar_at; - int tflag; - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - string_size = strlen (string); - - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - temp = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return ((temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - if (expanded_something) - *expanded_something = 1; - - temp = string_extract (string, &sindex, "`", 0); - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - temp1 = command_substitute (temp, quoted); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = make_word (temp); /* XXX */ - free (temp); - temp = (char *)NULL; - - has_dollar_at = 0; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL); - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - dispose_words (list); -#if 1 - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* HOWEVER, this fails if the string contains a literal - CTLNUL or CTLNUL is contained in the (non-null) expansion - of some variable. I'm not sure what to do about this - yet. There has to be some way to indicate the difference - between the two. An auxiliary data structure might be - necessary. */ - if (QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ -#endif - } - } - 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 == 0 && quoted_state == PARTIALLY_QUOTED) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - 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. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - 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 == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1) - sindex--; - - if (MB_CUR_MAX > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* 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. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* 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_bare_word (t); - free (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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = v ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - - ifs_firstc = ifs_value ? *ifs_value : 0; -} - -char * -getifs () -{ - return ifs_value; -} - -/* 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, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & 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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* 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 SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (!tlist) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_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->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_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->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_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->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_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); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* 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_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - 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. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - report_error (_("no match: %s"), tlist->word->word); - jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = 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 `xstrchr', 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 (xstrchr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = make_word (temp_string); - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - output_list = make_word_list (w, output_list); - free (expansions[eindex]); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && - (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) && - (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))) - { - tlist->word->word = bash_tilde_expand (temp_string, 1); - free (temp_string); - } - else if (temp_string[0] == '~') - { - tlist->word->word = bash_tilde_expand (temp_string, 0); - free (temp_string); - } - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = 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); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_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 ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_assign_func_t *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 (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/subst.c.save1 b/subst.c.save1 deleted file mode 100644 index e33a1dd91..000000000 --- a/subst.c.save1 +++ /dev/null @@ -1,7346 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, and - globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the string extraction functions. */ -#define EX_NOALLOC 0x01 /* just skip; don't return substring */ -#define EX_VARNAME 0x02 /* variable name; for string_extract () */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -unsigned char ifs_firstc; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment; -extern int subshell_level; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static char expand_param_error, expand_param_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *dequote_escapes __P((char *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); -static char *remove_quoted_escapes __P((char *)); -static char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -static int do_assignment_internal __P((const char *, int)); - -static char *string_extract_verbatim __P((char *, int *, char *)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static unsigned char *mb_getcharlens __P((char *, int)); - -static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -# if !defined (HAVE_WCSDUP) -static wchar_t *wcsdup __P((wchar_t *)); -# endif -static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern __P((char *, char *, int)); - -static int match_pattern_char __P((char *, char *)); -static int match_upattern __P((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_pattern_wchar __P((wchar_t *, wchar_t *)); -static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); - -static char *parameter_brace_expand_word __P((char *, int, int)); -static char *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static char *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, char *, int)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, char *, int)); - -static char *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static char *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (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 freeing 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 = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* 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) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* 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. If (flags & EX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & EX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & EX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - - temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[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: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - 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++; - i++; - 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; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ - else - ret = extract_dollar_brace_string (string, &si, 1, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j++] = string[si]; - - i = si + 1; - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, sindex, charlist) - char *string; - int *sindex; - char *charlist; -{ - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - for (i = *sindex; c = string[i]; i++) - { - if (c == CTLESC) - { - i++; - continue; - } - - if (MEMBER (c, charlist)) - break; - } - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", 0)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & EX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - 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 of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ - i = si + 1; - continue; - } - - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - report_error ("bad substitution: no closing `%s' in %s", "}", string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)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 - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims) - char *string; - int start; - char *delims; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (member (c, delims)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - d2 = (char *)xmalloc (strlen (delims) + 1); - for (i = ts = 0; delims[i]; i++) - { - if (whitespace(delims[i]) == 0) - d2[ts++] = delims[i]; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitspace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - while (1) - { - te = skip_to_delim (string, ts, d); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING, add an additional null argument and set the current - word pointer to that. */ - if (cwp && cw == -1 && sentinel >= slen) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* 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. */ -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 == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* 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 = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - 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 sep[2]; - - sep[0] = ifs_firstc; - sep[1] = '\0'; - - return (string_list_internal (list, sep)); -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, sep[2]; - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; - - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) - ? quote_list (list) - : list_quote_escapes (list); - return (string_list_internal (tlist, 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! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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. */ - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - current_word = string_extract_verbatim (string, &sindex, separators); - if (current_word == 0) - 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)) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* 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++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (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. This is never called with SEPARATORS != $IFS; - it should be simplified. - - 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, whitesep; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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) && isifs (*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; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (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]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (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) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -/* 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) - const char *string; - int expand; -{ - int offset; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - int assign_list = 0; - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - name[offset] = 0; - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) - { - assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); - } - else -#endif - - /* Perform tilde expansion. */ - if (expand && temp[0]) - { - temp = (xstrchr (temp, '~') && unquoted_member ('~', temp)) - ? bash_tilde_expand (temp, 1) - : savestring (temp); - - value = expand_string_if_necessary (temp, 0, expand_string_unsplit); - free (temp); - } - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - xtrace_print_assignment (name, value, assign_list, 1); - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - -#if defined (ARRAY_VARS) - if (t = xstrchr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - entry = assign_array_from_string (name, value); - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value); - - stupidly_hack_special_variables (name); - - if (entry) - VUNSETATTR (entry, att_invisible); - - /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ -int -do_assignment (string) - const 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. */ -int -do_assignment_no_expand (string) - const char *string; -{ - return do_assignment_internal (string, 0); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* 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; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#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 * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - slen = strlen (string); - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - 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 & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is nonzero, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. The - caller is responsible for removing the backslashes if the unquoted - words is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - if (xstrchr (w->word, '~') && unquoted_member ('~', w->word)) - { - p = bash_tilde_expand (w->word, 0); - free (w->word); - w->word = p; - } - - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* 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, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - 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 == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - -/* 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 - substitution, 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 == 0 || *string == '\0') - 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); -} - -/* 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; - - td.flags = 0; - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* 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. */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or 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. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - s = string; - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, s)); - - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)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. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quoted quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 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) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - free (t); - w->word->flags |= W_QUOTED; - } - return list; -} - -static WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -static char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* 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 () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -static char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - i++; - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* 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; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -#if 0 /* Currently unused */ -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -#endif -#endif - -/* 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_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register int len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (savestring (param)); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) - -#if !defined (HAVE_WCSDUP) -static wchar_t * -wcsdup (ws) - wchar_t *ws; -{ - wchar_t *ret; - size_t len; - - len = wcslen (ws); - ret = xmalloc ((len + 1) * sizeof (wchar_t)); - if (ret == 0) - return ret; - return (wcscpy (ret, ws)); -} -#endif /* !HAVE_WCSDUP */ - -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc; - int n, n1; - wchar_t *ret; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wcsdup (wparam)); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - char *xret; - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - return (remove_upattern (param, pattern, op)); - n = xdupmbstowcs (&wparam, NULL, param); - if (n == (size_t)-1) - { - free (wpattern); - return (remove_upattern (param, pattern, op)); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - return (remove_upattern (param, pattern, op)); -} - -/* Return 1 of the first character of STRING could match the first - character of pattern PAT. Used to avoid n2 calls to strmatch(). */ -static int -match_pattern_char (pat, string) - char *pat, *string; -{ - char c; - - if (*string == 0) - return (0); - - switch (c = *pat++) - { - default: - return (*string == c); - case '\\': - return (*string == *pat); - case '?': - return (*pat == LPAREN ? 1 : (*string != '\0')); - case '*': - return (1); - case '+': - case '!': - case '@': - return (*pat == LPAREN ? 1 : (*string == c)); - case '[': - return (*string != '\0'); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len; - register char *p, *p1; - char *end; - - len = STRLEN (string); - end = string + len; - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { - for (p1 = end; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - - for (p = end; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - } - - return (0); - - case MATCH_END: - for (p = string; p <= end; p++) - { - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } - - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) -/* Return 1 of the first character of WSTRING could match the first - character of pattern WPAT. Wide character version. */ -static int -match_pattern_wchar (wpat, wstring) - wchar_t *wpat, *wstring; -{ - wchar_t wc; - - if (*wstring == 0) - return (0); - - switch (wc = *wpat++) - { - default: - return (*wstring == wc); - case L'\\': - return (*wstring == *wpat); - case L'?': - return (*wpat == LPAREN ? 1 : (*wstring != L'\0')); - case L'*': - return (1); - case L'+': - case L'!': - case L'@': - return (*wpat == LPAREN ? 1 : (*wstring == wc)); - case L'[': - return (*wstring != L'\0'); - } -} - -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { - if (match_pattern_wchar (wpat, wstring + n)) - { - for (n1 = wstrlen; n1 >= n; n1--) - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring) == 0) - return (0); - - for (n = wstrlen; n >= 0; n--) - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; - } - - return (0); - - case MATCH_END: - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } - } - - return (0); - } - - return (0); -} -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; -#endif - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value); - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - FREE (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (a, pattern, patspec, varname, quoted) - ARRAY *a; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - list = array_to_word_list (a); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) - char *varname, *value, *patstr; - int rtype, quoted; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - pattern = getpattern (patstr, quoted, 1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * 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, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : 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_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : 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; -{ - return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL)); -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#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 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#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; -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 = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - 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 %ld: dev_fd_list:", (long)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, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - 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 || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - 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]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (!pathname) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - 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) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - 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_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannout reset nodelay mode for fd %d"), fd); - 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) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - 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", (SEVAL_NONINT|SEVAL_NOHIST)); - -#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 */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted) - int fd, quoted; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = 0; - -#ifdef __CYGWIN__ - setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ -#endif - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - 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, istring_index - 1, 1); - - return istring; -} - -/* Perform command substitution on STRING. This returns a string, - possibly quoted. */ -char * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp; - char *istring; - int result, fildes[2], function_value, pflags, rc; - - istring = (char *)NULL; - - /* 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); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = 125; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = interactive ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif - - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((char *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - 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; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - istring = read_comsub (fildes[0], quoted); - - close (fildes[0]); - - current_command_subst_pid = pid; - 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) && last_command_exit_signal == 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. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ -#if 0 - if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) -#else - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) -#endif - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - return (istring); - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *t, c; - ARRAY *array; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_p (var) ? array_num_elements (array) : 1); - - ind = array_expand_index (t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - - len = STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -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; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = xstrchr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - 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, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - /* Handle multiple digit arguments, as in ${11}. */ - - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - if (tt) - temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (tt) - : quote_escapes (tt); - else - temp = (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp = array_value (name, quoted, &atype); - if (atype == 0 && temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - return (temp); -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static char * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - - t = parameter_brace_expand_word (name, var_is_special, quoted); - /* Have to dequote here if necessary */ - if (t) - { - temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - ? dequote_string (t) - : dequote_escapes (t); - free (t); - t = temp; - } - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (t); - temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - return temp; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static char * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* XXX - Should we tilde expand in an assignment context if C is `='? */ - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) - { - hasdol = 0; - t = string_extract_double_quoted (temp, &hasdol, 1); - free (temp); - temp = t; - } - - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. We use string_list_dollar_star instead. */ - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); - - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - return (temp); - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1); - else -#endif /* ARRAY_VARS */ - 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; -{ - WORD_LIST *l; - char *temp; - - if (value && *value) - { - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - l = expand_string (temp, 0); - FREE (temp); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - 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] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = STRLEN (t); - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (value, substr, vtype, e1p, e2p) - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = strlen (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. */ - len = array_max_index (a); /* arrays index from 0 to n - 1 */ - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p >= len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - if (*e2p < 0) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, quoted, varp, valp) - char *varname, *value; - int quoted; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - if (v && array_p (v)) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = (char *)array_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else - return -1; - } - else if ((v = find_variable (varname)) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif -#if 1 - { - if (value && vtype == VT_VARIABLE) - { - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - *valp = value; - } -#else - *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; -#endif - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - slen = STRLEN (string); - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, substr, quoted) - char *varname, *value, *substr; - int quoted; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - if (r <= 0) - return ((r == 0) ? &expand_param_error : (char *)NULL); - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str; - int rsize, rptr, l, replen, mtype; - - mtype = mflags & MATCH_TYPEMASK; - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = strlen (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rep, replen); - rptr += replen; - } - str = e; /* e == end of match */ - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - e++, str++; /* avoid infinite recursion on zero-length match */ - } - - /* Now copy the unmatched portion of the input string */ - if (*str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret, *tt; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = make_bare_word (ret); - dispose_word (params->word); - params->word = w; - FREE (ret); - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, patsub, quoted) - char *varname, *value, *patsub; - int quoted; -{ - int vtype, mflags, starsub; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - -#if 0 - /* Expand PAT and REP for command, variable and parameter, arithmetic, - and process substitution. Also perform quote removal. Do not - perform word splitting or filename generation. */ - pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); -#else - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); -#endif - - if (rep) - { - if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - p = pat; - if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = array_patsub (array_cell (v), p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static char * -parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub; - char *name, *value, *temp, *temp1; - int t_index, sindex, c; - intmax_t number; - - value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = 0; - - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && - (string[t_index] == '-' || - string[t_index] == '?' || - string[t_index] == '#')) || - (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) - { - t_index++; - free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xmalloc (3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' && string[sindex] != RBRACE) - want_patsub = 1; - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* 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. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - - *indexp = sindex; - return ((number < 0) ? &expand_param_error : itos (number)); - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (x); - free (xlist); - free (temp1); - *indexp = sindex; - return (temp); - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - free (temp1); - *indexp = sindex; - return (temp); - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - temp = parameter_brace_expand_word (name, var_is_special, quoted); - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, 0); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_param_error; - - case RBRACE: - if (var_is_set == 0 && unbound_vars_is_error) - { - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted); - free (temp); - free (value); - temp = temp1; - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_param_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - } - free (value); - } - - break; - } - free (name); - return (temp); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static char * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - - /* 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': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } -#if 1 - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (char *)NULL; -#else - temp = temp1 ? quote_escapes (temp1) : (char *)NULL; -#endif - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ - temp = string_list_dollar_star (list); - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* 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 '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, quoted); - - dispose_words (list); - break; - - case LBRACE: - temp = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - return (temp); - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (temp && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - temp = (char *)NULL; - } - - } - - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_param_fatal); - } - else - return (&expand_param_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - - /* Do initial variable expansion. */ - temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - else if (unbound_vars_is_error) - goto unbound_variable; - } - else -#endif - { - temp = value_cell (var); - - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - } - - free (temp1); - - goto return0; - } - - temp = (char *)NULL; - -unbound_variable: - if (unbound_vars_is_error) - err_unboundvar (temp1); - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_param_fatal - : &expand_param_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - return (temp); -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal 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 contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - 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, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - int had_quoted_null; - int has_dollar_at; - int tflag; - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - string_size = strlen (string); - - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - temp = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return ((temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - if (expanded_something) - *expanded_something = 1; - - temp = string_extract (string, &sindex, "`", 0); - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - temp1 = command_substitute (temp, quoted); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = make_word (temp); /* XXX */ - free (temp); - temp = (char *)NULL; - - has_dollar_at = 0; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL); - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - dispose_words (list); -#if 1 - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* HOWEVER, this fails if the string contains a literal - CTLNUL or CTLNUL is contained in the (non-null) expansion - of some variable. I'm not sure what to do about this - yet. There has to be some way to indicate the difference - between the two. An auxiliary data structure might be - necessary. */ - if (QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ -#endif - } - } - 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 == 0 && quoted_state == PARTIALLY_QUOTED) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - 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. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - 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 == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1) - sindex--; - - if (MB_CUR_MAX > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* 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. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* 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_bare_word (t); - free (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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = v ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - - ifs_firstc = ifs_value ? *ifs_value : 0; -} - -char * -getifs () -{ - return ifs_value; -} - -/* 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, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & 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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* 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 SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (!tlist) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_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->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_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->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_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->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_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); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* 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_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - 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. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - report_error (_("no match: %s"), tlist->word->word); - jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = 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 `xstrchr', 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 (xstrchr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = make_word (temp_string); - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - output_list = make_word_list (w, output_list); - free (expansions[eindex]); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && - (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) && - (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))) - { - tlist->word->word = bash_tilde_expand (temp_string, 1); - free (temp_string); - } - else if (temp_string[0] == '~') - { - tlist->word->word = bash_tilde_expand (temp_string, 0); - free (temp_string); - } - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = 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); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_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 ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_assign_func_t *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 (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/subst.c.save2 b/subst.c.save2 deleted file mode 100644 index 0878f8739..000000000 --- a/subst.c.save2 +++ /dev/null @@ -1,7005 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, and - globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the string extraction functions. */ -#define EX_NOALLOC 0x01 /* just skip; don't return substring */ -#define EX_VARNAME 0x02 /* variable name; for string_extract () */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -unsigned char ifs_firstc; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment; -extern int subshell_level; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static char expand_param_error, expand_param_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *dequote_escapes __P((char *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); -static char *remove_quoted_escapes __P((char *)); -static char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -static int do_assignment_internal __P((const char *, int)); - -static char *string_extract_verbatim __P((char *, int *, char *)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static char *remove_pattern __P((char *, char *, int)); -static int match_pattern_char __P((char *, char *)); -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); - -static char *parameter_brace_expand_word __P((char *, int, int)); -static char *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static char *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, char *, int)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, char *, int)); - -static char *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static char *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (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 freeing 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 = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* 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) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* 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. If (flags & EX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & EX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & EX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - - temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[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: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - 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++; - i++; - 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; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ - else - ret = extract_dollar_brace_string (string, &si, 1, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j++] = string[si]; - - i = si + 1; - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, sindex, charlist) - char *string; - int *sindex; - char *charlist; -{ - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - for (i = *sindex; c = string[i]; i++) - { - if (c == CTLESC) - { - i++; - continue; - } - - if (MEMBER (c, charlist)) - break; - } - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", 0)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & EX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - 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 of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ - i = si + 1; - continue; - } - - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - report_error ("bad substitution: no closing `%s' in %s", "}", string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)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 - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims) - char *string; - int start; - char *delims; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (member (c, delims)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - d2 = (char *)xmalloc (strlen (delims) + 1); - for (i = ts = 0; delims[i]; i++) - { - if (whitespace(delims[i]) == 0) - d2[ts++] = delims[i]; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitspace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - while (1) - { - te = skip_to_delim (string, ts, d); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING, add an additional null argument and set the current - word pointer to that. */ - if (cwp && cw == -1 && sentinel >= slen) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* 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. */ -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 == 0) - 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 = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - 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 sep[2]; - - sep[0] = ifs_firstc; - sep[1] = '\0'; - - return (string_list_internal (list, sep)); -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, sep[2]; - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; - - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) - ? quote_list (list) - : list_quote_escapes (list); - return (string_list_internal (tlist, 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! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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. */ - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - current_word = string_extract_verbatim (string, &sindex, separators); - if (current_word == 0) - 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)) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* 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++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (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. This is never called with SEPARATORS != $IFS; - it should be simplified. - - 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, whitesep; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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) && isifs (*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; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (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]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (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) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -/* 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) - const char *string; - int expand; -{ - int offset; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni, assign_list = 0; -#endif - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - name[offset] = 0; - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) - { - assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); - } - else -#endif - - /* Perform tilde expansion. */ - if (expand && temp[0]) - { - temp = (xstrchr (temp, '~') && unquoted_member ('~', temp)) - ? bash_tilde_expand (temp, 1) - : savestring (temp); - - value = expand_string_if_necessary (temp, 0, expand_string_unsplit); - free (temp); - } - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { -#if defined (ARRAY_VARS) - if (assign_list) - fprintf (stderr, "%s%s=(%s)\n", indirection_level_string (), name, value); - else -#endif - fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value); - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - -#if defined (ARRAY_VARS) - if (t = xstrchr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - entry = assign_array_from_string (name, value); - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value); - - stupidly_hack_special_variables (name); - - if (entry) - VUNSETATTR (entry, att_invisible); - - /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ -int -do_assignment (string) - const 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. */ -int -do_assignment_no_expand (string) - const char *string; -{ - return do_assignment_internal (string, 0); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* 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; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#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 * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - slen = strlen (string); - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - 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 & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is nonzero, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. The - caller is responsible for removing the backslashes if the unquoted - words is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - if (xstrchr (w->word, '~') && unquoted_member ('~', w->word)) - { - p = bash_tilde_expand (w->word, 0); - free (w->word); - w->word = p; - } - - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* 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, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - 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 == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - -/* 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 - substitution, 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 == 0 || *string == '\0') - 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); -} - -/* 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; - - td.flags = 0; - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* 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. */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or 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. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - s = string; - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, s)); - - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)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. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quoted quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 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) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - free (t); - w->word->flags |= W_QUOTED; - } - return list; -} - -static WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -static char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* 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 () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -static char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - i++; - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* 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; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and 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; - register char *end; - register char *p, *ret, c; - - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - /* BACKUP_CHAR_P (param, len, p); */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - /* ADVANCE_CHAR_P (p, end - p),p++ */ - for (p = param; p <= end; p++) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - /* ADVANCE_CHAR_P (p, end - p),p++ */ - for (p = param; p <= end; p++) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - /* BACKUP_CHAR_P (param, len, p); */ - for (p = end; p >= param; p--) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - return (savestring (param)); /* no match, return original string */ -} - -/* Return 1 of the first character of STRING could match the first - character of pattern PAT. Used to avoid n2 calls to strmatch(). */ -static int -match_pattern_char (pat, string) - char *pat, *string; -{ - char c; - - if (*string == 0) - return (0); - - switch (c = *pat++) - { - default: - return (*string == c); - case '\\': - return (*string == *pat); - case '?': - return (*pat == LPAREN ? 1 : (*string != '\0')); - case '*': - return (1); - case '+': - case '!': - case '@': - return (*pat == LPAREN ? 1 : (*string == c)); - case '[': - return (*string != '\0'); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len; - register char *p, *p1; - char *end; - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - - len = STRLEN (string); - end = string + len; - - switch (mtype) - { - case MATCH_ANY: - /* ADVANCE_CHAR_P (p, end - p),p++ */ - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { - /* BACKUP_CHAR_P (p, end - p, p1) */ - for (p1 = end; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; - } - } - } - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - /* BACKUP_CHAR_P (string, len, p) */ - for (p = end; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - } - return (0); - - case MATCH_END: - /* ADVANCE_CHAR_P(p, end - p), p++ */ - for (p = string; p <= end; p++) - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } - return (0); - } - - return (0); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value); - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - FREE (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (a, pattern, patspec, varname, quoted) - ARRAY *a; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - list = array_to_word_list (a); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) - char *varname, *value, *patstr; - int rtype, quoted; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - pattern = getpattern (patstr, quoted, 1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * 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, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : 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_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : 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; -{ - return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL)); -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#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 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#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; -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 = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - 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 %ld: dev_fd_list:", (long)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, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - 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 || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - 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]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (!pathname) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - 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) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - 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_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannout reset nodelay mode for fd %d"), fd); - 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) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - 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", (SEVAL_NONINT|SEVAL_NOHIST)); - -#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 */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted) - int fd, quoted; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = 0; - -#ifdef __CYGWIN__ - setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ -#endif - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - 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, istring_index - 1, 1); - - return istring; -} - -/* Perform command substitution on STRING. This returns a string, - possibly quoted. */ -char * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp; - char *istring; - int result, fildes[2], function_value, pflags, rc; - - istring = (char *)NULL; - - /* 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); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = 125; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = interactive ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif - - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((char *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - 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; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - istring = read_comsub (fildes[0], quoted); - - close (fildes[0]); - - current_command_subst_pid = pid; - 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) && last_command_exit_signal == 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. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ -#if 0 - if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) -#else - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) -#endif - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - return (istring); - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *t, c; - ARRAY *array; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_p (var) ? array_num_elements (array) : 1); - - ind = array_expand_index (t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - - len = STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -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; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = xstrchr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - 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, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - /* Handle multiple digit arguments, as in ${11}. */ - - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp = array_value (name, quoted, &atype); - if (atype == 0 && temp) - temp = quote_escapes (temp); - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = quote_escapes (temp); - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - return (temp); -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static char * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - - t = parameter_brace_expand_word (name, var_is_special, quoted); - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (t); - temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - return temp; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static char * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* XXX - Should we tilde expand in an assignment context if C is `='? */ - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) - { - hasdol = 0; - t = string_extract_double_quoted (temp, &hasdol, 1); - free (temp); - temp = t; - } - - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. */ - temp = string_list (l); - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if ((hasdol && quoted) || l->next) - *qdollaratp = 1; - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - return (temp); - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1); - else -#endif /* ARRAY_VARS */ - 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; -{ - WORD_LIST *l; - char *temp; - - if (value && *value) - { - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - l = expand_string (temp, 0); - FREE (temp); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - 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] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = STRLEN (t); - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (value, substr, vtype, e1p, e2p) - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = strlen (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. */ - len = array_max_index (a); /* arrays index from 0 to n - 1 */ - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p >= len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - if (*e2p < 0) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, varp, valp) - char *varname, *value; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - if (v && array_p (v)) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = (char *)array_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else - return -1; - } - else if ((v = find_variable (varname)) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif - *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - slen = STRLEN (string); - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, substr, quoted) - char *varname, *value, *substr; - int quoted; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - if (r <= 0) - return ((r == 0) ? &expand_param_error : (char *)NULL); - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str; - int rsize, rptr, l, replen, mtype; - - mtype = mflags & MATCH_TYPEMASK; - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = strlen (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rep, replen); - rptr += replen; - } - str = e; /* e == end of match */ - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - e++, str++; /* avoid infinite recursion on zero-length match */ - } - - /* Now copy the unmatched portion of the input string */ - if (*str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret, *tt; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = make_bare_word (ret); - dispose_word (params->word); - params->word = w; - FREE (ret); - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, patsub, quoted) - char *varname, *value, *patsub; - int quoted; -{ - int vtype, mflags, starsub; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - -#if 0 - /* Expand PAT and REP for command, variable and parameter, arithmetic, - and process substitution. Also perform quote removal. Do not - perform word splitting or filename generation. */ - pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); -#else - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); -#endif - - if (rep) - { - if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - p = pat; - if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = array_patsub (array_cell (v), p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static char * -parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub; - char *name, *value, *temp, *temp1; - int t_index, sindex, c; - intmax_t number; - - value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = 0; - - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && - (string[t_index] == '-' || - string[t_index] == '?' || - string[t_index] == '#')) || - (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) - { - t_index++; - free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xmalloc (3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' && string[sindex] != RBRACE) - want_patsub = 1; - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* 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. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - - *indexp = sindex; - return ((number < 0) ? &expand_param_error : itos (number)); - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (x); - free (xlist); - free (temp1); - *indexp = sindex; - return (temp); - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - free (temp1); - *indexp = sindex; - return (temp); - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - temp = parameter_brace_expand_word (name, var_is_special, quoted); - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, 0); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_param_error; - - case RBRACE: - if (var_is_set == 0 && unbound_vars_is_error) - { - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted); - free (temp); - free (value); - temp = temp1; - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_param_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - } - free (value); - } - - break; - } - free (name); - return (temp); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static char * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - - /* 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': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - temp = temp1 ? quote_escapes (temp1) : (char *)NULL; - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ - temp = string_list_dollar_star (list); - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* 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 '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, quoted); - - dispose_words (list); - break; - - case LBRACE: - temp = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - return (temp); - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (temp && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - temp = (char *)NULL; - } - - } - - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_param_fatal); - } - else - return (&expand_param_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - - /* Do initial variable expansion. */ - temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = quote_escapes (temp); - } - else -#endif - temp = quote_escapes (value_cell (var)); - free (temp1); - - goto return0; - } - - temp = (char *)NULL; - - if (unbound_vars_is_error) - err_unboundvar (temp1); - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_param_fatal - : &expand_param_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - return (temp); -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal 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 contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - 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, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - int had_quoted_null; - int has_dollar_at; - int tflag; - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - string_size = strlen (string); - - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - int i; - mbstate_t state_bak; - size_t mblength; - - state_bak = state; - mblength = mbrlen (string + sindex, string_size - sindex, &state); - if (MB_INVALIDCH (mblength)) - { - state = state_bak; - mblength = 1; - } - if (mblength < 1) - mblength = 1; - temp = (char *)xmalloc (mblength + 2); - temp[0] = CTLESC; - for (i = 0; i < mblength; i++) - temp[i+1] = string[sindex++]; - temp[mblength + 1] = '\0'; - - goto add_string; - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - temp = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return ((temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - if (expanded_something) - *expanded_something = 1; - - temp = string_extract (string, &sindex, "`", 0); - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - temp1 = command_substitute (temp, quoted); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = make_word (temp); /* XXX */ - free (temp); - temp = (char *)NULL; - - has_dollar_at = 0; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL); - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - dispose_words (list); -#if 1 - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* HOWEVER, this fails if the string contains a literal - CTLNUL or CTLNUL is contained in the (non-null) expansion - of some variable. I'm not sure what to do about this - yet. There has to be some way to indicate the difference - between the two. An auxiliary data structure might be - necessary. */ - if (QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ -#endif - } - } - 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 == 0 && quoted_state == PARTIALLY_QUOTED) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - 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. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - 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 == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - /* XXX - I'd like to use SCOPY_CHAR_I here. */ - if (MB_CUR_MAX > 1) - { - int i; - mbstate_t state_bak; - size_t mblength; - - sindex--; - state_bak = state; - mblength = mbrlen (string + sindex, string_size - sindex, &state); - if (MB_INVALIDCH (mblength)) - { - state = state_bak; - mblength = 1; - } - if (mblength < 1) - mblength = 1; - - temp = (char *)xmalloc (mblength + 2); - temp[0] = CTLESC; - for (i = 0; i < mblength; i++) - temp[i + 1] = string[sindex++]; - temp[mblength + 1] = '\0'; - - goto add_string; - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* 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. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* 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_bare_word (t); - free (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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = v ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - - ifs_firstc = ifs_value ? *ifs_value : 0; -} - -char * -getifs () -{ - return ifs_value; -} - -/* 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, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & 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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* 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 SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (!tlist) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_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->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_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->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_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->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_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); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* 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_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - 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. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - report_error (_("no match: %s"), tlist->word->word); - jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = 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 `xstrchr', 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 (xstrchr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = make_word (temp_string); - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - output_list = make_word_list (w, output_list); - free (expansions[eindex]); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && - (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) && - (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))) - { - tlist->word->word = bash_tilde_expand (temp_string, 1); - free (temp_string); - } - else if (temp_string[0] == '~') - { - tlist->word->word = bash_tilde_expand (temp_string, 0); - free (temp_string); - } - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = 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); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_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 ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_assign_func_t *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 (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/subst.c~ b/subst.c~ deleted file mode 100644 index f808537e0..000000000 --- a/subst.c~ +++ /dev/null @@ -1,7383 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, and - globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the string extraction functions. */ -#define EX_NOALLOC 0x01 /* just skip; don't return substring */ -#define EX_VARNAME 0x02 /* variable name; for string_extract () */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; -unsigned char ifs_firstc; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment; -extern int subshell_level; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static char expand_param_error, expand_param_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *dequote_escapes __P((char *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); -static char *remove_quoted_escapes __P((char *)); -static char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -static int do_assignment_internal __P((const char *, int)); - -static char *string_extract_verbatim __P((char *, int *, char *)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static unsigned char *mb_getcharlens __P((char *, int)); - -static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -# if !defined (HAVE_WCSDUP) -static wchar_t *wcsdup __P((wchar_t *)); -# endif -static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern __P((char *, char *, int)); - -static int match_pattern_char __P((char *, char *)); -static int match_upattern __P((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_pattern_wchar __P((wchar_t *, wchar_t *)); -static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((ARRAY *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); - -static char *parameter_brace_expand_word __P((char *, int, int)); -static char *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static char *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, char *, int)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, char *, int)); - -static char *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static char *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (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 freeing 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 = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* 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) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* 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. If (flags & EX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & EX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & EX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - - temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[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: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - 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++; - i++; - 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; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - int free_ret = 1; - - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ - else - ret = extract_dollar_brace_string (string, &si, 1, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error - is set. */ - if (ret == 0 && no_longjmp_on_fatal_error) - { - free_ret = 0; - ret = string + i + 2; - } - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j] = string[si]; - - if (string[si]) - { - j++; - i = si + 1; - } - else - i = si; - - if (free_ret) - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, sindex, charlist) - char *string; - int *sindex; - char *charlist; -{ - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - for (i = *sindex; c = string[i]; i++) - { - if (c == CTLESC) - { - i++; - continue; - } - - if (MEMBER (c, charlist)) - break; - } - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", 0)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & EX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - 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 of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|EX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ - i = si + 1; - continue; - } - - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - report_error ("bad substitution: no closing `%s' in %s", "}", string); - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)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 - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims) - char *string; - int start; - char *delims; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (member (c, delims)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - d2 = (char *)xmalloc (strlen (delims) + 1); - for (i = ts = 0; delims[i]; i++) - { - if (whitespace(delims[i]) == 0) - d2[ts++] = delims[i]; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitspace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - while (1) - { - te = skip_to_delim (string, ts, d); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING, add an additional null argument and set the current - word pointer to that. */ - if (cwp && cw == -1 && sentinel >= slen) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* 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. */ -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 == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* 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 = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - 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 sep[2]; - - sep[0] = ifs_firstc; - sep[1] = '\0'; - - return (string_list_internal (list, sep)); -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, sep[2]; - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; - - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) - ? quote_list (list) - : list_quote_escapes (list); - return (string_list_internal (tlist, 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! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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. */ - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - current_word = string_extract_verbatim (string, &sindex, separators); - if (current_word == 0) - 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)) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = make_bare_word (""); - t->flags |= W_QUOTED; - free (t->word); - t->word = make_quoted_char ('\0'); - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* 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++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (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. This is never called with SEPARATORS != $IFS; - it should be simplified. - - 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, whitesep; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - /* 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) && isifs (*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; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (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]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (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) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -/* 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) - const char *string; - int expand; -{ - int offset; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - int assign_list = 0; - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - name[offset] = 0; - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) - { - assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); - } - else -#endif - - /* Perform tilde expansion. */ - if (expand && temp[0]) - { - temp = (xstrchr (temp, '~') && unquoted_member ('~', temp)) - ? bash_tilde_expand (temp, 1) - : savestring (temp); - - value = expand_string_if_necessary (temp, 0, expand_string_unsplit); - free (temp); - } - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - xtrace_print_assignment (name, value, assign_list, 1); - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - -#if defined (ARRAY_VARS) - if (t = xstrchr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - entry = assign_array_from_string (name, value); - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value); - - stupidly_hack_special_variables (name); - - if (entry) - VUNSETATTR (entry, att_invisible); - - /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ -int -do_assignment (string) - const 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. */ -int -do_assignment_no_expand (string) - const char *string; -{ - return do_assignment_internal (string, 0); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* 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; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') -#if 0 - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h); -#else - { - if (quoted & Q_DOUBLE_QUOTES) - ret = string_list_dollar_star (quote_list (h)); - else if (quoted & Q_HERE_DOCUMENT) - ret = string_list (quote_list (h)); - else - ret = string_list (h); - } -#endif - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#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 * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - slen = strlen (string); - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - 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 & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is nonzero, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. The - caller is responsible for removing the backslashes if the unquoted - words is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - if (xstrchr (w->word, '~') && unquoted_member ('~', w->word)) - { - p = bash_tilde_expand (w->word, 0); - free (w->word); - w->word = p; - } - - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* 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, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - 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 == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - remove_quoted_nulls (value->word->word); - dequote_list (value); - } - return (value); -} - -/* 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 - substitution, 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 == 0 || *string == '\0') - 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); -} - -/* 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; - - td.flags = 0; - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - 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 == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* 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. */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or 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. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - s = string; - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, s)); - - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)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. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quoted quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 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) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - free (t); - w->word->flags |= W_QUOTED; - } - return list; -} - -static WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -static char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* 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 () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -static char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - i++; - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* 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; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -#if 0 /* Currently unused */ -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -#endif -#endif - -/* 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_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register int len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, param, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != 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 (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (savestring (param)); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) - -#if !defined (HAVE_WCSDUP) -static wchar_t * -wcsdup (ws) - wchar_t *ws; -{ - wchar_t *ret; - size_t len; - - len = wcslen (ws); - ret = xmalloc ((len + 1) * sizeof (wchar_t)); - if (ret == 0) - return ret; - return (wcscpy (ret, ws)); -} -#endif /* !HAVE_WCSDUP */ - -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc; - int n, n1; - wchar_t *ret; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wcsdup (wparam)); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - char *xret; - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - return (remove_upattern (param, pattern, op)); - n = xdupmbstowcs (&wparam, NULL, param); - if (n == (size_t)-1) - { - free (wpattern); - return (remove_upattern (param, pattern, op)); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - return (remove_upattern (param, pattern, op)); -} - -/* Return 1 of the first character of STRING could match the first - character of pattern PAT. Used to avoid n2 calls to strmatch(). */ -static int -match_pattern_char (pat, string) - char *pat, *string; -{ - char c; - - if (*string == 0) - return (0); - - switch (c = *pat++) - { - default: - return (*string == c); - case '\\': - return (*string == *pat); - case '?': - return (*pat == LPAREN ? 1 : (*string != '\0')); - case '*': - return (1); - case '+': - case '!': - case '@': - return (*pat == LPAREN ? 1 : (*string == c)); - case '[': - return (*string != '\0'); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len; - register char *p, *p1; - char *end; - - len = STRLEN (string); - end = string + len; - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { - for (p1 = end; p1 >= p; p1--) - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - - for (p = end; p >= string; p--) - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; - } - - return (0); - - case MATCH_END: - for (p = string; p <= end; p++) - { - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } - - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) -/* Return 1 of the first character of WSTRING could match the first - character of pattern WPAT. Wide character version. */ -static int -match_pattern_wchar (wpat, wstring) - wchar_t *wpat, *wstring; -{ - wchar_t wc; - - if (*wstring == 0) - return (0); - - switch (wc = *wpat++) - { - default: - return (*wstring == wc); - case L'\\': - return (*wstring == *wpat); - case L'?': - return (*wpat == LPAREN ? 1 : (*wstring != L'\0')); - case L'*': - return (1); - case L'+': - case L'!': - case L'@': - return (*wpat == LPAREN ? 1 : (*wstring == wc)); - case L'[': - return (*wstring != L'\0'); - } -} - -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { - if (match_pattern_wchar (wpat, wstring + n)) - { - for (n1 = wstrlen; n1 >= n; n1--) - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring) == 0) - return (0); - - for (n = wstrlen; n >= 0; n--) - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; - } - - return (0); - - case MATCH_END: - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } - } - - return (0); - } - - return (0); -} -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; -#endif - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value); - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - FREE (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') -#if 0 - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); -#else - tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l); -#endif - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (a, pattern, patspec, varname, quoted) - ARRAY *a; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - list = array_to_word_list (a); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) - char *varname, *value, *patstr; - int rtype, quoted; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - pattern = getpattern (patstr, quoted, 1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * 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, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : 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_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : 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; -{ - return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL)); -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#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 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#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; -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 = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - 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 %ld: dev_fd_list:", (long)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, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - 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 || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - 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]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (!pathname) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - 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) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - 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_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannout reset nodelay mode for fd %d"), fd); - 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) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - 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", (SEVAL_NONINT|SEVAL_NOHIST)); - -#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 */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted) - int fd, quoted; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = 0; - -#ifdef __CYGWIN__ - setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ -#endif - - /* Read the output of the command through the pipe. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - 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, istring_index - 1, 1); - - return istring; -} - -/* Perform command substitution on STRING. This returns a string, - possibly quoted. */ -char * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp; - char *istring; - int result, fildes[2], function_value, pflags, rc; - - istring = (char *)NULL; - - /* 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); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = 125; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = interactive ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif - - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((char *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - 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; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - istring = read_comsub (fildes[0], quoted); - - close (fildes[0]); - - current_command_subst_pid = pid; - 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) && last_command_exit_signal == 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. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ -#if 0 - if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) -#else - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) -#endif - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - return (istring); - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *t, c; - ARRAY *array; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_p (var) ? array_num_elements (array) : 1); - - ind = array_expand_index (t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - - len = STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -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; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = xstrchr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - 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, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - /* Handle multiple digit arguments, as in ${11}. */ - - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - if (tt) - temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (tt) - : quote_escapes (tt); - else - temp = (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, 0); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp = array_value (name, quoted, &atype); - if (atype == 0 && temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } - else - temp = (char *)NULL; - } - else - temp = (char *)NULL; - - return (temp); -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static char * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - - t = parameter_brace_expand_word (name, var_is_special, quoted); - /* Have to dequote here if necessary */ - if (t) - { - temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - ? dequote_string (t) - : dequote_escapes (t); - free (t); - t = temp; - } - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (t); - temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - return temp; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static char * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* XXX - Should we tilde expand in an assignment context if C is `='? */ - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) - { - hasdol = 0; - t = string_extract_double_quoted (temp, &hasdol, 1); - free (temp); - temp = t; - } - - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. We use string_list_dollar_star instead. */ - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); - - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - return (temp); - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1); - else -#endif /* ARRAY_VARS */ - 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; -{ - WORD_LIST *l; - char *temp; - - if (value && *value) - { - if (*value == '~') - temp = bash_tilde_expand (value, 0); - else if (xstrchr (value, '~') && unquoted_substring ("=~", value)) - temp = bash_tilde_expand (value, 1); - else - temp = savestring (value); - - l = expand_string (temp, 0); - FREE (temp); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - 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] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = STRLEN (t); - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (value, substr, vtype, e1p, e2p) - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = strlen (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. */ - len = array_max_index (a); /* arrays index from 0 to n - 1 */ - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p >= len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - if (*e2p < 0) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, quoted, varp, valp) - char *varname, *value; - int quoted; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - if (v && array_p (v)) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = (char *)array_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else - return -1; - } - else if ((v = find_variable (varname)) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif -#if 1 - { - if (value && vtype == VT_VARIABLE) - { - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - *valp = value; - } -#else - *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; -#endif - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - slen = STRLEN (string); - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, substr, quoted) - char *varname, *value, *substr; - int quoted; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - if (r <= 0) - return ((r == 0) ? &expand_param_error : (char *)NULL); - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str; - int rsize, rptr, l, replen, mtype; - - mtype = mflags & MATCH_TYPEMASK; - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = strlen (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rep, replen); - rptr += replen; - } - str = e; /* e == end of match */ - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - e++, str++; /* avoid infinite recursion on zero-length match */ - } - - /* Now copy the unmatched portion of the input string */ - if (*str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret, *tt; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = make_bare_word (ret); - dispose_word (params->word); - params->word = w; - FREE (ret); - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, patsub, quoted) - char *varname, *value, *patsub; - int quoted; -{ - int vtype, mflags, starsub; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - -#if 0 - /* Expand PAT and REP for command, variable and parameter, arithmetic, - and process substitution. Also perform quote removal. Do not - perform word splitting or filename generation. */ - pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); -#else - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); -#endif - - if (rep) - { - if ((mflags & MATCH_QUOTED) == 0) - rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit); - else - rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); - } - - p = pat; - if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = array_patsub (array_cell (v), p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static char * -parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub; - char *name, *value, *temp, *temp1; - int t_index, sindex, c; - intmax_t number; - - value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = 0; - - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && - (string[t_index] == '-' || - string[t_index] == '?' || - string[t_index] == '#')) || - (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) - { - t_index++; - free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xmalloc (3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' && string[sindex] != RBRACE) - want_patsub = 1; - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* 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. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - - *indexp = sindex; - return ((number < 0) ? &expand_param_error : itos (number)); - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (x); - free (xlist); - free (temp1); - *indexp = sindex; - return (temp); - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - free (temp1); - *indexp = sindex; - return (temp); - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - temp = parameter_brace_expand_word (name, var_is_special, quoted); - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, 0); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - return (temp1); - } - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_param_error; - - case RBRACE: - if (var_is_set == 0 && unbound_vars_is_error) - { - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted); - free (temp); - free (value); - temp = temp1; - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_param_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - } - free (value); - } - - break; - } - free (name); - return (temp); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static char * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - - /* 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': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } -#if 1 - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (char *)NULL; -#else - temp = temp1 ? quote_escapes (temp1) : (char *)NULL; -#endif - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_param_error : &expand_param_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ -#if 0 - temp = string_list_dollar_star (list); -#else - temp = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); -#endif - temp1 = quote_string (temp); - free (temp); - temp = temp1; - } - else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* 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 '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, quoted); - - dispose_words (list); - break; - - case LBRACE: - temp = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - return (temp); - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (temp && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - temp = (char *)NULL; - } - - } - - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_param_fatal); - } - else - return (&expand_param_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - - /* Do initial variable expansion. */ - temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - else if (unbound_vars_is_error) - goto unbound_variable; - } - else -#endif - { - temp = value_cell (var); - - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - } - - free (temp1); - - goto return0; - } - - temp = (char *)NULL; - -unbound_variable: - if (unbound_vars_is_error) - err_unboundvar (temp1); - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_param_fatal - : &expand_param_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - return (temp); -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal 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 contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - 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, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - int had_quoted_null; - int has_dollar_at; - int tflag; - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - string_size = strlen (string); - - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - temp = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return ((temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - if (expanded_something) - *expanded_something = 1; - - temp = string_extract (string, &sindex, "`", 0); - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - temp1 = command_substitute (temp, quoted); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = make_word (temp); /* XXX */ - free (temp); - temp = (char *)NULL; - - has_dollar_at = 0; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL); - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - dispose_words (list); -#if 1 - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* HOWEVER, this fails if the string contains a literal - CTLNUL or CTLNUL is contained in the (non-null) expansion - of some variable. I'm not sure what to do about this - yet. There has to be some way to indicate the difference - between the two. An auxiliary data structure might be - necessary. */ - if (QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ -#endif - } - } - 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 == 0 && quoted_state == PARTIALLY_QUOTED) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE)) -#else - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) -#endif - goto add_character; - - 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. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - 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 == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1) - sindex--; - - if (MB_CUR_MAX > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* 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. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - list = make_word_list (tword, (WORD_LIST *)NULL); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* 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_bare_word (t); - free (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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = v ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - - ifs_firstc = ifs_value ? *ifs_value : 0; -} - -char * -getifs () -{ - return ifs_value; -} - -/* 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, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & 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, *t, *tresult; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - result = (WORD_LIST *) list_append (result, tresult); - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* 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 SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (!tlist) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_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->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_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->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_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->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_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); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* 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_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - 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. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - report_error (_("no match: %s"), tlist->word->word); - jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = 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 `xstrchr', 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 (xstrchr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = make_word (temp_string); - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - output_list = make_word_list (w, output_list); - free (expansions[eindex]); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && - (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) && - (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))) - { - tlist->word->word = bash_tilde_expand (temp_string, 1); - free (temp_string); - } - else if (temp_string[0] == '~') - { - tlist->word->word = bash_tilde_expand (temp_string, 0); - free (temp_string); - } - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = 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); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_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 ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_assign_func_t *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 (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/support/bashbug.sh.orig b/support/bashbug.sh.orig deleted file mode 100644 index 3db0f8a30..000000000 --- a/support/bashbug.sh.orig +++ /dev/null @@ -1,294 +0,0 @@ -#!/bin/sh - -# -# bashbug - create a bug report and mail it to the bug address -# -# The bug address depends on the release status of the shell. Versions -# with status `devel', `alpha', `beta', or `rc' mail bug reports to -# chet@po.cwru.edu and, optionally, to bash-testers@po.cwru.edu. -# Other versions send mail to bug-bash@gnu.org. -# -# Copyright (C) 1996-2004 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -# -# configuration section: -# these variables are filled in by the make target in Makefile -# -MACHINE="!MACHINE!" -OS="!OS!" -CC="!CC!" -CFLAGS="!CFLAGS!" -RELEASE="!RELEASE!" -PATCHLEVEL="!PATCHLEVEL!" -RELSTATUS="!RELSTATUS!" -MACHTYPE="!MACHTYPE!" - -PATH=/bin:/usr/bin:/usr/local/bin:$PATH -export PATH - -# If the OS supplies a program to make temp files with semi-random names, -# use it. -: ${TMPDIR:=/tmp} -rm_tmp1=false -rm_tmp2=false - -# if we don't have mktemp or tempfile, we don't want to see error messages -# like `mktemp: not found', so temporarily redirect stderr using {...} while -# trying to run them. this may fail using old versions of the bourne shell -# that run {...} blocks with redirections in subshells; in that case we're -# no worse off than previous versions - -{ TEMPFILE1=`mktemp "$TMPDIR/bbug.XXXXXX" 2>/dev/null` ; } 2>/dev/null -if [ -z "$TEMPFILE1" ]; then - { TEMPFILE1=`tempfile --prefix bbug --mode 600 2>/dev/null`; } 2>/dev/null -fi -if [ -z "$TEMPFILE1" ]; then - TEMPFILE1=$TMPDIR/bbug.$$ - rm_tmp1=true -fi -{ TEMPFILE2=`mktemp "$TMPDIR/bbug.XXXXXX" 2>/dev/null`; } 2>/dev/null -if [ -z "$TEMPFILE2" ]; then - { TEMPFILE2=`tempfile --prefix bbug --mode 600 2>/dev/null`; } 2>/dev/null -fi -if [ -z "$TEMPFILE2" ]; then - TEMPFILE2="$TMPDIR/bbug.$$.x" - rm_tmp2=true -fi - -USAGE="Usage: $0 [--help] [--version] [bug-report-email-address]" -VERSTR="GNU bashbug, version ${RELEASE}.${PATCHLEVEL}-${RELSTATUS}" - -do_help= do_version= - -while [ $# -gt 0 ]; do - case "$1" in - --help) shift ; do_help=y ;; - --version) shift ; do_version=y ;; - --) shift ; break ;; - -*) echo "bashbug: ${1}: invalid option" >&2 - echo "$USAGE" >& 2 - exit 2 ;; - *) break ;; - esac -done - -if [ -n "$do_version" ]; then - echo "${VERSTR}" - exit 0 -fi - -if [ -n "$do_help" ]; then - echo "${VERSTR}" - echo "${USAGE}" - echo - cat << HERE_EOF -Bashbug is used to send mail to the Bash maintainers -for when Bash doesn't behave like you'd like, or expect. - -Bashbug will start up your editor (as defined by the shell's -EDITOR environment variable) with a preformatted bug report -template for you to fill in. The report will be mailed to the -bash maintainers by default. See the manual for details. - -If you invoke bashbug by accident, just quit your editor without -saving any changes to the template, and no bug report will be sent. -HERE_EOF - exit 0 -fi - -# Figure out how to echo a string without a trailing newline -N=`echo 'hi there\c'` -case "$N" in -*c) n=-n c= ;; -*) n= c='\c' ;; -esac - -BASHTESTERS="bash-testers@po.cwru.edu" - -case "$RELSTATUS" in -alpha*|beta*|devel*|rc*) BUGBASH=chet@po.cwru.edu ;; -*) BUGBASH=bug-bash@gnu.org ;; -esac - -case "$RELSTATUS" in -alpha*|beta*|devel*|rc*) - echo "$0: This is a testing release. Would you like your bug report" - echo "$0: to be sent to the bash-testers mailing list?" - echo $n "$0: Send to bash-testers? $c" - read ans - case "$ans" in - y*|Y*) BUGBASH="${BUGBASH},${BASHTESTERS}" ;; - esac ;; -esac - -BUGADDR="${1-$BUGBASH}" - -if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then - if [ -x /usr/bin/editor ]; then - DEFEDITOR=editor - elif [ -x /usr/local/bin/ce ]; then - DEFEDITOR=ce - elif [ -x /usr/local/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/contrib/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/bin/xemacs ]; then - DEFEDITOR=xemacs - elif [ -x /usr/contrib/bin/jove ]; then - DEFEDITOR=jove - elif [ -x /usr/local/bin/jove ]; then - DEFEDITOR=jove - elif [ -x /usr/bin/vi ]; then - DEFEDITOR=vi - else - echo "$0: No default editor found: attempting to use vi" >&2 - DEFEDITOR=vi - fi -fi - - -: ${EDITOR=$DEFEDITOR} - -: ${USER=${LOGNAME-`whoami`}} - -trap 'rm -f "$TEMPFILE1" "$TEMPFILE2"; exit 1' 1 2 3 13 15 -trap 'rm -f "$TEMPFILE1" "$TEMPFILE2"' 0 - -UN= -if (uname) >/dev/null 2>&1; then - UN=`uname -a` -fi - -if [ -f /usr/lib/sendmail ] ; then - RMAIL="/usr/lib/sendmail" - SMARGS="-i -t" -elif [ -f /usr/sbin/sendmail ] ; then - RMAIL="/usr/sbin/sendmail" - SMARGS="-i -t" -else - RMAIL=rmail - SMARGS="$BUGADDR" -fi - -INITIAL_SUBJECT='[50 character or so descriptive subject here (for reference)]' - -# this is raceable unless (hopefully) we used mktemp(1) or tempfile(1) -$rm_tmp1 && rm -f "$TEMPFILE1" - -cat > "$TEMPFILE1" <> $HOME/dead.bashbug - echo "$0: mail failed: report saved in $HOME/dead.bashbug" >&2 -} - -exit 0 diff --git a/support/bashbug.sh~ b/support/bashbug.sh~ deleted file mode 100644 index 32b8fc562..000000000 --- a/support/bashbug.sh~ +++ /dev/null @@ -1,271 +0,0 @@ -#!/bin/sh - -# -# bashbug - create a bug report and mail it to the bug address -# -# The bug address depends on the release status of the shell. Versions -# with status `devel', `alpha', `beta', or `rc' mail bug reports to -# chet@cwru.edu and, optionally, to bash-testers@cwru.edu. -# Other versions send mail to bug-bash@gnu.org. -# -# Copyright (C) 1996-2004 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -# -# configuration section: -# these variables are filled in by the make target in Makefile -# -MACHINE="!MACHINE!" -OS="!OS!" -CC="!CC!" -CFLAGS="!CFLAGS!" -RELEASE="!RELEASE!" -PATCHLEVEL="!PATCHLEVEL!" -RELSTATUS="!RELSTATUS!" -MACHTYPE="!MACHTYPE!" - -PATH=/bin:/usr/bin:/usr/local/bin:$PATH -export PATH - -# Check if TMPDIR is set, default to /tmp -: ${TMPDIR:=/tmp} - -#Securely create a temporary directory for the temporary files -TEMPDIR=$TMPDIR/bbug.$$ -(umask 077 && mkdir $TEMPDIR) || { - echo "Could not create temporary directory. Exiting!" - exit 1 - } -TEMPFILE1=$TEMPDIR/bbug1 -TEMPFILE2=$TEMPDIR/bbug2 - -USAGE="Usage: $0 [--help] [--version] [bug-report-email-address]" -VERSTR="GNU bashbug, version ${RELEASE}.${PATCHLEVEL}-${RELSTATUS}" - -do_help= do_version= - -while [ $# -gt 0 ]; do - case "$1" in - --help) shift ; do_help=y ;; - --version) shift ; do_version=y ;; - --) shift ; break ;; - -*) echo "bashbug: ${1}: invalid option" >&2 - echo "$USAGE" >& 2 - exit 2 ;; - *) break ;; - esac -done - -if [ -n "$do_version" ]; then - echo "${VERSTR}" - exit 0 -fi - -if [ -n "$do_help" ]; then - echo "${VERSTR}" - echo "${USAGE}" - echo - cat << HERE_EOF -Bashbug is used to send mail to the Bash maintainers -for when Bash doesn't behave like you'd like, or expect. - -Bashbug will start up your editor (as defined by the shell's -EDITOR environment variable) with a preformatted bug report -template for you to fill in. The report will be mailed to the -bash maintainers by default. See the manual for details. - -If you invoke bashbug by accident, just quit your editor without -saving any changes to the template, and no bug report will be sent. -HERE_EOF - exit 0 -fi - -# Figure out how to echo a string without a trailing newline -N=`echo 'hi there\c'` -case "$N" in -*c) n=-n c= ;; -*) n= c='\c' ;; -esac - -BASHTESTERS="bash-testers@cwru.edu" - -case "$RELSTATUS" in -alpha*|beta*|devel*|rc*) BUGBASH=chet@cwru.edu ;; -*) BUGBASH=bug-bash@gnu.org ;; -esac - -case "$RELSTATUS" in -alpha*|beta*|devel*|rc*) - echo "$0: This is a testing release. Would you like your bug report" - echo "$0: to be sent to the bash-testers mailing list?" - echo $n "$0: Send to bash-testers? $c" - read ans - case "$ans" in - y*|Y*) BUGBASH="${BUGBASH},${BASHTESTERS}" ;; - esac ;; -esac - -BUGADDR="${1-$BUGBASH}" - -if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then - if [ -x /usr/bin/editor ]; then - DEFEDITOR=editor - elif [ -x /usr/local/bin/ce ]; then - DEFEDITOR=ce - elif [ -x /usr/local/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/contrib/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/bin/emacs ]; then - DEFEDITOR=emacs - elif [ -x /usr/bin/xemacs ]; then - DEFEDITOR=xemacs - elif [ -x /usr/contrib/bin/jove ]; then - DEFEDITOR=jove - elif [ -x /usr/local/bin/jove ]; then - DEFEDITOR=jove - elif [ -x /usr/bin/vi ]; then - DEFEDITOR=vi - else - echo "$0: No default editor found: attempting to use vi" >&2 - DEFEDITOR=vi - fi -fi - - -: ${EDITOR=$DEFEDITOR} - -: ${USER=${LOGNAME-`whoami`}} - -trap 'rm -rf "$TEMPDIR"; exit 1' 1 2 3 13 15 -trap 'rm -rf "$TEMPDIR"' 0 - -UN= -if (uname) >/dev/null 2>&1; then - UN=`uname -a` -fi - -if [ -f /usr/lib/sendmail ] ; then - RMAIL="/usr/lib/sendmail" - SMARGS="-i -t" -elif [ -f /usr/sbin/sendmail ] ; then - RMAIL="/usr/sbin/sendmail" - SMARGS="-i -t" -else - RMAIL=rmail - SMARGS="$BUGADDR" -fi - -INITIAL_SUBJECT='[50 character or so descriptive subject here (for reference)]' - -cat > "$TEMPFILE1" <> $HOME/dead.bashbug - echo "$0: mail failed: report saved in $HOME/dead.bashbug" >&2 -} - -exit 0 diff --git a/syntax.h~ b/syntax.h~ deleted file mode 100644 index 7af17abf7..000000000 --- a/syntax.h~ +++ /dev/null @@ -1,100 +0,0 @@ -/* syntax.h -- Syntax definitions for the shell */ - -/* Copyright (C) 2000 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#ifndef _SYNTAX_H_ -#define _SYNTAX_H_ - -/* Defines for use by mksyntax.c */ - -#define slashify_in_quotes "\\`$\"\n" -#define slashify_in_here_document "\\`$" - -#define shell_meta_chars "()<>;&|" -#define shell_break_chars "()<>;&| \t\n" - -#define shell_quote_chars "\"`'" - -#if defined (PROCESS_SUBSTITUTION) -# define shell_exp_chars "$<>" -#else -# define shell_exp_chars "$" -#endif - -#if defined (EXTENDED_GLOB) -# define ext_glob_chars "@*+?!" -#else -# define ext_glob_chars "" -#endif -#define shell_glob_chars "*?[]^" - -/* Defines shared by mksyntax.c and the rest of the shell code. */ - -/* Values for character flags in syntax tables */ - -#define CWORD 0x0000 /* nothing special; an ordinary character */ -#define CSHMETA 0x0001 /* shell meta character */ -#define CSHBRK 0x0002 /* shell break character */ -#define CBACKQ 0x0004 /* back quote */ -#define CQUOTE 0x0008 /* shell quote character */ -#define CSPECL 0x0010 /* special character that needs quoting */ -#define CEXP 0x0020 /* shell expansion character */ -#define CBSDQUOTE 0x0040 /* characters escaped by backslash in double quotes */ -#define CBSHDOC 0x0080 /* characters escaped by backslash in here doc */ -#define CGLOB 0x0100 /* globbing characters */ -#define CXGLOB 0x0200 /* extended globbing characters */ -#define CXQUOTE 0x0400 /* cquote + backslash */ -#define CSPECVAR 0x0800 /* single-character shell variable name */ -#define CSUBSTOP 0x1000 /* values of OP for ${word[:]OPstuff} */ - -/* Defines for use by the rest of the shell. */ -extern int sh_syntaxtab[]; -extern int sh_syntabsiz; - -#define shellmeta(c) (sh_syntaxtab[(unsigned char)(c)] & CSHMETA) -#define shellbreak(c) (sh_syntaxtab[(unsigned char)(c)] & CSHBRK) -#define shellquote(c) (sh_syntaxtab[(unsigned char)(c)] & CQUOTE) - -#define issyntype(c, t) ((sh_syntaxtab[(unsigned char)(c)] & (t)) != 0) -#define notsyntype(c,t) ((sh_syntaxtab[(unsigned char)(c)] & (t)) == 0) - -#if defined (PROCESS_SUBSTITUTION) -# define shellexp(c) ((c) == '$' || (c) == '<' || (c) == '>') -#else -# define shellexp(c) ((c) == '$') -#endif - -#if defined (EXTENDED_GLOB) -# define PATTERN_CHAR(c) \ - ((c) == '@' || (c) == '*' || (c) == '+' || (c) == '?' || (c) == '!') -#else -# define PATTERN_CHAR(c) 0 -#endif - -#define GLOB_CHAR(c) \ - ((c) == '*' || (c) == '?' || (c) == '[' || (c) == ']' || (c) == '^') - -#define CTLESC '\001' -#define CTLNUL '\177' - -#if !defined (HAVE_ISBLANK) && !defined (isblank) -# define isblank(x) ((x) == ' ' || (x) == '\t') -#endif - -#endif /* _SYNTAX_H_ */ diff --git a/tests/RUN-ONE-TEST~ b/tests/RUN-ONE-TEST~ deleted file mode 100755 index 3efcf32d6..000000000 --- a/tests/RUN-ONE-TEST~ +++ /dev/null @@ -1,9 +0,0 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current -THIS_SH=$BUILD_DIR/bash -PATH=$PATH:$BUILD_DIR - -export THIS_SH PATH - -rm -f /tmp/xx - -/bin/sh "$@" diff --git a/tests/arith.tests~ b/tests/arith.tests~ deleted file mode 100644 index ce6a372a3..000000000 --- a/tests/arith.tests~ +++ /dev/null @@ -1,281 +0,0 @@ -set +o posix -declare -i iv jv - -iv=$(( 3 + 5 * 32 )) -echo $iv -iv=iv+3 -echo $iv -iv=2 -jv=iv - -let "jv *= 2" -echo $jv -jv=$(( $jv << 2 )) -echo $jv - -let jv="$jv / 2" -echo $jv -jv="jv >> 2" -echo $jv - -iv=$((iv+ $jv)) -echo $iv -echo $((iv -= jv)) -echo $iv -echo $(( iv == jv )) -echo $(( iv != $jv )) -echo $(( iv < jv )) -echo $(( $iv > $jv )) -echo $(( iv <= $jv )) -echo $(( $iv >= jv )) - -echo $jv -echo $(( ~$jv )) -echo $(( ~1 )) -echo $(( ! 0 )) - -echo $(( jv % 2 )) -echo $(( $iv % 4 )) - -echo $(( iv <<= 16 )) -echo $(( iv %= 33 )) - -echo $(( 33 & 55 )) -echo $(( 33 | 17 )) - -echo $(( iv && $jv )) -echo $(( $iv || jv )) - -echo $(( iv && 0 )) -echo $(( iv & 0 )) -echo $(( iv && 1 )) -echo $(( iv & 1 )) - -echo $(( $jv || 0 )) -echo $(( jv | 0 )) -echo $(( jv | 1 )) -echo $(( $jv || 1 )) - -let 'iv *= jv' -echo $iv -echo $jv -let "jv += $iv" -echo $jv - -echo $(( jv /= iv )) -echo $(( jv <<= 8 )) -echo $(( jv >>= 4 )) - -echo $(( iv |= 4 )) -echo $(( iv &= 4 )) - -echo $(( iv += (jv + 9))) -echo $(( (iv + 4) % 7 )) - -# unary plus, minus -echo $(( +4 - 8 )) -echo $(( -4 + 8 )) - -# conditional expressions -echo $(( 4<5 ? 1 : 32)) -echo $(( 4>5 ? 1 : 32)) -echo $(( 4>(2+3) ? 1 : 32)) -echo $(( 4<(2+3) ? 1 : 32)) -echo $(( (2+2)<(2+3) ? 1 : 32)) -echo $(( (2+2)>(2+3) ? 1 : 32)) - -# check that the unevaluated part of the ternary operator does not do -# evaluation or assignment -x=i+=2 -y=j+=2 -declare -i i=1 j=1 -echo $((1 ? 20 : (x+=2))) -echo $i,$x -echo $((0 ? (y+=2) : 30)) -echo $j,$y - -x=i+=2 -y=j+=2 -declare -i i=1 j=1 -echo $((1 ? 20 : (x+=2))) -echo $i,$x -echo $((0 ? (y+=2) : 30)) -echo $i,$y - -# check precedence of assignment vs. conditional operator -# should be an error -declare -i x=2 -y=$((1 ? 20 : x+=2)) - -# check precedence of assignment vs. conditional operator -declare -i x=2 -echo $((0 ? x+=2 : 20)) - -# associativity of assignment-operator operator -declare -i i=1 j=2 k=3 -echo $((i += j += k)) -echo $i,$j,$k - -# octal, hex -echo $(( 0x100 | 007 )) -echo $(( 0xff )) -echo $(( 16#ff )) -echo $(( 16#FF/2 )) -echo $(( 8#44 )) - -echo $(( 8 ^ 32 )) - -# other bases -echo $(( 16#a )) -echo $(( 32#a )) -echo $(( 56#a )) -echo $(( 64#a )) - -echo $(( 16#A )) -echo $(( 32#A )) -echo $(( 56#A )) -echo $(( 64#A )) - -echo $(( 64#@ )) -echo $(( 64#_ )) - -# weird bases -echo $(( 3425#56 )) - -# missing number after base -echo $(( 2# )) - -# these should generate errors -echo $(( 7 = 43 )) -echo $(( 2#44 )) -echo $(( 44 / 0 )) -let 'jv += $iv' -echo $(( jv += \$iv )) -let 'rv = 7 + (43 * 6' - -# more errors -declare -i i -i=0#4 -i=2#110#11 - -((echo abc; echo def;); echo ghi) - -if (((4+4) + (4 + 7))); then - echo ok -fi - -(()) # make sure the null expression works OK - -a=(0 2 4 6) -echo $(( a[1] + a[2] )) -echo $(( (a[1] + a[2]) == a[3] )) -(( (a[1] + a[2]) == a[3] )) ; echo $? - -# test pushing and popping the expression stack -unset A -A="4 + " -echo $(( ( 4 + A ) + 4 )) -A="3 + 5" -echo $(( ( 4 + A ) + 4 )) - -# badly-formed conditional expressions -echo $(( 4 ? : $A )) -echo $(( 1 ? 20 )) -echo $(( 4 ? 20 : )) - -# precedence and short-circuit evaluation -B=9 -echo $B - -echo $(( 0 && B=42 )) -echo $B - -echo $(( 1 || B=88 )) -echo $B - -echo $(( 0 && (B=42) )) -echo $B - -echo $(( (${$} - $$) && (B=42) )) -echo $B - -echo $(( 1 || (B=88) )) -echo $B - -# until command with (( )) command -x=7 - -echo $x -until (( x == 4 )) -do - echo $x - x=4 -done - -echo $x - -# exponentiation -echo $(( 2**15 - 1)) -echo $(( 2**(16-1))) -echo $(( 2**16*2 )) -echo $(( 2**31-1)) -echo $(( 2**0 )) - -# {pre,post}-{inc,dec}rement and associated errors - -x=4 - -echo $x -echo $(( x++ )) -echo $x -echo $(( x-- )) -echo $x - -echo $(( --x )) -echo $x - -echo $(( ++x )) -echo $x - -echo $(( ++7 )) -echo $(( 7-- )) - -echo $(( --x=7 )) -echo $(( ++x=7 )) - -echo $(( x++=7 )) -echo $(( x--=7 )) - -echo $x - -echo $(( +7 )) -echo $(( -7 )) - -echo $(( ++7 )) -echo $(( --7 )) - -x=4 -y=7 - -(( x=8 , y=12 )) - -echo $x $y - -# should be an error -(( x=9 y=41 )) - -# These are errors -unset b -echo $((a b)) -((a b)) - -n=42 -printf "%d\n" $n -printf "%i\n" $n -echo $(( 8#$(printf "%o\n" $n) )) -printf "%u\n" $n -echo $(( 16#$(printf "%x\n" $n) )) -echo $(( 16#$(printf "%X\n" $n) )) - -# causes longjmp botches through bash-2.05b -a[b[c]d]=e diff --git a/tests/cprint.right.save1 b/tests/cprint.right.save1 deleted file mode 100644 index 6b711b8c5..000000000 --- a/tests/cprint.right.save1 +++ /dev/null @@ -1,72 +0,0 @@ -tf is a function -tf () -{ - echo this is ${0##*/} >/dev/null; - echo a | cat - >/dev/null; - test -f ${0##*/} && echo ${0##*/} is a regular file; - test -d ${0##*/} || echo ${0##*/} is not a directory; - echo a; - echo b; - echo c; - echo background >/dev/null & ( exit 1 ); - echo $?; - { - echo a - }; - i=0; - while (( " i < 3 " )); do - test -r /dev/fd/$i; - i=$(( i + 1 )); - done; - [[ -r /dev/fd/0 && -w /dev/fd/1 ]] || echo oops >/dev/null; - for name in $( echo 1 2 3 ); - do - test -r /dev/fd/$name; - done; - if [[ -r /dev/fd/0 && -w /dev/fd/1 ]]; then - echo ok >/dev/null; - else - if (( " 7 > 40 " )); then - echo oops; - else - echo done; - fi; - fi >/dev/null; - case $PATH in - *$PWD*) - echo \$PWD in \$PATH - ;; - *) - echo \$PWD not in \$PATH - ;; - esac >/dev/null; - while false; do - echo z; - done >/dev/null; - until true; do - echo z; - done >/dev/null; - echo \&\|'()' \{ echo abcde \; \}; - eval fu\%nc'()' \{ echo abcde \; \}; - type fu\%nc -} -tf2 is a function -tf2 () -{ - ( { - time -p echo a | cat - >/dev/null - } ) 2>&1 -} -cprint.tests is a regular file -cprint.tests is not a directory -a -b -c -1 -a -&|() { echo abcde ; } -fu%nc is a function -fu%nc () -{ - echo abcde -} diff --git a/tests/dollar-at-star~ b/tests/dollar-at-star~ deleted file mode 100755 index 7b6d75ae0..000000000 --- a/tests/dollar-at-star~ +++ /dev/null @@ -1,218 +0,0 @@ -# first, let's start with the basics - -recho "$@" -recho "$*" - -recho $@ -recho $* - -set a b - -recho "$*" - -# If IFS is null, the parameters are joined without separators -IFS='' -recho "$*" - -# If IFS is unset, the parameters are separated by spaces -unset IFS -recho "${*}" - -recho "$@" -recho $@ - -IFS='/' -set bob 'tom dick harry' joe -set $* -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set ${*} -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set $@ -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set ${@} -recho $# -recho $1 -recho $2 -recho $3 - -# according to POSIX.2, unquoted $* should expand to multiple words if -# $IFS is null, just like unquoted $@ -IFS='' -set bob 'tom dick harry' joe -set $* -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set $@ -recho $# -recho $1 -recho $2 -recho $3 - -# if IFS is unset, the individual positional parameters are split on -# " \t\n" if $* or $@ are unquoted -unset IFS -set bob 'tom dick harry' joe -set $* -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set $@ -recho $# -recho $1 -recho $2 -recho $3 - -# but not for "$@" or "$*" -set bob 'tom dick harry' joe -set "$*" -recho $# -recho $1 -recho $2 -recho $3 - -set bob 'tom dick harry' joe -set "$@" -recho $# -recho $1 -recho $2 -recho $3 - -# POSIX.2 says these should both expand the positional parameters -# to multiple words -set a b c d e -IFS="" -recho $@ -recho "$@" - -# this example is straight from the POSIX.2 rationale -set foo bar bam - -recho "$@" -recho "$*" - -unset IFS - -recho "$@" -recho $@ -recho "$*" - -IFS=: - -# special variables -set -- 1 2 3 4 5 6 7 8 9 10 - -bar=${*} -foo=$* -echo foo = "$foo" -echo bar = "$bar" - -foo1=$@ -bar1=${@} - -echo foo1 = "$foo1" -echo bar1 = "$bar1" - -foo2="$*" -bar2="${*}" - -echo foo2 = "$foo2" -echo bar2 = "$bar2" - -eval foo3='$*' bar3='${*}' -echo foo3 = "$foo3" -echo bar3 = "$bar3" - -case $* in -*\:*) echo ok 1;; -*) echo bad 1;; -esac - -case $@ in -*\:*) echo bad 2;; -*) echo ok 2;; -esac - -case "$*" in -*\:*) echo ok 3;; -*) echo bad 3;; -esac - -case "$@" in -*\:*) echo bad 4;; -*) echo ok 4;; -esac - -IFS=$' \t\n' - -bar=${*} -foo=$* -echo foo = "$foo" -echo bar = "$bar" - -foo1=$@ -bar1=${@} - -echo foo1 = "$foo1" -echo bar1 = "$bar1" - -foo2="$*" -bar2="${*}" - -echo foo2 = "$foo2" -echo bar2 = "$bar2" - -eval foo3='$*' bar3='${*}' -echo foo3 = "$foo3" -echo bar3 = "$bar3" - -case $* in -*\ *) echo ok 1;; -*) echo bad 1;; -esac - -case $@ in -*\ *) echo ok 2;; -*) echo bad 2;; -esac - -case "$*" in -*\ *) echo ok 3;; -*) echo bad 3;; -esac - -case "$@" in -*\ *) echo ok 4;; -*) echo bad 4;; -esac - -# tests for special expansion of "$*" and "${array[*]}" when used with other -# expansions -- bugs through bash-2.05b -${THIS_SH} ./dollar-star1.sub - -# tests for expansion of "$@" on rhs of things like ${param:+word}. Bugs -# though bash-2.05b -${THIS_SH} ./dollar-at1.sub - -exit 0 diff --git a/tests/dollar-at1.sub~ b/tests/dollar-at1.sub~ deleted file mode 100644 index 45f7cc56d..000000000 --- a/tests/dollar-at1.sub~ +++ /dev/null @@ -1,29 +0,0 @@ -echo_argc() -{ - echo $# -} - -a() -{ - shift - echo_argc "$@" - echo_argc ${1:+"$@"} - echo_argc "${1:+$@}" - echo_argc 1 2 3 -} - -b() -{ - _IFS="$IFS" - IFS="$1" - shift - echo_argc "$@" - echo_argc ${1:+"$@"} - echo_argc "${1:+$@}" - echo_argc 1 2 3 - IFS="$_IFS" -} - -#a "X" foo bar hoge -#echo -b "X" foo bar hoge diff --git a/tests/errors.right~ b/tests/errors.right~ deleted file mode 100644 index 1f3487be2..000000000 --- a/tests/errors.right~ +++ /dev/null @@ -1,100 +0,0 @@ -./errors.tests: line 17: alias: -x: invalid option -alias: usage: alias [-p] [name[=value] ... ] -./errors.tests: line 18: unalias: -x: invalid option -unalias: usage: unalias [-a] name [name ...] -./errors.tests: line 19: alias: hoowah: not found -./errors.tests: line 20: unalias: hoowah: not found -./errors.tests: line 23: `1': not a valid identifier -declare -fr func -./errors.tests: line 36: func: readonly function -./errors.tests: line 39: unset: -x: invalid option -unset: usage: unset [-f] [-v] [name ...] -./errors.tests: line 42: unset: func: cannot unset: readonly function -./errors.tests: line 45: declare: func: readonly function -./errors.tests: line 49: unset: XPATH: cannot unset: readonly variable -./errors.tests: line 52: unset: `/bin/sh': not a valid identifier -./errors.tests: line 55: unset: cannot simultaneously unset a function and a variable -./errors.tests: line 58: declare: -z: invalid option -declare: usage: declare [-afFirtx] [-p] [name[=value] ...] -./errors.tests: line 60: declare: `-z': not a valid identifier -./errors.tests: line 61: declare: `/bin/sh': not a valid identifier -./errors.tests: line 65: declare: cannot use `-f' to make functions -./errors.tests: line 68: exec: -i: invalid option -exec: usage: exec [-cl] [-a name] file [redirection ...] -./errors.tests: line 72: export: XPATH: not a function -./errors.tests: line 75: break: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 76: continue: only meaningful in a `for', `while', or `until' loop -./errors.tests: line 79: shift: label: numeric argument required -./errors.tests: line 84: shift: too many arguments -./errors.tests: line 90: let: expression expected -./errors.tests: line 93: local: can only be used in a function -./errors.tests: line 96: logout: not login shell: use `exit' -./errors.tests: line 99: hash: notthere: not found -./errors.tests: line 102: hash: -v: invalid option -hash: usage: hash [-lr] [-p pathname] [-dt] [name ...] -./errors.tests: line 106: hash: hashing disabled -./errors.tests: line 109: export: `AA[4]': not a valid identifier -./errors.tests: line 110: readonly: `AA[4]': not a valid identifier -./errors.tests: line 113: [-2]: bad array subscript -./errors.tests: line 117: AA: readonly variable -./errors.tests: line 121: AA: readonly variable -./errors.tests: line 129: shift: 5: shift count out of range -./errors.tests: line 130: shift: -2: shift count out of range -./errors.tests: line 133: shopt: no_such_option: invalid shell option name -./errors.tests: line 134: shopt: no_such_option: invalid shell option name -./errors.tests: line 137: umask: 09: octal number out of range -./errors.tests: line 138: umask: `:': invalid symbolic mode character -./errors.tests: line 139: umask: `:': invalid symbolic mode operator -./errors.tests: line 142: umask: -i: invalid option -umask: usage: umask [-p] [-S] [mode] -./errors.tests: line 146: umask: `u': invalid symbolic mode character -./errors.tests: line 155: VAR: readonly variable -./errors.tests: line 158: declare: VAR: readonly variable -./errors.tests: line 159: declare: VAR: readonly variable -./errors.tests: line 161: declare: unset: not found -./errors.tests: line 164: VAR: readonly variable -./errors.tests: command substitution: line 168: syntax error: unexpected end of file -./errors.tests: command substitution: line 168: syntax error near unexpected token `done' -./errors.tests: command substitution: line 168: ` for z in 1 2 3; done ' -./errors.tests: line 171: cd: HOME not set -./errors.tests: line 172: cd: /tmp/xyz.bash: No such file or directory -./errors.tests: line 174: cd: OLDPWD not set -./errors.tests: line 175: cd: /bin/sh: Not a directory -./errors.tests: line 177: cd: /tmp/cd-notthere: No such file or directory -./errors.tests: line 180: .: filename argument required -.: usage: . filename [arguments] -./errors.tests: line 181: source: filename argument required -source: usage: source filename [arguments] -./errors.tests: line 184: .: -i: invalid option -.: usage: . filename [arguments] -./errors.tests: line 187: set: -q: invalid option -set: usage: set [--abefhkmnptuvxBCHP] [-o option] [arg ...] -./errors.tests: line 190: enable: sh: not a shell builtin -./errors.tests: line 190: enable: bash: not a shell builtin -./errors.tests: line 193: shopt: cannot set and unset shell options simultaneously -./errors.tests: line 196: read: var: invalid timeout specification -./errors.tests: line 199: read: `/bin/sh': not a valid identifier -./errors.tests: line 202: VAR: readonly variable -./errors.tests: line 205: readonly: -x: invalid option -readonly: usage: readonly [-af] [name[=value] ...] or readonly -p -./errors.tests: line 208: eval: -i: invalid option -eval: usage: eval [arg ...] -./errors.tests: line 209: command: -i: invalid option -command: usage: command [-pVv] command [arg ...] -./errors.tests: line 212: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 213: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") -./errors.tests: line 216: trap: NOSIG: invalid signal specification -./errors.tests: line 219: trap: -s: invalid option -trap: usage: trap [-lp] [[arg] signal_spec ...] -./errors.tests: line 225: return: can only `return' from a function or sourced script -./errors.tests: line 229: break: 0: loop count out of range -./errors.tests: line 233: continue: 0: loop count out of range -./errors.tests: line 238: builtin: bash: not a shell builtin -./errors.tests: line 242: bg: no job control -./errors.tests: line 243: fg: no job control -./errors.tests: line 246: kill: -s: option requires an argument -./errors.tests: line 248: kill: S: invalid signal specification -./errors.tests: line 250: kill: `': not a pid or valid job spec -kill: usage: kill [-s sigspec | -n signum | -sigspec] [pid | job]... or kill -l [sigspec] -./errors.tests: line 255: set: trackall: invalid option name -./errors.tests: line 262: `!!': not a valid identifier diff --git a/tests/exec.right~ b/tests/exec.right~ deleted file mode 100644 index ec3d9e2e1..000000000 --- a/tests/exec.right~ +++ /dev/null @@ -1,53 +0,0 @@ -before exec1.sub: one two three -calling exec1.sub -aa bb cc dd ee -after exec1.sub with args: 0 - -after exec1.sub without args: 0 -./execscript: line 20: notthere: command not found -127 -/tmp/bash: notthere: No such file or directory -127 -/bin/sh: /bin/sh: cannot execute binary file -126 -./execscript: line 38: /: is a directory -126 -/: /: cannot execute binary file -126 -./execscript: line 45: .: /: is a directory -1 -127 -0 -this is bashenv -./exec3.sub: line 3: /tmp/bash-notthere: No such file or directory -./exec3.sub: line 3: exec: /tmp/bash-notthere: cannot execute: No such file or directory -126 -./execscript: line 67: notthere: No such file or directory -127 -./execscript: line 70: notthere: No such file or directory -127 -./execscript: line 73: notthere: No such file or directory -127 -this is sh -this is sh -unset -ok -5 -./exec5.sub: line 4: exec: bash-notthere: not found -127 -this is ohio-state -0 -1 -1 -0 -42 -42 -0 -1 -1 -0 -0 -1 -0 -1 -testb diff --git a/tests/execscript~ b/tests/execscript~ deleted file mode 100644 index 03f9570be..000000000 --- a/tests/execscript~ +++ /dev/null @@ -1,105 +0,0 @@ -export LC_ALL=C -export LANG=C - -if [ $UID -eq 0 ]; then - echo "execscript: the test suite should not be run as root" >&2 -fi - -set -- one two three -echo before exec1.sub: "$@" -echo calling exec1.sub -./exec1.sub aa bb cc dd ee -echo after exec1.sub with args: $? -./exec1.sub -echo after exec1.sub without args: $? - -# set up a fixed path so we know notthere will not be found -PATH=/usr/bin:/bin:/usr/local/bin: -export PATH - -notthere -echo $? - -# this is iffy, since the error messages may vary from system to system -# and /tmp might not exist -ln -s ${THIS_SH} /tmp/bash 2>/dev/null -if [ -f /tmp/bash ]; then - /tmp/bash notthere -else - ${THIS_SH} notthere -fi -echo $? - -# /bin/sh should be there on all systems -${THIS_SH} /bin/sh -echo $? - -# try executing a directory -/ -echo $? - -${THIS_SH} / -echo $? - -# try sourcing a directory -. / -echo $? - -# try sourcing a binary file -- post-2.04 versions don't do the binary file -# check, and will probably fail with `command not found', or status 127 -. ${THIS_SH} 2>/dev/null -echo $? - -# post-bash-2.05 versions allow sourcing non-regular files -. /dev/null -echo $? - -# kill two birds with one test -- test out the BASH_ENV code -echo echo this is bashenv > /tmp/bashenv -export BASH_ENV=/tmp/bashenv -${THIS_SH} ./exec3.sub -rm -f /tmp/bashenv -unset BASH_ENV - -# we're resetting the $PATH to empty, so this should be last -PATH= - -notthere -echo $? - -command notthere -echo $? - -command -p notthere -echo $? - -# but -p should guarantee that we find all the standard utilities, even -# with an empty or unset $PATH -command -p sh -c 'echo this is $0' -unset PATH -command -p sh -c 'echo this is $0' - -# a bug in bash before bash-2.01 caused PATH to be set to the empty string -# when command -p was run with PATH unset -echo ${PATH-unset} - -echo "echo ok" | ${THIS_SH} -t - -${THIS_SH} ./exec2.sub -echo $? - -${THIS_SH} ./exec4.sub - -# try exec'ing a command that cannot be found in $PATH -${THIS_SH} ./exec5.sub - -# this was a bug in bash versions before bash-2.04 -${THIS_SH} -c 'cat /dev/null' >&- - -# checks for proper return values in subshell commands with inverted return -# values - -${THIS_SH} ./exec6.sub - -# checks for properly deciding what constitutes an executable file -${THIS_SH} ./exec7.sub diff --git a/tests/histexp.right~ b/tests/histexp.right~ deleted file mode 100644 index ff6453e5f..000000000 --- a/tests/histexp.right~ +++ /dev/null @@ -1,129 +0,0 @@ -echo $BASH_VERSION -./histexp.tests: line 22: history: !!:z: history expansion failed - 1 for i in one two three; do echo $i; done - 2 /bin/sh -c 'echo this is $0' - 3 ls - 4 echo $BASH_VERSION - 1 for i in one two three; do echo $i; done - 2 /bin/sh -c 'echo this is $0' - 3 ls - 4 echo $BASH_VERSION - 5 HISTFILE=/tmp/newhistory - 6 echo line 2 for history -echo line 2 for history -echo line 2 for history -set -H -echo line 2 for history -line 2 for history - 1 for i in one two three; do echo $i; done - 2 /bin/sh -c 'echo this is $0' - 3 ls - 4 echo $BASH_VERSION - 5 HISTFILE=/tmp/newhistory - 6 echo line 2 for history - 7 set -H - 8 echo line 2 for history -a b c d e -echo a b c d e -a b c d e -echo line 2 for history -line 2 for history -echo line 8 for history -line 8 for history -/bin/sh -c 'echo this is $0' -this is /bin/sh -echo sh -sh -echo /bin -/bin -echo e -e -a b c d e -echo b c d e -b c d e -echo b c d -b c d -echo d e -d e -echo d e -d e -echo b c d -b c d -file.c -echo file -file -echo .c -.c -echo 'file' -file -bax.c -echo $file -bax -echo .c -.c -echo '$file' -$file -a b c d e -echo 'a' 'b' 'c' 'd' 'e' -a b c d e -echo 'a b c d e' -a b c d e -foo.c foo.o foo.html foo.h -echo bar.c foo.o foo.html foo.h -bar.c foo.o foo.html foo.h -echo bar.c bar.o bar.html bar.h -bar.c bar.o bar.html bar.h -echo xbar.c xbar.o xbar.html xbar.h -xbar.c xbar.o xbar.html xbar.h -echo xbar.c xbar.o xbar.html xbar.h -xbar.c xbar.o xbar.html xbar.h -echo xwhix.c xwhix.o xwhix.html xwhix.h -xwhix.c xwhix.o xwhix.html xwhix.h -echo xwhix.c xwhix.o xwhix.html xwhix.h -echo 'xwhix' -xwhix -echo 'xwhix.h' -xwhix.h -echo 'xwhix.h' -xwhix.h -echo 'xwhix.h' -xwhix.h - 8 echo line 2 for history - 9 echo a b c d e - 10 echo line 2 for history - 11 echo line 8 for history - 12 /bin/sh -c 'echo this is $0' - 13 echo sh - 14 echo /bin - 15 echo e - 16 echo a b c d e - 17 echo b c d e - 18 echo b c d - 19 echo d e - 20 echo b c d - 21 echo file.c - 22 echo file - 23 echo .c - 24 echo 'file' - 25 echo $file.c - 26 echo $file - 27 echo .c - 28 echo '$file' - 29 echo a b c d e - 30 echo 'a' 'b' 'c' 'd' 'e' - 31 echo 'a b c d e' - 32 echo foo.c foo.o foo.html foo.h - 33 echo bar.c foo.o foo.html foo.h - 34 echo bar.c bar.o bar.html bar.h - 35 echo xbar.c xbar.o xbar.html xbar.h - 36 echo xwhix.c xwhix.o xwhix.html xwhix.h - 37 echo xwhix.c xwhix.o xwhix.html xwhix.h - 38 echo 'xwhix' - 39 echo 'xwhix.h' -!! -!! -echo '!!' \!\! -!! !! -ok 1 -ok 2 -ok 3 diff --git a/tests/history.tests.save b/tests/history.tests.save deleted file mode 100644 index 4a218c301..000000000 --- a/tests/history.tests.save +++ /dev/null @@ -1,97 +0,0 @@ -trap 'rm /tmp/newhistory' 0 - -# bad options -history -x -# cannot use -r and -w at the same time -history -r -w /dev/null - -# bad option -fc -v - -# all of these should result in an empty history list -history -c -history -r /dev/null -history -n /dev/null -history -c - -HISTFILE=history.list -HISTCONTROL=ignoreboth -HISTIGNORE='&:history*:fc*' -HISTSIZE=32 - -shopt -s cmdhist -set -o history - -history - -fc -l -fc -nl - -fc -lr -fc -nlr - -history -s "echo line for history" -history - -history -p '!!' - -fc -nl - -HISTFILE=/tmp/newhistory -history -a -echo displaying \$HISTFILE after history -a -cat $HISTFILE - -history -history -w -cat $HISTFILE - -history -s "echo line 2 for history" -history -history -p '!e' -history -p '!!' - -# this should show up as one history entry -for x in one two three -do - : -done -history - -# just a basic test. a full test suite for history expansion should be -# created -set -H -!! -!e - -unset HISTSIZE -unset HISTFILE - -fc -l 4 -fc -l 4 8 - -fc -l 502 -fc -l one=two three=four 502 - -history 4 - -shopt -so history -shopt -s expand_aliases - -alias r="fc -s" - -echo aa ab ac - -r a=x -r x=4 b=8 - -# this had better fail with `no command found' -r cc - -unalias -a -alias - -set +o history - -shopt -q -o history -echo $? diff --git a/tests/jobs.right~ b/tests/jobs.right~ deleted file mode 100644 index 049d3cdd5..000000000 --- a/tests/jobs.right~ +++ /dev/null @@ -1,97 +0,0 @@ -./jobs2.sub: line 9: fg: job 1 started without job control -fg: 1 -Waiting for job 0 -job 0 returns 0 -Waiting for job 1 -job 1 returns 0 -Waiting for job 2 -job 2 returns 0 -Waiting for job 3 -job 3 returns 0 -Waiting for job 4 -job 4 returns 0 -Waiting for job 5 -job 5 returns 0 -Waiting for job 6 -job 6 returns 0 -Waiting for job 7 -job 7 returns 0 -0 -./jobs.tests: line 15: wait: no job control -./jobs.tests: line 20: fg: no job control -wait-for-pid -wait-errors -./jobs.tests: line 33: wait: `1-1': not a pid or valid job spec -./jobs.tests: line 34: wait: `-4': not a pid or valid job spec -wait-for-background-pids -async list wait-for-background-pids -async list wait for child -forked -wait-when-no-children -wait-for-job -./jobs.tests: line 56: wait: %2: no such job -127 -async list wait-for-job -forked -fg-bg 1 -sleep 5 -fg-bg 2 -sleep 5 -fg-bg 3 -sleep 5 -fg-bg 4 -sleep 5 -fg-bg 5 -./jobs.tests: line 83: fg: %2: no such job -./jobs.tests: line 84: bg: job 1 already in background -fg-bg 6 -./jobs.tests: line 91: fg: -s: invalid option -fg: usage: fg [job_spec] -./jobs.tests: line 92: bg: -s: invalid option -bg: usage: bg [job_spec] -./jobs.tests: line 97: disown: -s: invalid option -disown: usage: disown [-h] [-ar] [jobspec ...] -./jobs.tests: line 101: disown: %1: no such job -./jobs.tests: line 104: disown: %2: no such job -wait-for-non-child -./jobs.tests: line 107: wait: pid 1 is not a child of this shell -127 -3 -- 1 2 3 -- 1 - 2 - 3 -[1] Running sleep 300 & -[2]- Running sleep 350 & -[3]+ Running sleep 400 & -running jobs: -[1] Running sleep 300 & -[2]- Running sleep 350 & -[3]+ Running sleep 400 & -./jobs.tests: line 123: kill: %4: no such job -./jobs.tests: line 125: jobs: %4: no such job -current job: -[3]+ Running sleep 400 & -previous job: -[2]- Running sleep 350 & -after kill -STOP -running jobs: -[1] Running sleep 300 & -[3]- Running sleep 400 & -stopped jobs: -[2]+ Stopped sleep 350 -after disown -[2]+ Stopped sleep 350 -[3]- Running sleep 400 & -running jobs: -[3]- Running sleep 400 & -stopped jobs: -[2]+ Stopped sleep 350 -after kill -s CONT -running jobs: -[2]+ Running sleep 350 & -[3]- Running sleep 400 & -stopped jobs: -after kill -STOP, backgrounding %3: -[3]+ sleep 400 & -killing... -done -after KILL -STOP, foregrounding %1 -sleep 10 -done diff --git a/tests/jobs.tests~ b/tests/jobs.tests~ deleted file mode 100644 index d54c1e94a..000000000 --- a/tests/jobs.tests~ +++ /dev/null @@ -1,179 +0,0 @@ -# test out %+, jobs -p, and $! agreement in a subshell first -${THIS_SH} ./jobs1.sub - -# test out fg/bg failure in a subshell -${THIS_SH} ./jobs2.sub - -# test out behavior of waiting for background pids -- bug in versions -# before 2.03 -${THIS_SH} ./jobs3.sub - -jobs -echo $? - -# should be a job-control-not-enabled error -wait %1 - -# make sure we can't fg a job started when job control was not active -sleep 30 & -pid=$! -fg %1 -# make sure the killed processes don't cause a message -exec 5>&2 -exec 2>/dev/null -kill -n 9 $pid -wait # make sure we reap the processes while stderr is still redirected -exec 2>&5 - -echo wait-for-pid -sleep 10 & -wait $! - -echo wait-errors -wait 1-1 -wait -- -4 - -echo wait-for-background-pids -sleep 5 & -sleep 8 & -wait - -echo async list wait-for-background-pids -sleep 5 & sleep 8 & -wait - -echo async list wait for child -sleep 5 & echo forked -wait - -echo wait-when-no-children -wait - -set -m - -echo wait-for-job -sleep 5 & -wait %2 # this should be a no-such-job error -echo $? -wait %1 - -echo async list wait-for-job -sleep 5 & echo forked -wait %1 - -echo fg-bg 1 -sleep 5 & -%1 - -echo fg-bg 2 -sleep 5 & -fg %% - -echo fg-bg 3 -sleep 5 & -fg %s - -echo fg-bg 4 -sleep 5 & -fg %?ee - -# these next two are error cases -echo fg-bg 5 -sleep 15 & -fg %2 # this should be a no-such-job error -bg %1 # this should be a `bg background job?' error -wait - -# these may someday mean to start the jobs, but not print the line -# describing the status, but for now they are errors -echo fg-bg 6 -sleep 5 & -fg -s %1 -bg -s %1 -wait - -# someday this may mean to disown all stopped jobs, but for now it is -# an error -disown -s - -# this is an error -- the job with the pid that is the value of $! is -# retained only until a `wait' is performed -disown %1 - -# this, however, is an error -disown %2 - -echo wait-for-non-child -wait 1 -echo $? - -exit 1 | exit 2 | exit 3 -echo $? -- ${PIPESTATUS[@]} -- ${PIPESTATUS[0]} - ${PIPESTATUS[1]} - ${PIPESTATUS[2]} - -sleep 300 & -sleep 350 & -sleep 400 & - -jobs - -echo running jobs: -jobs -r - -# should be an error -kill -n 1 %4 -# should be an error -jobs %4 -echo current job: -jobs %+ -echo previous job: -jobs %- - -kill -STOP %2 -sleep 5 # give time for the shell to get the stop notification -echo after kill -STOP -echo running jobs: -jobs -r -echo stopped jobs: -jobs -s - -disown %1 - -echo after disown -jobs -echo running jobs: -jobs -r -echo stopped jobs: -jobs -s - -kill -s CONT %2 -echo after kill -s CONT -echo running jobs: -jobs -r -echo stopped jobs: -jobs -s - -kill -STOP %3 -sleep 5 # give time for the shell to get the stop notification -echo after kill -STOP, backgrounding %3: -bg %3 - -disown -h %2 - -# make sure the killed processes don't cause a message -exec 5>&2 -exec 2>/dev/null - -echo killing... -kill -n 9 %2 %3 -wait # make sure we reap the processes while stderr is still redirected -echo done - -exec 2>&5 - -sleep 10 & -kill -STOP %1 -sleep 5 # give time for the shell to get the stop notification -echo after KILL -STOP, foregrounding %1 -fg %1 - -echo done diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig deleted file mode 100644 index c1f1e1991..000000000 --- a/tests/misc/regress/log.orig +++ /dev/null @@ -1,50 +0,0 @@ -:; ./shx - -sh: -<&$fd ok -nlbq Mon Aug 3 02:45:00 EDT 1992 -bang geoff -quote 712824302 -setbq defmsgid=<1992Aug3.024502.6176@host> -bgwait sleep done... wait 6187 - - -bash: -<&$fd ok -nlbq Mon Aug 3 02:45:09 EDT 1992 -bang geoff -quote 712824311 -setbq defmsgid=<1992Aug3.024512.6212@host> -bgwait sleep done... wait 6223 - - -ash: -<&$fd shx1: 4: Syntax error: Bad fd number -nlbq Mon Aug 3 02:45:19 EDT 1992 -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.` echo 024521 -bgwait sleep done... wait 6241 - - -ksh: -<&$fd ok -nlbq ./shx: 6248 Memory fault - core dumped -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.024530.6257@host> -bgwait no such job: 6265 -wait 6265 -sleep done... - -zsh: -<&$fd ok -nlbq Mon Aug 3 02:45:36 EDT 1992 -bang shx3: event not found: /s/ [4] -quote 712824337 -setbq defmsgid=<..6290@host> -bgwait shx7: unmatched " [9] -sleep done... -:; diff --git a/tests/misc/regress/shx.orig b/tests/misc/regress/shx.orig deleted file mode 100644 index 4b3bf2b82..000000000 --- a/tests/misc/regress/shx.orig +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh -for cmd in sh bash ash ksh zsh -do - echo - echo $cmd: - for demo in shx? - do - $cmd $demo - done -done diff --git a/tests/read.tests~ b/tests/read.tests~ deleted file mode 100644 index e8b7e8f81..000000000 --- a/tests/read.tests~ +++ /dev/null @@ -1,92 +0,0 @@ -echo " a " | (read x; echo "$x.") - -echo " a b " | ( read x y ; echo -"$x"-"$y"- ) -echo " a b\ " | ( read x y ; echo -"$x"-"$y"- ) -echo " a b " | ( read x ; echo -"$x"- ) -echo " a b\ " | ( read x ; echo -"$x"- ) - -echo " a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) -echo " a b\ " | ( read -r x ; echo -"$x"- ) - -echo "\ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) -echo "\ a b\ " | ( read -r x ; echo -"$x"- ) -echo " \ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) -echo " \ a b\ " | ( read -r x ; echo -"$x"- ) - -# make sure that CTLESC and CTLNUL are passed through correctly -echo $'\001' | ( read var ; recho "$var" ) -echo $'\001' | ( read ; recho "$REPLY" ) - -echo $'\177' | ( read var ; recho "$var" ) -echo $'\177' | ( read ; recho "$REPLY" ) - -# make sure a backslash-quoted \\n still disappears from the input when -# we're not reading in `raw' mode, and no stray CTLESC chars are left in -# the input stream -echo $'ab\\\ncd' | ( read ; recho "$REPLY" ) - -echo "A B " > /tmp/IN -unset x y z -read x y z < /tmp/IN -echo 1: "x[$x] y[$y] z[$z]" -echo 1a: ${z-z not set} -read x < /tmp/IN -echo 2: "x[$x]" -rm /tmp/IN - -# this is where the bash `read' behavior with respect to $REPLY differs -# from ksh93 -echo "A B " > /tmp/IN - -read < /tmp/IN -echo "[$REPLY]" - -rm /tmp/IN - -echo " A B " > /tmp/IN - -read < /tmp/IN -echo "[$REPLY]" - -rm /tmp/IN - -# make sure that read with more variables than words sets the extra -# variables to the empty string - -bvar=bvar -cvar=cvar -echo aa > /tmp/IN -read avar bvar cvar < /tmp/IN -echo =="$avar"== -echo =="$bvar"== -echo =="$cvar"== - -rm /tmp/IN - -# test behavior of read with various settings of IFS - -echo " foo" | { IFS= read line; recho "$line"; } - -echo " foo" | { IFS= ; read line; recho "$line"; } - -echo " foo" | { unset IFS ; read line; recho "$line"; } - -echo " foo" | { IFS=$'\n' ; read line; recho "$line"; } - -echo " foo" | { IFS=$' \n' ; read line; recho "$line"; } - -echo " foo" | { IFS=$' \t\n' ; read line; recho "$line"; } - -echo " foo" | { IFS=$':' ; read line; recho "$line"; } - -# test read -d delim behavior -${THIS_SH} ./read1.sub - -# test read -t timeout behavior -${THIS_SH} ./read2.sub - -# test read -n nchars behavior -${THIS_SH} ./read3.sub - -# test read -u fd behavior -${THIS_SH} ./read4.sub diff --git a/tests/trap.tests~ b/tests/trap.tests~ deleted file mode 100644 index 3e2d00dd1..000000000 --- a/tests/trap.tests~ +++ /dev/null @@ -1,86 +0,0 @@ -# test the trap code - -trap 'echo exiting' 0 -trap 'echo aborting' 1 2 3 6 15 - -# make sure a user-specified subshell runs the exit trap, but does not -# inherit the exit trap from a parent shell -( trap 'echo subshell exit' 0; exit 0 ) -( exit 0 ) - -trap - -func() -{ - trap 'echo ${FUNCNAME:-$0}[$LINENO] funcdebug' DEBUG - echo funcdebug line -} - -trap 'echo [$LINENO] debug' DEBUG -echo debug line - -trap - -func - -trap - -trap 'echo ${FUNCNAME:-$0}[$LINENO] debug' DEBUG -func2() -{ - echo func2debug line -} -declare -ft func2 -func2 - -unset -f func2 - -trap '' DEBUG - -trap - -trap - debug - -trap - -trap - HUP -trap hup -trap '' INT -trap '' int - -trap - -# exit 0 in exit trap should set exit status -( -set -e -trap 'exit 0' EXIT -false -echo bad -) -echo $? - -# hmmm...should this set the handling to SIG_IGN for children, too? -trap '' USR2 -./trap1.sub - -# test ERR trap -./trap2.sub - -# -# show that setting a trap on SIGCHLD is not disastrous. -# -set -o monitor - -trap 'echo caught a child death' SIGCHLD - -sleep 7 & sleep 6 & sleep 5 & - -wait - -trap -p SIGCHLD - -# Now reset some of the signals the shell handles specially back to -# their default values (with or without the SIG prefix) -trap SIGINT QUIT TERM - -trap diff --git a/variables.c~ b/variables.c~ deleted file mode 100644 index b51c4b813..000000000 --- a/variables.c~ +++ /dev/null @@ -1,4090 +0,0 @@ -/* variables.c -- Functions for hacking shell variables. */ - -/* Copyright (C) 1987-2004 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include "posixstat.h" -#include "posixtime.h" - -#if defined (qnx) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "chartypes.h" -#include -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "mailcheck.h" -#include "input.h" -#include "hashcmd.h" -#include "pathexp.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#if defined (READLINE) -# include "bashline.h" -# include -#else -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include -#endif /* HISTORY */ - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ - -#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') - -/* Variables used here and defined in other files. */ -extern int posixly_correct; -extern int line_number; -extern int subshell_environment, indirection_level, subshell_level; -extern int build_version, patch_level; -extern int expanding_redir; -extern char *dist_version, *release_status; -extern char *shell_name; -extern char *primary_prompt, *secondary_prompt; -extern char *current_host_name; -extern sh_builtin_func_t *this_shell_builtin; -extern SHELL_VAR *this_shell_function; -extern char *the_printed_command_except_trap; -extern char *this_command_name; -extern char *command_execution_string; -extern time_t shell_start_time; - -#if defined (READLINE) -extern int perform_hostname_completion; -#endif - -/* The list of shell variables that the user has created at the global - scope, or that came from the environment. */ -VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; - -/* The current list of shell variables, including function scopes */ -VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; - -/* The list of shell functions that the user has created, or that came from - the environment. */ -HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; - -#if defined (DEBUGGER) -/* The table of shell function definitions that the user defined or that - came from the environment. */ -HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; -#endif - -/* The current variable context. This is really a count of how deep into - executing functions we are. */ -int variable_context = 0; - -/* The set of shell assignments which are made only in the environment - for a single command. */ -HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; - -/* Set to non-zero if an assignment error occurs while putting variables - into the temporary environment. */ -int tempenv_assign_errors; - -/* 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 $$. */ -pid_t dollar_dollar_pid; - -/* An array which is passed to commands as their environment. It is - manufactured from the union of the initial environment and the - shell variables that are marked for export. */ -char **export_env = (char **)NULL; -static int export_env_index; -static int export_env_size; - -/* Non-zero means that we have to remake EXPORT_ENV. */ -int array_needs_making = 1; - -/* The number of times BASH has been executed. This is set - by initialize_variables (). */ -int shell_level = 0; - -/* Some forward declarations. */ -static void set_machine_vars __P((void)); -static void set_home_var __P((void)); -static void set_shell_var __P((void)); -static char *get_bash_name __P((void)); -static void initialize_shell_level __P((void)); -static void uidset __P((void)); -#if defined (ARRAY_VARS) -static void make_vers_array __P((void)); -#endif - -static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t)); -#if defined (ARRAY_VARS) -static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t)); -#endif -static SHELL_VAR *get_self __P((SHELL_VAR *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); -#endif - -static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t)); -static SHELL_VAR *get_seconds __P((SHELL_VAR *)); -static SHELL_VAR *init_seconds_var __P((void)); - -static int brand __P((void)); -static void sbrand __P((unsigned long)); /* set bash random number generator. */ -static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t)); -static SHELL_VAR *get_random __P((SHELL_VAR *)); - -static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t)); -static SHELL_VAR *get_lineno __P((SHELL_VAR *)); - -static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t)); -static SHELL_VAR *get_subshell __P((SHELL_VAR *)); - -#if defined (HISTORY) -static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t)); -static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); -#endif - -#if defined (ARRAY_VARS) -static SHELL_VAR *get_groupset __P((SHELL_VAR *)); -#endif - -static SHELL_VAR *get_funcname __P((SHELL_VAR *)); -static SHELL_VAR *init_funcname_var __P((void)); - -static void initialize_dynamic_variables __P((void)); - -static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *)); -static SHELL_VAR *new_shell_variable __P((const char *)); -static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *)); -static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int)); - -static void free_variable_hash_data __P((PTR_T)); - -static VARLIST *vlist_alloc __P((int)); -static VARLIST *vlist_realloc __P((VARLIST *, int)); -static void vlist_add __P((VARLIST *, SHELL_VAR *, int)); - -static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); - -static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **)); - -static SHELL_VAR **vapply __P((sh_var_map_func_t *)); -static SHELL_VAR **fapply __P((sh_var_map_func_t *)); - -static int visible_var __P((SHELL_VAR *)); -static int visible_and_exported __P((SHELL_VAR *)); -static int local_and_exported __P((SHELL_VAR *)); -static int variable_in_context __P((SHELL_VAR *)); -#if defined (ARRAY_VARS) -static int visible_array_vars __P((SHELL_VAR *)); -#endif - -static SHELL_VAR *bind_tempenv_variable __P((const char *, char *)); -static void push_temp_var __P((PTR_T)); -static void propagate_temp_var __P((PTR_T)); -static void dispose_temporary_env __P((sh_free_func_t *)); - -static inline char *mk_env_string __P((const char *, const char *)); -static char **make_env_array_from_var_list __P((SHELL_VAR **)); -static char **make_var_export_array __P((VAR_CONTEXT *)); -static char **make_func_export_array __P((void)); -static void add_temp_array_to_env __P((char **, int, int)); - -static int n_shell_variables __P((void)); -static int set_context __P((SHELL_VAR *)); - -static void push_func_var __P((PTR_T)); -static void push_exported_var __P((PTR_T)); - -static inline int find_special_var __P((const char *)); - -/* Initialize the shell variables from the current environment. - If PRIVMODE is nonzero, don't import functions from ENV or - parse $SHELLOPTS. */ -void -initialize_shell_variables (env, privmode) - char **env; - int privmode; -{ - char *name, *string, *temp_string; - int c, char_index, string_index, string_length; - SHELL_VAR *temp_var; - - if (shell_variables == 0) - { - shell_variables = global_variables = new_var_context ((char *)NULL, 0); - shell_variables->scope = 0; - shell_variables->table = hash_create (0); - } - - if (shell_functions == 0) - shell_functions = hash_create (0); - -#if defined (DEBUGGER) - if (shell_function_defs == 0) - shell_function_defs = hash_create (0); -#endif - - for (string_index = 0; string = env[string_index++]; ) - { - char_index = 0; - name = string; - while ((c = *string++) && c != '=') - ; - if (string[-1] == '=') - char_index = string - name - 1; - - /* If there are weird things in the environment, like `=xxx' or a - string without an `=', just skip them. */ - if (char_index == 0) - continue; - - /* ASSERT(name[char_index] == '=') */ - name[char_index] = '\0'; - /* Now, name = env variable name, string = env variable value, and - char_index == strlen (name) */ - - /* If exported function, define it now. Don't import functions from - the environment in privileged mode. */ - if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) - { - string_length = strlen (string); - temp_string = (char *)xmalloc (3 + string_length + char_index); - - strcpy (temp_string, name); - temp_string[char_index] = ' '; - strcpy (temp_string + char_index + 1, string); - - parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST); - - /* Ancient backwards compatibility. Old versions of bash exported - functions like name()=() {...} */ - if (name[char_index - 1] == ')' && name[char_index - 2] == '(') - name[char_index - 2] = '\0'; - - if (temp_var = find_function (name)) - { - VSETATTR (temp_var, (att_exported|att_imported)); - array_needs_making = 1; - } - else - report_error (_("error importing function definition for `%s'"), name); - - /* ( */ - if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') - name[char_index - 2] = '('; /* ) */ - } -#if defined (ARRAY_VARS) -# if 0 - /* Array variables may not yet be exported. */ - else if (*string == '(' && string[1] == '[' && xstrchr (string, ')')) - { - string_length = 1; - temp_string = extract_array_assignment_list (string, &string_length); - temp_var = assign_array_from_string (name, temp_string); - FREE (temp_string); - VSETATTR (temp_var, (att_exported | att_imported)); - array_needs_making = 1; - } -# endif -#endif - else - { - temp_var = bind_variable (name, string); - VSETATTR (temp_var, (att_exported | att_imported)); - array_needs_making = 1; - } - - name[char_index] = '='; - /* temp_var can be NULL if it was an exported function with a syntax - error (a different bug, but it still shouldn't dump core). */ - if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ - { - CACHE_IMPORTSTR (temp_var, name); - } - } - - set_pwd (); - - /* Set up initial value of $_ */ - temp_var = bind_variable ("_", dollar_vars[0]); - - /* Remember this pid. */ - dollar_dollar_pid = 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); -#if 0 - set_auto_export (temp_var); /* XXX */ -#endif - - temp_var = set_if_not ("TERM", "dumb"); -#if 0 - set_auto_export (temp_var); /* XXX */ -#endif - -#if defined (qnx) - /* set node id -- don't import it from the environment */ - { - char node_name[22]; - qnx_nidtostr (getnid (), node_name, sizeof (node_name)); - temp_var = bind_variable ("NODE", node_name); - set_auto_export (temp_var); - } -#endif - - /* set up the prompts. */ - if (interactive_shell) - { -#if defined (PROMPT_STRING_DECODE) - set_if_not ("PS1", primary_prompt); -#else - if (current_user.uid == -1) - get_current_user_info (); - set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); -#endif - set_if_not ("PS2", secondary_prompt); - } - set_if_not ("PS4", "+ "); - - /* Don't allow IFS to be imported from the environment. */ - temp_var = bind_variable ("IFS", " \t\n"); - setifs (temp_var); - - /* Magic machine types. Pretty convenient. */ - set_machine_vars (); - - /* Default MAILCHECK for interactive shells. Defer the creation of a - default MAILPATH until the startup files are read, because MAIL - names a mail file if MAILPATH is not set, and we should provide a - default only if neither is set. */ - if (interactive_shell) - set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); - - /* Do some things with shell level. */ - initialize_shell_level (); - - set_ppid (); - - /* Initialize the `getopts' stuff. */ - bind_variable ("OPTIND", "1"); - getopts_reset (0); - bind_variable ("OPTERR", "1"); - sh_opterr = 1; - - if (login_shell == 1) - set_home_var (); - - /* Get the full pathname to THIS shell, and set the BASH variable - to it. */ - name = get_bash_name (); - temp_var = bind_variable ("BASH", name); - free (name); - - /* Make the exported environment variable SHELL be the user's login - shell. Note that the `tset' command looks at this variable - to determine what style of commands to output; if it ends in "csh", - then C-shell commands are output, else Bourne shell commands. */ - set_shell_var (); - - /* Make a variable called BASH_VERSION which contains the version info. */ - bind_variable ("BASH_VERSION", shell_version_string ()); -#if defined (ARRAY_VARS) - make_vers_array (); -#endif - - if (command_execution_string) - bind_variable ("BASH_EXECUTION_STRING", command_execution_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) - { - name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0); - - 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 + shell_start_time); - - /* Handle some "special" variables that we may have inherited from a - parent shell. */ - if (interactive_shell) - { - 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_history_control ("HISTCONTROL"); - sv_histignore ("HISTIGNORE"); - } -#endif /* HISTORY */ - - /* - * 24 October 2001 - * - * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT - * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in - * isnetconn() to avoid running the startup files more often than wanted. - * That will, of course, only work if the user's login shell is bash, so - * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined - * in config-top.h. - */ -#if 0 - temp_var = find_variable ("SSH_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } - temp_var = find_variable ("SSH2_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } -#endif - - /* Get the user's real and effective user ids. */ - uidset (); - - /* Initialize the dynamic variables, and seed their values. */ - initialize_dynamic_variables (); -} - -/* **************************************************************** */ -/* */ -/* Setting values for special shell variables */ -/* */ -/* **************************************************************** */ - -static void -set_machine_vars () -{ - SHELL_VAR *temp_var; - - temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); - temp_var = set_if_not ("OSTYPE", OSTYPE); - temp_var = set_if_not ("MACHTYPE", MACHTYPE); - - temp_var = set_if_not ("HOSTNAME", current_host_name); -} - -/* Set $HOME to the information in the password file if we didn't get - it from the environment. */ - -/* This function is not static so the tilde and readline libraries can - use it. */ -char * -sh_get_home_dir () -{ - if (current_user.home_dir == 0) - get_current_user_info (); - return current_user.home_dir; -} - -static void -set_home_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("HOME"); - if (temp_var == 0) - temp_var = bind_variable ("HOME", sh_get_home_dir ()); -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -/* Set $SHELL to the user's login shell if it is not already set. Call - get_current_user_info if we haven't already fetched the shell. */ -static void -set_shell_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("SHELL"); - if (temp_var == 0) - { - if (current_user.shell == 0) - get_current_user_info (); - temp_var = bind_variable ("SHELL", current_user.shell); - } -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -static char * -get_bash_name () -{ - char *name; - - if ((login_shell == 1) && RELPATH(shell_name)) - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - else if (ABSPATH(shell_name)) - name = savestring (shell_name); - else if (shell_name[0] == '.' && shell_name[1] == '/') - { - /* Fast path for common case. */ - char *cdir; - int len; - - cdir = get_string_value ("PWD"); - if (cdir) - { - len = strlen (cdir); - name = (char *)xmalloc (len + strlen (shell_name) + 1); - strcpy (name, cdir); - strcpy (name + len, shell_name + 1); - } - else - name = savestring (shell_name); - } - else - { - char *tname; - int s; - - tname = find_user_command (shell_name); - - if (tname == 0) - { - /* Try the current directory. If there is not an executable - there, just punt and use the login shell. */ - s = file_status (shell_name); - if (s & FS_EXECABLE) - { - tname = make_absolute (shell_name, get_string_value ("PWD")); - if (*shell_name == '.') - { - name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - if (name == 0) - name = tname; - else - free (tname); - } - else - name = tname; - } - else - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - } - else - { - name = full_pathname (tname); - free (tname); - } - } - - return (name); -} - -void -adjust_shell_level (change) - int change; -{ - char new_level[5], *old_SHLVL; - intmax_t old_level; - SHELL_VAR *temp_var; - - old_SHLVL = get_string_value ("SHLVL"); - if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) - old_level = 0; - - shell_level = old_level + change; - if (shell_level < 0) - shell_level = 0; - else if (shell_level > 1000) - { - internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); - shell_level = 1; - } - - /* We don't need the full generality of itos here. */ - if (shell_level < 10) - { - new_level[0] = shell_level + '0'; - new_level[1] = '\0'; - } - else if (shell_level < 100) - { - new_level[0] = (shell_level / 10) + '0'; - new_level[1] = (shell_level % 10) + '0'; - new_level[2] = '\0'; - } - else if (shell_level < 1000) - { - new_level[0] = (shell_level / 100) + '0'; - old_level = shell_level % 100; - new_level[1] = (old_level / 10) + '0'; - new_level[2] = (old_level % 10) + '0'; - new_level[3] = '\0'; - } - - temp_var = bind_variable ("SHLVL", new_level); - set_auto_export (temp_var); -} - -static void -initialize_shell_level () -{ - adjust_shell_level (1); -} - -/* 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 getcwd () to fail on shell startup, - and in that case, PWD would be undefined. If this is an interactive - login shell, see if $HOME is the current working directory, and if - that's not the same string as $PWD, set PWD=$HOME. */ - -void -set_pwd () -{ - SHELL_VAR *temp_var, *home_var; - char *temp_string, *home_string; - - home_var = find_variable ("HOME"); - home_string = home_var ? value_cell (home_var) : (char *)NULL; - - temp_var = find_variable ("PWD"); - if (temp_var && imported_p (temp_var) && - (temp_string = value_cell (temp_var)) && - same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - set_working_directory (temp_string); - else if (home_string && interactive_shell && login_shell && - same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - { - set_working_directory (home_string); - temp_var = bind_variable ("PWD", home_string); - set_auto_export (temp_var); - } - else - { - temp_string = get_working_directory ("shell-init"); - if (temp_string) - { - temp_var = bind_variable ("PWD", temp_string); - set_auto_export (temp_var); - free (temp_string); - } - } - - /* According to the Single Unix Specification, v2, $OLDPWD is an - `environment variable' and therefore should be auto-exported. - Make a dummy invisible variable for OLDPWD, and mark it as exported. */ - temp_var = bind_variable ("OLDPWD", (char *)NULL); - VSETATTR (temp_var, (att_exported | att_invisible)); -} - -/* Make a variable $PPID, which holds the pid of the shell's parent. */ -void -set_ppid () -{ - char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; - SHELL_VAR *temp_var; - - name = inttostr (getppid (), namebuf, sizeof(namebuf)); - temp_var = find_variable ("PPID"); - if (temp_var) - VUNSETATTR (temp_var, (att_readonly | att_exported)); - temp_var = bind_variable ("PPID", name); - VSETATTR (temp_var, (att_readonly | att_integer)); -} - -static void -uidset () -{ - char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; - register SHELL_VAR *v; - - b = inttostr (current_user.uid, buff, sizeof (buff)); - v = find_variable ("UID"); - if (v == 0) - { - v = bind_variable ("UID", b); - VSETATTR (v, (att_readonly | att_integer)); - } - - if (current_user.euid != current_user.uid) - b = inttostr (current_user.euid, buff, sizeof (buff)); - - v = find_variable ("EUID"); - if (v == 0) - { - v = bind_variable ("EUID", b); - VSETATTR (v, (att_readonly | att_integer)); - } -} - -#if defined (ARRAY_VARS) -static void -make_vers_array () -{ - SHELL_VAR *vv; - ARRAY *av; - char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; - - unbind_variable ("BASH_VERSINFO"); - - vv = make_new_array_variable ("BASH_VERSINFO"); - av = array_cell (vv); - strcpy (d, dist_version); - s = xstrchr (d, '.'); - if (s) - *s++ = '\0'; - array_insert (av, 0, d); - array_insert (av, 1, s); - s = inttostr (patch_level, b, sizeof (b)); - array_insert (av, 2, s); - s = inttostr (build_version, b, sizeof (b)); - array_insert (av, 3, s); - array_insert (av, 4, release_status); - array_insert (av, 5, MACHTYPE); - - VSETATTR (vv, att_readonly); -} -#endif /* ARRAY_VARS */ - -/* Set the environment variables $LINES and $COLUMNS in response to - a window size change. */ -void -sh_set_lines_and_columns (lines, cols) - int lines, cols; -{ - char val[INT_STRLEN_BOUND(int) + 1], *v; - - v = inttostr (lines, val, sizeof (val)); - bind_variable ("LINES", v); - - v = inttostr (cols, val, sizeof (val)); - bind_variable ("COLUMNS", v); -} - -/* **************************************************************** */ -/* */ -/* Printing variables and values */ -/* */ -/* **************************************************************** */ - -/* Print LIST (a list of shell variables) 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) == 0) - print_assignment (var); -} - -/* Print LIST (a list of shell functions) to stdout in such a way that - they can be read back in. */ -void -print_func_list (list) - register SHELL_VAR **list; -{ - register int i; - register SHELL_VAR *var; - - for (i = 0; list && (var = list[i]); i++) - { - printf ("%s ", var->name); - print_var_function (var); - printf ("\n"); - } -} - -/* 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 (var_isset (var) == 0) - return; - - if (function_p (var)) - { - printf ("%s", var->name); - print_var_function (var); - printf ("\n"); - } -#if defined (ARRAY_VARS) - else if (array_p (var)) - print_array_assignment (var, 0); -#endif /* ARRAY_VARS */ - else - { - printf ("%s=", var->name); - print_var_value (var, 1); - printf ("\n"); - } -} - -/* Print the value cell of VAR, a shell variable. Do not print - the name, nor leading/trailing newline. If QUOTE is non-zero, - and the value contains shell metacharacters, quote the value - in such a way that it can be read back in. */ -void -print_var_value (var, quote) - SHELL_VAR *var; - int quote; -{ - char *t; - - if (var_isset (var) == 0) - return; - - if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) - { - t = ansic_quote (value_cell (var), 0, (int *)0); - printf ("%s", t); - free (t); - } - else if (quote && sh_contains_shell_metas (value_cell (var))) - { - t = sh_single_quote (value_cell (var)); - printf ("%s", t); - free (t); - } - else - printf ("%s", value_cell (var)); -} - -/* 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_isset (var)) - printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1)); -} - -/* **************************************************************** */ -/* */ -/* Dynamic Variables */ -/* */ -/* **************************************************************** */ - -/* 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, if arrays are compiled into the shell, some of the functions in - arrayfunc.c, and dynamic_value, which is called from find_variable. - - assign_func is called from bind_variable_internal, if - bind_variable_internal discovers that the variable being assigned to - has such a function. The function is called as - SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) - and the (SHELL_VAR *)temp is returned as the value of bind_variable. It - is usually ENTRY (self). IND is an index for an array variable, and - unused otherwise. - - dynamic_value is called from find_variable_internal 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_internal, in the same style as - stupidly_hack_special_variables, but I wanted the changes as - localized as possible. */ - -#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ - do \ - { \ - v = bind_variable (var, (val)); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_array_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -static SHELL_VAR * -null_assign (self, value, unused) - SHELL_VAR *self; - char *value; - arrayind_t unused; -{ - return (self); -} - -#if defined (ARRAY_VARS) -static SHELL_VAR * -null_array_assign (self, value, ind) - SHELL_VAR *self; - char *value; - arrayind_t ind; -{ - return (self); -} -#endif - -/* Degenerate `dynamic_value' function; just returns what's passed without - manipulation. */ -static SHELL_VAR * -get_self (self) - SHELL_VAR *self; -{ - return (self); -} - -#if defined (ARRAY_VARS) -/* A generic dynamic array variable initializer. Intialize array variable - NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ -static SHELL_VAR * -init_dynamic_array_var (name, getfunc, setfunc, attrs) - char *name; - sh_var_value_func_t *getfunc; - sh_var_assign_func_t *setfunc; - int attrs; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v) - return (v); - INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); - if (attrs) - VSETATTR (v, attrs); - return v; -} -#endif - - -/* 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 intmax_t seconds_value_assigned; - -static SHELL_VAR * -assign_seconds (self, value, unused) - SHELL_VAR *self; - char *value; - arrayind_t unused; -{ - if (legal_number (value, &seconds_value_assigned) == 0) - seconds_value_assigned = 0; - 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(seconds_value_assigned + time_since_start); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -init_seconds_var () -{ - SHELL_VAR *v; - - v = find_variable ("SECONDS"); - if (v) - { - if (legal_number (value_cell(v), &seconds_value_assigned) == 0) - seconds_value_assigned = 0; - } - INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); - return v; -} - -/* The random number seed. You can change this by setting RANDOM. */ -static unsigned long rseed = 1; -static int last_random_value; - -/* A linear congruential random number generator based on the example - one in the ANSI C standard. This one isn't very good, but 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 >> 16) & 32767)); /* was % 32768 */ -} - -/* Set the random number generator seed to SEED. */ -static void -sbrand (seed) - unsigned long seed; -{ - rseed = seed; - last_random_value = 0; -} - -static SHELL_VAR * -assign_random (self, value, unused) - SHELL_VAR *self; - char *value; - arrayind_t unused; -{ - sbrand (strtoul (value, (char **)NULL, 10)); - return (self); -} - -int -get_random_number () -{ - int rv; - - /* Reset for command and process substitution. */ - if (subshell_environment) - sbrand (rseed + getpid() + NOW); - - do - rv = brand (); - while (rv == last_random_value); - return rv; -} - -static SHELL_VAR * -get_random (var) - SHELL_VAR *var; -{ - int rv; - char *p; - - rv = get_random_number (); - last_random_value = rv; - p = itos (rv); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_lineno (var, value, unused) - SHELL_VAR *var; - char *value; - arrayind_t unused; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - line_number = new_value; - return var; -} - -/* Function which returns the current line number. */ -static SHELL_VAR * -get_lineno (var) - SHELL_VAR *var; -{ - char *p; - int ln; - - ln = executing_line_number (); - p = itos (ln); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_subshell (var, value, unused) - SHELL_VAR *var; - char *value; - arrayind_t unused; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - subshell_level = new_value; - return var; -} - -static SHELL_VAR * -get_subshell (var) - SHELL_VAR *var; -{ - char *p; - - p = itos (subshell_level); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bash_command (var) - SHELL_VAR *var; -{ - char *p; - - p = savestring (the_printed_command_except_trap); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -#if defined (HISTORY) -static SHELL_VAR * -get_histcmd (var) - SHELL_VAR *var; -{ - char *p; - - p = itos (history_number ()); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} -#endif - -#if defined (READLINE) -/* When this function returns, VAR->value points to malloced memory. */ -static SHELL_VAR * -get_comp_wordbreaks (var) - SHELL_VAR *var; -{ - char *p; - - /* If we don't have anything yet, assign a default value. */ - if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0) - enable_hostname_completion (perform_hostname_completion); - -#if 0 - FREE (value_cell (var)); - p = savestring (rl_completer_word_break_characters); - - var_setvalue (var, p); -#else - var_setvalue (var, rl_completer_word_break_characters); -#endif - - return (var); -} - -/* When this function returns, rl_completer_word_break_characters points to - malloced memory. */ -static SHELL_VAR * -assign_comp_wordbreaks (self, value, unused) - SHELL_VAR *self; - char *value; - arrayind_t unused; -{ - if (rl_completer_word_break_characters && - rl_completer_word_break_characters != rl_basic_word_break_characters) - free (rl_completer_word_break_characters); - - rl_completer_word_break_characters = savestring (value); - return self; -} -#endif /* READLINE */ - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR * -assign_dirstack (self, value, ind) - SHELL_VAR *self; - char *value; - arrayind_t ind; -{ - set_dirstack_element (ind, 1, value); - return self; -} - -static SHELL_VAR * -get_dirstack (self) - SHELL_VAR *self; -{ - ARRAY *a; - WORD_LIST *l; - - l = get_directory_stack (); - a = array_from_word_list (l); - array_dispose (array_cell (self)); - dispose_words (l); - var_setarray (self, a); - return self; -} -#endif /* PUSHD AND POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) -/* We don't want to initialize the group set with a call to getgroups() - unless we're asked to, but we only want to do it once. */ -static SHELL_VAR * -get_groupset (self) - SHELL_VAR *self; -{ - register int i; - int ng; - ARRAY *a; - static char **group_set = (char **)NULL; - - if (group_set == 0) - { - group_set = get_group_list (&ng); - a = array_cell (self); - for (i = 0; i < ng; i++) - array_insert (a, i, group_set[i]); - } - return (self); -} -#endif /* ARRAY_VARS */ - -/* If ARRAY_VARS is not defined, this just returns the name of any - currently-executing function. If we have arrays, it's a call stack. */ -static SHELL_VAR * -get_funcname (self) - SHELL_VAR *self; -{ -#if ! defined (ARRAY_VARS) - char *t; - if (variable_context && this_shell_function) - { - FREE (value_cell (self)); - t = savestring (this_shell_function->name); - var_setvalue (self, t); - } -#endif - return (self); -} - -void -make_funcname_visible (on_or_off) - int on_or_off; -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v == 0 || v->dynamic_value == 0) - return; - - if (on_or_off) - VUNSETATTR (v, att_invisible); - else - VSETATTR (v, att_invisible); -} - -static SHELL_VAR * -init_funcname_var () -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v) - return v; -#if defined (ARRAY_VARS) - INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); -#else - INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); -#endif - VSETATTR (v, att_invisible|att_noassign); - return v; -} - -static void -initialize_dynamic_variables () -{ - SHELL_VAR *v; - - v = init_seconds_var (); - - INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL); - INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); - - INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); - INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); - -#if defined (HISTORY) - INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); -#endif - -#if defined (READLINE) - INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) - v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); -#endif /* PUSHD_AND_POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) - v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); - -# if defined (DEBUGGER) - v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign)); - v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign)); -# endif /* DEBUGGER */ - v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign)); - v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign)); -#endif - - v = init_funcname_var (); -} - -/* **************************************************************** */ -/* */ -/* Retrieving variables and values */ -/* */ -/* **************************************************************** */ - -/* 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). */ - -static SHELL_VAR * -hash_lookup (name, hashed_vars) - const char *name; - HASH_TABLE *hashed_vars; -{ - BUCKET_CONTENTS *bucket; - - bucket = hash_search (name, hashed_vars, 0); - return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); -} - -SHELL_VAR * -var_lookup (name, vcontext) - const char *name; - VAR_CONTEXT *vcontext; -{ - VAR_CONTEXT *vc; - SHELL_VAR *v; - - v = (SHELL_VAR *)NULL; - for (vc = vcontext; vc; vc = vc->down) - if (v = hash_lookup (name, vc->table)) - break; - - return v; -} - -/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, - then also search the temporarily built list of exported variables. - The lookup order is: - temporary_env - shell_variables list -*/ - -SHELL_VAR * -find_variable_internal (name, force_tempenv) - const char *name; - int force_tempenv; -{ - SHELL_VAR *var; - int search_tempenv; - - 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". */ - search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); - - if (search_tempenv && temporary_env) - var = hash_lookup (name, temporary_env); - - if (var == 0) - var = var_lookup (name, shell_variables); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -/* Look up the variable entry named NAME. Returns the entry or NULL. */ -SHELL_VAR * -find_variable (name) - const char *name; -{ - return (find_variable_internal (name, (expanding_redir == 0 && this_shell_builtin != 0))); -} - -/* Look up the function entry whose name matches STRING. - Returns the entry or NULL. */ -SHELL_VAR * -find_function (name) - const char *name; -{ - return (hash_lookup (name, shell_functions)); -} - -/* Find the function definition for the shell function named NAME. Returns - the entry or NULL. */ -FUNCTION_DEF * -find_function_def (name) - const char *name; -{ - return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); -} - -/* Return the value of VAR. VAR is assumed to have been the result of a - lookup without any subscript, if arrays are compiled into the shell. */ -char * -get_variable_value (var) - SHELL_VAR *var; -{ - if (var == 0) - return ((char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (var)) - return (array_reference (array_cell (var), 0)); -#endif - else - return (value_cell (var)); -} - -/* Return the string value of a variable. Return NULL if the variable - doesn't exist. Don't cons a new string. This is a potential memory - leak if the variable is found in the temporary environment. Since - functions and variables have separate name spaces, returns NULL if - var_name is a shell function only. */ -char * -get_string_value (var_name) - const char *var_name; -{ - SHELL_VAR *var; - - var = find_variable (var_name); - return ((var) ? get_variable_value (var) : (char *)NULL); -} - -/* This is present for use by the tilde and readline libraries. */ -char * -sh_get_env_value (v) - const char *v; -{ - return get_string_value (v); -} - -/* **************************************************************** */ -/* */ -/* Creating and setting variables */ -/* */ -/* **************************************************************** */ - -/* Set NAME to VALUE if NAME has no value. */ -SHELL_VAR * -set_if_not (name, value) - char *name, *value; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v == 0) - v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH); - return (v); -} - -/* Create a local variable referenced by NAME. */ -SHELL_VAR * -make_local_variable (name) - const char *name; -{ - SHELL_VAR *new_var, *old_var; - VAR_CONTEXT *vc; - int was_tmpvar; - char *tmp_value; - - /* local foo; local foo; is a no-op. */ - old_var = find_variable (name); - if (old_var && local_p (old_var) && old_var->context == variable_context) - return (old_var); - - was_tmpvar = old_var && tempvar_p (old_var); - if (was_tmpvar) - tmp_value = value_cell (old_var); - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("make_local_variable: no function context at current scope")); - return ((SHELL_VAR *)NULL); - } - else if (vc->table == 0) - vc->table = hash_create (TEMPENV_HASH_BUCKETS); - - /* Since this is called only from the local/declare/typeset code, we can - call builtin_error here without worry (of course, it will also work - for anything that sets this_command_name). Variables with the `noassign' - attribute may not be made local. The test against old_var's context - level is to disallow local copies of readonly global variables (since I - believe that this could be a security hole). Readonly copies of calling - function local variables are OK. */ - if (old_var && (noassign_p (old_var) || - (readonly_p (old_var) && old_var->context == 0))) - { - if (readonly_p (old_var)) - sh_readonly (name); - return ((SHELL_VAR *)NULL); - } - - if (old_var == 0) - new_var = bind_variable_internal (name, "", vc->table, HASH_NOSRCH); - else - { - new_var = make_new_variable (name, vc->table); - - /* If we found this variable in one of the temporary environments, - inherit its value. Watch to see if this causes problems with - things like `x=4 local x'. */ - if (was_tmpvar) - var_setvalue (new_var, savestring (tmp_value)); - - new_var->attributes = exported_p (old_var) ? att_exported : 0; - } - - vc->flags |= VC_HASLOCAL; - - new_var->context = variable_context; - VSETATTR (new_var, att_local); - - if (ifsname (name)) - setifs (new_var); - - return (new_var); -} - -#if defined (ARRAY_VARS) -SHELL_VAR * -make_local_array_variable (name) - char *name; -{ - SHELL_VAR *var; - ARRAY *array; - - var = make_local_variable (name); - if (var == 0 || array_p (var)) - return var; - - array = array_create (); - - FREE (value_cell(var)); - var_setarray (var, array); - VSETATTR (var, att_array); - return var; -} -#endif /* ARRAY_VARS */ - -/* Create a new shell variable with name NAME. */ -static SHELL_VAR * -new_shell_variable (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - - entry->name = savestring (name); - var_setvalue (entry, (char *)NULL); - CLEAR_EXPORTSTR (entry); - - entry->dynamic_value = (sh_var_value_func_t *)NULL; - entry->assign_func = (sh_var_assign_func_t *)NULL; - - entry->attributes = 0; - - /* Always assume variables are to be made at toplevel! - make_local_variable has the responsibilty of changing the - variable context. */ - entry->context = 0; - - return (entry); -} - -/* Create a new shell variable with name NAME and add it to the hash table - TABLE. */ -static SHELL_VAR * -make_new_variable (name, table) - const char *name; - HASH_TABLE *table; -{ - SHELL_VAR *entry; - BUCKET_CONTENTS *elt; - - entry = new_shell_variable (name); - - /* Make sure we have a shell_variables hash table to add to. */ - if (shell_variables == 0) - { - shell_variables = global_variables = new_var_context ((char *)NULL, 0); - shell_variables->scope = 0; - shell_variables->table = hash_create (0); - } - - elt = hash_insert (savestring (name), table, HASH_NOSRCH); - elt->data = (PTR_T)entry; - - return entry; -} - -#if defined (ARRAY_VARS) -SHELL_VAR * -make_new_array_variable (name) - char *name; -{ - SHELL_VAR *entry; - ARRAY *array; - - entry = make_new_variable (name, global_variables->table); - array = array_create (); - var_setarray (entry, array); - VSETATTR (entry, att_array); - return entry; -} -#endif - -char * -make_variable_value (var, value) - SHELL_VAR *var; - char *value; -{ - char *retval; - intmax_t lval; - int expok; - - /* If this variable has had its type set to integer (via `declare -i'), - then do expression evaluation on it and store the result. The - functions in expr.c (evalexp()) and bind_int_variable() are responsible - for turning off the integer flag if they don't want further - evaluation done. */ - if (integer_p (var)) - { - lval = evalexp (value, &expok); - if (expok == 0) - jump_to_top_level (DISCARD); - retval = itos (lval); - } - else if (value) - { - if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - } - else - retval = (char *)NULL; - - return retval; -} - -/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the - temporary environment (but usually is not). */ -static SHELL_VAR * -bind_variable_internal (name, value, table, hflags) - const char *name; - char *value; - HASH_TABLE *table; - int hflags; -{ - char *newval; - SHELL_VAR *entry; - - entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); - - if (entry == 0) - { - entry = make_new_variable (name, table); - var_setvalue (entry, make_variable_value (entry, value)); - } - else if (entry->assign_func) /* array vars have assign functions now */ - { - INVALIDATE_EXPORTSTR (entry); - return ((*(entry->assign_func)) (entry, value, -1)); - } - else - { - if (readonly_p (entry) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - - /* Variables which are bound are visible. */ - VUNSETATTR (entry, att_invisible); - - newval = make_variable_value (entry, value); - - /* Invalidate any cached export string */ - INVALIDATE_EXPORTSTR (entry); - -#if defined (ARRAY_VARS) - /* XXX -- this bears looking at again -- XXX */ - /* If an existing array variable x is being assigned to with x=b or - `read x' or something of that nature, silently convert it to - x[0]=b or `read x[0]'. */ - if (array_p (entry)) - { - array_insert (array_cell (entry), 0, newval); - free (newval); - } - else -#endif - { - FREE (value_cell (entry)); - var_setvalue (entry, newval); - } - } - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - if (exported_p (entry)) - array_needs_making = 1; - - return (entry); -} - -/* Bind a variable NAME to VALUE. This conses up the name - and value strings. If we have a temporary environment, we bind there - first, then we bind into shell_variables. */ - -SHELL_VAR * -bind_variable (name, value) - const char *name; - char *value; -{ - SHELL_VAR *v; - VAR_CONTEXT *vc; - - if (shell_variables == 0) - { - shell_variables = global_variables = new_var_context ((char *)NULL, 0); - shell_variables->scope = 0; - shell_variables->table = hash_create (0); - } - - /* If we have a temporary environment, look there first for the variable, - and, if found, modify the value there before modifying it in the - shell_variables table. This allows sourced scripts to modify values - given to them in a temporary environment while modifying the variable - value that the caller sees. */ - if (temporary_env) - bind_tempenv_variable (name, value); - - /* XXX -- handle local variables here. */ - for (vc = shell_variables; vc; vc = vc->down) - { - if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) - { - v = hash_lookup (name, vc->table); - if (v) - return (bind_variable_internal (name, value, vc->table, 0)); - } - } - return (bind_variable_internal (name, value, global_variables->table, 0)); -} - -/* Make VAR, a simple shell variable, have value VALUE. Once assigned a - value, variables are no longer invisible. This is a duplicate of part - of the internals of bind_variable. If the variable is exported, or - all modified variables should be exported, mark the variable for export - and note that the export environment needs to be recreated. */ -SHELL_VAR * -bind_variable_value (var, value) - SHELL_VAR *var; - char *value; -{ - char *t; - - VUNSETATTR (var, att_invisible); - - t = make_variable_value (var, value); - FREE (value_cell (var)); - var_setvalue (var, t); - - INVALIDATE_EXPORTSTR (var); - - if (mark_modified_vars) - VSETATTR (var, att_exported); - - if (exported_p (var)) - array_needs_making = 1; - - return (var); -} - -/* 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 used to be in expr.c, but it is here so that all of the - variable binding 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. */ - -SHELL_VAR * -bind_int_variable (lhs, rhs) - char *lhs, *rhs; -{ - register SHELL_VAR *v; - char *t; - int isint, isarr; - - isint = isarr = 0; -#if defined (ARRAY_VARS) -# if 0 - if (t = xstrchr (lhs, '[')) /*]*/ -# else - if (valid_array_reference (lhs)) -# endif - { - isarr = 1; - v = array_variable_part (lhs, (char **)0, (int *)0); - } - else -#endif - v = find_variable (lhs); - - if (v) - { - isint = integer_p (v); - VUNSETATTR (v, att_integer); - } - -#if defined (ARRAY_VARS) - if (isarr) - v = assign_array_element (lhs, rhs); - else -#endif - v = bind_variable (lhs, rhs); - - if (isint) - VSETATTR (v, att_integer); - - return (v); -} - -SHELL_VAR * -bind_var_to_int (var, val) - char *var; - intmax_t val; -{ - char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; - - p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); - return (bind_int_variable (var, p)); -} - -/* 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) - const char *name; - COMMAND *value; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry == 0) - { - BUCKET_CONTENTS *elt; - - elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); - entry = new_shell_variable (name); - elt->data = (PTR_T)entry; - } - else - INVALIDATE_EXPORTSTR (entry); - - if (var_isset (entry)) - dispose_command (function_cell (entry)); - - if (value) - var_setfunc (entry, copy_command (value)); - else - var_setfunc (entry, 0); - - VSETATTR (entry, att_function); - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - VUNSETATTR (entry, att_invisible); /* Just to be sure */ - - if (exported_p (entry)) - array_needs_making = 1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - return (entry); -} - -/* Bind a function definition, which includes source file and line number - information in addition to the command, into the FUNCTION_DEF hash table.*/ -void -bind_function_def (name, value) - const char *name; - FUNCTION_DEF *value; -{ - FUNCTION_DEF *entry; - BUCKET_CONTENTS *elt; - COMMAND *cmd; - - entry = find_function_def (name); - if (entry) - { - dispose_function_def_contents (entry); - entry = copy_function_def_contents (value, entry); - } - else - { - cmd = value->command; - value->command = 0; - entry = copy_function_def (value); - value->command = cmd; - - elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); - elt->data = (PTR_T *)entry; - } -} - -/* Add STRING, which is of the form foo=bar, to the temporary environment - HASH_TABLE (temporary_env). The functions in execute_cmd.c are - responsible for moving the main temporary env to one of the other - temporary environments. The expansion code in subst.c calls this. */ -int -assign_in_env (string) - const char *string; -{ - int offset; - char *name, *temp, *value; - SHELL_VAR *var; - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - name[offset] = 0; - - var = find_variable (name); - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - err_readonly (name); - free (name); - return (0); - } - - temp = name + offset + 1; - temp = (xstrchr (temp, '~') != 0) ? bash_tilde_expand (temp, 1) : savestring (temp); - - value = expand_string_unsplit_to_string (temp, 0); - free (temp); - } - - if (temporary_env == 0) - temporary_env = hash_create (TEMPENV_HASH_BUCKETS); - - var = hash_lookup (name, temporary_env); - if (var == 0) - var = make_new_variable (name, temporary_env); - else - FREE (value_cell (var)); - - if (value == 0) - { - value = (char *)xmalloc (1); /* like do_assignment_internal */ - value[0] = '\0'; - } - - var_setvalue (var, value); - var->attributes |= (att_exported|att_tempvar); - var->context = variable_context; /* XXX */ - - INVALIDATE_EXPORTSTR (var); - var->exportstr = mk_env_string (name, value); - - array_needs_making = 1; - - if (ifsname (name)) - setifs (var); - - if (echo_command_at_execute) - /* The Korn shell prints the `+ ' in front of assignment statements, - so we do too. */ - xtrace_print_assignment (name, value, 0, 1); - - free (name); - return 1; -} - -/* **************************************************************** */ -/* */ -/* Copying variables */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -/* 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)) - var_setfunc (copy, copy_command (function_cell (var))); -#if defined (ARRAY_VARS) - else if (array_p (var)) - var_setarray (copy, dup_array (array_cell (var))); -#endif - else if (value_cell (var)) - var_setvalue (copy, savestring (value_cell (var))); - else - var_setvalue (copy, (char *)NULL); - - copy->dynamic_value = var->dynamic_value; - copy->assign_func = var->assign_func; - - copy->exportstr = COPY_EXPORTSTR (var); - - copy->context = var->context; - } - return (copy); -} -#endif - -/* **************************************************************** */ -/* */ -/* Deleting and unsetting variables */ -/* */ -/* **************************************************************** */ - -/* Dispose of the information attached to VAR. */ -void -dispose_variable (var) - SHELL_VAR *var; -{ - if (var == 0) - return; - - if (function_p (var)) - dispose_command (function_cell (var)); -#if defined (ARRAY_VARS) - else if (array_p (var)) - array_dispose (array_cell (var)); -#endif - else - FREE (value_cell (var)); - - FREE_EXPORTSTR (var); - - free (var->name); - - if (exported_p (var)) - array_needs_making = 1; - - free (var); -} - -/* Unset the shell variable referenced by NAME. */ -int -unbind_variable (name) - const char *name; -{ - return makunbound (name, shell_variables); -} - -/* Unset the shell function named NAME. */ -int -unbind_func (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - SHELL_VAR *func; - - elt = hash_remove (name, shell_functions, 0); - - if (elt == 0) - return -1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - func = (SHELL_VAR *)elt->data; - if (func) - { - if (exported_p (func)) - array_needs_making++; - dispose_variable (func); - } - - free (elt->key); - free (elt); - - return 0; -} - -int -unbind_function_def (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - FUNCTION_DEF *funcdef; - - elt = hash_remove (name, shell_function_defs, 0); - - if (elt == 0) - return -1; - - funcdef = (FUNCTION_DEF *)elt->data; - if (funcdef) - dispose_function_def (funcdef); - - free (elt->key); - free (elt); - - 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. */ -int -makunbound (name, vc) - const char *name; - VAR_CONTEXT *vc; -{ - BUCKET_CONTENTS *elt, *new_elt; - SHELL_VAR *old_var; - VAR_CONTEXT *v; - char *t; - - for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) - if (elt = hash_remove (name, v->table, 0)) - break; - - if (elt == 0) - return (-1); - - old_var = (SHELL_VAR *)elt->data; - - if (old_var && exported_p (old_var)) - array_needs_making++; - - /* If we're unsetting a local variable and we're still executing inside - the function, just mark the variable as invisible. The function - eventually called by pop_var_context() will clean it up later. This - must be done so that if the variable is subsequently assigned a new - value inside the function, the `local' attribute is still present. - We also need to add it back into the correct hash table. */ - if (old_var && local_p (old_var) && variable_context == old_var->context) - { - /* Reset the attributes. Preserve the export attribute if the variable - came from a temporary environment. Make sure it stays local, and - make it invisible. */ - old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; - VSETATTR (old_var, att_local); - VSETATTR (old_var, att_invisible); - FREE (value_cell (old_var)); - var_setvalue (old_var, (char *)NULL); - INVALIDATE_EXPORTSTR (old_var); - - new_elt = hash_insert (savestring (old_var->name), v->table, 0); - new_elt->data = (PTR_T)old_var; - stupidly_hack_special_variables (old_var->name); - - free (elt->key); - free (elt); - return (0); - } - - /* 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); -} - -/* Get rid of all of the variables in the current context. */ -void -kill_all_local_variables () -{ - VAR_CONTEXT *vc; - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - if (vc == 0) - return; /* XXX */ - - if (vc->table && vc_haslocals (vc)) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - vc->table = (HASH_TABLE *)NULL; -} - -static void -free_variable_hash_data (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - dispose_variable (var); -} - -/* Delete the entire contents of the hash table. */ -void -delete_all_variables (hashed_vars) - HASH_TABLE *hashed_vars; -{ - hash_flush (hashed_vars, free_variable_hash_data); -} - -/* **************************************************************** */ -/* */ -/* Setting variable attributes */ -/* */ -/* **************************************************************** */ - -#define FIND_OR_MAKE_VARIABLE(name, entry) \ - do \ - { \ - entry = find_variable (name); \ - if (!entry) \ - { \ - entry = bind_variable (name, ""); \ - if (!no_invisible_vars) entry->attributes |= att_invisible; \ - } \ - } \ - while (0) - -/* Make the variable associated with NAME be readonly. - If NAME does not exist yet, create it. */ -void -set_var_read_only (name) - char *name; -{ - SHELL_VAR *entry; - - FIND_OR_MAKE_VARIABLE (name, entry); - VSETATTR (entry, att_readonly); -} - -#ifdef INCLUDE_UNUSED -/* Make the function associated with NAME be readonly. - If NAME does not exist, we just punt, like auto_export code below. */ -void -set_func_read_only (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - VSETATTR (entry, 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_OR_MAKE_VARIABLE (name, entry); - set_auto_export (entry); -} - -/* Make the function associated with NAME be auto-exported. */ -void -set_func_auto_export (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - set_auto_export (entry); -} -#endif - -/* **************************************************************** */ -/* */ -/* Creating lists of variables */ -/* */ -/* **************************************************************** */ - -static VARLIST * -vlist_alloc (nentries) - int nentries; -{ - VARLIST *vlist; - - vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); - vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); - vlist->list_size = nentries; - vlist->list_len = 0; - vlist->list[0] = (SHELL_VAR *)NULL; - - return vlist; -} - -static VARLIST * -vlist_realloc (vlist, n) - VARLIST *vlist; - int n; -{ - if (vlist == 0) - return (vlist = vlist_alloc (n)); - if (n > vlist->list_size) - { - vlist->list_size = n; - vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); - } - return vlist; -} - -static void -vlist_add (vlist, var, flags) - VARLIST *vlist; - SHELL_VAR *var; - int flags; -{ - register int i; - - for (i = 0; i < vlist->list_len; i++) - if (STREQ (var->name, vlist->list[i]->name)) - break; - if (i < vlist->list_len) - return; - - if (i >= vlist->list_size) - vlist = vlist_realloc (vlist, vlist->list_size + 16); - - vlist->list[vlist->list_len++] = var; - vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; -} - -/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the - variables for which FUNCTION returns a non-zero value. A NULL value - for FUNCTION means to use all variables. */ -SHELL_VAR ** -map_over (function, vc) - sh_var_map_func_t *function; - VAR_CONTEXT *vc; -{ - VAR_CONTEXT *v; - VARLIST *vlist; - SHELL_VAR **ret; - int nentries; - - for (nentries = 0, v = vc; v; v = v->down) - nentries += HASH_ENTRIES (v->table); - - if (nentries == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (nentries); - - for (v = vc; v; v = v->down) - flatten (v->table, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -SHELL_VAR ** -map_over_funcs (function) - sh_var_map_func_t *function; -{ - VARLIST *vlist; - SHELL_VAR **ret; - - if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) - return ((SHELL_VAR **)NULL); - - vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); - - flatten (shell_functions, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those - elements for which FUNC succeeds to VLIST->list. FLAGS is reserved - for future use. Only unique names are added to VLIST. If FUNC is - NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is - NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST - and FUNC are both NULL, nothing happens. */ -static void -flatten (var_hash_table, func, vlist, flags) - HASH_TABLE *var_hash_table; - sh_var_map_func_t *func; - VARLIST *vlist; - int flags; -{ - register int i; - register BUCKET_CONTENTS *tlist; - int r; - SHELL_VAR *var; - - if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) - return; - - for (i = 0; i < var_hash_table->nbuckets; i++) - { - for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) - { - var = (SHELL_VAR *)tlist->data; - - r = func ? (*func) (var) : 1; - if (r && vlist) - vlist_add (vlist, var, flags); - } - } -} - -void -sort_variables (array) - SHELL_VAR **array; -{ - qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)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); -} - -/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -vapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over (func, shell_variables); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -fapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over_funcs (func); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Create a NULL terminated array of all the shell variables. */ -SHELL_VAR ** -all_shell_variables () -{ - return (vapply ((sh_var_map_func_t *)NULL)); -} - -/* Create a NULL terminated array of all the shell functions. */ -SHELL_VAR ** -all_shell_functions () -{ - return (fapply ((sh_var_map_func_t *)NULL)); -} - -static int -visible_var (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0); -} - -SHELL_VAR ** -all_visible_functions () -{ - return (fapply (visible_var)); -} - -SHELL_VAR ** -all_visible_variables () -{ - return (vapply (visible_var)); -} - -/* Return non-zero if the variable VAR is visible and exported. Array - variables cannot be exported. */ -static int -visible_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && exported_p (var)); -} - -/* Return non-zero if VAR is a local variable in the current context and - is exported. */ -static int -local_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); -} - -SHELL_VAR ** -all_exported_variables () -{ - return (vapply (visible_and_exported)); -} - -SHELL_VAR ** -local_exported_variables () -{ - return (vapply (local_and_exported)); -} - -static int -variable_in_context (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); -} - -SHELL_VAR ** -all_local_variables () -{ - VARLIST *vlist; - SHELL_VAR **ret; - VAR_CONTEXT *vc; - - vc = shell_variables; - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("all_local_variables: no function context at current scope")); - return (SHELL_VAR **)NULL; - } - if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (HASH_ENTRIES (vc->table)); - - flatten (vc->table, variable_in_context, vlist, 0); - - ret = vlist->list; - free (vlist); - if (ret) - sort_variables (ret); - return ret; -} - -#if defined (ARRAY_VARS) -/* Return non-zero if the variable VAR is visible and an array. */ -static int -visible_array_vars (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && array_p (var)); -} - -SHELL_VAR ** -all_array_variables () -{ - return (vapply (visible_array_vars)); -} -#endif /* ARRAY_VARS */ - -char ** -all_variables_matching_prefix (prefix) - const char *prefix; -{ - SHELL_VAR **varlist; - char **rlist; - int vind, rind, plen; - - plen = STRLEN (prefix); - varlist = all_visible_variables (); - for (vind = 0; varlist && varlist[vind]; vind++) - ; - if (varlist == 0 || vind == 0) - return ((char **)NULL); - rlist = strvec_create (vind + 1); - for (vind = rind = 0; varlist[vind]; vind++) - { - if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) - rlist[rind++] = savestring (varlist[vind]->name); - } - rlist[rind] = (char *)0; - free (varlist); - - return rlist; -} - -/* **************************************************************** */ -/* */ -/* Managing temporary variable scopes */ -/* */ -/* **************************************************************** */ - -/* Make variable NAME have VALUE in the temporary environment. */ -static SHELL_VAR * -bind_tempenv_variable (name, value) - const char *name; - char *value; -{ - SHELL_VAR *var; - - var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; - - if (var) - { - FREE (value_cell (var)); - var_setvalue (var, savestring (value)); - INVALIDATE_EXPORTSTR (var); - } - - return (var); -} - -/* Find a variable in the temporary environment that is named NAME. - Return the SHELL_VAR *, or NULL if not found. */ -SHELL_VAR * -find_tempenv_variable (name) - const char *name; -{ - return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); -} - -/* Push the variable described by (SHELL_VAR *)DATA down to the next - variable context from the temporary environment. */ -static void -push_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - HASH_TABLE *binding_table; - - var = (SHELL_VAR *)data; - - binding_table = shell_variables->table; - if (binding_table == 0) - { - if (shell_variables == global_variables) - /* shouldn't happen */ - binding_table = shell_variables->table = global_variables->table = hash_create (0); - else - binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); - } - - v = bind_variable_internal (var->name, value_cell (var), binding_table, 0); - - /* XXX - should we set the context here? It shouldn't matter because of how - assign_in_env works, but might want to check. */ - if (binding_table == global_variables->table) /* XXX */ - var->attributes &= ~(att_tempvar|att_propagate); - else - { - var->attributes |= att_propagate; - if (binding_table == shell_variables->table) - shell_variables->flags |= VC_HASTMPVAR; - } - v->attributes |= var->attributes; - - dispose_variable (var); -} - -static void -propagate_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - if (tempvar_p (var) && (var->attributes & att_propagate)) - push_temp_var (data); - else - dispose_variable (var); -} - -/* Free the storage used in the hash table for temporary - environment variables. PUSHF is a function to be called - to free each hash table entry. It takes care of pushing variables - to previous scopes if appropriate. */ -static void -dispose_temporary_env (pushf) - sh_free_func_t *pushf; -{ - hash_flush (temporary_env, pushf); - hash_dispose (temporary_env); - temporary_env = (HASH_TABLE *)NULL; - - array_needs_making = 1; - - sv_ifs ("IFS"); /* XXX here for now */ -} - -void -dispose_used_env_vars () -{ - if (temporary_env) - dispose_temporary_env (propagate_temp_var); -} - -/* Take all of the shell variables in the temporary environment HASH_TABLE - and make shell variables from them at the current variable context. */ -void -merge_temporary_env () -{ - if (temporary_env) - dispose_temporary_env (push_temp_var); -} - -/* **************************************************************** */ -/* */ -/* Creating and manipulating the environment */ -/* */ -/* **************************************************************** */ - -static inline char * -mk_env_string (name, value) - const char *name, *value; -{ - int name_len, value_len; - char *p; - - name_len = strlen (name); - value_len = STRLEN (value); - p = (char *)xmalloc (2 + name_len + value_len); - strcpy (p, name); - p[name_len] = '='; - if (value && *value) - strcpy (p + name_len + 1, value); - else - p[name_len + 1] = '\0'; - return (p); -} - -#ifdef DEBUG -/* Debugging */ -static int -valid_exportstr (v) - SHELL_VAR *v; -{ - char *s; - - s = v->exportstr; - if (legal_variable_starter ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - for (s = v->exportstr + 1; s && *s; s++) - { - if (*s == '=') - break; - if (legal_variable_char ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - } - if (*s != '=') - { - internal_error (_("no `=' in exportstr for %s"), v->name); - return (0); - } - return (1); -} -#endif - -static char ** -make_env_array_from_var_list (vars) - SHELL_VAR **vars; -{ - register int i, list_index; - register SHELL_VAR *var; - char **list, *value; - - list = strvec_create ((1 + strvec_len ((char **)vars))); - -#define USE_EXPORTSTR (value == var->exportstr) - - for (i = 0, list_index = 0; var = vars[i]; i++) - { -#if defined (__CYGWIN__) - /* We don't use the exportstr stuff on Cygwin at all. */ - INVALIDATE_EXPORTSTR (var); -#endif - if (var->exportstr) - value = var->exportstr; - else if (function_p (var)) - value = named_function_string ((char *)NULL, function_cell (var), 0); -#if defined (ARRAY_VARS) - else if (array_p (var)) -# if 0 - value = array_to_assignment_string (array_cell (var)); -# else - continue; /* XXX array vars cannot yet be exported */ -# endif -#endif - else - value = value_cell (var); - - if (value) - { - /* Gee, I'd like to get away with not using savestring() if we're - using the cached exportstr... */ - list[list_index] = USE_EXPORTSTR ? savestring (value) - : mk_env_string (var->name, value); - - if (USE_EXPORTSTR == 0) - SAVE_EXPORTSTR (var, list[list_index]); - - list_index++; -#undef USE_EXPORTSTR - -#if 0 /* not yet */ -#if defined (ARRAY_VARS) - if (array_p (var)) - free (value); -#endif -#endif - } - } - - list[list_index] = (char *)NULL; - return (list); -} - -/* Make an array of assignment statements from the hash table - HASHED_VARS which contains SHELL_VARs. Only visible, exported - variables are eligible. */ -static char ** -make_var_export_array (vcxt) - VAR_CONTEXT *vcxt; -{ - char **list; - SHELL_VAR **vars; - - vars = map_over (visible_and_exported, vcxt); - - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -static char ** -make_func_export_array () -{ - char **list; - SHELL_VAR **vars; - - vars = map_over_funcs (visible_and_exported); - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ -#define add_to_export_env(envstr,do_alloc) \ -do \ - { \ - if (export_env_index >= (export_env_size - 1)) \ - { \ - export_env_size += 16; \ - export_env = strvec_resize (export_env, export_env_size); \ - } \ - export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ - export_env[export_env_index] = (char *)NULL; \ - } while (0) - -/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the - array with the same left-hand side. Return the new EXPORT_ENV. */ -char ** -add_or_supercede_exported_var (assign, do_alloc) - char *assign; - int do_alloc; -{ - register int i; - int equal_offset; - - equal_offset = assignment (assign, 0); - if (equal_offset == 0) - return (export_env); - - /* If this is a function, then only supersede the function definition. - We do this by including the `=() {' in the comparison, like - initialize_shell_variables does. */ - if (assign[equal_offset + 1] == '(' && - strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ - equal_offset += 4; - - for (i = 0; i < export_env_index; i++) - { - if (STREQN (assign, export_env[i], equal_offset + 1)) - { - free (export_env[i]); - export_env[i] = do_alloc ? savestring (assign) : assign; - return (export_env); - } - } - add_to_export_env (assign, do_alloc); - return (export_env); -} - -static void -add_temp_array_to_env (temp_array, do_alloc, do_supercede) - char **temp_array; - int do_alloc, do_supercede; -{ - register int i; - - if (temp_array == 0) - return; - - for (i = 0; temp_array[i]; i++) - { - if (do_supercede) - export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); - else - add_to_export_env (temp_array[i], do_alloc); - } - - free (temp_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++'. - - The order to add to the array is: - temporary_env - list of var contexts whose head is shell_variables - shell_functions - - This is the shell variable lookup order. We add only new variable - names at each step, which allows local variables and variables in - the temporary environments to shadow variables in the global (or - any previous) scope. -*/ - -static int -n_shell_variables () -{ - VAR_CONTEXT *vc; - int n; - - for (n = 0, vc = shell_variables; vc; vc = vc->down) - n += HASH_ENTRIES (vc->table); - return n; -} - -void -maybe_make_export_env () -{ - register char **temp_array; - int new_size; - VAR_CONTEXT *tcxt; - - if (array_needs_making) - { - if (export_env) - strvec_flush (export_env); - - /* Make a guess based on how many shell variables and functions we - have. Since there will always be array variables, and array - variables are not (yet) exported, this will always be big enough - for the exported variables and functions. */ - new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + - HASH_ENTRIES (temporary_env); - if (new_size > export_env_size) - { - export_env_size = new_size; - export_env = strvec_resize (export_env, export_env_size); - } - export_env[export_env_index = 0] = (char *)NULL; - - /* Make a dummy variable context from the temporary_env, stick it on - the front of shell_variables, call make_var_export_array on the - whole thing to flatten it, and convert the list of SHELL_VAR *s - to the form needed by the environment. */ - if (temporary_env) - { - tcxt = new_var_context ((char *)NULL, 0); - tcxt->table = temporary_env; - tcxt->down = shell_variables; - } - else - tcxt = shell_variables; - - temp_array = make_var_export_array (tcxt); - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - if (tcxt != shell_variables) - free (tcxt); - -#if defined (RESTRICTED_SHELL) - /* Restricted shells may not export shell functions. */ - temp_array = restricted ? (char **)0 : make_func_export_array (); -#else - temp_array = make_func_export_array (); -#endif - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - array_needs_making = 0; - } -} - -/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so - we will need to remake the exported environment every time we - change directories. `_' is always put into the environment for - every external command, so without special treatment it will always - cause the environment to be remade. - - If there is no other reason to make the exported environment, we can - just update the variables in place and mark the exported environment - as no longer needing a remake. */ -void -update_export_env_inplace (env_prefix, preflen, value) - char *env_prefix; - int preflen; - char *value; -{ - char *evar; - - evar = (char *)xmalloc (STRLEN (value) + preflen + 1); - strcpy (evar, env_prefix); - if (value) - strcpy (evar + preflen, value); - export_env = add_or_supercede_exported_var (evar, 0); -} - -/* We always put _ in the environment as the name of this command. */ -void -put_command_name_into_env (command_name) - char *command_name; -{ - update_export_env_inplace ("_=", 2, command_name); -} - -#if 0 /* UNUSED -- it caused too many problems */ -void -put_gnu_argv_flags_into_env (pid, flags_string) - intmax_t pid; - char *flags_string; -{ - char *dummy, *pbuf; - int l, fl; - - pbuf = itos (pid); - l = strlen (pbuf); - - fl = strlen (flags_string); - - dummy = (char *)xmalloc (l + fl + 30); - dummy[0] = '_'; - strcpy (dummy + 1, pbuf); - strcpy (dummy + 1 + l, "_GNU_nonoption_argv_flags_"); - dummy[l + 27] = '='; - strcpy (dummy + l + 28, flags_string); - - free (pbuf); - - export_env = add_or_supercede_exported_var (dummy, 0); -} -#endif - -/* **************************************************************** */ -/* */ -/* Managing variable contexts */ -/* */ -/* **************************************************************** */ - -/* Allocate and return a new variable context with NAME and FLAGS. - NAME can be NULL. */ - -VAR_CONTEXT * -new_var_context (name, flags) - char *name; - int flags; -{ - VAR_CONTEXT *vc; - - vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); - vc->name = name ? savestring (name) : (char *)NULL; - vc->scope = variable_context; - vc->flags = flags; - - vc->up = vc->down = (VAR_CONTEXT *)NULL; - vc->table = (HASH_TABLE *)NULL; - - return vc; -} - -/* Free a variable context and its data, including the hash table. Dispose - all of the variables. */ -void -dispose_var_context (vc) - VAR_CONTEXT *vc; -{ - FREE (vc->name); - - if (vc->table) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - - free (vc); -} - -/* Set VAR's scope level to the current variable context. */ -static int -set_context (var) - SHELL_VAR *var; -{ - return (var->context = variable_context); -} - -/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of - temporary variables, and push it onto shell_variables. This is - for shell functions. */ -VAR_CONTEXT * -push_var_context (name, flags, tempvars) - char *name; - int flags; - HASH_TABLE *tempvars; -{ - VAR_CONTEXT *vc; - - vc = new_var_context (name, flags); - vc->table = tempvars; - if (tempvars) - { - /* Have to do this because the temp environment was created before - variable_context was incremented. */ - flatten (tempvars, set_context, (VARLIST *)NULL, 0); - vc->flags |= VC_HASTMPVAR; - } - vc->down = shell_variables; - shell_variables->up = vc; - - return (shell_variables = vc); -} - -static void -push_func_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - - var = (SHELL_VAR *)data; - - if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate))) - { - /* XXX - should we set v->context here? */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0); - if (shell_variables == global_variables) - var->attributes &= ~(att_tempvar|att_propagate); - else - shell_variables->flags |= VC_HASTMPVAR; - v->attributes |= var->attributes; - } - - dispose_variable (var); -} - -/* Pop the top context off of VCXT and dispose of it, returning the rest of - the stack. */ -void -pop_var_context () -{ - VAR_CONTEXT *ret, *vcxt; - - vcxt = shell_variables; - if (vc_isfuncenv (vcxt) == 0) - { - internal_error (_("pop_var_context: head of shell_variables not a function context")); - return; - } - - if (ret = vcxt->down) - { - ret->up = (VAR_CONTEXT *)NULL; - shell_variables = ret; - if (vcxt->table) - hash_flush (vcxt->table, push_func_var); - dispose_var_context (vcxt); - } - else - internal_error (_("pop_var_context: no global_variables context")); -} - -/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and - all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ -void -delete_all_contexts (vcxt) - VAR_CONTEXT *vcxt; -{ - VAR_CONTEXT *v, *t; - - for (v = vcxt; v != global_variables; v = t) - { - t = v->down; - dispose_var_context (v); - } - - delete_all_variables (global_variables->table); - shell_variables = global_variables; -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping temporary variable scopes */ -/* */ -/* **************************************************************** */ - -VAR_CONTEXT * -push_scope (flags, tmpvars) - int flags; - HASH_TABLE *tmpvars; -{ - return (push_var_context ((char *)NULL, flags, tmpvars)); -} - -static void -push_exported_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - - var = (SHELL_VAR *)data; - - /* If a temp var had its export attribute set, or it's marked to be - propagated, bind it in the previous scope before disposing it. */ - if (exported_p (var) || (var->attributes & att_propagate)) - { - var->attributes &= ~att_tempvar; /* XXX */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0); - if (shell_variables == global_variables) - var->attributes &= ~att_propagate; - v->attributes |= var->attributes; - } - - dispose_variable (var); -} - -void -pop_scope (is_special) - int is_special; -{ - VAR_CONTEXT *vcxt, *ret; - - vcxt = shell_variables; - if (vc_istempscope (vcxt) == 0) - { - internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); - return; - } - - ret = vcxt->down; - if (ret) - ret->up = (VAR_CONTEXT *)NULL; - - shell_variables = ret; - - /* Now we can take care of merging variables in VCXT into set of scopes - whose head is RET (shell_variables). */ - FREE (vcxt->name); - if (vcxt->table) - { - if (is_special) - hash_flush (vcxt->table, push_func_var); - else - hash_flush (vcxt->table, push_exported_var); - hash_dispose (vcxt->table); - } - free (vcxt); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping function contexts */ -/* */ -/* **************************************************************** */ - -static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; -static int dollar_arg_stack_slots; -static int dollar_arg_stack_index; - -/* XXX - we might want to consider pushing and popping the `getopts' state - when we modify the positional parameters. */ -void -push_context (name, is_subshell, tempvars) - char *name; /* function name */ - int is_subshell; - HASH_TABLE *tempvars; -{ - if (is_subshell == 0) - push_dollar_vars (); - variable_context++; - push_var_context (name, VC_FUNCENV, tempvars); -} - -/* Only called when subshell == 0, so we don't need to check, and can - unconditionally pop the dollar vars off the stack. */ -void -pop_context () -{ - pop_dollar_vars (); - variable_context--; - pop_var_context (); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* 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 == 0) - 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; - set_dollar_vars_unchanged (); -} - -void -dispose_saved_dollar_vars () -{ - if (!dollar_arg_stack || dollar_arg_stack_index == 0) - return; - - dispose_words (dollar_arg_stack[dollar_arg_stack_index]); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; -} - -/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */ - -void -push_args (list) - WORD_LIST *list; -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bash_argv_v, *bash_argc_v; - ARRAY *bash_argv_a, *bash_argc_a; - WORD_LIST *l; - arrayind_t i; - char *t; - - GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); - GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); - - for (l = list, i = 0; l; l = l->next, i++) - array_push (bash_argv_a, l->word->word); - - t = itos (i); - array_push (bash_argc_a, t); - free (t); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC - array and use that value as the count of elements to remove from - BASH_ARGV. */ -void -pop_args () -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bash_argv_v, *bash_argc_v; - ARRAY *bash_argv_a, *bash_argc_a; - ARRAY_ELEMENT *ce; - intmax_t i; - - GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); - GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); - - ce = array_shift (bash_argc_a, 1, 0); - if (ce == 0 || legal_number (element_value (ce), &i) == 0) - i = 0; - - for ( ; i > 0; i--) - array_pop (bash_argv_a); - array_dispose_element (ce); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/************************************************* - * * - * Functions to manage special variables * - * * - *************************************************/ - -/* Extern declarations for variables this code has to manage. */ -extern int eof_encountered, eof_encountered_limit, ignoreeof; - -#if defined (READLINE) -extern int no_line_editing; -extern int hostname_list_initialized; -#endif - -/* 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. */ - -#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 - -/* This table will be sorted with qsort() the first time it's accessed. */ -struct name_and_function { - char *name; - sh_sv_func_t *function; -}; - -static struct name_and_function special_vars[] = { - { "GLOBIGNORE", sv_globignore }, - -#if defined (HISTORY) - { "HISTCONTROL", sv_history_control }, - { "HISTFILESIZE", sv_histsize }, - { "HISTIGNORE", sv_histignore }, - { "HISTSIZE", sv_histsize }, - { "HISTTIMEFORMAT", sv_histtimefmt }, -#endif - -#if defined (READLINE) - { "HOSTFILE", sv_hostfile }, -#endif - - { "IFS", sv_ifs }, - { "IGNOREEOF", sv_ignoreeof }, - - { "LANG", sv_locale }, - { "LC_ALL", sv_locale }, - { "LC_COLLATE", sv_locale }, - { "LC_CTYPE", sv_locale }, - { "LC_MESSAGES", sv_locale }, - { "LC_NUMERIC", sv_locale }, - - { "MAIL", sv_mail }, - { "MAILCHECK", sv_mail }, - { "MAILPATH", sv_mail }, - - { "OPTERR", sv_opterr }, - { "OPTIND", sv_optind }, - - { "PATH", sv_path }, - { "POSIXLY_CORRECT", sv_strict_posix }, - -#if defined (READLINE) - { "TERM", sv_terminal }, - { "TERMCAP", sv_terminal }, - { "TERMINFO", sv_terminal }, -#endif /* READLINE */ - - { "TEXTDOMAIN", sv_locale }, - { "TEXTDOMAINDIR", sv_locale }, - -#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) - { "TZ", sv_tz }, -#endif - -#if defined (HISTORY) && defined (BANG_HISTORY) - { "histchars", sv_histchars }, -#endif /* HISTORY && BANG_HISTORY */ - - { "ignoreeof", sv_ignoreeof }, - - { (char *)0, (sh_sv_func_t *)0 } -}; - -#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) - -static int -sv_compare (sv1, sv2) - struct name_and_function *sv1, *sv2; -{ - int r; - - if ((r = sv1->name[0] - sv2->name[0]) == 0) - r = strcmp (sv1->name, sv2->name); - return r; -} - -static inline int -find_special_var (name) - const char *name; -{ - register int i, r; - - for (i = 0; special_vars[i].name; i++) - { - r = special_vars[i].name[0] - name[0]; - if (r == 0) - r = strcmp (special_vars[i].name, name); - if (r == 0) - return i; - else if (r > 0) - /* Can't match any of rest of elements in sorted list. Take this out - if it causes problems in certain environments. */ - break; - } - return -1; -} - -/* 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; -{ - static int sv_sorted = 0; - int i; - - if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ - { - qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), - (QSFUNC *)sv_compare); - sv_sorted = 1; - } - - i = find_special_var (name); - if (i != -1) - (*(special_vars[i].function)) (name); -} - -void -sv_ifs (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable ("IFS"); - setifs (v); -} - -/* What to do just after the PATH variable has changed. */ -void -sv_path (name) - char *name; -{ - /* hash -r */ - phash_flush (); -} - -/* 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 (); - } -} - -/* What to do when GLOBIGNORE changes. */ -void -sv_globignore (name) - char *name; -{ - setup_glob_ignore (name); -} - -#if defined (READLINE) -/* What to do just after one of the TERMxxx variables has changed. - If we are an interactive shell, then try to reset the terminal - information in readline. */ -void -sv_terminal (name) - char *name; -{ - if (interactive_shell && no_line_editing == 0) - rl_reset_terminal (get_string_value ("TERM")); -} - -void -sv_hostfile (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v == 0) - clear_hostname_list (); - else - hostname_list_initialized = 0; -} -#endif /* READLINE */ - -#if defined (HISTORY) -/* What to do after the HISTSIZE or HISTFILESIZE variables change. - If there is a value for this HISTSIZE (and it is numeric), then stifle - the history. Otherwise, if there is NO value for this variable, - unstifle the history. If name is HISTFILESIZE, and its value is - numeric, truncate the history file to hold no more than that many - lines. */ -void -sv_histsize (name) - char *name; -{ - char *temp; - intmax_t num; - - temp = get_string_value (name); - - if (temp && *temp) - { - if (legal_number (temp, &num)) - { - if (name[4] == 'S') - { - stifle_history (num); - num = where_history (); - if (history_lines_this_session > num) - history_lines_this_session = num; - } - else - { - history_truncate_file (get_string_value ("HISTFILE"), (int)num); - if (num <= history_lines_in_file) - history_lines_in_file = num; - } - } - } - else if (name[4] == 'S') - unstifle_history (); -} - -/* What to do after the HISTIGNORE variable changes. */ -void -sv_histignore (name) - char *name; -{ - setup_history_ignore (name); -} - -/* What to do after the HISTCONTROL variable changes. */ -void -sv_history_control (name) - char *name; -{ - char *temp; - char *val; - int tptr; - - history_control = 0; - temp = get_string_value (name); - - if (temp == 0 || *temp == 0) - return; - - tptr = 0; - while (val = extract_colon_unit (temp, &tptr)) - { - if (STREQ (val, "ignorespace")) - history_control |= HC_IGNSPACE; - else if (STREQ (val, "ignoredups")) - history_control |= HC_IGNDUPS; - else if (STREQ (val, "ignoreboth")) - history_control |= HC_IGNBOTH; - else if (STREQ (val, "erasedups")) - history_control |= HC_ERASEDUPS; - - free (val); - } -} - -#if defined (BANG_HISTORY) -/* Setting/unsetting of the history expansion character. */ -void -sv_histchars (name) - char *name; -{ - char *temp; - - 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 */ - -void -sv_histtimefmt (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - history_write_timestamps = (v != 0); -} -#endif /* HISTORY */ - -#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) -void -sv_tz (name) - char *name; -{ - tzset (); -} -#endif - -/* If the variable exists, then the value of it can be the number - of times we actually ignore the EOF. The default is small, - (smaller than csh, anyway). */ -void -sv_ignoreeof (name) - char *name; -{ - SHELL_VAR *tmp_var; - char *temp; - - eof_encountered = 0; - - tmp_var = find_variable (name); - ignoreeof = tmp_var != 0; - temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; - if (temp) - eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; - set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ -} - -void -sv_optind (name) - char *name; -{ - char *tt; - int s; - - tt = get_string_value ("OPTIND"); - 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; - } - else - s = 0; - getopts_reset (s); -} - -void -sv_opterr (name) - char *name; -{ - char *tt; - - tt = get_string_value ("OPTERR"); - sh_opterr = (tt && *tt) ? atoi (tt) : 1; -} - -void -sv_strict_posix (name) - char *name; -{ - SET_INT_VAR (name, posixly_correct); - posix_initialize (posixly_correct); -#if defined (READLINE) - if (interactive_shell) - posix_readline_initialize (posixly_correct); -#endif /* READLINE */ - set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ -} - -void -sv_locale (name) - char *name; -{ - char *v; - - v = get_string_value (name); - if (name[0] == 'L' && name[1] == 'A') /* LANG */ - set_lang (name, v); - else - set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ -} - -#if defined (ARRAY_VARS) -void -set_pipestatus_array (ps, nproc) - int *ps; - int nproc; -{ - SHELL_VAR *v; - ARRAY *a; - ARRAY_ELEMENT *ae; - register int i; - char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; - - v = find_variable ("PIPESTATUS"); - if (v == 0) - v = make_new_array_variable ("PIPESTATUS"); - if (array_p (v) == 0) - return; /* Do nothing if not an array variable. */ - a = array_cell (v); - - if (a == 0 || array_num_elements (a) == 0) - { - for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - return; - } - - /* Fast case */ - if (array_num_elements (a) == nproc && nproc == 1) - { - ae = element_forw (a->head); - free (element_value (ae)); - ae->value = itos (ps[0]); - } - else if (array_num_elements (a) <= nproc) - { - /* modify in array_num_elements members in place, then add */ - ae = a->head; - for (i = 0; i < array_num_elements (a); i++) - { - ae = element_forw (ae); - free (element_value (ae)); - ae->value = itos (ps[i]); - } - /* add any more */ - for ( ; i < nproc; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } - else - { - /* deleting elements. it's faster to rebuild the array. */ - array_flush (a); - for (i = 0; ps[i] != -1; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } -} -#endif - -void -set_pipestatus_from_exit (s) - int s; -{ -#if defined (ARRAY_VARS) - static int v[2] = { 0, -1 }; - - v[0] = s; - set_pipestatus_array (v, 1); -#endif -} diff --git a/xx b/xx deleted file mode 100755 index 5420d3737f950a57b42edd8b91ff6c3c631c569f..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc-jL100001 literal 16288 zc-rk-eQ;D)6+drx^93mh6>OCdUTRtsTi8uVVaW$B5ZWLV89|HH>C4OROR~-G+vV+B z*wCff0Ifi=-4;5-D5a@`jE-NWYQ<3z=!YF0tDT`Eb=nTCj#H;p8B06WV&m_A>}E+e zr1cNSKi-+Sdw=iVbI&>VeB33=eeb{dujh#9N)qHkt0XF|NBb<1vEdE3g* zeU=KSnkFHSSf}jOv<)jaZWzBtm6-QsXeF|drrAcy9^;<4{^KoR?I)VnB5mcA;VN@$ z;^AOoFxnG~XbC&nGf~F8gQBlGc&Q93m#|*b3Ir6jV@esb3hZD~nu^O%G81KZaxzp+ z3npwUZ1zp+kGdLsoFST7Qz&B`ma*tuwqaS}T3BcaRgh0Vf;YH0Gk z1Y^-?%)E>Y#FE+zYM{XXmtfS>npJC8uk2ivk7Yo{fcdm)M8-lXkTpZtN0r`W!tzGK zJ>Ib`F+Z_-xcbxaQy1uFu`VjnjuDN6j$RA%f`uzwSl$RXh?cT>Y@veN@=H zc%59&>hCdWcY`?d9CFAZhyFh(-8wzxuN%F%p^jSoc+TRa+Fv(%BC{2zPAgES0CrT}OU7JbE6y<=`Dz{s@%}z3w`aPR~iDAO1utef;`V7b!>E zHKKjnXYb_wH)ikR{i)e|S)W-x`=#OS_-@-vwCp%lZrklXvNq$XlXGW^&2^FI-)w$( z`|JZ5oVMP~_<4F;&hIZa-#&yr1xpY6hbaL2jEqhJ?+(sW4%x$O|5E?yEWR;@JBYSj zvpVJ74W2_3T7s|kCHMx}RRO-zoO{j#Fs$#bCg{n@ z?B5pVdR3k`kB(l**_vKDJ(azSQrSb4hD-&z8W4w%rMu^(vb7Y*+>Ta@c^7#kP6L-S z4E+r(MmvrJcPsPZi<8-HRLyYa5Zkl+flM9jQdqvakNgaJ*`Bx!Cr95cY6HvvTI!PW zHeo#AhaDK}gwD>4OT;E{h~*2V_}FrmFR%}G4sGXiYYN88nay&%B`1UF7+%U{cHy}? zi+qxp$!|dHYY^X~IXQmD0~=P4j;6=PlC-Q~B8A8EbF6 z#5eHAWWLGe6YAwvQ5#o!Ah(>y2dzL~V8q4#0qR+LeTH0thq;ex_?n)XPhtJA#3z71 z|6%pB++#Xrj5;$SCV`<$bzs>+uIoTX#Hx$=h53%n1;kuL*gkWYzlR=ce*`|=={lP^ z4jHe2_kDgIoa8=(48$t{`x_>%aTC^bVGZMd0CH!sHGbFVDASAh>|%NmFGa@d%gAd2 zUkTeA+sn3o*O86^oFCZt-S<|fWn9!r=DVku@0?=3VT$?6%g6!XWXm_Inh zd}fOI&=m7sx%sib9kpmIq}hfQ)q0a=Fi|kB4;Wg=i0Fd`XG%s4Eo_GEupS9-H7qTt zMZlCZ6aA%~|C#v1?{)us6v{yfe3=ZixQIpmN- z4msqILk>CQkVE|clYKjhY6C=b>xpVcvaV;lv#uutS=XCqv#w(*+DKMe)Sabj%2u4C ztkRC>wvj9?&SdHI$Ot{ZVT5L$K)X0XZJ`mWUQ=9GP0I1NLk>CQkV6hR8u;fDKLh-f#J>VQBk`|+&r19|;6F?Jd*F8^evxPnN&GUfN8(q2 zua@`?U{&ICz&?rJ1a6o3Ja9nbe*mwO_$}aWi7x<$Bz_w>CGk7Jy9#)6K7oyM4omz` z;O|QO9`KI@R^Z(^CnTN@{F20#z>wuxQJ?p@=hm^9dV(8DtoG6rrja(lt~f?O&U;~c|^TA4pAwzau>f&b>^_^$w#{%7w! z%**9`6>u)+;e&bcg0=RT%y~N{hHvKWmw2{#-=_3jecqn3tH$!J?3#>t=K{LQZUeqk zj`tVv3`-uIhh@7ZMtsX26gj~5Rkly$0Mk{rU*-TCe<+k6Cr?!=vtQi*mzbRi$tod- z?RS7_nA@62m9TW{GhI zDp`ry`$*rB7_nBKl^ExP@|wgr8(nURaaOpll^C_{S|u^7)mxnmCp@VPS-IE z#H#Y&3-t9XNKx2t%;0$xnAmT}IOih*^WTtvBk)Wn=W)S*40gI+kQk-ndXHme5za$* zg}`m#aeD=BXZTi*E6%ZVK@n@8gwNf#b4-ijXV)D<*Yg{IHwm6+nM_OYoMv)*1!l2u zZIQNJBz{F#S%r2V8oo1>zo5O2hBH{fd8>fOjmmW6Y;k`P?GI=$#&ZoC&YqILK_IKm zuabDDgq_=8LEDY?AR0Tn??u~#1|9Ukf5Cr0+C6Cd&{)0P%_5<#-MGx^3(9^oX`04v zoSAym$lZ5i*Wa{AEH;pg=Z4sIH!aw21P3sZuyxBO%`i8It(Zxifxm{=6E;I(vrp?c zB5}ha$;aL@v$ljytuGi{2xW$4^o0|)VQIYfZW}4q z2X#Bh7=uQf3D+z=oG>OCX8W}-KdFU7hG~cGL2yN4!2wN==vEYah(|CKifK_DOU;-a z?j6)Z%xdB9aWiHNyES2RV!{-=Ovvsa8nzLdFv%8aF*7J6CX7vHEO8l?MHt3uF2XUv zfFe8vb{LjrBC5jMoafRwMfI>ra8S?)Z-x`~Xgp#h3bLRt66?_;x%3;$7?zs7F-y}! zhL=d`ygnDacZ#2fk5hJvK5JG5&hwNBE zMHCEvpgQFnX}zhzcSBQS2mhqav2du>7FfsG(z*_~xv|6I-J}}@>t@cnu(9J)=vqW~ zqgZ%jV{ZF6XX27ixQ~mKe&U=IZWX#H&Ou8fZQ=kc*oEF!z(qp(;>M0%VJY$VJrOc~ z@0VwXxc6IZuvIRK3sG#bI7eG=7K+7b%AcTA9*w!ju_Km`z`O|+!6*E}#wEf=NG*EE zNmeQn&erw9ybl-D+$wRBNA#_OxtDQs2RaTnYfz*Lp|Vk2Q4|2HtMOkLxqPCW-lU1o zkf_mo(Q5r*F3M6^w1SJj)S0k?UeuNz@%HG6e*Q7P+2?EVH8n5sQYtku+t~q=OH+$? zlO|#=sSsazjk;ANu*gl3NNv7C!qdXVd1|9Xc&nl1Q!^4X`_!bF2=|#rNX>~yB1pkx IHc24pKRn!$bpQYW diff --git a/xx.c b/xx.c deleted file mode 100644 index 8236c0553..000000000 --- a/xx.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -main() -{ - size_t wstrlen, n, n1; -#ifdef BUG - size_t n, n1; -#else - int n, n1; -#endif - - wstrlen = 4; - - for (n = 0; n < wstrlen; n++) { - for (n1 = wstrlen; n1 >= n; n1--) { - fprintf(stderr, "n = %lu n1 = %lu wstrlen = %lu\n", n, n1, wstrlen); - if (n1 > wstrlen) { - fprintf(stderr, "n1 (%lu) > wstrlen (%lu)\n", n1, wstrlen); - break; - } - } - } - exit (0); -} diff --git a/xx.o b/xx.o deleted file mode 100644 index 74d00e264dc39bd026207343cd93a8d337064b98..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc-jL100001 literal 1856 zc-nL| z0Jee{3}*m9(ONot4{ZlC&~IEw=#+CESvYq}HK*mt`S|hN_&)@nMLa0D<#UwVTnPGN zD&?X*H(i)9ZD+O+Z^MD{pkr)Ia0JIthL9s9?JDO+-pTvVkr^2u`74KALIx_Z#^AhY zJJqr^xn?dN$Drg;dccqHVFS)F>9a#ls)e1t*ft~h5I-HOSLZ`Y{pIV%&m{(-+xr?1 z=Z|fujXr>m#qUa8qvZC0P6dWCqtuhd6*c z%CcGko(??#(5|td`vN(>pzm+c(dP=rP^`Xq6?FYR^tFizV@wuf$p19X9*WVFMuYY} z*=XFLeKiFboe}j34R06yIw&{FWnoIG4_}~M1NG~-z*)E%sGo9!>KgXkirrF&)&1tI zYQ-hEh~;IL6_dLM#_daP;j^sav||0Dj+Hz=1$J^{dg!G<0QTQ4r&6FLi%j`rJB zBR>0*&{Wh8m<9sVI<_I4o-Y$EU8E&2Dj@vrsV^_R$I>RT#m*x8RmJegn zCxdvs#CYFq>no8v=Eb&sWh;G=^@N)}l5IDd>%h8Occr!<9AM(T)9Cl%&ZZBa&X+AP z=1hZAL*|9DWnf$6Qzf%fqJG5f6TnNgvIG2l1v{p59-^~$HELIjQFEr4H=~8TJ>`84 zCStKvES@+Tg<9=U5hjbp1TW4^SITC|I0UrQ;EBFie>^f=^+ft$BAyyZX~`ogE!~6z zX~1m;9nS^ia~VV}5gEpBQbZ>s>6m|@mK=a M5s<|AKqV044{M+zH~;_u diff --git a/xx2 b/xx2 deleted file mode 100755 index fcc08aac8e949f0ac3b63f66f8d17d1a1ec28342..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc-jL100001 literal 16288 zc-rk-dvH`&8UOC?<^?GU6)H*yH!ZEf7IqU-Sn|LHLK}o4BWTe&y}8-FNp7=ycYF6P zZ0OQ#fL2Pe-3oOWr8ISr(eYKPRvZ<9KJ4gN?F=2MQ#-UePMx;ev5%=18-M4qn=YjVrHT^Z7NO z{uC8aElol`u};~iX`9z<**t!YDlzXX(8^>ZO>>O2GsZn}{YP8C+D|mCMcT?K%T?yr zB+PJfFxC@~YDp*6Gf~F;L!z%abfFBYlyHHj6$vP5$CNT=71_b0G?kX2WGBk-RIPJ9=>}O08#$)$#g@ z)`lIdU(9(a1&j!e-$^H8S~L z!tq!vZe2tMVoB{qHBjXL3ozHA2+|fu)ieV9D_04 z>0ix*x_D)gYcALV@+Z)Z{s6)TT~-6+mHmt1nmrT-7gv`$Y48%ED>ZlIPRo^v><4m6CO%x=di`Bn0@g-N;b zw%XRrkw47pBB~lXN0pgM&(U8DkG>AxO7M=XdXUP7UiKW#Wag$b4_uMXoVYsOMar>u zjcEVQ*}HlF_1SxPe|q*l)@N7Eetvi-zT5T@tvo^1JMQux-H`P)$hotn=DNuDZ#F-? zbN0b3PFsI={5-uS=MR*cZy&;*!sSPT!xVyjMpmbge;4PegzRCqf2sdW4&NBV9Yi}W zUzhgZ1)jqcS&pyv<@g5KQw6_Kg~R0^ra;EC<$LnkAA+nM>n@$Oe1H_THd9rYqtM~e zv;Mt&O?7Y@DX_OPJ5T7$d1mK^o_r&nt(SHmrrO=*9q;_Cm!vlfH zHFrbzom9!jf+Msc2>so=8~TIYy(-U}heqGb+nQN1J)OIq(z(NwflLLu8WD$&WV+|3bM+L;-i%g{c@Oy{&Hz_3 z4E>EPM!QY`cPoqFi&MEBRLgMoFx#{DzH9^RQdquvkNy;T*`Bx!r$*l?X#>mudg_w$ zZpC;g2s<#=37wr;kBCj^Fv}N8^RZPdUtk~X9NNj}))$ReGMnXiOI`-kF}#Ay?80+x z4*4W8li!Hg*CD>g@^XTV2R5u59nFmG5A%>CbEQSDua?hs`RDBI)Rn3BrVFvhGuB>v zfp6fC$$XQ~C)CS}qBbt|L2f0F4_cAF(1?fq1Jt+T>MVIe4{#sV@ijd&AIJJ(iBAH5 z=7Z{IxyN+M7w z3CMT>yzlYz;1u^6WFTH4*xxvDjhC>d3u_qveULkgtqFQYN10y4XAjehcquYoUqD_H z_{!Mc*j{$@dyaMt;QYY8@3^}*Bjch@GT%MLeCHJNjZ@55Uwppi^(p4hOfi3aiuprR z%x9;Vk4!P&m7gE`+fj?fBbsB_F|9Xcg_A|&`hcNDjHo_naHdq$&`is8Og(CDH*77e zN283LHuoFqfMHukR86K5iMZ{ky>VN0FdP}Q^q3h|qoxH8)l8~Z+))#@ku)qvb>ga> zvcQP(gdOj*_1NNRM3&m2UKvfPR+9wVl8zlUMfL&NUnBeV;%|KKZ4rKfnB8Ob?#dQ4 zd%sbHe=K?WfsYsAXNvIO+sF9do55~(Q=pc}_aTYdU0>={=n=us@y~(xNqiDGC-EuZ zgA$(x9+CKQ;BQL&1n|!!eiHa`iGK-vR^nd)pOg5vz<-wbcfjvR{2b9-lK79nK8ard zo+I%qz^cTr0tY014Y*z6*MUP4{{wiV#BTt1OZ+BqMB=xA(-OZ8yr+mK?-STK_lU&* z1pbc1?*ji&UBT9ai@76@T0)T zfa`%z7xDk52tNm&9}vH5?RyEB*)k3I72rpS-|hFk3I3lDzdT=d$w`qX*jL$%a~w0< z%4!yHc?uh^olzL)_Fq+m7sAYHiLVB(lbGc)>Z9zc1qJ@HRasI#CiQ+&=w)lm)(O3J zh*#Nqp_gCdxdDM)Bp%Cd0$wb!3GA0Rt;!4GzH-zzZtZLs`DLT^2Cqx@_UexbeSd_gXii*b$-!+M!N?CyJgzFsaNnxE&N0WAGb zHNg3t$G+$1bABdpqG+u%CUgF7iDv^JkoYq3zD@aS3kvpB%o)qKiYv0>oeSuyxC!_+ zIc^s5?97VydvG3B?3Ebtt=KPefbFZ|fXD%+tKxo{18n>&k-|9nYRcJO#QlGX*_n{4 z5pvjmXUTDvlP7BUr5*l$$xB}Tt^j{u=WRKT{VG+!j2|_ws1hURl@5s!Yb7i(e4=cX z7-yi8lbF4a^lga|Yvn14aXu(7NsP16J9? zbsPinn!@)2eeDub6!sf4cpd^K_S-Se`KZABH{@RnJd??JMDQPnot|eUMyYt-N2cR3o)p0d9| zAgj$Uk$9(so!ehTy9@2hXzc918*MKdbkKeO1^>NhccSe_WA$mb zX&Sq6X6Z2_f8UK=f77Dz_&_R=A7a9>7S_(QSt`!`f=vaf>(ue+{q4v?8X} zr}Z1rgkh89V{e(++e}OA3x}6LnPD4!X3{Zit=EQD$nK3Zt^s2()@N&xZMxmttQDA& zM%XdqR+7D)m58R2+!prW^xK9mO|#=E$F$fEV*Q$tHo_^#fEjwkU~iMfdu|D@<*RhZ zNV7hyJ7LBcHWEy@X6t6sm}Hpk*SYwlW=0IlF`YqhMdRTCO^@n!40}jKF%*ewF&#^- zxMTJXY7u6&@b|bGD~{b-usJzlid`mTcMuK7h)kGdi?p~E77~-jtyVmF5tStv#%V6W zF~NWmJVkaGwrwG*!rPqZ!Z^ir(;_%1Y?xc&L_L;>8p)z8=!?dC^k_c)#xjPbW^dfq z^avs!)BB9cS!^Q~hwMBT*Ds{gm>R>;bQsNphB^ov$>cT!Q@(~MxssAAWtHaBd*U`v zswn0OX>BltTJk#Jgl$?*uc(E^Ny0;`)6`)%wJmCHYFXA2T(Yz!*j9kc+9=$w+pSJ> zhuz#3XlrW52>Ca~Q+C)`4L2J8)yWiVi&~cYC!GjGSC~+5&FqcFgc&s=iwPlwc6i8% z7ga>j;QOjmzLD1J8UxofE$rZ*v^8!$#Y#VMPBL4CE=q9FvXE}&04vyq-d4b+Li)0W9lgR*;_rJR zWc=PQ&kk|#x71*(T$B)^*kW;xwq7q3i_?@pL8&|%^N(XkEFXb+6DopF1ci;ug^iF} z@{p6PR3e -#include -#include - -main() -{ - size_t wstrlen; - int n, n1; - - wstrlen = 4; - - for (n = 0; n < wstrlen; n++) { - for (n1 = wstrlen; n1 >= n; n1--) { - fprintf(stderr, "n = %lu n1 = %lu wstrlen = %lu\n", n, n1, wstrlen); - if (n1 > wstrlen) { - fprintf(stderr, "n1 (%lu) > wstrlen (%lu)\n", n1, wstrlen); - break; - } - } - } - exit (0); -} diff --git a/xx2.o b/xx2.o deleted file mode 100644 index cf85b3c2c6469929f8cea287555990f10a39757c..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc-jL100001 literal 1856 zc-nXYt@cP{czIdhjkD8sF?pleJB8VD^1)-h1E7n|<@ve*O6X z0DFNCg3|*aDJ`9Rgtmid=$GaaI>p?^ERn$_~8G<_zM-bC<~$Ag4hzC_t$gVz;P zF6GUIx!k;NTGd>*4F|@9im@Ti;k|&;ha5g(mnqei=jWktkyuJcf8=>OrE#t&Yg=f#F| zY~$`03cVy6BVYuirL)uMqIvJ<@oz zc&fX0`XO{I|B&hmOYRV;tiVtvZ8oPsUAA|t6ZgTF0=S23D%w&un^TZP8>rl-k5K^o zG)XBrcs}+JK)FG@_ABK0hQ4c{qR%yqVX^A+bx_p@FxV!>k1;8XVg46!_Ocj7YBbos z=NgS$Y+pqJ!p?~Lq=L7LejO|~mdnztR3E>@a`n`2-T`arwx@pH_R3q>GwXIk9+!{m zRoMs&a2d->FNozX!1X}{0r^zZ;^c%SRU&vdlk zWi{fmuW+5Dcul~f;L%x4yZmOkPP~F=dIQg-n+NSN)F-)}c+oy2^bFI{-plG;#IK@# zyUpxpQ zM6#X!07=AM0^@y?o;N&q%!~AXC+mHY^!b}TlJslMbs)Q1cO|zV93%X_voYktolPG) zmn|8fE$A9$4VmUjhK6mC&KC4?f%PM5o&{Q{l`Nn$W$c*N3Lai1V$wM)pkI?-5T)Ctdv=Lxi#m^3ghQfjIiX#%kk#KA@rbJJ~ zltdGbCII(|TaF8e_Yy}f5*WvClt)JciI97s79DMl1em2O10nq1-qFgo1Qqd@A R@;ZGq01h#3V}u28#$ReLB0&HE -- 2.47.3